diff --git a/FLINT/Data/Sources/DTO/User/NicknameCheckDTO.swift b/FLINT/Data/Sources/DTO/Auth/NicknameCheckDTO.swift similarity index 81% rename from FLINT/Data/Sources/DTO/User/NicknameCheckDTO.swift rename to FLINT/Data/Sources/DTO/Auth/NicknameCheckDTO.swift index 0b81c4d2..55d5d73b 100644 --- a/FLINT/Data/Sources/DTO/User/NicknameCheckDTO.swift +++ b/FLINT/Data/Sources/DTO/Auth/NicknameCheckDTO.swift @@ -16,7 +16,7 @@ public struct NicknameCheckDTO: Codable { extension NicknameCheckDTO { public var isAvailable: Bool { get throws { - return try unwrap(available, key: CodingKeys.available) + return try unwrap(available) } } } diff --git a/FLINT/Data/Sources/DTO/Auth/SignupDTO.swift b/FLINT/Data/Sources/DTO/Auth/SignupDTO.swift index 0692df63..e4080763 100644 --- a/FLINT/Data/Sources/DTO/Auth/SignupDTO.swift +++ b/FLINT/Data/Sources/DTO/Auth/SignupDTO.swift @@ -1,5 +1,5 @@ // -// File.swift +// SignupDTO.swift // Data // // Created by 김호성 on 2026.01.21. @@ -19,16 +19,16 @@ extension SignupDTO { public var loginEntity: LoginEntity { get throws { return try LoginEntity( - accessToken: unwrap(accessToken, key: CodingKeys.accessToken), - refreshToken: unwrap(refreshToken, key: CodingKeys.refreshToken), - userId: unwrap(userId, key: CodingKeys.userId) + accessToken: unwrap(accessToken), + refreshToken: unwrap(refreshToken), + userId: unwrap(userId) ) } } public var userIdValue: String { get throws { - return try unwrap(userId, key: CodingKeys.userId) + return try unwrap(userId) } } } diff --git a/FLINT/Data/Sources/DTO/Auth/SignupRequestDTO.swift b/FLINT/Data/Sources/DTO/Auth/SignupRequestDTO.swift index f8873627..3a256ef7 100644 --- a/FLINT/Data/Sources/DTO/Auth/SignupRequestDTO.swift +++ b/FLINT/Data/Sources/DTO/Auth/SignupRequestDTO.swift @@ -1,5 +1,5 @@ // -// File.swift +// SignupRequestDTO.swift // Data // // Created by 김호성 on 2026.01.23. @@ -7,7 +7,7 @@ import Foundation -import Domain +import Entity public struct SignupRequestDTO: Codable { public let tempToken: String diff --git a/FLINT/Data/Sources/DTO/Auth/SocialRegisterDTO.swift b/FLINT/Data/Sources/DTO/Auth/SocialRegisterDTO.swift deleted file mode 100644 index 18400a77..00000000 --- a/FLINT/Data/Sources/DTO/Auth/SocialRegisterDTO.swift +++ /dev/null @@ -1,13 +0,0 @@ -// -// File.swift -// Data -// -// Created by 김호성 on 2026.01.23. -// - -import Foundation - -struct SocialRegisterDTO { - public let isRegistered: Bool? - public let tempToken: String? -} diff --git a/FLINT/Data/Sources/DTO/Auth/SocialVerifyRequestDTO.swift b/FLINT/Data/Sources/DTO/Auth/SocialVerifyRequestDTO.swift index 16bcb5c4..989a6878 100644 --- a/FLINT/Data/Sources/DTO/Auth/SocialVerifyRequestDTO.swift +++ b/FLINT/Data/Sources/DTO/Auth/SocialVerifyRequestDTO.swift @@ -1,5 +1,5 @@ // -// File.swift +// SocialVerifyRequestDTO.swift // Data // // Created by 김호성 on 2026.01.23. diff --git a/FLINT/Data/Sources/DTO/Auth/SocialVerifyResponseDTO.swift b/FLINT/Data/Sources/DTO/Auth/SocialVerifyResponseDTO.swift index c78acbbb..cb98ee2d 100644 --- a/FLINT/Data/Sources/DTO/Auth/SocialVerifyResponseDTO.swift +++ b/FLINT/Data/Sources/DTO/Auth/SocialVerifyResponseDTO.swift @@ -1,5 +1,5 @@ // -// File.swift +// SocialVerifyResponseDTO.swift // Data // // Created by 김호성 on 2026.01.23. @@ -16,15 +16,6 @@ public struct SocialVerifyResponseDTO: Codable { public let userId: String? public let nickname: String? public let tempToken: String? - - public init(isRegistered: Bool, accessToken: String?, refreshToken: String?, userId: String?, nickname: String?, tempToken: String?) { - self.isRegistered = isRegistered - self.accessToken = accessToken - self.refreshToken = refreshToken - self.userId = userId - self.nickname = nickname - self.tempToken = tempToken - } } extension SocialVerifyResponseDTO { diff --git a/FLINT/Data/Sources/DTO/Base/BaseResponse.swift b/FLINT/Data/Sources/DTO/Base/BaseResponse.swift index e8b3903b..cd097c8a 100644 --- a/FLINT/Data/Sources/DTO/Base/BaseResponse.swift +++ b/FLINT/Data/Sources/DTO/Base/BaseResponse.swift @@ -1,5 +1,5 @@ // -// BaseResponseDTO.swift +// BaseResponse.swift // FLINT // // Created by 진소은 on 1/10/26. diff --git a/FLINT/Data/Sources/DTO/Base/Unwrap.swift b/FLINT/Data/Sources/DTO/Base/Unwrap.swift index 957097e2..e59ef5db 100644 --- a/FLINT/Data/Sources/DTO/Base/Unwrap.swift +++ b/FLINT/Data/Sources/DTO/Base/Unwrap.swift @@ -1,5 +1,5 @@ // -// File.swift +// Unwrap.swift // Data // // Created by 김호성 on 2026.01.21. @@ -21,12 +21,11 @@ public enum DTOMappingError: Error, LocalizedError { } } -public func unwrap( - _ value: T?, - key: CodingKey? = nil -) throws -> T { - guard let value else { - throw DTOMappingError.missingField(key?.stringValue) +extension Decodable { + public func unwrap(_ value: T?) throws -> T { + guard let value else { + throw DTOMappingError.missingField("\(self)") + } + return value } - return value } diff --git a/FLINT/Data/Sources/DTO/Bookmark/CollectionBookmarkUsersDTO.swift b/FLINT/Data/Sources/DTO/Bookmark/CollectionBookmarkUsersDTO.swift deleted file mode 100644 index d3645e25..00000000 --- a/FLINT/Data/Sources/DTO/Bookmark/CollectionBookmarkUsersDTO.swift +++ /dev/null @@ -1,82 +0,0 @@ -// -// CollectionBookmarkUsersDTO.swift -// Entity -// -// Created by 소은 on 1/23/26. -// - -import Foundation - -import Entity - -public struct CollectionBookmarkUsersDTO: Codable { - public let status: Int? - public let message: String? - public let data: DataDTO? - - public init(status: Int?, message: String?, data: DataDTO?) { - self.status = status - self.message = message - self.data = data - } -} - -// MARK: - Nested DTOs -public extension CollectionBookmarkUsersDTO { - - struct DataDTO: Codable { - public let bookmarkCount: Int? - public let userList: [UserDTO]? - - public init(bookmarkCount: Int?, userList: [UserDTO]?) { - self.bookmarkCount = bookmarkCount - self.userList = userList - } - } - - struct UserDTO: Codable { - public let userId: String? - public let nickName: String? - public let profileImageUrl: String? - public let userRole: String? - - public init(userId: String?, nickName: String?, profileImageUrl: String?, userRole: String?) { - self.userId = userId - self.nickName = nickName - self.profileImageUrl = profileImageUrl - self.userRole = userRole - } - } -} - -extension CollectionBookmarkUsersDTO { - public var entity: CollectionBookmarkUsersEntity { - get throws { - return try unwrap(data).entity - } - } -} - -extension CollectionBookmarkUsersDTO.DataDTO { - public var entity: CollectionBookmarkUsersEntity { - get throws { - return CollectionBookmarkUsersEntity( - bookmarkCount: bookmarkCount ?? 0, - users: try (userList ?? []).map { try $0.entity } - ) - } - } -} - -extension CollectionBookmarkUsersDTO.UserDTO { - public var entity: CollectionBookmarkUserEntity { - get throws { - return CollectionBookmarkUserEntity( - userId: userId ?? "", - nickname: nickName ?? "", - profileImageUrl: URL(string: profileImageUrl ?? ""), - userRole: userRole ?? "" - ) - } - } -} diff --git a/FLINT/Data/Sources/DTO/Collection/CollectionDTO.swift b/FLINT/Data/Sources/DTO/Collection/CollectionDTO.swift new file mode 100644 index 00000000..19214e6c --- /dev/null +++ b/FLINT/Data/Sources/DTO/Collection/CollectionDTO.swift @@ -0,0 +1,45 @@ +// +// CollectionDTO.swift +// Data +// +// Created by 김호성 on 2026.02.09. +// + +import Foundation + +import Entity + +public struct CollectionDTO: Codable { + public let id: String? + public let thumbnailUrl: String? + public let title: String? + public let description: String? + public let imageList: [String]? + public let bookmarkCount: Int? + public let isBookmarked: Bool? + public let userId: String? + public let nickname: String? + public let profileImageUrl: String? +} + +extension CollectionDTO { + public var collectionEntity: CollectionEntity { + get throws { + return try CollectionEntity( + id: unwrap(id), + thumbnailUrl: URL(string: thumbnailUrl ?? ""), + title: title ?? "", + description: description ?? "", + imageList: imageList?.compactMap({ URL(string: $0) }) ?? [], + bookmarkCount: bookmarkCount ?? 0, + isBookmarked: isBookmarked ?? false, + user: UserProfileEntity( + id: unwrap(userId), + nickname: nickname ?? "", + profileImageUrl: URL(string: profileImageUrl ?? ""), + role: .unknown + ) + ) + } + } +} diff --git a/FLINT/Data/Sources/DTO/Collection/CollectionDetailDTO.swift b/FLINT/Data/Sources/DTO/Collection/CollectionDetailDTO.swift index c2c0f21e..921adc06 100644 --- a/FLINT/Data/Sources/DTO/Collection/CollectionDetailDTO.swift +++ b/FLINT/Data/Sources/DTO/Collection/CollectionDetailDTO.swift @@ -10,41 +10,25 @@ import Foundation import Entity public struct CollectionDetailDTO: Codable { - - public let status: Int? - public let message: String? - public let data: DataDTO? - - public init(status: Int?, message: String?, data: DataDTO?) { - self.status = status - self.message = message - self.data = data - } + public let id: String? + public let title: String? + public let description: String? + public let thumbnailUrl: String? + public let createdAt: String? + public let isBookmarked: Bool? + public let author: AuthorDTO? + public let contents: [ContentDTO]? } -// MARK: - Nested DTOs - -public extension CollectionDetailDTO { - - struct DataDTO: Codable { - public let id: String? - public let title: String? - public let description: String? - public let thumbnailUrl: String? - public let createdAt: String? - public let isBookmarked: Bool? - public let author: AuthorDTO? - public let contents: [ContentDTO]? - } - - struct AuthorDTO: Codable { +extension CollectionDetailDTO { + public struct AuthorDTO: Codable { public let id: String? public let nickname: String? public let profileImageUrl: String? public let userRole: String? } - - struct ContentDTO: Codable { + + public struct ContentDTO: Codable { public let id: String? public let title: String? public let imageUrl: String? @@ -57,7 +41,7 @@ public extension CollectionDetailDTO { } } -extension CollectionDetailDTO.DataDTO { +extension CollectionDetailDTO { public var entity: CollectionDetailEntity { get throws { return try CollectionDetailEntity( @@ -67,30 +51,30 @@ extension CollectionDetailDTO.DataDTO { thumbnailUrl: URL(string: thumbnailUrl ?? ""), createdAt: createdAt ?? "", isBookmarked: isBookmarked ?? false, - author: try author?.entity, - contents: try (contents ?? []).map { try $0.entity } + author: unwrap(author?.entity), + contents: contents?.map { try $0.entity } ?? [] ) } } } extension CollectionDetailDTO.AuthorDTO { - public var entity: CollectionAuthorEntity { + public var entity: UserProfileEntity { get throws { - return try CollectionAuthorEntity( + return try UserProfileEntity( id: unwrap(id), nickname: nickname ?? "", profileImageUrl: URL(string: profileImageUrl ?? ""), - userRole: userRole ?? "" + role: UserRole(rawValue: userRole ?? "") ?? .unknown ) } } } extension CollectionDetailDTO.ContentDTO { - public var entity: CollectionContentEntity { + public var entity: CollectionDetailEntity.CollectionContentEntity { get throws { - return try CollectionContentEntity( + return try CollectionDetailEntity.CollectionContentEntity( id: unwrap(id), title: title ?? "", imageUrl: URL(string: imageUrl ?? ""), diff --git a/FLINT/Data/Sources/DTO/Collection/CollectionsDTO.swift b/FLINT/Data/Sources/DTO/Collection/CollectionsDTO.swift index bce08488..6c12fb6b 100644 --- a/FLINT/Data/Sources/DTO/Collection/CollectionsDTO.swift +++ b/FLINT/Data/Sources/DTO/Collection/CollectionsDTO.swift @@ -1,61 +1,22 @@ // -// File.swift +// HomeRecommendedCollectionsDTO.swift // Data // -// Created by 김호성 on 2026.01.22. +// Created by 소은 on 1/20/26. // import Foundation -import Domain +import Entity public struct CollectionsDTO: Codable { - public let data: [CollectionDTO]? - public let meta: CollectionsMetaDTO? - - public init(data: [CollectionDTO]?, meta: CollectionsMetaDTO?) { - self.data = data - self.meta = meta - } -} - -extension CollectionsDTO { - public struct CollectionDTO: Codable { - public let collectionId: String? - public let imageUrl: String? - public let contentTitle: String? - public let contentDescription: String? - } -} - -extension CollectionsDTO { - public struct CollectionsMetaDTO: Codable { - public let type: String? - public let returned: Int? - public let nextCursor: String? - } + public let collections: [CollectionDTO]? } extension CollectionsDTO { - public var entity: CollectionPagingEntity { - get throws { - return try CollectionPagingEntity( - collections: data?.map({ try $0.entity }) ?? [], - cursor: unwrap(UInt(unwrap(meta?.nextCursor))) - ) - } - } -} - -extension CollectionsDTO.CollectionDTO { - public var entity: ExploreInfoEntity { + public var entities: [CollectionEntity] { get throws { - return try ExploreInfoEntity( - id: unwrap(collectionId, key: CodingKeys.collectionId), - imageUrl: URL(string: imageUrl ?? ""), - title: contentTitle ?? "", - description: contentDescription ?? "" - ) + return try collections?.map { try $0.collectionEntity } ?? [] } } } diff --git a/FLINT/Data/Sources/DTO/Collection/CreateCollectionDTO.swift b/FLINT/Data/Sources/DTO/Collection/CreateCollectionDTO.swift new file mode 100644 index 00000000..db3882bd --- /dev/null +++ b/FLINT/Data/Sources/DTO/Collection/CreateCollectionDTO.swift @@ -0,0 +1,20 @@ +// +// CreateCollectionDTO.swift +// DTO +// +// Created by 소은 on 1/23/26. +// + +import Foundation + +public struct CreateCollectionDTO: Codable { + public let collectionId: String? +} + +extension CreateCollectionDTO { + public var createdCollectionId: Int64 { + get throws { + return try unwrap(Int64(collectionId ?? "")) + } + } +} diff --git a/FLINT/Data/Sources/DTO/Collection/CreateCollectionResponseDTO.swift b/FLINT/Data/Sources/DTO/Collection/CreateCollectionResponseDTO.swift deleted file mode 100644 index 2c2bccda..00000000 --- a/FLINT/Data/Sources/DTO/Collection/CreateCollectionResponseDTO.swift +++ /dev/null @@ -1,12 +0,0 @@ -// -// CreateCollectionResponseDTO.swift -// DTO -// -// Created by 소은 on 1/23/26. -// - -import Foundation - -public struct CreateCollectionResponseDTO: Codable { - public let collectionId: String? -} diff --git a/FLINT/Data/Sources/DTO/Collection/PagedCollectionsDTO.swift b/FLINT/Data/Sources/DTO/Collection/PagedCollectionsDTO.swift new file mode 100644 index 00000000..3736a3f2 --- /dev/null +++ b/FLINT/Data/Sources/DTO/Collection/PagedCollectionsDTO.swift @@ -0,0 +1,56 @@ +// +// PagedCollectionsDTO.swift +// Data +// +// Created by 김호성 on 2026.01.22. +// + +import Foundation + +import Entity + +public struct PagedCollectionsDTO: Codable { + public let data: [CollectionDTO]? + public let meta: CollectionsMetaDTO? +} + +extension PagedCollectionsDTO { + public struct CollectionDTO: Codable { + public let collectionId: String? + public let imageUrl: String? + public let contentTitle: String? + public let contentDescription: String? + } +} + +extension PagedCollectionsDTO { + public struct CollectionsMetaDTO: Codable { + public let type: String? + public let returned: Int? + public let nextCursor: String? + } +} + +extension PagedCollectionsDTO { + public var entity: CollectionPagingEntity { + get throws { + return try CollectionPagingEntity( + collections: data?.map({ try $0.entity }) ?? [], + cursor: Int64(meta?.nextCursor ?? "") + ) + } + } +} + +extension PagedCollectionsDTO.CollectionDTO { + public var entity: ExploreInfoEntity { + get throws { + return try ExploreInfoEntity( + collectionId: unwrap(Int64(collectionId ?? "")), + imageUrl: URL(string: imageUrl ?? ""), + title: contentTitle ?? "", + description: contentDescription ?? "" + ) + } + } +} diff --git a/FLINT/Data/Sources/DTO/Collection/WatchiingCollectionsDTO.swift b/FLINT/Data/Sources/DTO/Collection/WatchiingCollectionsDTO.swift deleted file mode 100644 index c7828626..00000000 --- a/FLINT/Data/Sources/DTO/Collection/WatchiingCollectionsDTO.swift +++ /dev/null @@ -1,55 +0,0 @@ -// -// WatchiingCollectionDTO.swift -// Data -// -// Created by 소은 on 1/24/26. -// - -import Foundation -import Entity - -public struct WatchingCollectionsDTO: Codable { - public let collections: [CollectionDTO]? -} - -public extension WatchingCollectionsDTO { - - struct CollectionDTO: Codable { - public let id: String? - public let thumbnailUrl: String? - public let title: String? - public let description: String? - public let imageList: [String]? - public let bookmarkCount: Int? - public let isBookmarked: Bool? - public let userId: String? - public let nickname: String? - public let profileImageUrl: String? - } -} - -// DTO -> Entity -public extension WatchingCollectionsDTO { - var entities: [CollectionEntity] { - (collections ?? []).compactMap { $0.entity } - } -} - -public extension WatchingCollectionsDTO.CollectionDTO { - var entity: CollectionEntity? { - guard let id, let title, let userId, let nickname else { return nil } - - return CollectionEntity( - id: id, - thumbnailUrl: thumbnailUrl ?? "", - title: title, - description: description ?? "", - imageList: imageList ?? [], - bookmarkCount: bookmarkCount ?? 0, - isBookmarked: isBookmarked ?? false, - userId: userId, - nickname: nickname, - profileImageUrl: profileImageUrl ?? "" - ) - } -} diff --git a/FLINT/Data/Sources/DTO/User/ContentsDTO.swift b/FLINT/Data/Sources/DTO/Content/ContentsDTO.swift similarity index 57% rename from FLINT/Data/Sources/DTO/User/ContentsDTO.swift rename to FLINT/Data/Sources/DTO/Content/ContentsDTO.swift index 298389a1..9b14499c 100644 --- a/FLINT/Data/Sources/DTO/User/ContentsDTO.swift +++ b/FLINT/Data/Sources/DTO/Content/ContentsDTO.swift @@ -13,42 +13,48 @@ public struct ContentsDTO: Codable { public let contents: [ContentDTO]? } -public extension ContentsDTO { - struct ContentDTO: Codable { +extension ContentsDTO { + public struct ContentDTO: Codable { public let id: String? public let title: String? public let imageUrl: String? public let year: Int? public let getOttSimpleList: [OttSimpleDTO]? } - - struct OttSimpleDTO: Codable { + + public struct OttSimpleDTO: Codable { public let ottName: String? public let logoUrl: String? } } -// MARK: - DTO -> Entity +extension ContentsDTO { + public var entities: [ContentInfoEntity] { + get throws { + return try contents?.map { try $0.entity } ?? [] + } + } +} -public extension ContentsDTO.ContentDTO { - var entity: ContentInfoEntity { +extension ContentsDTO.ContentDTO { + public var entity: ContentInfoEntity { get throws { return try ContentInfoEntity( - id: unwrap(id, key: CodingKeys.id), + id: unwrap(id), title: title ?? "", imageUrl: imageUrl ?? "", year: year ?? 0, - ottList: try (getOttSimpleList ?? []).map { try $0.entity } + ottList: getOttSimpleList?.map { try $0.entity } ?? [] ) } } } -public extension ContentsDTO.OttSimpleDTO { - var entity: OttSimpleEntity { +extension ContentsDTO.OttSimpleDTO { + public var entity: OttSimpleEntity { get throws { return try OttSimpleEntity( - ottName: unwrap(ottName, key: CodingKeys.ottName), + ottName: unwrap(ottName), logoUrl: logoUrl ?? "" ) } diff --git a/FLINT/Data/Sources/DTO/Content/OTTPlatformsDTO.swift b/FLINT/Data/Sources/DTO/Content/OTTPlatformsDTO.swift index c8c19110..a05d983d 100644 --- a/FLINT/Data/Sources/DTO/Content/OTTPlatformsDTO.swift +++ b/FLINT/Data/Sources/DTO/Content/OTTPlatformsDTO.swift @@ -1,5 +1,5 @@ // -// FetchOTTPlatformsDTO.swift +// OTTPlatformsDTO.swift // Data // // Created by 소은 on 1/21/26. @@ -34,10 +34,10 @@ extension OTTPlatformsDTO.OTTPlatformDTO { public var entity: OTTPlatformEntity { get throws { return try OTTPlatformEntity( - ottId: unwrap(ottId, key: CodingKeys.ottId), + ottId: unwrap(ottId), name: name ?? "", - logoUrl: logoUrl ?? "", - contentUrl: contentUrl ?? "" + logoUrl: URL(string: logoUrl ?? ""), + contentUrl: URL(string: contentUrl ?? "") ) } } diff --git a/FLINT/Data/Sources/DTO/Search/SearchContentsDTO.swift b/FLINT/Data/Sources/DTO/Content/SearchContentsDTO.swift similarity index 92% rename from FLINT/Data/Sources/DTO/Search/SearchContentsDTO.swift rename to FLINT/Data/Sources/DTO/Content/SearchContentsDTO.swift index a3f411e8..b700240d 100644 --- a/FLINT/Data/Sources/DTO/Search/SearchContentsDTO.swift +++ b/FLINT/Data/Sources/DTO/Content/SearchContentsDTO.swift @@ -13,8 +13,8 @@ public struct SearchContentsDTO: Codable { public let contents: [ContentDTO]? } -public extension SearchContentsDTO { - struct ContentDTO: Codable { +extension SearchContentsDTO { + public struct ContentDTO: Codable { public let id: String? public let title: String? public let author: String? diff --git a/FLINT/Data/Sources/DTO/Home/HomeRecommendedCollectionsDTO.swift b/FLINT/Data/Sources/DTO/Home/HomeRecommendedCollectionsDTO.swift deleted file mode 100644 index 69f54822..00000000 --- a/FLINT/Data/Sources/DTO/Home/HomeRecommendedCollectionsDTO.swift +++ /dev/null @@ -1,48 +0,0 @@ -// -// HomeRecommendedCollectionsDTO.swift -// Data -// -// Created by 소은 on 1/20/26. -// - -import Combine -import Foundation - -import Entity - -public struct HomeRecommendedCollectionsDTO: Codable { - public let collections: [CollectionDTO]? -} - -public extension HomeRecommendedCollectionsDTO { - struct CollectionDTO: Codable { - public let id: String? - public let thumbnailUrl: String? - public let title: String? - public let description: String? - public let imageList: [String]? - public let bookmarkCount: Int? - public let isBookmarked: Bool? - public let userId: String? - public let nickname: String? - public let profileUrl: String? - } -} - -public extension HomeRecommendedCollectionsDTO { - var entities: [CollectionInfoEntity] { - (collections ?? []).map { $0.entity } - } -} - -public extension HomeRecommendedCollectionsDTO.CollectionDTO { - var entity: CollectionInfoEntity { - CollectionInfoEntity( - id: id ?? "", - imageUrlString: thumbnailUrl ?? "", - profileImageUrlString: profileUrl ?? "", - title: title ?? "", - userName: nickname ?? "" - ) - } -} diff --git a/FLINT/Data/Sources/DTO/User/CollectionBookmarkUsersDTO.swift b/FLINT/Data/Sources/DTO/User/CollectionBookmarkUsersDTO.swift new file mode 100644 index 00000000..e4011207 --- /dev/null +++ b/FLINT/Data/Sources/DTO/User/CollectionBookmarkUsersDTO.swift @@ -0,0 +1,48 @@ +// +// CollectionBookmarkUsersDTO.swift +// Entity +// +// Created by 소은 on 1/23/26. +// + +import Foundation + +import Entity + +public struct CollectionBookmarkUsersDTO: Codable { + public let bookmarkCount: Int? + public let userList: [UserDTO]? +} + +extension CollectionBookmarkUsersDTO { + public struct UserDTO: Codable { + public let userId: String? + public let nickName: String? + public let profileImageUrl: String? + public let userRole: String? + } +} + +extension CollectionBookmarkUsersDTO { + public var entity: CollectionBookmarkUsersEntity { + get throws { + return try CollectionBookmarkUsersEntity( + bookmarkCount: bookmarkCount ?? 0, + users: userList?.map({ try $0.entity }) ?? [] + ) + } + } +} + +extension CollectionBookmarkUsersDTO.UserDTO { + public var entity: UserProfileEntity { + get throws { + return try UserProfileEntity( + id: unwrap(userId), + nickname: nickName ?? "", + profileImageUrl: URL(string: profileImageUrl ?? ""), + role: UserRole(rawValue: userRole ?? "") ?? .unknown + ) + } + } +} diff --git a/FLINT/Data/Sources/DTO/User/KeywordDTO.swift b/FLINT/Data/Sources/DTO/User/KeywordDTO.swift index 1721ed75..129798b0 100644 --- a/FLINT/Data/Sources/DTO/User/KeywordDTO.swift +++ b/FLINT/Data/Sources/DTO/User/KeywordDTO.swift @@ -8,29 +8,38 @@ import Foundation import Entity -// Data 모듈 public struct KeywordsDTO: Codable { public let keywords: [KeywordDTO]? } -public struct KeywordDTO: Codable { - public let color: String? - public let rank: Int? - public let name: String? - public let percentage: Int? - public let imageUrl: String? +extension KeywordsDTO { + public struct KeywordDTO: Codable { + public let color: String? + public let rank: Int? + public let name: String? + public let percentage: Int? + public let imageUrl: String? + } +} + +extension KeywordsDTO { + public var entities: [KeywordEntity] { + get throws { + return try keywords?.map { try $0.entity } ?? [] + } + } } -extension KeywordDTO { +extension KeywordsDTO.KeywordDTO { public var entity: KeywordEntity { get throws { return try KeywordEntity( - color: color ?? "", - rank: unwrap(rank, key: CodingKeys.rank), + color: unwrap(KeywordColor(rawValue: color ?? "")), + rank: unwrap(rank), name: name ?? "", percentage: percentage ?? 0, - imageUrl: imageUrl ?? "" + imageUrl: URL(string: imageUrl ?? "") ) } } diff --git a/FLINT/Data/Sources/DTO/User/UserCollectionsDTO.swift b/FLINT/Data/Sources/DTO/User/UserCollectionsDTO.swift deleted file mode 100644 index 69e30250..00000000 --- a/FLINT/Data/Sources/DTO/User/UserCollectionsDTO.swift +++ /dev/null @@ -1,48 +0,0 @@ -// -// UserCollectionsDTO.swift -// Data -// -// Created by 진소은 on 1/23/26. -// - -import Foundation - -import Entity - -public struct UserCollectionsDTO: Codable { - public let collections: [CollectionDTO]? -} - -public extension UserCollectionsDTO { - struct CollectionDTO: Codable { - public let id: String? - public let thumbnailUrl: String? - public let title: String? - public let description: String? - public let imageList: [String]? - public let bookmarkCount: Int? - public let isBookmarked: Bool? - public let userId: String? - public let nickname: String? - public let profileImageUrl: String? - } -} - -public extension UserCollectionsDTO.CollectionDTO { - var entity: CollectionEntity { - get throws { - return try CollectionEntity( - id: unwrap(id, key: CodingKeys.id), - thumbnailUrl: thumbnailUrl ?? "", - title: title ?? "", - description: description ?? "", - imageList: imageList ?? [], - bookmarkCount: bookmarkCount ?? 0, - isBookmarked: isBookmarked ?? false, - userId: userId ?? "", - nickname: nickname ?? "", - profileImageUrl: profileImageUrl ?? "" - ) - } - } -} diff --git a/FLINT/Data/Sources/DTO/User/UserProfileDTO.swift b/FLINT/Data/Sources/DTO/User/UserProfileDTO.swift index 35f9c919..7ab6b046 100644 --- a/FLINT/Data/Sources/DTO/User/UserProfileDTO.swift +++ b/FLINT/Data/Sources/DTO/User/UserProfileDTO.swift @@ -20,10 +20,10 @@ extension UserProfileDTO { public var entity: UserProfileEntity { get throws { return try UserProfileEntity( - id: unwrap(id, key: CodingKeys.id), + id: unwrap(id), nickname: nickname ?? "", - profileImageUrl: profileImageUrl ?? "", - isFliner: isFliner ?? false + profileImageUrl: URL(string: profileImageUrl ?? ""), + role: (isFliner ?? false) ? .fliner : .unknown ) } } diff --git a/FLINT/Data/Sources/Networking/API/AuthAPI.swift b/FLINT/Data/Sources/Networking/API/AuthAPI.swift index 061fc20f..e9f26dbb 100644 --- a/FLINT/Data/Sources/Networking/API/AuthAPI.swift +++ b/FLINT/Data/Sources/Networking/API/AuthAPI.swift @@ -1,5 +1,5 @@ // -// File.swift +// AuthAPI.swift // Data // // Created by 김호성 on 2026.01.21. @@ -9,20 +9,18 @@ import Foundation import Moya -import Domain - import DTO public enum AuthAPI { case logout case logoutAll case refresh - case signup(_ signupInfoEntity: SignupRequestDTO) - case socialVerify(_socialVerifyRequestDTO: SocialVerifyRequestDTO) + case signup(userInfo: SignupRequestDTO) + case socialVerify(socialAuthCredential: SocialVerifyRequestDTO) + case withdraw } extension AuthAPI: TargetType { - public var path: String { switch self { case .signup: @@ -31,6 +29,8 @@ extension AuthAPI: TargetType { return "TODO" case .socialVerify: return "/api/v1/auth/social/verify" + case .withdraw: + return "/api/v1/auth/withdraw" } } @@ -38,17 +38,19 @@ extension AuthAPI: TargetType { switch self { case .logout, .logoutAll, .refresh, .signup, .socialVerify: return .post + case .withdraw: + return .delete } } public var task: Moya.Task { switch self { - case .signup(let signupInfoEntity): - return .requestJSONEncodable(signupInfoEntity) - case .logout, .logoutAll, .refresh: + case let .signup(userInfo): + return .requestJSONEncodable(userInfo) + case let .socialVerify(socialAuthCredential): + return .requestJSONEncodable(socialAuthCredential) + case .logout, .logoutAll, .refresh, .withdraw: return .requestPlain - case .socialVerify(let socialVerifyRequestDTO): - return .requestJSONEncodable(socialVerifyRequestDTO) } } } diff --git a/FLINT/Data/Sources/Networking/API/BookmarkAPI.swift b/FLINT/Data/Sources/Networking/API/BookmarkAPI.swift index 048ceabb..70e59f76 100644 --- a/FLINT/Data/Sources/Networking/API/BookmarkAPI.swift +++ b/FLINT/Data/Sources/Networking/API/BookmarkAPI.swift @@ -7,47 +7,38 @@ import Foundation -import Domain - import Moya public enum BookmarkAPI { - case toggleCollectionBookmark(_ collectionId: Int64) - case toggleContentBookmark(_ contentId: Int64) case fetchCollectionBookmarkUsers(collectionId: Int64) + case toggleCollectionBookmark(collectionId: Int64) + case toggleContentBookmark(contentId: Int64) } extension BookmarkAPI: TargetType { - public var path: String { switch self { - case .toggleCollectionBookmark(let collectionId): - return "/api/v1/bookmarks/collections/\(collectionId)" - case .toggleContentBookmark(let contentId): - return "/api/v1/bookmarks/contents/\(contentId)" case let .fetchCollectionBookmarkUsers(collectionId): return "/api/v1/bookmarks/\(collectionId)" + case let .toggleCollectionBookmark(collectionId): + return "/api/v1/bookmarks/collections/\(collectionId)" + case let .toggleContentBookmark(contentId): + return "/api/v1/bookmarks/contents/\(contentId)" } } public var method: Moya.Method { switch self { - case .toggleCollectionBookmark: - return .post - case .toggleContentBookmark: - return .post case .fetchCollectionBookmarkUsers: return .get + case .toggleCollectionBookmark, .toggleContentBookmark: + return .post } } public var task: Moya.Task { switch self { - case .toggleCollectionBookmark: - return .requestPlain - case .toggleContentBookmark: - return .requestPlain - case .fetchCollectionBookmarkUsers: + case .fetchCollectionBookmarkUsers, .toggleCollectionBookmark, .toggleContentBookmark: return .requestPlain } } diff --git a/FLINT/Data/Sources/Networking/API/CollectionAPI.swift b/FLINT/Data/Sources/Networking/API/CollectionAPI.swift index 041363d0..01e41785 100644 --- a/FLINT/Data/Sources/Networking/API/CollectionAPI.swift +++ b/FLINT/Data/Sources/Networking/API/CollectionAPI.swift @@ -7,48 +7,41 @@ import Foundation -import Domain - import Moya +import Domain + public enum CollectionAPI { - case fetchCollections(cursor: UInt?, size: Int) - case createCollection(_ request: CreateCollectionEntity) + case fetchCollections(cursor: Int64?, size: Int32) + case createCollection(collectionInfo: CreateCollectionEntity) case fetchCollectionDetail(collectionId: Int64) - case fetchWatchingCollections + case fetchRecentViewedCollections } extension CollectionAPI: TargetType { - public var path: String { switch self { - case .fetchCollections: - return "/api/v1/collections" - case .createCollection: + case .fetchCollections, .createCollection: return "/api/v1/collections" case let .fetchCollectionDetail(collectionId): return "/api/v1/collections/\(collectionId)" - case let .fetchWatchingCollections: + case .fetchRecentViewedCollections: return "/api/v1/collections/recent" } } public var method: Moya.Method { switch self { - case .fetchCollections: + case .fetchCollections, .fetchCollectionDetail, .fetchRecentViewedCollections: return .get case .createCollection: return .post - case .fetchCollectionDetail: - return .get - case .fetchWatchingCollections: - return .get } } public var task: Moya.Task { switch self { - case .fetchCollections(let cursor, let size): + case let .fetchCollections(cursor, size): var parameters: [String: Any] = [ "size": size, ] @@ -59,13 +52,10 @@ extension CollectionAPI: TargetType { parameters: parameters, encoding: URLEncoding.queryString ) - case .createCollection(let request): - return .requestJSONEncodable(request) - case .fetchCollectionDetail: - return .requestPlain - case .fetchWatchingCollections: + case let .createCollection(collectionInfo): + return .requestJSONEncodable(collectionInfo) + case .fetchCollectionDetail, .fetchRecentViewedCollections: return .requestPlain } } } - diff --git a/FLINT/Data/Sources/Networking/API/ContentAPI.swift b/FLINT/Data/Sources/Networking/API/ContentAPI.swift index 91d0739d..6d5a3af4 100644 --- a/FLINT/Data/Sources/Networking/API/ContentAPI.swift +++ b/FLINT/Data/Sources/Networking/API/ContentAPI.swift @@ -5,38 +5,36 @@ // Created by 소은 on 1/21/26. // - import Foundation import Moya -import Domain - public enum ContentAPI { - case fetchOTTPlatforms(_ contentId: Int64) + case fetchMyBookmarkedContents + case fetchOTTPlatformsForContent(contentId: Int64) } extension ContentAPI: TargetType { - public var path: String { switch self { - case .fetchOTTPlatforms(let contentId): + case .fetchMyBookmarkedContents: + return "/api/v1/contents/bookmarks" + case let .fetchOTTPlatformsForContent(contentId): return "/api/v1/contents/ott/\(contentId)" } } public var method: Moya.Method { switch self { - case .fetchOTTPlatforms: + case .fetchMyBookmarkedContents, .fetchOTTPlatformsForContent: return .get } } public var task: Moya.Task { switch self { - case .fetchOTTPlatforms: + case .fetchMyBookmarkedContents, .fetchOTTPlatformsForContent: return .requestPlain } } } - diff --git a/FLINT/Data/Sources/Networking/API/HomeAPI.swift b/FLINT/Data/Sources/Networking/API/HomeAPI.swift index 248ceaba..e0cfed3b 100644 --- a/FLINT/Data/Sources/Networking/API/HomeAPI.swift +++ b/FLINT/Data/Sources/Networking/API/HomeAPI.swift @@ -9,14 +9,11 @@ import Foundation import Moya -import Domain - public enum HomeAPI { case fetchRecommendedCollections } extension HomeAPI: TargetType { - public var path: String { switch self { case .fetchRecommendedCollections: diff --git a/FLINT/Data/Sources/Networking/API/SearchAPI.swift b/FLINT/Data/Sources/Networking/API/SearchAPI.swift index 72b9fac5..5ae0e55c 100644 --- a/FLINT/Data/Sources/Networking/API/SearchAPI.swift +++ b/FLINT/Data/Sources/Networking/API/SearchAPI.swift @@ -1,5 +1,5 @@ // -// SearchContentsAPI.swift +// SearchAPI.swift // Data // // Created by 소은 on 1/20/26. @@ -9,14 +9,12 @@ import Foundation import Moya -import Domain - public enum SearchAPI { - case searchContents(_ keyword: String?) + /// keyword가 nil인 경우 인기 순 작품 리스트를 받는다. + case searchContents(keyword: String?) } extension SearchAPI: TargetType { - public var path: String { switch self { case .searchContents: @@ -33,7 +31,7 @@ extension SearchAPI: TargetType { public var task: Moya.Task { switch self { - case .searchContents(let keyword): + case let .searchContents(keyword): var parameters: [String: Any] = [:] if let keyword { parameters["keyword"] = keyword diff --git a/FLINT/Data/Sources/Networking/API/UserAPI.swift b/FLINT/Data/Sources/Networking/API/UserAPI.swift index 0cbf7363..96d34c2c 100644 --- a/FLINT/Data/Sources/Networking/API/UserAPI.swift +++ b/FLINT/Data/Sources/Networking/API/UserAPI.swift @@ -1,5 +1,5 @@ // -// File.swift +// UserAPI.swift // Data // // Created by 김호성 on 2026.01.19. @@ -9,102 +9,69 @@ import Foundation import Moya -import Domain - public enum UserAPI { - case checkNickname(_ nickname: String) case fetchUserProfile(userId: Int64) - case fetchMyProfile - case fetchMyKeywords + case fetchUserBookmarkedCollections(userId: Int64) + case fetchUserBookmarkedContents(userId: Int64) + case fetchUserCreatedCollections(userId: Int64) case fetchUserKeywords(userId: Int64) - case fetchMyCollections - case fetchUserCollections(userId: Int64) + + case fetchMyProfile case fetchMyBookmarkedCollections - case fetchBookmarkedCollections(userId: Int64) - case fetchMyBookmarkedContents - case fetchBookmarkedContents(userId: Int64) + case fetchMyCreatedCollections + case fetchMyKeywords + case recalculateMyKeywords + + case checkNickname(_ nickname: String) } extension UserAPI: TargetType { public var path: String { switch self { - case .checkNickname: - return "/api/v1/users/nickname/check" case let .fetchUserProfile(userId): return "/api/v1/users/\(userId)" - case .fetchMyProfile: - return "/api/v1/users/me" - case .fetchMyKeywords: - return "/api/v1/users/me/keywords" + case let .fetchUserBookmarkedCollections(userId): + return "/api/v1/users/\(userId)/bookmarked-collections" + case let .fetchUserBookmarkedContents(userId): + return "/api/v1/users/\(userId)/bookmarked-contents" + case let .fetchUserCreatedCollections(userId): + return "/api/v1/users/\(userId)/collections" case let .fetchUserKeywords(userId): return "/api/v1/users/\(userId)/keywords" - case .fetchMyCollections: - return "/api/v1/users/me/collections" - case let .fetchUserCollections(userId): - return "/api/v1/users/\(userId)/collections" + + case .fetchMyProfile: + return "/api/v1/users/me" case .fetchMyBookmarkedCollections: return "/api/v1/users/me/bookmarked-collections" - case let .fetchBookmarkedCollections(userId): - return "/api/v1/users/\(userId)/bookmarked-collections" - case .fetchMyBookmarkedContents: - return "/api/v1/contents/bookmarks" - case let .fetchBookmarkedContents(userId): - return "/api/v1/users/\(userId)/bookmarked-contents" + case .fetchMyCreatedCollections: + return "/api/v1/users/me/collections" + case .fetchMyKeywords: + return "/api/v1/users/me/keywords" + case .recalculateMyKeywords: + return "/api/v1/users/me/keywords/recalculate" + + case .checkNickname: + return "/api/v1/users/nickname/check" } } public var method: Moya.Method { switch self { - case .checkNickname: - return .get - case .fetchUserProfile: - return .get - case .fetchMyProfile: - return .get - case .fetchMyKeywords: - return .get - case .fetchUserKeywords: - return .get - case .fetchUserCollections: - return .get - case .fetchMyCollections: - return .get - case .fetchMyBookmarkedCollections: - return .get - case .fetchBookmarkedCollections: - return .get - case .fetchMyBookmarkedContents: - return .get - case .fetchBookmarkedContents: + case .fetchUserProfile, .fetchUserBookmarkedCollections, .fetchUserBookmarkedContents, .fetchUserCreatedCollections, .fetchUserKeywords, .fetchMyProfile, .fetchMyBookmarkedCollections, .fetchMyCreatedCollections, .fetchMyKeywords, .checkNickname: return .get + case .recalculateMyKeywords: + return .patch } } public var task: Moya.Task { switch self { - case .checkNickname(let nickname): + case let .checkNickname(nickname): return .requestParameters( parameters: ["nickname": nickname], - encoding: URLEncoding.queryString) - case .fetchUserProfile: - return .requestPlain - case .fetchMyProfile: - return .requestPlain - case .fetchMyKeywords: - return .requestPlain - case .fetchUserKeywords: - return .requestPlain - case .fetchUserCollections: - return .requestPlain - case .fetchMyCollections: - return .requestPlain - case .fetchMyBookmarkedCollections: - return .requestPlain - case .fetchBookmarkedCollections: - return .requestPlain - case .fetchMyBookmarkedContents: - return .requestPlain - case .fetchBookmarkedContents: + encoding: URLEncoding.queryString + ) + case .fetchUserProfile, .fetchUserBookmarkedCollections, .fetchUserBookmarkedContents, .fetchUserCreatedCollections, .fetchUserKeywords, .fetchMyProfile, .fetchMyBookmarkedCollections, .fetchMyCreatedCollections, .fetchMyKeywords, .recalculateMyKeywords: return .requestPlain } } diff --git a/FLINT/Data/Sources/Networking/Extension/AnyPublisher+.swift b/FLINT/Data/Sources/Networking/Extension/AnyPublisher+BaseResponse.swift similarity index 75% rename from FLINT/Data/Sources/Networking/Extension/AnyPublisher+.swift rename to FLINT/Data/Sources/Networking/Extension/AnyPublisher+BaseResponse.swift index a0c63837..e385abf2 100644 --- a/FLINT/Data/Sources/Networking/Extension/AnyPublisher+.swift +++ b/FLINT/Data/Sources/Networking/Extension/AnyPublisher+BaseResponse.swift @@ -1,5 +1,5 @@ // -// File.swift +// AnyPublisher+BaseResponse.swift // Data // // Created by 김호성 on 2026.01.20. @@ -8,15 +8,15 @@ import Combine import Foundation -import Moya import CombineMoya +import Moya import Domain import DTO public extension AnyPublisher where Output == Response, Failure == MoyaError { - func extractData(_ type: D.Type, atKeyPath keyPath: String? = nil, using decoder: JSONDecoder = JSONDecoder(), failsOnEmptyData: Bool = true) -> AnyPublisher { + func mapBaseResponseData(_ type: D.Type, atKeyPath keyPath: String? = nil, using decoder: JSONDecoder = JSONDecoder(), failsOnEmptyData: Bool = true) -> AnyPublisher { return map(BaseResponse.self) .tryMap({ baseResponse in Log.d(baseResponse) diff --git a/FLINT/Data/Sources/Networking/NetworkConfig.swift b/FLINT/Data/Sources/Networking/NetworkConfig.swift index 15b65e5b..c355bd10 100644 --- a/FLINT/Data/Sources/Networking/NetworkConfig.swift +++ b/FLINT/Data/Sources/Networking/NetworkConfig.swift @@ -1,5 +1,5 @@ // -// File.swift +// NetworkConfig.swift // Data // // Created by 김호성 on 2026.01.20. diff --git a/FLINT/Data/Sources/Networking/Service/AuthService.swift b/FLINT/Data/Sources/Networking/Service/AuthService.swift index 79dfaf1c..06b9ee9f 100644 --- a/FLINT/Data/Sources/Networking/Service/AuthService.swift +++ b/FLINT/Data/Sources/Networking/Service/AuthService.swift @@ -1,5 +1,5 @@ // -// File.swift +// AuthService.swift // Data // // Created by 김호성 on 2026.01.21. @@ -15,10 +15,10 @@ import Domain import DTO - public protocol AuthService { - func signup(_ signupInfoEntity: SignupInfoEntity) -> AnyPublisher - func socialVerify(socialVerifyRequestDTO: SocialVerifyRequestDTO) -> AnyPublisher + func signup(userInfo: SignupInfoEntity) -> AnyPublisher + func socialVerify(socialAuthCredential: SocialVerifyRequestDTO) -> AnyPublisher + func withDraw() -> AnyPublisher } public final class DefaultAuthService: AuthService { @@ -31,14 +31,13 @@ public final class DefaultAuthService: AuthService { self.authAPIProvider = authAPIProvider } - public func signup(_ signupInfoEntity: SignupInfoEntity) -> AnyPublisher { + public func signup(userInfo: SignupInfoEntity) -> AnyPublisher { guard let tempToken = tokenStorage.load(type: .tempToken) else { return Fail(error: TokenError.noToken).eraseToAnyPublisher() } - let signupRequestDTO = SignupRequestDTO(tempToken: tempToken, signupEntity: signupInfoEntity) - Log.d(signupRequestDTO) - return authAPIProvider.requestPublisher(.signup(signupRequestDTO)) - .extractData(SignupDTO.self) + let signupRequestDTO = SignupRequestDTO(tempToken: tempToken, signupEntity: userInfo) + return authAPIProvider.requestPublisher(.signup(userInfo: signupRequestDTO)) + .mapBaseResponseData(SignupDTO.self) .tryMap({ [weak self] in let loginEntity = try $0.loginEntity self?.tokenStorage.save(loginEntity.accessToken, type: .accessToken) @@ -48,19 +47,16 @@ public final class DefaultAuthService: AuthService { .eraseToAnyPublisher() } - public func socialVerify(socialVerifyRequestDTO: SocialVerifyRequestDTO) -> AnyPublisher { - return authAPIProvider.requestPublisher(.socialVerify(_socialVerifyRequestDTO: socialVerifyRequestDTO)) - .extractData(SocialVerifyResponseDTO.self) + public func socialVerify(socialAuthCredential: SocialVerifyRequestDTO) -> AnyPublisher { + return authAPIProvider.requestPublisher(.socialVerify(socialAuthCredential: socialAuthCredential)) + .mapBaseResponseData(SocialVerifyResponseDTO.self) .map({ [weak self] socialVerifyResponseDTO in - Log.d(socialVerifyResponseDTO) guard let self, let isRegister = socialVerifyResponseDTO.isRegistered else { return socialVerifyResponseDTO } if !isRegister, let tempToken = socialVerifyResponseDTO.tempToken { - Log.d(tempToken) tokenStorage.save(tempToken, type: .tempToken) } else if let accessToken = socialVerifyResponseDTO.accessToken, let refreshToken = socialVerifyResponseDTO.refreshToken { - Log.d(accessToken) tokenStorage.save(accessToken, type: .accessToken) tokenStorage.save(refreshToken, type: .refreshToken) } @@ -68,4 +64,11 @@ public final class DefaultAuthService: AuthService { }) .eraseToAnyPublisher() } + + public func withDraw() -> AnyPublisher { + authAPIProvider.requestPublisher(.withdraw) + .mapBaseResponseData(BlankData.self) + .map({ _ in }) + .eraseToAnyPublisher() + } } diff --git a/FLINT/Data/Sources/Networking/Service/BookmarkService.swift b/FLINT/Data/Sources/Networking/Service/BookmarkService.swift index 3a6a14b7..cab7e148 100644 --- a/FLINT/Data/Sources/Networking/Service/BookmarkService.swift +++ b/FLINT/Data/Sources/Networking/Service/BookmarkService.swift @@ -5,47 +5,40 @@ // Created by 소은 on 1/21/26. // - - import Combine import Foundation import CombineMoya import Moya -import Domain - import DTO public protocol BookmarkService { - func toggleCollectionBookmark(_ collectionId: Int64) -> AnyPublisher - func toggleContentBookmark(_ contentId: Int64) -> AnyPublisher - - func fetchCollectionBookmarkUsers(_ collectionId: Int64) - -> AnyPublisher + func fetchCollectionBookmarkUsers(collectionId: Int64) -> AnyPublisher + func toggleCollectionBookmark(collectionId: Int64) -> AnyPublisher + func toggleContentBookmark(contentId: Int64) -> AnyPublisher } public final class DefaultBookmarkService: BookmarkService { - - private let provider: MoyaProvider - - public init(provider: MoyaProvider) { - self.provider = provider + + private let bookmarkAPIProvider: MoyaProvider + + public init(bookmarkAPIProvider: MoyaProvider) { + self.bookmarkAPIProvider = bookmarkAPIProvider } - - public func toggleCollectionBookmark(_ collectionId: Int64) -> AnyPublisher { - provider.requestPublisher(.toggleCollectionBookmark(collectionId)) - .extractData(Bool.self) + + public func fetchCollectionBookmarkUsers(collectionId: Int64) -> AnyPublisher { + return bookmarkAPIProvider.requestPublisher(.fetchCollectionBookmarkUsers(collectionId: collectionId)) + .mapBaseResponseData(CollectionBookmarkUsersDTO.self) } - - public func toggleContentBookmark(_ contentId: Int64) -> AnyPublisher { - provider.requestPublisher(.toggleContentBookmark(contentId)) - .extractData(Bool.self) + + public func toggleCollectionBookmark(collectionId: Int64) -> AnyPublisher { + return bookmarkAPIProvider.requestPublisher(.toggleCollectionBookmark(collectionId: collectionId)) + .mapBaseResponseData(Bool.self) } - - public func fetchCollectionBookmarkUsers(_ collectionId: Int64) - -> AnyPublisher { - provider.requestPublisher(.fetchCollectionBookmarkUsers(collectionId: collectionId)) - .extractData(CollectionBookmarkUsersDTO.DataDTO.self) + + public func toggleContentBookmark(contentId: Int64) -> AnyPublisher { + return bookmarkAPIProvider.requestPublisher(.toggleContentBookmark(contentId: contentId)) + .mapBaseResponseData(Bool.self) } } diff --git a/FLINT/Data/Sources/Networking/Service/CollectionService.swift b/FLINT/Data/Sources/Networking/Service/CollectionService.swift index 04add454..70f01c2f 100644 --- a/FLINT/Data/Sources/Networking/Service/CollectionService.swift +++ b/FLINT/Data/Sources/Networking/Service/CollectionService.swift @@ -16,46 +16,37 @@ import Domain import DTO public protocol CollectionService { - func fetchCollections(cursor: UInt?, size: Int) -> AnyPublisher - func createCollection(_ entity: CreateCollectionEntity) -> AnyPublisher - func fetchCollectionDetail(collectionId: Int64) -> AnyPublisher - func fetchWatchingCollections() -> AnyPublisher + func fetchCollections(cursor: Int64?, size: Int32) -> AnyPublisher + func createCollection(collectionInfo: CreateCollectionEntity) -> AnyPublisher + func fetchCollectionDetail(collectionId: Int64) -> AnyPublisher + func fetchRecentViewedCollections() -> AnyPublisher } public final class DefaultCollectionService: CollectionService { - private let provider: MoyaProvider + private let collectionAPIProvider: MoyaProvider - public init(provider: MoyaProvider) { - self.provider = provider + public init(collectionAPIProvider: MoyaProvider) { + self.collectionAPIProvider = collectionAPIProvider } - public func fetchCollections(cursor: UInt?, size: Int) -> AnyPublisher { - return provider.requestPublisher(.fetchCollections(cursor: cursor, size: size)) - .extractData(CollectionsDTO.self) + public func fetchCollections(cursor: Int64?, size: Int32) -> AnyPublisher { + return collectionAPIProvider.requestPublisher(.fetchCollections(cursor: cursor, size: size)) + .mapBaseResponseData(PagedCollectionsDTO.self) } - public func createCollection(_ entity: CreateCollectionEntity) -> AnyPublisher { - return provider.requestPublisher(.createCollection(entity)) - .handleEvents(receiveOutput: { response in - if response.statusCode == 404 { - let body = String(data: response.data, encoding: .utf8) ?? "" - print("404 body:", body) - } - }) - .eraseToAnyPublisher() - .extractData(CreateCollectionResponseDTO.self) - .map { _ in () } + public func createCollection(collectionInfo: CreateCollectionEntity) -> AnyPublisher { + return collectionAPIProvider.requestPublisher(.createCollection(collectionInfo: collectionInfo)) + .mapBaseResponseData(CreateCollectionDTO.self) .eraseToAnyPublisher() } - public func fetchCollectionDetail(collectionId: Int64) -> AnyPublisher { - provider.requestPublisher(.fetchCollectionDetail(collectionId: collectionId)) - .extractData(CollectionDetailDTO.DataDTO.self) + public func fetchCollectionDetail(collectionId: Int64) -> AnyPublisher { + return collectionAPIProvider.requestPublisher(.fetchCollectionDetail(collectionId: collectionId)) + .mapBaseResponseData(CollectionDetailDTO.self) } - public func fetchWatchingCollections() -> AnyPublisher { - return provider.requestPublisher(.fetchWatchingCollections) - .extractData(WatchingCollectionsDTO.self) - .eraseToAnyPublisher() + public func fetchRecentViewedCollections() -> AnyPublisher { + return collectionAPIProvider.requestPublisher(.fetchRecentViewedCollections) + .mapBaseResponseData(CollectionsDTO.self) } } diff --git a/FLINT/Data/Sources/Networking/Service/ContentService.swift b/FLINT/Data/Sources/Networking/Service/ContentService.swift index 0e882e07..8f21a532 100644 --- a/FLINT/Data/Sources/Networking/Service/ContentService.swift +++ b/FLINT/Data/Sources/Networking/Service/ContentService.swift @@ -4,31 +4,36 @@ // // Created by 소은 on 1/21/26. // + import Combine import Foundation import CombineMoya import Moya -import Domain - import DTO public protocol ContentService { - func fetchOTTPlatforms(_ contentId: Int64) -> AnyPublisher + func fetchMyBookmarkedContents() -> AnyPublisher + func fetchOTTPlatformsForContent(contentId: Int64) -> AnyPublisher } public final class DefaultContentService: ContentService { - private let provider: MoyaProvider + private let contentAPIProvider: MoyaProvider - public init(provider: MoyaProvider) { - self.provider = provider + public init(contentAPIProvider: MoyaProvider) { + self.contentAPIProvider = contentAPIProvider } - - public func fetchOTTPlatforms(_ contentId: Int64) -> AnyPublisher { - return provider.requestPublisher(.fetchOTTPlatforms(contentId)) - .extractData(OTTPlatformsDTO.self) + + public func fetchMyBookmarkedContents() -> AnyPublisher { + return contentAPIProvider.requestPublisher(.fetchMyBookmarkedContents) + .mapBaseResponseData(ContentsDTO.self) + } + + public func fetchOTTPlatformsForContent(contentId: Int64) -> AnyPublisher { + return contentAPIProvider.requestPublisher(.fetchOTTPlatformsForContent(contentId: contentId)) + .mapBaseResponseData(OTTPlatformsDTO.self) } } diff --git a/FLINT/Data/Sources/Networking/Service/HomeService.swift b/FLINT/Data/Sources/Networking/Service/HomeService.swift index 4e137857..24f99f38 100644 --- a/FLINT/Data/Sources/Networking/Service/HomeService.swift +++ b/FLINT/Data/Sources/Networking/Service/HomeService.swift @@ -11,26 +11,23 @@ import Foundation import CombineMoya import Moya -import Domain - import DTO public protocol HomeService { - func fetchRecommendedCollections() -> AnyPublisher + func fetchRecommendedCollections() -> AnyPublisher } public final class DefaultHomeService: HomeService { - private let provider: MoyaProvider + private let homeAPIProvider: MoyaProvider - public init(provider: MoyaProvider) { - self.provider = provider + public init(homeAPIProvider: MoyaProvider) { + self.homeAPIProvider = homeAPIProvider } - public func fetchRecommendedCollections() -> AnyPublisher { - provider.requestPublisher(.fetchRecommendedCollections) - .extractData(HomeRecommendedCollectionsDTO.self) - .eraseToAnyPublisher() + public func fetchRecommendedCollections() -> AnyPublisher { + return homeAPIProvider.requestPublisher(.fetchRecommendedCollections) + .mapBaseResponseData(CollectionsDTO.self) } } diff --git a/FLINT/Data/Sources/Networking/Service/SearchService.swift b/FLINT/Data/Sources/Networking/Service/SearchService.swift index cb1827e5..2f4ce298 100644 --- a/FLINT/Data/Sources/Networking/Service/SearchService.swift +++ b/FLINT/Data/Sources/Networking/Service/SearchService.swift @@ -1,5 +1,5 @@ // -// SearchContentsService.swift +// SearchService.swift // Data // // Created by 소은 on 1/20/26. @@ -11,26 +11,23 @@ import Foundation import CombineMoya import Moya -import Domain - import DTO public protocol SearchService { - func searchContents(_ keyword: String?) -> AnyPublisher + func searchContents(keyword: String?) -> AnyPublisher } public final class DefaultSearchService: SearchService { - private let provider: MoyaProvider + private let searchAPIProvider: MoyaProvider - public init(provider: MoyaProvider) { - self.provider = provider + public init(searchAPIProvider: MoyaProvider) { + self.searchAPIProvider = searchAPIProvider } - public func searchContents(_ keyword: String?) -> AnyPublisher { - provider.requestPublisher(.searchContents(keyword)) - .extractData(SearchContentsDTO.self) - .eraseToAnyPublisher() + public func searchContents(keyword: String?) -> AnyPublisher { + return searchAPIProvider.requestPublisher(.searchContents(keyword: keyword)) + .mapBaseResponseData(SearchContentsDTO.self) } } diff --git a/FLINT/Data/Sources/Networking/Service/UserService.swift b/FLINT/Data/Sources/Networking/Service/UserService.swift index 9ba41d46..9ee9639d 100644 --- a/FLINT/Data/Sources/Networking/Service/UserService.swift +++ b/FLINT/Data/Sources/Networking/Service/UserService.swift @@ -1,5 +1,5 @@ // -// File.swift +// UserService.swift // Data // // Created by 김호성 on 2026.01.19. @@ -11,22 +11,22 @@ import Foundation import CombineMoya import Moya -import Domain - import DTO public protocol UserService { - func checkNickname(_ nickname: String) -> AnyPublisher func fetchUserProfile(userId: Int64) -> AnyPublisher + func fetchUserBookmarkedCollections(userId: Int64) -> AnyPublisher + func fetchUserBookmarkedContents(userId: Int64) -> AnyPublisher + func fetchUserCreatedCollections(userId: Int64) -> AnyPublisher + func fetchUserKeywords(userId: Int64) -> AnyPublisher + func fetchMyProfile() -> AnyPublisher + func fetchMyBookmarkedCollections() -> AnyPublisher + func fetchMyCreatedCollections() -> AnyPublisher func fetchMyKeywords() -> AnyPublisher - func fetchUserKeywords(userId: Int64) -> AnyPublisher - func fetchMyCollections() -> AnyPublisher - func fetchUserCollections(userId: Int64) -> AnyPublisher - func fetchMyBookmarkedCollections() -> AnyPublisher - func fetchBookmarkedCollections(userId: Int64) -> AnyPublisher - func fetchMyBookmarkedContents() -> AnyPublisher - func fetchBookmarkedContents(userId: Int64) -> AnyPublisher + func recalculateMyKeywords() -> AnyPublisher + + func checkNickname(_ nickname: String) -> AnyPublisher } public final class DefaultUserService: UserService { @@ -37,57 +37,60 @@ public final class DefaultUserService: UserService { self.userAPIProvider = userAPIProvider } - public func checkNickname(_ nickname: String) -> AnyPublisher { - return userAPIProvider.requestPublisher(.checkNickname(nickname)) - .extractData(NicknameCheckDTO.self) - } - public func fetchUserProfile(userId: Int64) -> AnyPublisher { return userAPIProvider.requestPublisher(.fetchUserProfile(userId: userId)) - .extractData(UserProfileDTO.self) + .mapBaseResponseData(UserProfileDTO.self) } - public func fetchMyProfile() -> AnyPublisher { - return userAPIProvider.requestPublisher(.fetchMyProfile) - .extractData(UserProfileDTO.self) + public func fetchUserBookmarkedCollections(userId: Int64) -> AnyPublisher { + return userAPIProvider.requestPublisher(.fetchUserBookmarkedCollections(userId: userId)) + .mapBaseResponseData(CollectionsDTO.self) } - public func fetchMyKeywords() -> AnyPublisher { - return userAPIProvider.requestPublisher(.fetchMyKeywords) - .extractData(KeywordsDTO.self) + public func fetchUserBookmarkedContents(userId: Int64) -> AnyPublisher { + return userAPIProvider.requestPublisher(.fetchUserBookmarkedContents(userId: userId)) + .mapBaseResponseData(ContentsDTO.self) } public func fetchUserKeywords(userId: Int64) -> AnyPublisher { return userAPIProvider.requestPublisher(.fetchUserKeywords(userId: userId)) - .extractData(KeywordsDTO.self) + .mapBaseResponseData(KeywordsDTO.self) } - - public func fetchMyCollections() -> AnyPublisher { - return userAPIProvider.requestPublisher(.fetchMyCollections) - .extractData(UserCollectionsDTO.self) + + public func fetchUserCreatedCollections(userId: Int64) -> AnyPublisher { + return userAPIProvider.requestPublisher(.fetchUserCreatedCollections(userId: userId)) + .mapBaseResponseData(CollectionsDTO.self) } - - public func fetchUserCollections(userId: Int64) -> AnyPublisher { - return userAPIProvider.requestPublisher(.fetchUserCollections(userId: userId)) - .extractData(UserCollectionsDTO.self) + + public func fetchMyProfile() -> AnyPublisher { + return userAPIProvider.requestPublisher(.fetchMyProfile) + .mapBaseResponseData(UserProfileDTO.self) } - public func fetchMyBookmarkedCollections() -> AnyPublisher { + + public func fetchMyBookmarkedCollections() -> AnyPublisher { return userAPIProvider.requestPublisher(.fetchMyBookmarkedCollections) - .extractData(UserCollectionsDTO.self) + .mapBaseResponseData(CollectionsDTO.self) } - public func fetchBookmarkedCollections(userId: Int64) -> AnyPublisher { - return userAPIProvider.requestPublisher(.fetchBookmarkedCollections(userId: userId)) - .extractData(UserCollectionsDTO.self) + public func fetchMyCreatedCollections() -> AnyPublisher { + return userAPIProvider.requestPublisher(.fetchMyCreatedCollections) + .mapBaseResponseData(CollectionsDTO.self) } - public func fetchMyBookmarkedContents() -> AnyPublisher { - return userAPIProvider.requestPublisher(.fetchMyBookmarkedContents) - .extractData(ContentsDTO.self) + public func fetchMyKeywords() -> AnyPublisher { + return userAPIProvider.requestPublisher(.fetchMyKeywords) + .mapBaseResponseData(KeywordsDTO.self) } - public func fetchBookmarkedContents(userId: Int64) -> AnyPublisher { - return userAPIProvider.requestPublisher(.fetchBookmarkedContents(userId: userId)) - .extractData(ContentsDTO.self) + public func recalculateMyKeywords() -> AnyPublisher { + return userAPIProvider.requestPublisher(.recalculateMyKeywords) + .mapBaseResponseData(BlankData.self) + .map({ _ in }) + .eraseToAnyPublisher() + } + + public func checkNickname(_ nickname: String) -> AnyPublisher { + return userAPIProvider.requestPublisher(.checkNickname(nickname)) + .mapBaseResponseData(NicknameCheckDTO.self) } } diff --git a/FLINT/Data/Sources/Networking/TokenStorage/TokenStorage.swift b/FLINT/Data/Sources/Networking/TokenStorage/TokenStorage.swift index 2636b4f8..47ea5d58 100644 --- a/FLINT/Data/Sources/Networking/TokenStorage/TokenStorage.swift +++ b/FLINT/Data/Sources/Networking/TokenStorage/TokenStorage.swift @@ -1,5 +1,5 @@ // -// File.swift +// TokenStorage.swift // Data // // Created by 김호성 on 2026.01.21. diff --git a/FLINT/Data/Sources/RepositoryImpl/Auth/AuthRepositoryImpl.swift b/FLINT/Data/Sources/RepositoryImpl/AuthRepositoryImpl.swift similarity index 50% rename from FLINT/Data/Sources/RepositoryImpl/Auth/AuthRepositoryImpl.swift rename to FLINT/Data/Sources/RepositoryImpl/AuthRepositoryImpl.swift index f14e1a00..c7647ec8 100644 --- a/FLINT/Data/Sources/RepositoryImpl/Auth/AuthRepositoryImpl.swift +++ b/FLINT/Data/Sources/RepositoryImpl/AuthRepositoryImpl.swift @@ -1,5 +1,5 @@ // -// File.swift +// AuthRepositoryImpl.swift // Data // // Created by 김호성 on 2026.01.21. @@ -21,15 +21,19 @@ public final class DefaultAuthRepository: AuthRepository { self.authService = authService } - public func signup(_ signupInfoEntity: SignupInfoEntity) -> AnyPublisher { - return authService.signup(signupInfoEntity) + public func signup(userInfo: SignupInfoEntity) -> AnyPublisher { + return authService.signup(userInfo: userInfo) .tryMap({ try $0.userIdValue }) .eraseToAnyPublisher() } - public func socialVerify(socialVerifyEntity: SocialVerifyEntity) -> AnyPublisher { - return authService.socialVerify(socialVerifyRequestDTO: SocialVerifyRequestDTO(entity: socialVerifyEntity)) + public func socialVerify(socialAuthCredential: SocialVerifyEntity) -> AnyPublisher { + return authService.socialVerify(socialAuthCredential: SocialVerifyRequestDTO(entity: socialAuthCredential)) .tryMap({ try $0.entity }) .eraseToAnyPublisher() } + + public func withDraw() -> AnyPublisher { + return authService.withDraw() + } } diff --git a/FLINT/Data/Sources/RepositoryImpl/Bookmark/BookmarkRepositoryImpl.swift b/FLINT/Data/Sources/RepositoryImpl/Bookmark/BookmarkRepositoryImpl.swift deleted file mode 100644 index cc879937..00000000 --- a/FLINT/Data/Sources/RepositoryImpl/Bookmark/BookmarkRepositoryImpl.swift +++ /dev/null @@ -1,39 +0,0 @@ -// -// DefaultBookmarkRepository.swift -// Data -// -// Created by 소은 on 1/21/26. -// - -import Combine -import Foundation - -import Domain - -import DTO -import Networking - -public final class DefaultBookmarkRepository: BookmarkRepository { - - private let bookmarkService: BookmarkService - - public init(bookmarkService: BookmarkService) { - self.bookmarkService = bookmarkService - } - - public func toggleCollectionBookmark(_ collectionId: Int64) -> AnyPublisher { - return bookmarkService.toggleCollectionBookmark(collectionId) - } - - public func toggleContentBookmark(_ contentId: Int64) -> AnyPublisher { - return bookmarkService.toggleContentBookmark(contentId) - } - - public func fetchCollectionBookmarkUsers(_ collectionId: Int64) - -> AnyPublisher { - bookmarkService.fetchCollectionBookmarkUsers(collectionId) - .tryMap { try $0.entity } - .eraseToAnyPublisher() - } - -} diff --git a/FLINT/Data/Sources/RepositoryImpl/BookmarkRepositoryImpl.swift b/FLINT/Data/Sources/RepositoryImpl/BookmarkRepositoryImpl.swift new file mode 100644 index 00000000..e1961aaf --- /dev/null +++ b/FLINT/Data/Sources/RepositoryImpl/BookmarkRepositoryImpl.swift @@ -0,0 +1,37 @@ +// +// BookmarkRepositoryImpl.swift +// Data +// +// Created by 소은 on 1/21/26. +// + +import Combine +import Foundation + +import Domain + +import DTO +import Networking + +public final class DefaultBookmarkRepository: BookmarkRepository { + + private let bookmarkService: BookmarkService + + public init(bookmarkService: BookmarkService) { + self.bookmarkService = bookmarkService + } + + public func fetchCollectionBookmarkUsers(collectionId: Int64) -> AnyPublisher { + return bookmarkService.fetchCollectionBookmarkUsers(collectionId: collectionId) + .tryMap { try $0.entity } + .eraseToAnyPublisher() + } + + public func toggleCollectionBookmark(collectionId: Int64) -> AnyPublisher { + return bookmarkService.toggleCollectionBookmark(collectionId: collectionId) + } + + public func toggleContentBookmark(contentId: Int64) -> AnyPublisher { + return bookmarkService.toggleContentBookmark(contentId: contentId) + } +} diff --git a/FLINT/Data/Sources/RepositoryImpl/Collection/CollectionRepositoryImpl.swift b/FLINT/Data/Sources/RepositoryImpl/CollectionRepositoryImpl.swift similarity index 55% rename from FLINT/Data/Sources/RepositoryImpl/Collection/CollectionRepositoryImpl.swift rename to FLINT/Data/Sources/RepositoryImpl/CollectionRepositoryImpl.swift index dda1d94a..be2dd5ca 100644 --- a/FLINT/Data/Sources/RepositoryImpl/Collection/CollectionRepositoryImpl.swift +++ b/FLINT/Data/Sources/RepositoryImpl/CollectionRepositoryImpl.swift @@ -21,26 +21,27 @@ public final class DefaultCollectionRepository: CollectionRepository { self.collectionService = collectionService } - public func fetchCollections(cursor: UInt?, size: Int) -> AnyPublisher { + public func fetchCollections(cursor: Int64?, size: Int32) -> AnyPublisher { return collectionService.fetchCollections(cursor: cursor, size: size) .tryMap({ try $0.entity }) .eraseToAnyPublisher() } - public func createCollection(_ entity: CreateCollectionEntity) -> AnyPublisher { - return collectionService.createCollection(entity) + public func createCollection(collectionInfo: CreateCollectionEntity) -> AnyPublisher { + return collectionService.createCollection(collectionInfo: collectionInfo) + .tryMap { try $0.createdCollectionId } + .eraseToAnyPublisher() } public func fetchCollectionDetail(collectionId: Int64) -> AnyPublisher { - collectionService.fetchCollectionDetail(collectionId: collectionId) + return collectionService.fetchCollectionDetail(collectionId: collectionId) .tryMap { try $0.entity } .eraseToAnyPublisher() } - public func fetchWatchingCollections() -> AnyPublisher<[CollectionEntity], Error> { - return collectionService.fetchWatchingCollections() - .map(\.entities) + public func fetchRecentViewedCollections() -> AnyPublisher<[CollectionEntity], Error> { + return collectionService.fetchRecentViewedCollections() + .tryMap { try $0.entities } .eraseToAnyPublisher() } - } diff --git a/FLINT/Data/Sources/RepositoryImpl/Content/ContentRepositoryImpl.swift b/FLINT/Data/Sources/RepositoryImpl/Content/ContentRepositoryImpl.swift deleted file mode 100644 index 5d4a74d2..00000000 --- a/FLINT/Data/Sources/RepositoryImpl/Content/ContentRepositoryImpl.swift +++ /dev/null @@ -1,31 +0,0 @@ -// -// ContentRepository.swift -// Data -// -// Created by 소은 on 1/21/26. -// - - -import Combine -import Foundation - -import Domain - -import DTO -import Networking - -public final class DefaultContentRepository: ContentRepository { - - private let contentService: ContentService - - public init(contentService: ContentService) { - self.contentService = contentService - } - - public func fetchOTTPlatforms(_ contentId: Int64) -> AnyPublisher<[OTTPlatformEntity], Error> { - return contentService.fetchOTTPlatforms(contentId) - .tryMap({ try $0.entity }) - .eraseToAnyPublisher() - } -} - diff --git a/FLINT/Data/Sources/RepositoryImpl/ContentRepositoryImpl.swift b/FLINT/Data/Sources/RepositoryImpl/ContentRepositoryImpl.swift new file mode 100644 index 00000000..1518b918 --- /dev/null +++ b/FLINT/Data/Sources/RepositoryImpl/ContentRepositoryImpl.swift @@ -0,0 +1,35 @@ +// +// ContentRepositoryImpl.swift +// Data +// +// Created by 소은 on 1/21/26. +// + +import Combine +import Foundation + +import Domain + +import DTO +import Networking + +public final class DefaultContentRepository: ContentRepository { + + private let contentService: ContentService + + public init(contentService: ContentService) { + self.contentService = contentService + } + + public func fetchMyBookmarkedContents() -> AnyPublisher<[ContentInfoEntity], Error> { + return contentService.fetchMyBookmarkedContents() + .tryMap { try $0.entities } + .eraseToAnyPublisher() + } + + public func fetchOTTPlatformsForContent(contentId: Int64) -> AnyPublisher<[OTTPlatformEntity], Error> { + return contentService.fetchOTTPlatformsForContent(contentId: contentId) + .tryMap({ try $0.entity }) + .eraseToAnyPublisher() + } +} diff --git a/FLINT/Data/Sources/RepositoryImpl/Home/HomeRecommendedCollectionsImpl.swift b/FLINT/Data/Sources/RepositoryImpl/HomeRepositoryImpl.swift similarity index 76% rename from FLINT/Data/Sources/RepositoryImpl/Home/HomeRecommendedCollectionsImpl.swift rename to FLINT/Data/Sources/RepositoryImpl/HomeRepositoryImpl.swift index ed9828b3..9681cbf5 100644 --- a/FLINT/Data/Sources/RepositoryImpl/Home/HomeRecommendedCollectionsImpl.swift +++ b/FLINT/Data/Sources/RepositoryImpl/HomeRepositoryImpl.swift @@ -14,17 +14,16 @@ import DTO import Networking public final class DefaultHomeRepository: HomeRepository { - + private let homeService: HomeService - + public init(homeService: HomeService) { self.homeService = homeService } - - public func fetchRecommendedCollections() -> AnyPublisher<[CollectionInfoEntity], Error> { - homeService.fetchRecommendedCollections() - .map { $0.entities } + + public func fetchRecommendedCollections() -> AnyPublisher<[CollectionEntity], Error> { + return homeService.fetchRecommendedCollections() + .tryMap { try $0.entities } .eraseToAnyPublisher() } } - diff --git a/FLINT/Data/Sources/RepositoryImpl/Search/SearchRepositoryImpl.swift b/FLINT/Data/Sources/RepositoryImpl/SearchRepositoryImpl.swift similarity index 70% rename from FLINT/Data/Sources/RepositoryImpl/Search/SearchRepositoryImpl.swift rename to FLINT/Data/Sources/RepositoryImpl/SearchRepositoryImpl.swift index 734a4ad5..4f4b1152 100644 --- a/FLINT/Data/Sources/RepositoryImpl/Search/SearchRepositoryImpl.swift +++ b/FLINT/Data/Sources/RepositoryImpl/SearchRepositoryImpl.swift @@ -1,5 +1,5 @@ // -// SearchContentsImpl.swift +// SearchRepositoryImpl.swift // Data // // Created by 소은 on 1/20/26. @@ -21,8 +21,8 @@ public final class DefaultSearchRepository: SearchRepository { self.searchService = searchService } - public func searchContents(_ keyword: String?) -> AnyPublisher<[ContentEntity], Error> { - searchService.searchContents(keyword) + public func searchContents(keyword: String?) -> AnyPublisher<[ContentEntity], Error> { + return searchService.searchContents(keyword: keyword) .tryMap({ try $0.entities }) .eraseToAnyPublisher() } diff --git a/FLINT/Data/Sources/RepositoryImpl/User/UserRepositoryImpl.swift b/FLINT/Data/Sources/RepositoryImpl/User/UserRepositoryImpl.swift deleted file mode 100644 index c36da857..00000000 --- a/FLINT/Data/Sources/RepositoryImpl/User/UserRepositoryImpl.swift +++ /dev/null @@ -1,106 +0,0 @@ -// -// File.swift -// Data -// -// Created by 김호성 on 2026.01.19. -// - -import Combine -import Foundation - -import Domain - -import DTO -import Networking - -public final class DefaultUserRepository: UserRepository { - - private let userService: UserService - - public init(userService: UserService) { - self.userService = userService - } - - public func checkNickname(_ nickname: String) -> AnyPublisher { - userService.checkNickname(nickname) - .tryMap({ try $0.isAvailable }) - .eraseToAnyPublisher() - } - - public func fetchUserProfile(userId: Int64) -> AnyPublisher { - userService.fetchUserProfile(userId: userId) - .tryMap { try $0.entity } - .eraseToAnyPublisher() - } - - public func fetchMyProfile() -> AnyPublisher { - userService.fetchMyProfile() - .tryMap { try $0.entity } - .eraseToAnyPublisher() - } - - public func fetchMyKeywords() -> AnyPublisher<[KeywordEntity], Error> { - userService.fetchMyKeywords() - .tryMap { dto in - try (dto.keywords ?? []).map { try $0.entity } - } - .eraseToAnyPublisher() - } - - public func fetchUserKeywords(userId: Int64) -> AnyPublisher<[KeywordEntity], Error> { - userService.fetchUserKeywords(userId: userId) - .tryMap { dto in - try (dto.keywords ?? []).map { try $0.entity } - } - .eraseToAnyPublisher() - } - - public func fetchMyCollections() -> AnyPublisher<[CollectionEntity], Error> { - userService.fetchMyCollections() - .tryMap { dto in - try (dto.collections ?? []).map { try $0.entity } - } - .eraseToAnyPublisher() - } - - public func fetchUserCollections(userId: Int64) -> AnyPublisher<[CollectionEntity], Error> { - userService.fetchUserCollections(userId: userId) - .tryMap { dto in - try (dto.collections ?? []).map { try $0.entity } - } - .eraseToAnyPublisher() - } - - public func fetchMyBookmarkedCollections() -> AnyPublisher<[CollectionEntity], Error> { - userService.fetchMyBookmarkedCollections() - .tryMap { dto in - try (dto.collections ?? []).map { try $0.entity } - } - .eraseToAnyPublisher() - } - - public func fetchBookmarkedCollections(userId: Int64) -> AnyPublisher<[CollectionEntity], Error> { - userService.fetchBookmarkedCollections(userId: userId) - .tryMap { dto in - try (dto.collections ?? []).map { try $0.entity } - } - .eraseToAnyPublisher() - } - - public func fetchMyBookmarkedContents() -> AnyPublisher<[ContentInfoEntity], Error> { - userService.fetchMyBookmarkedContents() - .tryMap { dto in - try (dto.contents ?? []).map { try $0.entity } - } - .eraseToAnyPublisher() - } - - public func fetchBookmarkedContents(userId: Int64) -> AnyPublisher<[ContentInfoEntity], Error> { - userService.fetchBookmarkedContents(userId: userId) - .tryMap { dto in - try (dto.contents ?? []).map { try $0.entity } - } - .eraseToAnyPublisher() - } - -} diff --git a/FLINT/Data/Sources/RepositoryImpl/UserRepositoryImpl.swift b/FLINT/Data/Sources/RepositoryImpl/UserRepositoryImpl.swift new file mode 100644 index 00000000..e6222f14 --- /dev/null +++ b/FLINT/Data/Sources/RepositoryImpl/UserRepositoryImpl.swift @@ -0,0 +1,87 @@ +// +// UserRepositoryImpl.swift +// Data +// +// Created by 김호성 on 2026.01.19. +// + +import Combine +import Foundation + +import Domain + +import DTO +import Networking + +public final class DefaultUserRepository: UserRepository { + + private let userService: UserService + + public init(userService: UserService) { + self.userService = userService + } + + public func fetchUserProfile(userId: Int64) -> AnyPublisher { + return userService.fetchUserProfile(userId: userId) + .tryMap { try $0.entity } + .eraseToAnyPublisher() + } + + public func fetchUserBookmarkedCollections(userId: Int64) -> AnyPublisher<[CollectionEntity], Error> { + return userService.fetchUserBookmarkedCollections(userId: userId) + .tryMap { try $0.entities } + .eraseToAnyPublisher() + } + + public func fetchUserBookmarkedContents(userId: Int64) -> AnyPublisher<[ContentInfoEntity], Error> { + return userService.fetchUserBookmarkedContents(userId: userId) + .tryMap { try $0.entities } + .eraseToAnyPublisher() + } + + public func fetchUserCreatedCollections(userId: Int64) -> AnyPublisher<[CollectionEntity], Error> { + return userService.fetchUserCreatedCollections(userId: userId) + .tryMap { try $0.entities } + .eraseToAnyPublisher() + } + + public func fetchUserKeywords(userId: Int64) -> AnyPublisher<[KeywordEntity], Error> { + return userService.fetchUserKeywords(userId: userId) + .tryMap { try $0.entities } + .eraseToAnyPublisher() + } + + public func fetchMyProfile() -> AnyPublisher { + return userService.fetchMyProfile() + .tryMap { try $0.entity } + .eraseToAnyPublisher() + } + + public func fetchMyBookmarkedCollections() -> AnyPublisher<[CollectionEntity], Error> { + return userService.fetchMyBookmarkedCollections() + .tryMap { try $0.entities } + .eraseToAnyPublisher() + } + + public func fetchMyCreatedCollections() -> AnyPublisher<[CollectionEntity], Error> { + return userService.fetchMyCreatedCollections() + .tryMap { try $0.entities } + .eraseToAnyPublisher() + } + + public func fetchMyKeywords() -> AnyPublisher<[KeywordEntity], Error> { + return userService.fetchMyKeywords() + .tryMap { try $0.entities } + .eraseToAnyPublisher() + } + + public func recalculateMyKeywords() -> AnyPublisher { + return userService.recalculateMyKeywords() + } + + public func checkNickname(_ nickname: String) -> AnyPublisher { + return userService.checkNickname(nickname) + .tryMap({ try $0.isAvailable }) + .eraseToAnyPublisher() + } +} diff --git a/FLINT/Domain/Sources/Domain/Util/Extension/Collection+.swift b/FLINT/Domain/Sources/Domain/Util/Extension/Collection+.swift new file mode 100644 index 00000000..bc7ce0e5 --- /dev/null +++ b/FLINT/Domain/Sources/Domain/Util/Extension/Collection+.swift @@ -0,0 +1,15 @@ +// +// Collection+.swift +// Domain +// +// Created by 김호성 on 2026.02.13. +// + + +import Foundation + +extension Collection { + public subscript(safe index: Index) -> Element? { + return indices.contains(index) ? self[index] : nil + } +} diff --git a/FLINT/Domain/Sources/Entity/Login/LoginEntity.swift b/FLINT/Domain/Sources/Entity/Auth/Login/LoginEntity.swift similarity index 94% rename from FLINT/Domain/Sources/Entity/Login/LoginEntity.swift rename to FLINT/Domain/Sources/Entity/Auth/Login/LoginEntity.swift index 0ca05372..d3f45ed5 100644 --- a/FLINT/Domain/Sources/Entity/Login/LoginEntity.swift +++ b/FLINT/Domain/Sources/Entity/Auth/Login/LoginEntity.swift @@ -1,5 +1,5 @@ // -// File.swift +// LoginEntity.swift // Domain // // Created by 김호성 on 2026.01.21. diff --git a/FLINT/Domain/Sources/Entity/Signup/SignupInfoEntity.swift b/FLINT/Domain/Sources/Entity/Auth/Signup/SignupInfoEntity.swift similarity index 94% rename from FLINT/Domain/Sources/Entity/Signup/SignupInfoEntity.swift rename to FLINT/Domain/Sources/Entity/Auth/Signup/SignupInfoEntity.swift index 3211b694..c851125a 100644 --- a/FLINT/Domain/Sources/Entity/Signup/SignupInfoEntity.swift +++ b/FLINT/Domain/Sources/Entity/Auth/Signup/SignupInfoEntity.swift @@ -1,5 +1,5 @@ // -// File.swift +// SignupInfoEntity.swift // Domain // // Created by 김호성 on 2026.01.21. diff --git a/FLINT/Domain/Sources/Entity/SocialVerify/SocialLoginType.swift b/FLINT/Domain/Sources/Entity/Auth/SocialVerify/SocialLoginType.swift similarity index 84% rename from FLINT/Domain/Sources/Entity/SocialVerify/SocialLoginType.swift rename to FLINT/Domain/Sources/Entity/Auth/SocialVerify/SocialLoginType.swift index f57ad09a..c9eefe89 100644 --- a/FLINT/Domain/Sources/Entity/SocialVerify/SocialLoginType.swift +++ b/FLINT/Domain/Sources/Entity/Auth/SocialVerify/SocialLoginType.swift @@ -1,5 +1,5 @@ // -// File.swift +// SocialLoginType.swift // Domain // // Created by 김호성 on 2026.01.23. diff --git a/FLINT/Domain/Sources/Entity/SocialVerify/SocialVerifyEntity.swift b/FLINT/Domain/Sources/Entity/Auth/SocialVerify/SocialVerifyEntity.swift similarity index 92% rename from FLINT/Domain/Sources/Entity/SocialVerify/SocialVerifyEntity.swift rename to FLINT/Domain/Sources/Entity/Auth/SocialVerify/SocialVerifyEntity.swift index 22a1d8de..adee98b4 100644 --- a/FLINT/Domain/Sources/Entity/SocialVerify/SocialVerifyEntity.swift +++ b/FLINT/Domain/Sources/Entity/Auth/SocialVerify/SocialVerifyEntity.swift @@ -1,5 +1,5 @@ // -// File.swift +// SocialVerifyEntity.swift // Domain // // Created by 김호성 on 2026.01.23. diff --git a/FLINT/Domain/Sources/Entity/SocialVerify/SocialVerifyResponseDTO.swift b/FLINT/Domain/Sources/Entity/Auth/SocialVerify/SocialVerifyResultEntity.swift similarity index 92% rename from FLINT/Domain/Sources/Entity/SocialVerify/SocialVerifyResponseDTO.swift rename to FLINT/Domain/Sources/Entity/Auth/SocialVerify/SocialVerifyResultEntity.swift index 0bc9da0a..66a3832f 100644 --- a/FLINT/Domain/Sources/Entity/SocialVerify/SocialVerifyResponseDTO.swift +++ b/FLINT/Domain/Sources/Entity/Auth/SocialVerify/SocialVerifyResultEntity.swift @@ -1,5 +1,5 @@ // -// File.swift +// SocialVerifyResultEntity.swift // Data // // Created by 김호성 on 2026.01.23. diff --git a/FLINT/Domain/Sources/Entity/Bookmark/CollectionBookmarkUsersEntity.swift b/FLINT/Domain/Sources/Entity/Bookmark/CollectionBookmarkUsersEntity.swift index 852e6d32..1ceb7366 100644 --- a/FLINT/Domain/Sources/Entity/Bookmark/CollectionBookmarkUsersEntity.swift +++ b/FLINT/Domain/Sources/Entity/Bookmark/CollectionBookmarkUsersEntity.swift @@ -9,24 +9,10 @@ import Foundation public struct CollectionBookmarkUsersEntity: Equatable { public let bookmarkCount: Int - public let users: [CollectionBookmarkUserEntity] + public let users: [UserProfileEntity] - public init(bookmarkCount: Int, users: [CollectionBookmarkUserEntity]) { + public init(bookmarkCount: Int, users: [UserProfileEntity]) { self.bookmarkCount = bookmarkCount self.users = users } } - -public struct CollectionBookmarkUserEntity: Equatable { - public let userId: String - public let nickname: String - public let profileImageUrl: URL? - public let userRole: String - - public init(userId: String, nickname: String, profileImageUrl: URL?, userRole: String) { - self.userId = userId - self.nickname = nickname - self.profileImageUrl = profileImageUrl - self.userRole = userRole - } -} diff --git a/FLINT/Domain/Sources/Entity/Collection/CollectionDetailEntity.swift b/FLINT/Domain/Sources/Entity/Collection/CollectionDetailEntity.swift index b8e27646..8c36c26c 100644 --- a/FLINT/Domain/Sources/Entity/Collection/CollectionDetailEntity.swift +++ b/FLINT/Domain/Sources/Entity/Collection/CollectionDetailEntity.swift @@ -14,7 +14,7 @@ public struct CollectionDetailEntity: Equatable { public let thumbnailUrl: URL? public let createdAt: String public let isBookmarked: Bool - public let author: CollectionAuthorEntity? + public let author: UserProfileEntity public let contents: [CollectionContentEntity] public init( @@ -24,7 +24,7 @@ public struct CollectionDetailEntity: Equatable { thumbnailUrl: URL?, createdAt: String, isBookmarked: Bool, - author: CollectionAuthorEntity?, + author: UserProfileEntity, contents: [CollectionContentEntity] ) { self.id = id @@ -38,55 +38,39 @@ public struct CollectionDetailEntity: Equatable { } } -public struct CollectionAuthorEntity: Equatable { - public let id: String - public let nickname: String - public let profileImageUrl: URL? - public let userRole: String +extension CollectionDetailEntity { + public struct CollectionContentEntity: Equatable { + public let id: String + public let title: String + public let imageUrl: URL? + public let director: String + public let isBookmarked: Bool + public let bookmarkCount: Int + public let isSpoiler: Bool + public let reason: String + public let year: Int - public init( - id: String, - nickname: String, - profileImageUrl: URL?, - userRole: String - ) { - self.id = id - self.nickname = nickname - self.profileImageUrl = profileImageUrl - self.userRole = userRole + public init( + id: String, + title: String, + imageUrl: URL?, + director: String, + isBookmarked: Bool, + bookmarkCount: Int, + isSpoiler: Bool, + reason: String, + year: Int + ) { + self.id = id + self.title = title + self.imageUrl = imageUrl + self.director = director + self.isBookmarked = isBookmarked + self.bookmarkCount = bookmarkCount + self.isSpoiler = isSpoiler + self.reason = reason + self.year = year + } } -} - -public struct CollectionContentEntity: Equatable { - public let id: String - public let title: String - public let imageUrl: URL? - public let director: String - public let isBookmarked: Bool - public let bookmarkCount: Int - public let isSpoiler: Bool - public let reason: String - public let year: Int - public init( - id: String, - title: String, - imageUrl: URL?, - director: String, - isBookmarked: Bool, - bookmarkCount: Int, - isSpoiler: Bool, - reason: String, - year: Int - ) { - self.id = id - self.title = title - self.imageUrl = imageUrl - self.director = director - self.isBookmarked = isBookmarked - self.bookmarkCount = bookmarkCount - self.isSpoiler = isSpoiler - self.reason = reason - self.year = year - } } diff --git a/FLINT/Domain/Sources/Entity/Collection/CollectionEntity.swift b/FLINT/Domain/Sources/Entity/Collection/CollectionEntity.swift new file mode 100644 index 00000000..5098b424 --- /dev/null +++ b/FLINT/Domain/Sources/Entity/Collection/CollectionEntity.swift @@ -0,0 +1,30 @@ +// +// CollectionEntity.swift +// Domain +// +// Created by 진소은 on 1/23/26. +// + +import Foundation + +public struct CollectionEntity: Equatable { + public let id: String + public let thumbnailUrl: URL? + public let title: String + public let description: String + public let imageList: [URL] + public let bookmarkCount: Int + public let isBookmarked: Bool + public let user: UserProfileEntity + + public init(id: String, thumbnailUrl: URL?, title: String, description: String, imageList: [URL], bookmarkCount: Int, isBookmarked: Bool, user: UserProfileEntity) { + self.id = id + self.thumbnailUrl = thumbnailUrl + self.title = title + self.description = description + self.imageList = imageList + self.bookmarkCount = bookmarkCount + self.isBookmarked = isBookmarked + self.user = user + } +} diff --git a/FLINT/Domain/Sources/Entity/Collection/CollectionPagingEntity.swift b/FLINT/Domain/Sources/Entity/Collection/CollectionPagingEntity.swift index 5f606e13..7f542604 100644 --- a/FLINT/Domain/Sources/Entity/Collection/CollectionPagingEntity.swift +++ b/FLINT/Domain/Sources/Entity/Collection/CollectionPagingEntity.swift @@ -1,5 +1,5 @@ // -// File.swift +// CollectionPagingEntity.swift // Domain // // Created by 김호성 on 2026.01.22. @@ -9,9 +9,9 @@ import Foundation public struct CollectionPagingEntity { public let collections: [ExploreInfoEntity] - public let cursor: UInt + public let cursor: Int64? - public init(collections: [ExploreInfoEntity], cursor: UInt) { + public init(collections: [ExploreInfoEntity], cursor: Int64?) { self.collections = collections self.cursor = cursor } diff --git a/FLINT/Domain/Sources/Entity/Collection/CreateCollectionEntity.swift b/FLINT/Domain/Sources/Entity/Collection/CreateCollectionEntity.swift index 3bdb1215..70d8407f 100644 --- a/FLINT/Domain/Sources/Entity/Collection/CreateCollectionEntity.swift +++ b/FLINT/Domain/Sources/Entity/Collection/CreateCollectionEntity.swift @@ -35,10 +35,7 @@ public extension CreateCollectionEntity { public let isSpoiler: Bool public let reason: String - public init(contentId: Int64, - isSpoiler: Bool, - reason: String - ) { + public init(contentId: Int64, isSpoiler: Bool, reason: String) { self.contentId = contentId self.isSpoiler = isSpoiler self.reason = reason diff --git a/FLINT/Domain/Sources/Entity/Collection/ExploreInfoEntity.swift b/FLINT/Domain/Sources/Entity/Collection/ExploreInfoEntity.swift index c7cbefd1..548685d5 100644 --- a/FLINT/Domain/Sources/Entity/Collection/ExploreInfoEntity.swift +++ b/FLINT/Domain/Sources/Entity/Collection/ExploreInfoEntity.swift @@ -1,5 +1,5 @@ // -// File.swift +// ExploreInfoEntity.swift // Domain // // Created by 김호성 on 2026.01.22. @@ -7,14 +7,16 @@ import Foundation -public struct ExploreInfoEntity { +public struct ExploreInfoEntity: Hashable, Sendable { public let id: String + public let collectionId: Int64 public let imageUrl: URL? public let title: String public let description: String - public init(id: String, imageUrl: URL?, title: String, description: String) { - self.id = id + public init(collectionId: Int64, imageUrl: URL?, title: String, description: String) { + id = UUID().uuidString + self.collectionId = collectionId self.imageUrl = imageUrl self.title = title self.description = description diff --git a/FLINT/Presentation/Sources/View/Component/OTTLogoStripeView/CircleOTTPlatform.swift b/FLINT/Domain/Sources/Entity/Content/CircleOTTPlatform.swift similarity index 72% rename from FLINT/Presentation/Sources/View/Component/OTTLogoStripeView/CircleOTTPlatform.swift rename to FLINT/Domain/Sources/Entity/Content/CircleOTTPlatform.swift index c220b4d8..bb7246d8 100644 --- a/FLINT/Presentation/Sources/View/Component/OTTLogoStripeView/CircleOTTPlatform.swift +++ b/FLINT/Domain/Sources/Entity/Content/CircleOTTPlatform.swift @@ -1,6 +1,6 @@ // // CircleOTTPlatform.swift -// FLINT +// Domain // // Created by 소은 on 1/13/26. // @@ -18,17 +18,6 @@ public enum CircleOTTPlatform: CaseIterable, Hashable, Sendable { public static let order: [CircleOTTPlatform] = [ .netflix, .tving, .coupangPlay, .wavve, .disneyPlus, .watcha ] - - public var smallLogoImage: UIImage? { - switch self { - case .netflix: return UIImage.imgSmallNetflix1 - case .tving: return UIImage.imgSmallTving1 - case .coupangPlay: return UIImage.imgSmallCoupang1 - case .wavve: return UIImage.imgSmallWavve1 - case .disneyPlus: return UIImage.imgSmallDisney1 - case .watcha: return UIImage.imgSmallWatcha1 - } - } } extension Sequence where Element == CircleOTTPlatform { diff --git a/FLINT/Domain/Sources/Entity/Content/ContentEntity.swift b/FLINT/Domain/Sources/Entity/Content/ContentEntity.swift index 5067e9be..45bcb18b 100644 --- a/FLINT/Domain/Sources/Entity/Content/ContentEntity.swift +++ b/FLINT/Domain/Sources/Entity/Content/ContentEntity.swift @@ -1,5 +1,5 @@ // -// File.swift +// ContentEntity.swift // Domain // // Created by 김호성 on 2026.01.22. diff --git a/FLINT/Domain/Sources/Entity/User/ContentInfoEntity.swift b/FLINT/Domain/Sources/Entity/Content/ContentInfoEntity.swift similarity index 96% rename from FLINT/Domain/Sources/Entity/User/ContentInfoEntity.swift rename to FLINT/Domain/Sources/Entity/Content/ContentInfoEntity.swift index dfc6e4cb..edfb4473 100644 --- a/FLINT/Domain/Sources/Entity/User/ContentInfoEntity.swift +++ b/FLINT/Domain/Sources/Entity/Content/ContentInfoEntity.swift @@ -29,6 +29,7 @@ public struct ContentInfoEntity: Equatable { } } +// TODO: - OTT Entity 통일하기 public struct OttSimpleEntity: Equatable { public let ottName: String public let logoUrl: String diff --git a/FLINT/Presentation/Sources/View/Component/BottomSheet/OTTPlatformList/OTTPlatform.swift b/FLINT/Domain/Sources/Entity/Content/OTTPlatform.swift similarity index 86% rename from FLINT/Presentation/Sources/View/Component/BottomSheet/OTTPlatformList/OTTPlatform.swift rename to FLINT/Domain/Sources/Entity/Content/OTTPlatform.swift index c0faf607..48654b41 100644 --- a/FLINT/Presentation/Sources/View/Component/BottomSheet/OTTPlatformList/OTTPlatform.swift +++ b/FLINT/Domain/Sources/Entity/Content/OTTPlatform.swift @@ -1,6 +1,6 @@ // // OTTPlatform.swift -// FLINT +// Domain // // Created by 소은 on 1/12/26. // @@ -27,17 +27,6 @@ public enum OTTPlatform: String, CaseIterable, Hashable { } } - public var icon: UIImage? { - switch self { - case .netflix: return UIImage.imgSmallNetflix1 - case .tving: return UIImage.imgSmallTving1 - case .wavve: return UIImage.imgSmallWavve1 - case .coupangPlay: return UIImage.imgSmallCoupang1 - case .watcha: return UIImage.imgSmallWatcha1 - case .disneyPlus: return UIImage.imgSmallDisney1 - } - } - // MARK: - URL //TODO: 서버 연동 시 서버 값으로 대체 diff --git a/FLINT/Domain/Sources/Entity/Content/OTTPlatformEntity.swift b/FLINT/Domain/Sources/Entity/Content/OTTPlatformEntity.swift index 100370f2..ae3190b0 100644 --- a/FLINT/Domain/Sources/Entity/Content/OTTPlatformEntity.swift +++ b/FLINT/Domain/Sources/Entity/Content/OTTPlatformEntity.swift @@ -10,10 +10,10 @@ import Foundation public struct OTTPlatformEntity { public let ottId: String public let name: String - public let logoUrl: String - public let contentUrl: String + public let logoUrl: URL? + public let contentUrl: URL? - public init(ottId: String, name: String, logoUrl: String, contentUrl: String) { + public init(ottId: String, name: String, logoUrl: URL?, contentUrl: URL?) { self.ottId = ottId self.name = name self.logoUrl = logoUrl diff --git a/FLINT/Domain/Sources/Entity/Ott.swift b/FLINT/Domain/Sources/Entity/Content/Ott.swift similarity index 97% rename from FLINT/Domain/Sources/Entity/Ott.swift rename to FLINT/Domain/Sources/Entity/Content/Ott.swift index a2e7f242..1888acc0 100644 --- a/FLINT/Domain/Sources/Entity/Ott.swift +++ b/FLINT/Domain/Sources/Entity/Content/Ott.swift @@ -1,6 +1,6 @@ // // Ott.swift -// Presentation +// Domain // // Created by 김호성 on 2026.01.23. // diff --git a/FLINT/Domain/Sources/Entity/Home/CollectionInfoEntity.swift b/FLINT/Domain/Sources/Entity/Home/CollectionInfoEntity.swift deleted file mode 100644 index a2c4040b..00000000 --- a/FLINT/Domain/Sources/Entity/Home/CollectionInfoEntity.swift +++ /dev/null @@ -1,33 +0,0 @@ -// -// File.swift -// Domain -// -// Created by 소은 on 1/22/26. -// - -import Foundation - -public struct CollectionInfoEntity { - public let id: String? - public let imageUrlString: String - public let profileImageUrlString: String - public let title: String - public let userName: String - - public init( - id: String, - imageUrlString: String, - profileImageUrlString: String, - title: String, - userName: String - ) { - self.id = id - self.imageUrlString = imageUrlString - self.profileImageUrlString = profileImageUrlString - self.title = title - self.userName = userName - } - - public var imageURL: URL? { URL(string: imageUrlString) } - public var profileImageURL: URL? { URL(string: profileImageUrlString) } -} diff --git a/FLINT/Domain/Sources/Entity/Home/HomeRecommendedCollectionsEntity.swift b/FLINT/Domain/Sources/Entity/Home/HomeRecommendedCollectionsEntity.swift deleted file mode 100644 index c3cf4772..00000000 --- a/FLINT/Domain/Sources/Entity/Home/HomeRecommendedCollectionsEntity.swift +++ /dev/null @@ -1,58 +0,0 @@ -// -// HomeRecommendedCollectionsEntity.swift -// Domain -// -// Created by 소은 on 1/20/26. -// - -import Foundation - -public struct HomeRecommendedCollectionsEntity { - - public let collections: [HomeRecommendedCollectionEntity] - - public init(collections: [HomeRecommendedCollectionEntity]) { - self.collections = collections - } -} - -public extension HomeRecommendedCollectionsEntity { - - struct HomeRecommendedCollectionEntity { - - public let id: String - public let thumbnailUrl: String - public let title: String - public let description: String - public let imageList: [String] - public let bookmarkCount: Int - public let isBookmarked: Bool - public let userId: String - public let nickname: String - public let profileUrl: String - - public init( - id: String, - thumbnailUrl: String, - title: String, - description: String, - imageList: [String], - bookmarkCount: Int, - isBookmarked: Bool, - userId: String, - nickname: String, - profileUrl: String - ) { - self.id = id - self.thumbnailUrl = thumbnailUrl - self.title = title - self.description = description - self.imageList = imageList - self.bookmarkCount = bookmarkCount - self.isBookmarked = isBookmarked - self.userId = userId - self.nickname = nickname - self.profileUrl = profileUrl - } - } -} diff --git a/FLINT/Domain/Sources/Entity/Nickname/NicknameCheckEntity.swift b/FLINT/Domain/Sources/Entity/Nickname/NicknameCheckEntity.swift deleted file mode 100644 index 91f349a9..00000000 --- a/FLINT/Domain/Sources/Entity/Nickname/NicknameCheckEntity.swift +++ /dev/null @@ -1,16 +0,0 @@ -// -// File.swift -// Domain -// -// Created by 김호성 on 2026.01.20. -// - -import Foundation - -public struct NicknameCheckEntity { - public let available: Bool - - public init(available: Bool) { - self.available = available - } -} diff --git a/FLINT/Domain/Sources/Entity/SocialVerify/SocialLoginEntity.swift b/FLINT/Domain/Sources/Entity/SocialVerify/SocialLoginEntity.swift deleted file mode 100644 index 5b477c1a..00000000 --- a/FLINT/Domain/Sources/Entity/SocialVerify/SocialLoginEntity.swift +++ /dev/null @@ -1,22 +0,0 @@ -// -// File.swift -// Domain -// -// Created by 김호성 on 2026.01.23. -// - -import Foundation - -public struct SocialLoginEntity { - public let accessToken: String - public let refreshToken: String - public let userId: String - public let nickname: String - - public init(accessToken: String, refreshToken: String, userId: String, nickname: String) { - self.accessToken = accessToken - self.refreshToken = refreshToken - self.userId = userId - self.nickname = nickname - } -} diff --git a/FLINT/Domain/Sources/Entity/User/CollectionEntity.swift b/FLINT/Domain/Sources/Entity/User/CollectionEntity.swift deleted file mode 100644 index aac459a9..00000000 --- a/FLINT/Domain/Sources/Entity/User/CollectionEntity.swift +++ /dev/null @@ -1,45 +0,0 @@ -// -// CollectionEntity.swift -// Domain -// -// Created by 진소은 on 1/23/26. -// - -import Foundation - -public struct CollectionEntity: Equatable { - public let id: String - public let thumbnailUrl: String - public let title: String - public let description: String - public let imageList: [String] - public let bookmarkCount: Int - public let isBookmarked: Bool - public let userId: String - public let nickname: String - public let profileImageUrl: String - - public init( - id: String, - thumbnailUrl: String, - title: String, - description: String, - imageList: [String], - bookmarkCount: Int, - isBookmarked: Bool, - userId: String, - nickname: String, - profileImageUrl: String - ) { - self.id = id - self.thumbnailUrl = thumbnailUrl - self.title = title - self.description = description - self.imageList = imageList - self.bookmarkCount = bookmarkCount - self.isBookmarked = isBookmarked - self.userId = userId - self.nickname = nickname - self.profileImageUrl = profileImageUrl - } -} diff --git a/FLINT/Domain/Sources/Entity/User/KeywordColor.swift b/FLINT/Domain/Sources/Entity/User/KeywordColor.swift new file mode 100644 index 00000000..3007625e --- /dev/null +++ b/FLINT/Domain/Sources/Entity/User/KeywordColor.swift @@ -0,0 +1,16 @@ +// +// KeywordColor.swift +// Domain +// +// Created by 김호성 on 2026.02.09. +// + +import Foundation + +public enum KeywordColor: String, Decodable { + case pink = "PINK" + case green = "GREEN" + case orange = "ORANGE" + case yellow = "YELLOW" + case blue = "BLUE" +} diff --git a/FLINT/Domain/Sources/Entity/User/KeywordEntity.swift b/FLINT/Domain/Sources/Entity/User/KeywordEntity.swift index e48d3760..adf636de 100644 --- a/FLINT/Domain/Sources/Entity/User/KeywordEntity.swift +++ b/FLINT/Domain/Sources/Entity/User/KeywordEntity.swift @@ -8,13 +8,13 @@ import Foundation public struct KeywordEntity { - public let color: String + public let color: KeywordColor public let rank: Int public let name: String public let percentage: Int - public let imageUrl: String + public let imageUrl: URL? - public init(color: String, rank: Int, name: String, percentage: Int, imageUrl: String) { + public init(color: KeywordColor, rank: Int, name: String, percentage: Int, imageUrl: URL?) { self.color = color self.rank = rank self.name = name diff --git a/FLINT/Domain/Sources/Entity/Nickname/NicknameState.swift b/FLINT/Domain/Sources/Entity/User/NicknameState.swift similarity index 85% rename from FLINT/Domain/Sources/Entity/Nickname/NicknameState.swift rename to FLINT/Domain/Sources/Entity/User/NicknameState.swift index ba52e62c..4f3c7afa 100644 --- a/FLINT/Domain/Sources/Entity/Nickname/NicknameState.swift +++ b/FLINT/Domain/Sources/Entity/User/NicknameState.swift @@ -1,5 +1,5 @@ // -// File.swift +// NicknameValidState.swift // Domain // // Created by 김호성 on 2026.01.22. diff --git a/FLINT/Domain/Sources/Entity/User/UserProfileEntity.swift b/FLINT/Domain/Sources/Entity/User/UserProfileEntity.swift index 66dd624c..2a9c838c 100644 --- a/FLINT/Domain/Sources/Entity/User/UserProfileEntity.swift +++ b/FLINT/Domain/Sources/Entity/User/UserProfileEntity.swift @@ -7,16 +7,16 @@ import Foundation -public struct UserProfileEntity { +public struct UserProfileEntity: Equatable { public let id: String public let nickname: String - public let profileImageUrl: String - public let isFliner: Bool + public let profileImageUrl: URL? + public let role: UserRole - public init(id: String, nickname: String, profileImageUrl: String, isFliner: Bool) { + public init(id: String, nickname: String, profileImageUrl: URL?, role: UserRole) { self.id = id self.nickname = nickname self.profileImageUrl = profileImageUrl - self.isFliner = isFliner + self.role = role } } diff --git a/FLINT/Domain/Sources/Entity/User/UserRole.swift b/FLINT/Domain/Sources/Entity/User/UserRole.swift new file mode 100644 index 00000000..9e5081ad --- /dev/null +++ b/FLINT/Domain/Sources/Entity/User/UserRole.swift @@ -0,0 +1,21 @@ +// +// UserRole.swift +// Domain +// +// Created by 김호성 on 2026.02.08. +// + +import Foundation + +public enum UserRole: String, Equatable { + /// 관리자 - 시스템 전체 관리 권한 + case admin = "ADMIN" + + /// 일반 사용자 - 컬렉션 생성 및 관리 가능 + case fliner = "FLINER" + + /// 게스트 사용자 - 조회만 가능 + case fling = "FLING" + + case unknown +} diff --git a/FLINT/Domain/Sources/Entity/User/UserTarget.swift b/FLINT/Domain/Sources/Entity/User/UserTarget.swift new file mode 100644 index 00000000..60477ad4 --- /dev/null +++ b/FLINT/Domain/Sources/Entity/User/UserTarget.swift @@ -0,0 +1,13 @@ +// +// UserTarget.swift +// Domain +// +// Created by 김호성 on 2026.02.08. +// + +import Foundation + +public enum UserTarget { + case me + case user(id: Int64) +} diff --git a/FLINT/Domain/Sources/Repository/AuthRepository.swift b/FLINT/Domain/Sources/Repository/AuthRepository.swift index 363a23c9..7ab15d08 100644 --- a/FLINT/Domain/Sources/Repository/AuthRepository.swift +++ b/FLINT/Domain/Sources/Repository/AuthRepository.swift @@ -1,5 +1,5 @@ // -// File.swift +// AuthRepository.swift // Domain // // Created by 김호성 on 2026.01.21. @@ -11,6 +11,7 @@ import Foundation import Entity public protocol AuthRepository { - func signup(_ signupInfoEntity: SignupInfoEntity) -> AnyPublisher - func socialVerify(socialVerifyEntity: SocialVerifyEntity) -> AnyPublisher + func signup(userInfo: SignupInfoEntity) -> AnyPublisher + func socialVerify(socialAuthCredential: SocialVerifyEntity) -> AnyPublisher + func withDraw() -> AnyPublisher } diff --git a/FLINT/Domain/Sources/Repository/BookmarkRepository.swift b/FLINT/Domain/Sources/Repository/BookmarkRepository.swift index 85e0b4a8..f06080f0 100644 --- a/FLINT/Domain/Sources/Repository/BookmarkRepository.swift +++ b/FLINT/Domain/Sources/Repository/BookmarkRepository.swift @@ -11,9 +11,7 @@ import Foundation import Entity public protocol BookmarkRepository { - func toggleCollectionBookmark(_ collectionId: Int64) -> AnyPublisher - - func toggleContentBookmark(_ contentId: Int64) -> AnyPublisher - - func fetchCollectionBookmarkUsers(_ collectionId: Int64) -> AnyPublisher + func fetchCollectionBookmarkUsers(collectionId: Int64) -> AnyPublisher + func toggleCollectionBookmark(collectionId: Int64) -> AnyPublisher + func toggleContentBookmark(contentId: Int64) -> AnyPublisher } diff --git a/FLINT/Domain/Sources/Repository/CollectionRepository.swift b/FLINT/Domain/Sources/Repository/CollectionRepository.swift index 0a79baf9..8d60e639 100644 --- a/FLINT/Domain/Sources/Repository/CollectionRepository.swift +++ b/FLINT/Domain/Sources/Repository/CollectionRepository.swift @@ -11,8 +11,8 @@ import Foundation import Entity public protocol CollectionRepository { - func fetchCollections(cursor: UInt?, size: Int) -> AnyPublisher - func createCollection(_ entity: CreateCollectionEntity) -> AnyPublisher + func fetchCollections(cursor: Int64?, size: Int32) -> AnyPublisher + func createCollection(collectionInfo: CreateCollectionEntity) -> AnyPublisher func fetchCollectionDetail(collectionId: Int64) -> AnyPublisher - func fetchWatchingCollections() -> AnyPublisher<[CollectionEntity], Error> + func fetchRecentViewedCollections() -> AnyPublisher<[CollectionEntity], Error> } diff --git a/FLINT/Domain/Sources/Repository/ContentRepository.swift b/FLINT/Domain/Sources/Repository/ContentRepository.swift index 1e1324be..2b8f1ab1 100644 --- a/FLINT/Domain/Sources/Repository/ContentRepository.swift +++ b/FLINT/Domain/Sources/Repository/ContentRepository.swift @@ -11,5 +11,6 @@ import Foundation import Entity public protocol ContentRepository { - func fetchOTTPlatforms(_ contentId: Int64) -> AnyPublisher<[OTTPlatformEntity], Error> + func fetchMyBookmarkedContents() -> AnyPublisher<[ContentInfoEntity], Error> + func fetchOTTPlatformsForContent(contentId: Int64) -> AnyPublisher<[OTTPlatformEntity], Error> } diff --git a/FLINT/Domain/Sources/Repository/HomeRepository.swift b/FLINT/Domain/Sources/Repository/HomeRepository.swift index dfad235e..c366fc9a 100644 --- a/FLINT/Domain/Sources/Repository/HomeRepository.swift +++ b/FLINT/Domain/Sources/Repository/HomeRepository.swift @@ -10,8 +10,6 @@ import Foundation import Entity - public protocol HomeRepository { - func fetchRecommendedCollections() -> AnyPublisher<[CollectionInfoEntity], Error> + func fetchRecommendedCollections() -> AnyPublisher<[CollectionEntity], Error> } - diff --git a/FLINT/Domain/Sources/Repository/SearchRepository.swift b/FLINT/Domain/Sources/Repository/SearchRepository.swift index 48222fdf..4b46e5f6 100644 --- a/FLINT/Domain/Sources/Repository/SearchRepository.swift +++ b/FLINT/Domain/Sources/Repository/SearchRepository.swift @@ -1,5 +1,5 @@ // -// SearchContentsRepository.swift +// SearchRepository.swift // Domain // // Created by 소은 on 1/20/26. @@ -10,5 +10,5 @@ import Combine import Entity public protocol SearchRepository { - func searchContents(_ keyword: String?) -> AnyPublisher<[ContentEntity], Error> + func searchContents(keyword: String?) -> AnyPublisher<[ContentEntity], Error> } diff --git a/FLINT/Domain/Sources/Repository/UserRepository.swift b/FLINT/Domain/Sources/Repository/UserRepository.swift index 56d4ac60..5be3578d 100644 --- a/FLINT/Domain/Sources/Repository/UserRepository.swift +++ b/FLINT/Domain/Sources/Repository/UserRepository.swift @@ -1,5 +1,5 @@ // -// File.swift +// UserRepository.swift // Domain // // Created by 김호성 on 2026.01.20. @@ -11,15 +11,17 @@ import Foundation import Entity public protocol UserRepository { - func checkNickname(_ nickname: String) -> AnyPublisher func fetchUserProfile(userId: Int64) -> AnyPublisher - func fetchMyProfile() -> AnyPublisher - func fetchMyKeywords() -> AnyPublisher<[KeywordEntity], Error> + func fetchUserBookmarkedCollections(userId: Int64) -> AnyPublisher<[CollectionEntity], Error> + func fetchUserBookmarkedContents(userId: Int64) -> AnyPublisher<[ContentInfoEntity], Error> + func fetchUserCreatedCollections(userId: Int64) -> AnyPublisher<[CollectionEntity], Error> func fetchUserKeywords(userId: Int64) -> AnyPublisher<[KeywordEntity], Error> - func fetchMyCollections() -> AnyPublisher<[CollectionEntity], Error> - func fetchUserCollections(userId: Int64) -> AnyPublisher<[CollectionEntity], Error> + + func fetchMyProfile() -> AnyPublisher func fetchMyBookmarkedCollections() -> AnyPublisher<[CollectionEntity], Error> - func fetchBookmarkedCollections(userId: Int64) -> AnyPublisher<[CollectionEntity], Error> - func fetchMyBookmarkedContents() -> AnyPublisher<[ContentInfoEntity], Error> - func fetchBookmarkedContents(userId: Int64) -> AnyPublisher<[ContentInfoEntity], Error> + func fetchMyCreatedCollections() -> AnyPublisher<[CollectionEntity], Error> + func fetchMyKeywords() -> AnyPublisher<[KeywordEntity], Error> + func recalculateMyKeywords() -> AnyPublisher + + func checkNickname(_ nickname: String) -> AnyPublisher } diff --git a/FLINT/Domain/Sources/UseCase/Signup/SignupUseCase.swift b/FLINT/Domain/Sources/UseCase/Auth/SignupUseCase.swift similarity index 60% rename from FLINT/Domain/Sources/UseCase/Signup/SignupUseCase.swift rename to FLINT/Domain/Sources/UseCase/Auth/SignupUseCase.swift index ac4af143..fde53cf3 100644 --- a/FLINT/Domain/Sources/UseCase/Signup/SignupUseCase.swift +++ b/FLINT/Domain/Sources/UseCase/Auth/SignupUseCase.swift @@ -1,5 +1,5 @@ // -// File.swift +// SignupUseCase.swift // Domain // // Created by 김호성 on 2026.01.21. @@ -12,7 +12,7 @@ import Entity import Repository public protocol SignupUseCase { - func signup(_ signupInfoEntity: SignupInfoEntity) -> AnyPublisher + func callAsFunction(userInfo: SignupInfoEntity) -> AnyPublisher } public final class DefaultSignupUseCase: SignupUseCase { @@ -23,7 +23,7 @@ public final class DefaultSignupUseCase: SignupUseCase { self.authRepository = authRepository } - public func signup(_ signupInfoEntity: SignupInfoEntity) -> AnyPublisher { - return authRepository.signup(signupInfoEntity) + public func callAsFunction(userInfo: SignupInfoEntity) -> AnyPublisher { + return authRepository.signup(userInfo: userInfo) } } diff --git a/FLINT/Domain/Sources/UseCase/SocialVerify/SocialVerifyUseCase.swift b/FLINT/Domain/Sources/UseCase/Auth/SocialVerifyUseCase.swift similarity index 53% rename from FLINT/Domain/Sources/UseCase/SocialVerify/SocialVerifyUseCase.swift rename to FLINT/Domain/Sources/UseCase/Auth/SocialVerifyUseCase.swift index b6e6bcac..13c2e313 100644 --- a/FLINT/Domain/Sources/UseCase/SocialVerify/SocialVerifyUseCase.swift +++ b/FLINT/Domain/Sources/UseCase/Auth/SocialVerifyUseCase.swift @@ -1,5 +1,5 @@ // -// File.swift +// SocialVerifyUseCase.swift // Domain // // Created by 김호성 on 2026.01.23. @@ -12,7 +12,7 @@ import Entity import Repository public protocol SocialVerifyUseCase { - func socialVerify(socialVerifyEntity: SocialVerifyEntity) -> AnyPublisher + func callAsFunction(socialAuthCredential: SocialVerifyEntity) -> AnyPublisher } public final class DefaultSocialVerifyUseCase: SocialVerifyUseCase { @@ -23,7 +23,7 @@ public final class DefaultSocialVerifyUseCase: SocialVerifyUseCase { self.authRepository = authRepository } - public func socialVerify(socialVerifyEntity: SocialVerifyEntity) -> AnyPublisher { - return authRepository.socialVerify(socialVerifyEntity: socialVerifyEntity) + public func callAsFunction(socialAuthCredential: SocialVerifyEntity) -> AnyPublisher { + return authRepository.socialVerify(socialAuthCredential: socialAuthCredential) } } diff --git a/FLINT/Domain/Sources/UseCase/Auth/WithDrawUseCase.swift b/FLINT/Domain/Sources/UseCase/Auth/WithDrawUseCase.swift new file mode 100644 index 00000000..afe2fdec --- /dev/null +++ b/FLINT/Domain/Sources/UseCase/Auth/WithDrawUseCase.swift @@ -0,0 +1,29 @@ +// +// WithDrawUseCase.swift +// Domain +// +// Created by 김호성 on 2026.01.24. +// + +import Combine +import Foundation + +import Entity +import Repository + +public protocol WithDrawUseCase { + func callAsFunction() -> AnyPublisher +} + +public final class DefaultWithDrawUseCase: WithDrawUseCase { + + private let authRepository: AuthRepository + + public init(authRepository: AuthRepository) { + self.authRepository = authRepository + } + + public func callAsFunction() -> AnyPublisher { + return authRepository.withDraw() + } +} diff --git a/FLINT/Domain/Sources/UseCase/Bookmark/ToggleContentBookmarkUseCase.swift b/FLINT/Domain/Sources/UseCase/Bookmark/ToggleContentBookmarkUseCase.swift deleted file mode 100644 index bd95959a..00000000 --- a/FLINT/Domain/Sources/UseCase/Bookmark/ToggleContentBookmarkUseCase.swift +++ /dev/null @@ -1,29 +0,0 @@ -// -// ToggleContentBookmarkUseCase.swift -// Domain -// -// Created by 소은 on 1/21/26. -// - -import Combine -import Foundation - -import Entity -import Repository - -public protocol ToggleContentBookmarkUseCase { - func toggleContentBookmark(_ contentId: Int64) -> AnyPublisher -} - -public class DefaultToggleContentBookmarkUseCase: ToggleContentBookmarkUseCase { - - let repository: BookmarkRepository - - public init(repository: BookmarkRepository) { - self.repository = repository - } - - public func toggleContentBookmark(_ contentId: Int64) -> AnyPublisher { - return repository.toggleContentBookmark(contentId) - } -} diff --git a/FLINT/Domain/Sources/UseCase/Collection/CreateCollectionUseCase.swift b/FLINT/Domain/Sources/UseCase/Collection/CreateCollectionUseCase.swift index 75ec82eb..0e5c8626 100644 --- a/FLINT/Domain/Sources/UseCase/Collection/CreateCollectionUseCase.swift +++ b/FLINT/Domain/Sources/UseCase/Collection/CreateCollectionUseCase.swift @@ -12,7 +12,7 @@ import Entity import Repository public protocol CreateCollectionUseCase { - func createCollection(_ entity: CreateCollectionEntity) -> AnyPublisher + func callAsFunction(collectionInfo: CreateCollectionEntity) -> AnyPublisher } public class DefaultCreateCollectionUseCase: CreateCollectionUseCase { @@ -23,7 +23,7 @@ public class DefaultCreateCollectionUseCase: CreateCollectionUseCase { self.collectionRepository = collectionRepository } - public func createCollection(_ entity: CreateCollectionEntity) -> AnyPublisher { - return collectionRepository.createCollection(entity) + public func callAsFunction(collectionInfo: CreateCollectionEntity) -> AnyPublisher { + return collectionRepository.createCollection(collectionInfo: collectionInfo) } } diff --git a/FLINT/Domain/Sources/UseCase/Collection/FetchBookmarkedCollectionsUseCase.swift b/FLINT/Domain/Sources/UseCase/Collection/FetchBookmarkedCollectionsUseCase.swift new file mode 100644 index 00000000..3d74aea4 --- /dev/null +++ b/FLINT/Domain/Sources/UseCase/Collection/FetchBookmarkedCollectionsUseCase.swift @@ -0,0 +1,34 @@ +// +// FetchBookmarkedCollectionsUseCase.swift +// Domain +// +// Created by 김호성 on 2026.02.08. +// + +import Combine +import Foundation + +import Entity +import Repository + +public protocol FetchBookmarkedCollectionsUseCase { + func callAsFunction(for target: UserTarget) -> AnyPublisher<[CollectionEntity], Error> +} + +public final class DefaultFetchBookmarkedCollectionsUseCase: FetchBookmarkedCollectionsUseCase { + + private let userRepository: UserRepository + + public init(userRepository: UserRepository) { + self.userRepository = userRepository + } + + public func callAsFunction(for target: UserTarget) -> AnyPublisher<[CollectionEntity], Error> { + switch target { + case .me: + return userRepository.fetchMyBookmarkedCollections() + case let .user(id): + return userRepository.fetchUserBookmarkedCollections(userId: id) + } + } +} diff --git a/FLINT/Domain/Sources/UseCase/Bookmark/FetchBookmarkedUserUseCase.swift b/FLINT/Domain/Sources/UseCase/Collection/FetchCollectionBookmarkUsersUseCase.swift similarity index 52% rename from FLINT/Domain/Sources/UseCase/Bookmark/FetchBookmarkedUserUseCase.swift rename to FLINT/Domain/Sources/UseCase/Collection/FetchCollectionBookmarkUsersUseCase.swift index f5c67a3f..a7e553b8 100644 --- a/FLINT/Domain/Sources/UseCase/Bookmark/FetchBookmarkedUserUseCase.swift +++ b/FLINT/Domain/Sources/UseCase/Collection/FetchCollectionBookmarkUsersUseCase.swift @@ -5,19 +5,17 @@ // Created by 진소은 on 1/23/26. // -import Foundation - import Combine +import Foundation import Entity import Repository -public protocol FetchBookmarkedUserUseCase { - func execute(collectionId: Int64) - -> AnyPublisher +public protocol FetchCollectionBookmarkUsersUseCase { + func callAsFunction(collectionId: Int64) -> AnyPublisher } -public final class DefaultFetchBookmarkedUserUseCase: FetchBookmarkedUserUseCase { +public final class DefaultFetchCollectionBookmarkUsersUseCase: FetchCollectionBookmarkUsersUseCase { private let bookmarkRepository: BookmarkRepository @@ -25,8 +23,7 @@ public final class DefaultFetchBookmarkedUserUseCase: FetchBookmarkedUserUseCase self.bookmarkRepository = bookmarkRepository } - public func execute(collectionId: Int64) - -> AnyPublisher { - return bookmarkRepository.fetchCollectionBookmarkUsers(collectionId) + public func callAsFunction(collectionId: Int64) -> AnyPublisher { + return bookmarkRepository.fetchCollectionBookmarkUsers(collectionId: collectionId) } } diff --git a/FLINT/Domain/Sources/UseCase/Collection/CollectionDetailUseCase.swift b/FLINT/Domain/Sources/UseCase/Collection/FetchCollectionDetailUseCase.swift similarity index 51% rename from FLINT/Domain/Sources/UseCase/Collection/CollectionDetailUseCase.swift rename to FLINT/Domain/Sources/UseCase/Collection/FetchCollectionDetailUseCase.swift index d0ce2a37..56f1ac3f 100644 --- a/FLINT/Domain/Sources/UseCase/Collection/CollectionDetailUseCase.swift +++ b/FLINT/Domain/Sources/UseCase/Collection/FetchCollectionDetailUseCase.swift @@ -1,5 +1,5 @@ // -// CollectionDetailUseCase.swift +// FetchCollectionDetailUseCase.swift // Domain // // Created by 진소은 on 1/23/26. @@ -11,19 +11,19 @@ import Foundation import Entity import Repository -public protocol CollectionDetailUseCase { - func fetchCollectionDetail(collectionId: Int64) -> AnyPublisher +public protocol FetchCollectionDetailUseCase { + func callAsFunction(collectionId: Int64) -> AnyPublisher } -public class DefaultCollectionDetailUseCase: CollectionDetailUseCase { - +public class DefaultFetchCollectionDetailUseCase: FetchCollectionDetailUseCase { + private let collectionRepository: CollectionRepository - + public init(collectionRepository: CollectionRepository) { self.collectionRepository = collectionRepository } - - public func fetchCollectionDetail(collectionId: Int64) -> AnyPublisher { + + public func callAsFunction(collectionId: Int64) -> AnyPublisher { return collectionRepository.fetchCollectionDetail(collectionId: collectionId) } } diff --git a/FLINT/Domain/Sources/UseCase/Collection/FetchCreatedCollectionsUseCase.swift b/FLINT/Domain/Sources/UseCase/Collection/FetchCreatedCollectionsUseCase.swift new file mode 100644 index 00000000..492567ec --- /dev/null +++ b/FLINT/Domain/Sources/UseCase/Collection/FetchCreatedCollectionsUseCase.swift @@ -0,0 +1,34 @@ +// +// FetchCreatedCollectionsUseCase.swift +// Domain +// +// Created by 김호성 on 2026.02.08. +// + +import Combine +import Foundation + +import Entity +import Repository + +public protocol FetchCreatedCollectionsUseCase { + func callAsFunction(for target: UserTarget) -> AnyPublisher<[CollectionEntity], Error> +} + +public final class DefaultFetchCreatedCollectionsUseCase: FetchCreatedCollectionsUseCase { + + private let userRepository: UserRepository + + public init(userRepository: UserRepository) { + self.userRepository = userRepository + } + + public func callAsFunction(for target: UserTarget) -> AnyPublisher<[CollectionEntity], Error> { + switch target { + case .me: + return userRepository.fetchMyCreatedCollections() + case let .user(id): + return userRepository.fetchUserCreatedCollections(userId: id) + } + } +} diff --git a/FLINT/Domain/Sources/UseCase/Collection/FetchExploreCollectionsUseCase.swift b/FLINT/Domain/Sources/UseCase/Collection/FetchExploreCollectionsUseCase.swift new file mode 100644 index 00000000..3b5520a6 --- /dev/null +++ b/FLINT/Domain/Sources/UseCase/Collection/FetchExploreCollectionsUseCase.swift @@ -0,0 +1,29 @@ +// +// FetchExploreCollectionsUseCase.swift +// Domain +// +// Created by 김호성 on 2026.01.22. +// + +import Combine +import Foundation + +import Entity +import Repository + +public protocol FetchExploreCollectionsUseCase { + func callAsFunction(cursor: Int64?) -> AnyPublisher +} + +public final class DefaultFetchExploreCollectionsUseCase: FetchExploreCollectionsUseCase { + + private let collectionRepository: CollectionRepository + + public init(collectionRepository: CollectionRepository) { + self.collectionRepository = collectionRepository + } + + public func callAsFunction(cursor: Int64?) -> AnyPublisher { + return collectionRepository.fetchCollections(cursor: cursor, size: 5) + } +} diff --git a/FLINT/Domain/Sources/UseCase/Collection/FetchRecentViewedCollectionsUseCase.swift b/FLINT/Domain/Sources/UseCase/Collection/FetchRecentViewedCollectionsUseCase.swift new file mode 100644 index 00000000..0c7d6b2e --- /dev/null +++ b/FLINT/Domain/Sources/UseCase/Collection/FetchRecentViewedCollectionsUseCase.swift @@ -0,0 +1,29 @@ +// +// FetchRecentViewedCollectionsUseCase.swift +// Domain +// +// Created by 소은 on 1/24/26. +// + +import Combine +import Foundation + +import Entity +import Repository + +public protocol FetchRecentViewedCollectionsUseCase { + func callAsFunction() -> AnyPublisher<[CollectionEntity], Error> +} + +public final class DefaultFetchRecentViewedCollectionsUseCase: FetchRecentViewedCollectionsUseCase { + + private let collectionRepository: CollectionRepository + + public init(collectionRepository: CollectionRepository) { + self.collectionRepository = collectionRepository + } + + public func callAsFunction() -> AnyPublisher<[CollectionEntity], Error> { + return collectionRepository.fetchRecentViewedCollections() + } +} diff --git a/FLINT/Domain/Sources/UseCase/Collection/FetchRecommendedCollectionsUseCase.swift b/FLINT/Domain/Sources/UseCase/Collection/FetchRecommendedCollectionsUseCase.swift new file mode 100644 index 00000000..0b618676 --- /dev/null +++ b/FLINT/Domain/Sources/UseCase/Collection/FetchRecommendedCollectionsUseCase.swift @@ -0,0 +1,29 @@ +// +// FetchRecommendedCollectionsUseCase.swift +// Domain +// +// Created by 김호성 on 2026.02.08. +// + +import Combine +import Foundation + +import Entity +import Repository + +public protocol FetchRecommendedCollectionsUseCase { + func callAsFunction() -> AnyPublisher<[CollectionEntity], Error> +} + +public final class DefaultFetchRecommendedCollectionsUseCase: FetchRecommendedCollectionsUseCase { + + private let homeRepository: HomeRepository + + public init(homeRepository: HomeRepository) { + self.homeRepository = homeRepository + } + + public func callAsFunction() -> AnyPublisher<[CollectionEntity], Error> { + return homeRepository.fetchRecommendedCollections() + } +} diff --git a/FLINT/Domain/Sources/UseCase/Collection/FetchWatchingCollectionsListUseCase.swift b/FLINT/Domain/Sources/UseCase/Collection/FetchWatchingCollectionsListUseCase.swift deleted file mode 100644 index 638c5345..00000000 --- a/FLINT/Domain/Sources/UseCase/Collection/FetchWatchingCollectionsListUseCase.swift +++ /dev/null @@ -1,29 +0,0 @@ -// -// WatchingCollections.swift -// Domain -// -// Created by 소은 on 1/24/26. -// - -import Combine -import Foundation - -import Entity -import Repository - -public protocol FetchWatchingCollectionsUseCase { - func fetchWatchingCollections() -> AnyPublisher<[CollectionEntity], Error> -} - -public final class DefaultFetchWatchingCollectionsUseCase: FetchWatchingCollectionsUseCase { - - private let collectionRepository: CollectionRepository - - public init(collectionRepository: CollectionRepository) { - self.collectionRepository = collectionRepository - } - - public func fetchWatchingCollections() -> AnyPublisher<[CollectionEntity], Error> { - collectionRepository.fetchWatchingCollections() - } -} diff --git a/FLINT/Domain/Sources/UseCase/Bookmark/ToggleCollectionBookmarkUseCase.swift b/FLINT/Domain/Sources/UseCase/Collection/ToggleCollectionBookmarkUseCase.swift similarity index 74% rename from FLINT/Domain/Sources/UseCase/Bookmark/ToggleCollectionBookmarkUseCase.swift rename to FLINT/Domain/Sources/UseCase/Collection/ToggleCollectionBookmarkUseCase.swift index 06dc889d..39849310 100644 --- a/FLINT/Domain/Sources/UseCase/Bookmark/ToggleCollectionBookmarkUseCase.swift +++ b/FLINT/Domain/Sources/UseCase/Collection/ToggleCollectionBookmarkUseCase.swift @@ -12,7 +12,7 @@ import Entity import Repository public protocol ToggleCollectionBookmarkUseCase { - func toggleCollectionBookmark(_ collectionId: Int64) -> AnyPublisher + func callAsFunction(collectionId: Int64) -> AnyPublisher } public class DefaultToggleCollectionBookmarkUseCase: ToggleCollectionBookmarkUseCase { @@ -23,8 +23,7 @@ public class DefaultToggleCollectionBookmarkUseCase: ToggleCollectionBookmarkUse self.bookmarkRepository = bookmarkRepository } - public func toggleCollectionBookmark(_ collectionId: Int64) -> AnyPublisher { - return bookmarkRepository.toggleCollectionBookmark(collectionId) + public func callAsFunction(collectionId: Int64) -> AnyPublisher { + return bookmarkRepository.toggleCollectionBookmark(collectionId: collectionId) } } - diff --git a/FLINT/Domain/Sources/UseCase/Content/ContentsUseCase.swift b/FLINT/Domain/Sources/UseCase/Content/ContentsUseCase.swift deleted file mode 100644 index 3744c8ce..00000000 --- a/FLINT/Domain/Sources/UseCase/Content/ContentsUseCase.swift +++ /dev/null @@ -1,29 +0,0 @@ -// -// File.swift -// Domain -// -// Created by 김호성 on 2026.01.22. -// - -import Combine -import Foundation - -import Entity -import Repository - -public protocol ContentsUseCase { - func fetchContents() -> AnyPublisher<[ContentEntity], Error> -} - -public class DefaultContentsUseCase: ContentsUseCase { - - private let searchRepository: SearchRepository - - public init(searchRepository: SearchRepository) { - self.searchRepository = searchRepository - } - - public func fetchContents() -> AnyPublisher<[ContentEntity], Error> { - return searchRepository.searchContents(nil) - } -} diff --git a/FLINT/Domain/Sources/UseCase/Content/FetchBookmarkedContentsUseCase.swift b/FLINT/Domain/Sources/UseCase/Content/FetchBookmarkedContentsUseCase.swift new file mode 100644 index 00000000..d64ce0fe --- /dev/null +++ b/FLINT/Domain/Sources/UseCase/Content/FetchBookmarkedContentsUseCase.swift @@ -0,0 +1,36 @@ +// +// FetchBookmarkedContentsUseCase.swift +// Domain +// +// Created by 김호성 on 2026.02.08. +// + +import Combine +import Foundation + +import Entity +import Repository + +public protocol FetchBookmarkedContentsUseCase { + func callAsFunction(for target: UserTarget) -> AnyPublisher<[ContentInfoEntity], Error> +} + +public final class DefaultFetchBookmarkedContentsUseCase: FetchBookmarkedContentsUseCase { + + private let contentRepository: ContentRepository + private let userRepository: UserRepository + + public init(contentRepository: ContentRepository, userRepository: UserRepository) { + self.contentRepository = contentRepository + self.userRepository = userRepository + } + + public func callAsFunction(for target: UserTarget) -> AnyPublisher<[ContentInfoEntity], Error> { + switch target { + case .me: + return contentRepository.fetchMyBookmarkedContents() + case let .user(id): + return userRepository.fetchUserBookmarkedContents(userId: id) + } + } +} diff --git a/FLINT/Domain/Sources/UseCase/Content/FetchOTTPlatformsForContentUseCase.swift b/FLINT/Domain/Sources/UseCase/Content/FetchOTTPlatformsForContentUseCase.swift new file mode 100644 index 00000000..a704bb6b --- /dev/null +++ b/FLINT/Domain/Sources/UseCase/Content/FetchOTTPlatformsForContentUseCase.swift @@ -0,0 +1,29 @@ +// +// FetchOTTPlatformsForContentUseCase.swift +// Domain +// +// Created by 소은 on 1/21/26. +// + +import Combine +import Foundation + +import Entity +import Repository + +public protocol FetchOTTPlatformsForContentUseCase { + func callAsFunction(contentId: Int64) -> AnyPublisher<[OTTPlatformEntity], Error> +} + +public class DefaultFetchOTTPlatformsForContentUseCase: FetchOTTPlatformsForContentUseCase { + + private let contentRepository: ContentRepository + + public init(contentRepository: ContentRepository) { + self.contentRepository = contentRepository + } + + public func callAsFunction(contentId: Int64) -> AnyPublisher<[OTTPlatformEntity], Error> { + return contentRepository.fetchOTTPlatformsForContent(contentId: contentId) + } +} diff --git a/FLINT/Domain/Sources/UseCase/Content/FetchOTTPlatformsUseCase.swift b/FLINT/Domain/Sources/UseCase/Content/FetchOTTPlatformsUseCase.swift deleted file mode 100644 index 86a45f58..00000000 --- a/FLINT/Domain/Sources/UseCase/Content/FetchOTTPlatformsUseCase.swift +++ /dev/null @@ -1,29 +0,0 @@ -// -// FetchOTTPlatformsUseCase.swift -// Domain -// -// Created by 소은 on 1/21/26. -// - -import Combine -import Foundation - -import Entity -import Repository - -public protocol FetchOTTPlatformsUseCase { - func fetchOTTPlatforms(_ contentId: Int64) -> AnyPublisher<[OTTPlatformEntity], Error> -} - -public class DefaultFetchOTTPlatformsUseCase: FetchOTTPlatformsUseCase { - - private let contentRepository: ContentRepository - - public init(contentRepository: ContentRepository) { - self.contentRepository = contentRepository - } - - public func fetchOTTPlatforms(_ contentId: Int64) -> AnyPublisher<[OTTPlatformEntity], Error> { - return contentRepository.fetchOTTPlatforms(contentId) - } -} diff --git a/FLINT/Domain/Sources/UseCase/Content/FetchPopularContentsUseCase.swift b/FLINT/Domain/Sources/UseCase/Content/FetchPopularContentsUseCase.swift new file mode 100644 index 00000000..4a385556 --- /dev/null +++ b/FLINT/Domain/Sources/UseCase/Content/FetchPopularContentsUseCase.swift @@ -0,0 +1,29 @@ +// +// FetchPopularContentsUseCase.swift +// Domain +// +// Created by 김호성 on 2026.01.22. +// + +import Combine +import Foundation + +import Entity +import Repository + +public protocol FetchPopularContentsUseCase { + func callAsFunction() -> AnyPublisher<[ContentEntity], Error> +} + +public class DefaultFetchPopularContentsUseCase: FetchPopularContentsUseCase { + + private let searchRepository: SearchRepository + + public init(searchRepository: SearchRepository) { + self.searchRepository = searchRepository + } + + public func callAsFunction() -> AnyPublisher<[ContentEntity], Error> { + return searchRepository.searchContents(keyword: nil) + } +} diff --git a/FLINT/Domain/Sources/UseCase/Search/SearchContentsUseCase.swift b/FLINT/Domain/Sources/UseCase/Content/SearchContentsUseCase.swift similarity index 65% rename from FLINT/Domain/Sources/UseCase/Search/SearchContentsUseCase.swift rename to FLINT/Domain/Sources/UseCase/Content/SearchContentsUseCase.swift index fdb68dcf..3ace5fe8 100644 --- a/FLINT/Domain/Sources/UseCase/Search/SearchContentsUseCase.swift +++ b/FLINT/Domain/Sources/UseCase/Content/SearchContentsUseCase.swift @@ -12,7 +12,7 @@ import Entity import Repository public protocol SearchContentsUseCase: AnyObject { - func searchContents(_ keyword: String) -> AnyPublisher<[ContentEntity], Error> + func callAsFunction(keyword: String) -> AnyPublisher<[ContentEntity], Error> } public class DefaultSearchContentsUseCase: SearchContentsUseCase { @@ -23,7 +23,7 @@ public class DefaultSearchContentsUseCase: SearchContentsUseCase { self.searchRepository = searchRepository } - public func searchContents(_ keyword: String) -> AnyPublisher<[ContentEntity], Error> { - return searchRepository.searchContents(keyword) + public func callAsFunction(keyword: String) -> AnyPublisher<[ContentEntity], Error> { + return searchRepository.searchContents(keyword: keyword) } } diff --git a/FLINT/Domain/Sources/UseCase/Content/ToggleContentBookmarkUseCase.swift b/FLINT/Domain/Sources/UseCase/Content/ToggleContentBookmarkUseCase.swift new file mode 100644 index 00000000..cf8b3964 --- /dev/null +++ b/FLINT/Domain/Sources/UseCase/Content/ToggleContentBookmarkUseCase.swift @@ -0,0 +1,29 @@ +// +// ToggleContentBookmarkUseCase.swift +// Domain +// +// Created by 소은 on 1/21/26. +// + +import Combine +import Foundation + +import Entity +import Repository + +public protocol ToggleContentBookmarkUseCase { + func callAsFunction(contentId: Int64) -> AnyPublisher +} + +public class DefaultToggleContentBookmarkUseCase: ToggleContentBookmarkUseCase { + + private let bookmarkRepository: BookmarkRepository + + public init(bookmarkRepository: BookmarkRepository) { + self.bookmarkRepository = bookmarkRepository + } + + public func callAsFunction(contentId: Int64) -> AnyPublisher { + return bookmarkRepository.toggleContentBookmark(contentId: contentId) + } +} diff --git a/FLINT/Domain/Sources/UseCase/Explore/ExploreUseCase.swift b/FLINT/Domain/Sources/UseCase/Explore/ExploreUseCase.swift deleted file mode 100644 index b636bb9f..00000000 --- a/FLINT/Domain/Sources/UseCase/Explore/ExploreUseCase.swift +++ /dev/null @@ -1,29 +0,0 @@ -// -// File.swift -// Domain -// -// Created by 김호성 on 2026.01.22. -// - -import Combine -import Foundation - -import Entity -import Repository - -public protocol ExploreUseCase { - func fetchExplore(cursor: UInt?) -> AnyPublisher -} - -public final class DefaultExploreUseCase: ExploreUseCase { - - private let collectionRepository: CollectionRepository - - public init(collectionRepository: CollectionRepository) { - self.collectionRepository = collectionRepository - } - - public func fetchExplore(cursor: UInt?) -> AnyPublisher { - collectionRepository.fetchCollections(cursor: cursor, size: 3) - } -} diff --git a/FLINT/Domain/Sources/UseCase/Home/HomeUseCase.swift b/FLINT/Domain/Sources/UseCase/Home/HomeUseCase.swift deleted file mode 100644 index a2eabfec..00000000 --- a/FLINT/Domain/Sources/UseCase/Home/HomeUseCase.swift +++ /dev/null @@ -1,28 +0,0 @@ -// -// HomeUsecase.swift -// Domain -// -// Created by 소은 on 1/20/26. -// -import Combine -import Foundation - -import Entity -import Repository - -public protocol HomeUseCase { - func fetchRecommendedCollections() -> AnyPublisher<[CollectionInfoEntity], Error> -} - -public class DefaultHomeUseCase: HomeUseCase { - - private let homeRepository: HomeRepository - - public init(homeRepository: HomeRepository) { - self.homeRepository = homeRepository - } - - public func fetchRecommendedCollections() -> AnyPublisher<[CollectionInfoEntity], Error> { - return homeRepository.fetchRecommendedCollections() - } -} diff --git a/FLINT/Domain/Sources/UseCase/Nickname/NicknameUseCase.swift b/FLINT/Domain/Sources/UseCase/Profile/CheckNicknameUseCase.swift similarity index 54% rename from FLINT/Domain/Sources/UseCase/Nickname/NicknameUseCase.swift rename to FLINT/Domain/Sources/UseCase/Profile/CheckNicknameUseCase.swift index 63d1e2fa..86183df1 100644 --- a/FLINT/Domain/Sources/UseCase/Nickname/NicknameUseCase.swift +++ b/FLINT/Domain/Sources/UseCase/Profile/CheckNicknameUseCase.swift @@ -1,5 +1,5 @@ // -// File.swift +// CheckNicknameUseCase.swift // Domain // // Created by 김호성 on 2026.01.20. @@ -11,11 +11,11 @@ import Foundation import Entity import Repository -public protocol NicknameUseCase { - func checkNickname(_ nickname: String) -> AnyPublisher +public protocol CheckNicknameUseCase { + func callAsFunction(_ nickname: String) -> AnyPublisher } -public final class DefaultNicknameUseCase: NicknameUseCase { +public final class DefaultCheckNicknameUseCase: CheckNicknameUseCase { private let userRepository: UserRepository @@ -23,7 +23,7 @@ public final class DefaultNicknameUseCase: NicknameUseCase { self.userRepository = userRepository } - public func checkNickname(_ nickname: String) -> AnyPublisher { + public func callAsFunction(_ nickname: String) -> AnyPublisher { return userRepository.checkNickname(nickname) } } diff --git a/FLINT/Domain/Sources/UseCase/Profile/FetchKeywordsUseCase.swift b/FLINT/Domain/Sources/UseCase/Profile/FetchKeywordsUseCase.swift new file mode 100644 index 00000000..9bfa5b73 --- /dev/null +++ b/FLINT/Domain/Sources/UseCase/Profile/FetchKeywordsUseCase.swift @@ -0,0 +1,34 @@ +// +// FetchKeywordsUseCase.swift +// Domain +// +// Created by 김호성 on 2026.02.08. +// + +import Combine +import Foundation + +import Entity +import Repository + +public protocol FetchKeywordsUseCase { + func callAsFunction(for target: UserTarget) -> AnyPublisher<[KeywordEntity], Error> +} + +public final class DefaultFetchKeywordsUseCase: FetchKeywordsUseCase { + + private let userRepository: UserRepository + + public init(userRepository: UserRepository) { + self.userRepository = userRepository + } + + public func callAsFunction(for target: UserTarget) -> AnyPublisher<[KeywordEntity], Error> { + switch target { + case .me: + return userRepository.fetchMyKeywords() + case let .user(id): + return userRepository.fetchUserKeywords(userId: id) + } + } +} diff --git a/FLINT/Domain/Sources/UseCase/Profile/FetchProfileUseCase.swift b/FLINT/Domain/Sources/UseCase/Profile/FetchProfileUseCase.swift new file mode 100644 index 00000000..d65f1cb2 --- /dev/null +++ b/FLINT/Domain/Sources/UseCase/Profile/FetchProfileUseCase.swift @@ -0,0 +1,34 @@ +// +// FetchProfileUseCase.swift +// Domain +// +// Created by 김호성 on 2026.02.08. +// + +import Combine +import Foundation + +import Entity +import Repository + +public protocol FetchProfileUseCase { + func callAsFunction(for target: UserTarget) -> AnyPublisher +} + +public final class DefaultFetchProfileUseCase: FetchProfileUseCase { + + private let userRepository: UserRepository + + public init(userRepository: UserRepository) { + self.userRepository = userRepository + } + + public func callAsFunction(for target: UserTarget) -> AnyPublisher { + switch target { + case .me: + return userRepository.fetchMyProfile() + case let .user(id): + return userRepository.fetchUserProfile(userId: id) + } + } +} diff --git a/FLINT/Domain/Sources/UseCase/Profile/UserProfileUseCase.swift b/FLINT/Domain/Sources/UseCase/Profile/UserProfileUseCase.swift deleted file mode 100644 index a7dfc0c4..00000000 --- a/FLINT/Domain/Sources/UseCase/Profile/UserProfileUseCase.swift +++ /dev/null @@ -1,75 +0,0 @@ -// -// UserProfileUseCase.swift -// Domain -// -// Created by 진소은 on 1/22/26. -// - - -import Combine -import Foundation - -import Entity -import Repository - -public protocol UserProfileUseCase { - func fetchUserProfile(userId: Int64) -> AnyPublisher - func fetchMyProfile() -> AnyPublisher - func fetchMyKeywords() -> AnyPublisher<[KeywordEntity], Error> - func fetchUserKeywords(userId: Int64) -> AnyPublisher<[KeywordEntity], Error> - func fetchMyCollections() -> AnyPublisher<[CollectionEntity], Error> - func fetchUserCollections(userId: Int64) -> AnyPublisher<[CollectionEntity], Error> - func fetchMyBookmarkedCollections() -> AnyPublisher<[CollectionEntity], Error> - func fetchBookmarkedCollections(userId: Int64) -> AnyPublisher<[CollectionEntity], Error> - func fetchMyBookmarkedContents() -> AnyPublisher<[ContentInfoEntity], Error> - func fetchBookmarkedContents(userId: Int64) -> AnyPublisher<[ContentInfoEntity], Error> -} - -public final class DefaultUserProfileUseCase: UserProfileUseCase { - - private let userRepository: UserRepository - - public init(userRepository: UserRepository) { - self.userRepository = userRepository - } - - public func fetchUserProfile(userId: Int64) -> AnyPublisher { - return userRepository.fetchUserProfile(userId: userId) - } - - public func fetchMyProfile() -> AnyPublisher { - return userRepository.fetchMyProfile() - } - - public func fetchUserKeywords(userId: Int64) -> AnyPublisher<[KeywordEntity], Error> { - return userRepository.fetchUserKeywords(userId: userId) - } - - public func fetchMyKeywords() -> AnyPublisher<[KeywordEntity], Error> { - return userRepository.fetchMyKeywords() - } - - public func fetchMyCollections() -> AnyPublisher<[CollectionEntity], Error> { - userRepository.fetchMyCollections() - } - - public func fetchUserCollections(userId: Int64) -> AnyPublisher<[CollectionEntity], Error> { - userRepository.fetchUserCollections(userId: userId) - } - - public func fetchMyBookmarkedCollections() -> AnyPublisher<[CollectionEntity], Error> { - return userRepository.fetchMyBookmarkedCollections() - } - - public func fetchBookmarkedCollections(userId: Int64) -> AnyPublisher<[CollectionEntity], Error> { - return userRepository.fetchBookmarkedCollections(userId: userId) - } - - public func fetchMyBookmarkedContents() -> AnyPublisher<[ContentInfoEntity], Error> { - return userRepository.fetchMyBookmarkedContents() - } - - public func fetchBookmarkedContents(userId: Int64) -> AnyPublisher<[ContentInfoEntity], Error> { - return userRepository.fetchBookmarkedContents(userId: userId) - } -} diff --git a/FLINT/FLINT/Application/AppDelegate.swift b/FLINT/FLINT/Application/AppDelegate.swift index 884ab483..c5272215 100644 --- a/FLINT/FLINT/Application/AppDelegate.swift +++ b/FLINT/FLINT/Application/AppDelegate.swift @@ -17,28 +17,25 @@ import Presentation @main class AppDelegate: UIResponder, UIApplicationDelegate { - + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // Override point for customization after application launch. UIFont.registerPretendardFonts() KakaoSDK.initSDK(appKey: NetworkConfig.kakaoAppKey) return true } - + // MARK: UISceneSession Lifecycle - + func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { // Called when a new scene session is being created. // Use this method to select a configuration to create the new scene with. return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) } - + func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { // Called when the user discards a scene session. // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. // Use this method to release any resources that were specific to the discarded scenes, as they will not return. } - - } - diff --git a/FLINT/FLINT/Application/SceneDelegate.swift b/FLINT/FLINT/Application/SceneDelegate.swift index cf36522b..2f7505b7 100644 --- a/FLINT/FLINT/Application/SceneDelegate.swift +++ b/FLINT/FLINT/Application/SceneDelegate.swift @@ -13,17 +13,17 @@ import Presentation import Domain class SceneDelegate: UIResponder, UIWindowSceneDelegate { - + var window: UIWindow? let diContainer: DIContainer = DIContainer() - + func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { guard let windowScene = (scene as? UIWindowScene) else { return } window = UIWindow(windowScene: windowScene) -// let viewController = diContainer.makeSplashViewController() - let viewController = diContainer.makeTabBarViewController() + let viewController = diContainer.makeSplashViewController() +// let viewController = diContainer.makeTabBarViewController() let navigationController = UINavigationController(rootViewController: viewController).configured({ $0.navigationBar.isHidden = true }) @@ -37,27 +37,28 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { // Release any resources associated with this scene that can be re-created the next time the scene connects. // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead). } - + func sceneDidBecomeActive(_ scene: UIScene) { // Called when the scene has moved from an inactive state to an active state. // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. } - + func sceneWillResignActive(_ scene: UIScene) { // Called when the scene will move from an active state to an inactive state. // This may occur due to temporary interruptions (ex. an incoming phone call). } - + func sceneWillEnterForeground(_ scene: UIScene) { // Called as the scene transitions from the background to the foreground. // Use this method to undo the changes made on entering the background. } - + func sceneDidEnterBackground(_ scene: UIScene) { // Called as the scene transitions from the foreground to the background. // Use this method to save data, release shared resources, and store enough scene-specific state information // to restore the scene back to its current state. } + func scene(_ scene: UIScene, openURLContexts URLContexts: Set) { if let url = URLContexts.first?.url { Log.d(url) @@ -67,4 +68,3 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { } } } - diff --git a/FLINT/FLINT/Dependency/DIContainer.swift b/FLINT/FLINT/Dependency/DIContainer.swift index 45446cd8..f2319ae4 100644 --- a/FLINT/FLINT/Dependency/DIContainer.swift +++ b/FLINT/FLINT/Dependency/DIContainer.swift @@ -15,171 +15,45 @@ import Data import Domain import Presentation -typealias AppFactory = ViewControllerFactory & OnboardingViewModelFactory & ExploreViewModelFactory & CreateCollectionFactory & AddContentSelectViewModelFactory & ProfileFactory & HomeFactory & CollectionDetailFactory & LoginViewModelFactory - -final class DIContainer: AppFactory { +typealias DependencyFactory = ViewControllerFactory & + + LoginViewModelFactory & + OnboardingViewModelFactory & + + HomeViewModelFactory & + ExploreViewModelFactory & + ProfileViewModelFactory & + + CreateCollectionViewModelFactory & + AddContentSelectViewModelFactory & + CollectionFolderListViewModelFactory & + CollectionDetailViewModelFactory + +final class DIContainer: DependencyFactory { // MARK: - Root Dependency -// private lazy var tokenStorage: TokenStorage = DefaultTokenStorage() - private lazy var tokenStorage: TokenStorage = TestTokenStorage() - private lazy var authInterceptor: AuthInterceptor = AuthInterceptor(tokenStorage: tokenStorage) private lazy var networkLoggerPlugin: NetworkLoggerPlugin = NetworkLoggerPlugin() - private lazy var userAPIProvider = MoyaProvider( - session: Session(interceptor: authInterceptor), - plugins: [ - networkLoggerPlugin - ] - ) - private lazy var collectionAPIProvider = MoyaProvider( - session: Session(interceptor: authInterceptor), - plugins: [ - networkLoggerPlugin - ] - ) - private lazy var searchAPIProvider = MoyaProvider( - session: Session(interceptor: authInterceptor), - plugins: [ - networkLoggerPlugin - ] - ) - private lazy var bookmarkAPIProvider = MoyaProvider( - session: Session(interceptor: authInterceptor), - plugins: [ - networkLoggerPlugin - ] - ) - - private lazy var authAPIProvider = MoyaProvider( - session: Session(interceptor: authInterceptor), - plugins: [ - networkLoggerPlugin - ] - ) + private lazy var session: Session = Session(interceptor: authInterceptor) + private lazy var plugins: [PluginType] = [] +// private lazy var plugins: [PluginType] = [networkLoggerPlugin] + + lazy var authAPIProvider = MoyaProvider(session: session, plugins: plugins) + lazy var bookmarkAPIProvider = MoyaProvider(session: session, plugins: plugins) + lazy var collectionAPIProvider = MoyaProvider(session: session, plugins: plugins) + lazy var contentAPIProvider = MoyaProvider(session: session, plugins: plugins) + lazy var homeAPIProvider = MoyaProvider(session: session, plugins: plugins) + lazy var searchAPIProvider = MoyaProvider(session: session, plugins: plugins) + lazy var userAPIProvider = MoyaProvider(session: session, plugins: plugins) - private lazy var homeAPIProvider = MoyaProvider( - session: Session(interceptor: authInterceptor), - plugins: [ - networkLoggerPlugin - ] - ) + lazy var tokenStorage: TokenStorage = DefaultTokenStorage() +// lazy var tokenStorage: TokenStorage = TestTokenStorage() // MARK: - Init init() { - tokenStorage.clearAll() - } - - // MARK: - ViewControllerFactory - - func makeSplashViewController() -> SplashViewController { - return SplashViewController(viewControllerFactory: self) - } - - func makeLoginViewController() -> LoginViewController { - return LoginViewController(loginViewModel: makeLoginViewModel(), viewControllerFactory: self) - } - - func makeTabBarViewController() -> TabBarViewController { - return TabBarViewController(viewControllerFactory: self) - } - - func makeNicknameViewController() -> NicknameViewController { - return NicknameViewController(onboardingViewModel: makeOnboardingViewModel(), viewControllerFactory: self) - } - - func makeAddContentSelectViewController() -> AddContentSelectViewController { - let vm = makeAddContentSelectViewModel() - return AddContentSelectViewController(viewModel: vm, viewControllerFactory: self) - } - - func makeCreateCollectionViewController() -> CreateCollectionViewController { - let vm = makeCreateCollectionViewModel() - return CreateCollectionViewController(viewModel: vm, viewControllerFactory: self) - } - - func makeHomeViewController() -> HomeViewController { - let vm = makeHomeViewModel() - return HomeViewController(viewModel: vm, viewControllerFactory: self) - } - - func makeFilmSelectViewController(onboardingViewModel: OnboardingViewModel) -> FilmSelectViewController { - return FilmSelectViewController(onboardingViewModel: onboardingViewModel, viewControllerFactory: self) - } - - func makeOttSelectViewController(onboardingViewModel: OnboardingViewModel) -> OttSelectViewController { - return OttSelectViewController(onboardingViewModel: onboardingViewModel, viewControllerFactory: self) - } - - func makeOnboardingDoneViewController(onboardingViewModel: OnboardingViewModel) -> OnboardingDoneViewController { - return OnboardingDoneViewController(onboardingViewModel: onboardingViewModel, viewControllerFactory: self) - } - - func makeExploreViewController() -> ViewController.ExploreViewController { - return ExploreViewController(exploreViewModel: makeExploreViewModel(), viewControllerFactory: self) - } - - - func makeProfileViewController() -> ProfileViewController { - makeProfileViewController(target: .me) - } - - func makeProfileViewController( - target: ProfileViewModel.Target = .me - ) -> ProfileViewController { - return ProfileViewController( - profileViewModel: makeProfileViewModel(target: target), - viewControllerFactory: self - ) - } - - -// func makeCollectionDetailViewController(collectionId: Int64) -> CollectionDetailViewController { -// let vm = makeCollectionDetailViewModel(collectionId: collectionId) -// return CollectionDetailViewController(viewModel: vm) -// } - func makeCollectionDetailViewController(collectionId: Int64) -> CollectionDetailViewController { - let vm = makeCollectionDetailViewModel(collectionId: collectionId) - return CollectionDetailViewController(viewModel: vm, viewControllerFactory: self) - } - - - func makeCollectionFolderListViewController() -> CollectionFolderListViewController { - let vm = CollectionFolderListViewModel(fetchWatchingCollectionsUseCase: makeFetchWatchingCollectionsUseCase()) - return CollectionFolderListViewController(viewModel: vm, viewControllerFactory: self) - } - - - - // MARK: - Root Dependency Injection - - func makeTokenStorage() -> TokenStorage { - return tokenStorage - } - - func makeUserAPIProvider() -> MoyaProvider { - return userAPIProvider - } - - func makeSearchAPIProvider() -> MoyaProvider { - return searchAPIProvider - } - - func makeCollectionAPIProvider() -> MoyaProvider { - return collectionAPIProvider - } - - func makeBookmarkAPIProvider() -> MoyaProvider { - return bookmarkAPIProvider - } - - func makeAuthAPIProvider() -> MoyaProvider { - return authAPIProvider - } - - func makeHomeAPIProvider() -> MoyaProvider { - return homeAPIProvider +// tokenStorage.clearAll() } } diff --git a/FLINT/FLINT/Dependency/Factory/APIProvider/AuthAPIFactory.swift b/FLINT/FLINT/Dependency/Factory/APIProvider/AuthAPIFactory.swift deleted file mode 100644 index 082fe532..00000000 --- a/FLINT/FLINT/Dependency/Factory/APIProvider/AuthAPIFactory.swift +++ /dev/null @@ -1,16 +0,0 @@ -// -// AuthAPIFactory.swift -// FLINT -// -// Created by 김호성 on 2026.01.23. -// - -import Foundation - -import Moya - -import Data - -protocol AuthAPIFactory { - func makeAuthAPIProvider() -> MoyaProvider -} diff --git a/FLINT/FLINT/Dependency/Factory/APIProvider/AuthAPIProviderFactory.swift b/FLINT/FLINT/Dependency/Factory/APIProvider/AuthAPIProviderFactory.swift new file mode 100644 index 00000000..96580873 --- /dev/null +++ b/FLINT/FLINT/Dependency/Factory/APIProvider/AuthAPIProviderFactory.swift @@ -0,0 +1,24 @@ +// +// AuthAPIProviderFactory.swift +// FLINT +// +// Created by 김호성 on 2026.01.23. +// + +import Foundation + +import Moya + +import Data + +protocol AuthAPIProviderFactory { + var authAPIProvider: MoyaProvider { get set } + + func makeAuthAPIProvider() -> MoyaProvider +} + +extension AuthAPIProviderFactory { + func makeAuthAPIProvider() -> MoyaProvider { + return authAPIProvider + } +} diff --git a/FLINT/FLINT/Dependency/Factory/APIProvider/BookmarkAPIProviderFactory.swift b/FLINT/FLINT/Dependency/Factory/APIProvider/BookmarkAPIProviderFactory.swift new file mode 100644 index 00000000..95341bfc --- /dev/null +++ b/FLINT/FLINT/Dependency/Factory/APIProvider/BookmarkAPIProviderFactory.swift @@ -0,0 +1,23 @@ +// +// BookmarkAPIProviderFactory.swift +// FLINT +// +// Created by 김호성 on 2026.01.31. +// + +import Foundation +import Moya + +import Data + +protocol BookmarkAPIProviderFactory { + var bookmarkAPIProvider: MoyaProvider { get set } + + func makeBookmarkAPIProvider() -> MoyaProvider +} + +extension BookmarkAPIProviderFactory { + func makeBookmarkAPIProvider() -> MoyaProvider { + return bookmarkAPIProvider + } +} diff --git a/FLINT/FLINT/Dependency/Factory/APIProvider/CollectionAPIFactory.swift b/FLINT/FLINT/Dependency/Factory/APIProvider/CollectionAPIFactory.swift deleted file mode 100644 index c4ac4e1a..00000000 --- a/FLINT/FLINT/Dependency/Factory/APIProvider/CollectionAPIFactory.swift +++ /dev/null @@ -1,16 +0,0 @@ -// -// CollectionAPIFactory.swift -// FLINT -// -// Created by 김호성 on 2026.01.22. -// - -import Foundation - -import Moya - -import Data - -protocol CollectionAPIFactory { - func makeCollectionAPIProvider() -> MoyaProvider -} diff --git a/FLINT/FLINT/Dependency/Factory/APIProvider/CollectionAPIProviderFactory.swift b/FLINT/FLINT/Dependency/Factory/APIProvider/CollectionAPIProviderFactory.swift new file mode 100644 index 00000000..fb02d1fd --- /dev/null +++ b/FLINT/FLINT/Dependency/Factory/APIProvider/CollectionAPIProviderFactory.swift @@ -0,0 +1,24 @@ +// +// CollectionAPIFactory.swift +// FLINT +// +// Created by 김호성 on 2026.01.22. +// + +import Foundation + +import Moya + +import Data + +protocol CollectionAPIProviderFactory { + var collectionAPIProvider: MoyaProvider { get set } + + func makeCollectionAPIProvider() -> MoyaProvider +} + +extension CollectionAPIProviderFactory { + func makeCollectionAPIProvider() -> MoyaProvider { + return collectionAPIProvider + } +} diff --git a/FLINT/FLINT/Dependency/Factory/APIProvider/ContentAPIProviderFactory.swift b/FLINT/FLINT/Dependency/Factory/APIProvider/ContentAPIProviderFactory.swift new file mode 100644 index 00000000..ec54d6a2 --- /dev/null +++ b/FLINT/FLINT/Dependency/Factory/APIProvider/ContentAPIProviderFactory.swift @@ -0,0 +1,24 @@ +// +// ContentAPIProviderFactory.swift +// FLINT +// +// Created by 김호성 on 2026.02.09. +// + +import Foundation + +import Moya + +import Data + +protocol ContentAPIProviderFactory { + var contentAPIProvider: MoyaProvider { get set } + + func makeContentAPIProvider() -> MoyaProvider +} + +extension ContentAPIProviderFactory { + func makeContentAPIProvider() -> MoyaProvider { + return contentAPIProvider + } +} diff --git a/FLINT/FLINT/Dependency/Factory/APIProvider/HomeAPIProviderFactory.swift b/FLINT/FLINT/Dependency/Factory/APIProvider/HomeAPIProviderFactory.swift new file mode 100644 index 00000000..45cab367 --- /dev/null +++ b/FLINT/FLINT/Dependency/Factory/APIProvider/HomeAPIProviderFactory.swift @@ -0,0 +1,24 @@ +// +// HomeAPIProviderFactory.swift +// FLINT +// +// Created by 김호성 on 2026.01.31. +// + +import Foundation + +import Moya + +import Data + +protocol HomeAPIProviderFactory { + var homeAPIProvider: MoyaProvider { get set } + + func makeHomeAPIProvider() -> MoyaProvider +} + +extension HomeAPIProviderFactory { + func makeHomeAPIProvider() -> MoyaProvider { + return homeAPIProvider + } +} diff --git a/FLINT/FLINT/Dependency/Factory/APIProvider/SearchAPIFactory.swift b/FLINT/FLINT/Dependency/Factory/APIProvider/SearchAPIFactory.swift deleted file mode 100644 index 1f56a58b..00000000 --- a/FLINT/FLINT/Dependency/Factory/APIProvider/SearchAPIFactory.swift +++ /dev/null @@ -1,16 +0,0 @@ -// -// SearchAPIFactory.swift -// FLINT -// -// Created by 김호성 on 2026.01.22. -// - -import Foundation - -import Moya - -import Data - -protocol SearchAPIFactory { - func makeSearchAPIProvider() -> MoyaProvider -} diff --git a/FLINT/FLINT/Dependency/Factory/APIProvider/SearchAPIProviderFactory.swift b/FLINT/FLINT/Dependency/Factory/APIProvider/SearchAPIProviderFactory.swift new file mode 100644 index 00000000..8ba2dc01 --- /dev/null +++ b/FLINT/FLINT/Dependency/Factory/APIProvider/SearchAPIProviderFactory.swift @@ -0,0 +1,24 @@ +// +// SearchAPIProviderFactory.swift +// FLINT +// +// Created by 김호성 on 2026.01.22. +// + +import Foundation + +import Moya + +import Data + +protocol SearchAPIProviderFactory { + var searchAPIProvider: MoyaProvider { get set } + + func makeSearchAPIProvider() -> MoyaProvider +} + +extension SearchAPIProviderFactory { + func makeSearchAPIProvider() -> MoyaProvider { + return searchAPIProvider + } +} diff --git a/FLINT/FLINT/Dependency/Factory/APIProvider/UserAPIFactory.swift b/FLINT/FLINT/Dependency/Factory/APIProvider/UserAPIFactory.swift deleted file mode 100644 index 92430ff5..00000000 --- a/FLINT/FLINT/Dependency/Factory/APIProvider/UserAPIFactory.swift +++ /dev/null @@ -1,16 +0,0 @@ -// -// File.swift -// FLINT -// -// Created by 김호성 on 2026.01.22. -// - -import Foundation - -import Moya - -import Data - -protocol UserAPIFactory { - func makeUserAPIProvider() -> MoyaProvider -} diff --git a/FLINT/FLINT/Dependency/Factory/APIProvider/UserAPIProviderFactory.swift b/FLINT/FLINT/Dependency/Factory/APIProvider/UserAPIProviderFactory.swift new file mode 100644 index 00000000..ab049839 --- /dev/null +++ b/FLINT/FLINT/Dependency/Factory/APIProvider/UserAPIProviderFactory.swift @@ -0,0 +1,24 @@ +// +// UserAPIProviderFactory.swift +// FLINT +// +// Created by 김호성 on 2026.01.22. +// + +import Foundation + +import Moya + +import Data + +protocol UserAPIProviderFactory { + var userAPIProvider: MoyaProvider { get set } + + func makeUserAPIProvider() -> MoyaProvider +} + +extension UserAPIProviderFactory { + func makeUserAPIProvider() -> MoyaProvider { + return userAPIProvider + } +} diff --git a/FLINT/FLINT/Dependency/Factory/BookmarkFactory.swift b/FLINT/FLINT/Dependency/Factory/BookmarkFactory.swift deleted file mode 100644 index 89b4f38d..00000000 --- a/FLINT/FLINT/Dependency/Factory/BookmarkFactory.swift +++ /dev/null @@ -1,31 +0,0 @@ -// -// BookmarkFactory.swift -// FLINT -// -// Created by 진소은 on 1/23/26. -// - -import Foundation -import Moya - -import Data -import Domain -import Presentation - -protocol BookmarkFactory: BookmarkRepositoryFactory { - - // UseCase - func makeFetchBookmarkedUserUseCase() -> FetchBookmarkedUserUseCase - func makeFetchBookmarkedUserUseCase(bookmarkRepository: BookmarkRepository) -> FetchBookmarkedUserUseCase -} - -extension BookmarkFactory { - - func makeFetchBookmarkedUserUseCase() -> FetchBookmarkedUserUseCase { - return makeFetchBookmarkedUserUseCase(bookmarkRepository: makeBookmarkRepository()) - } - - func makeFetchBookmarkedUserUseCase(bookmarkRepository: BookmarkRepository) -> FetchBookmarkedUserUseCase { - return DefaultFetchBookmarkedUserUseCase(bookmarkRepository: bookmarkRepository) - } -} diff --git a/FLINT/FLINT/Dependency/Factory/CollectionDetailFactory.swift b/FLINT/FLINT/Dependency/Factory/CollectionDetailFactory.swift deleted file mode 100644 index 619e1fcd..00000000 --- a/FLINT/FLINT/Dependency/Factory/CollectionDetailFactory.swift +++ /dev/null @@ -1,57 +0,0 @@ -// -// CollectionDetailFactory.swift -// FLINT -// -// Created by 진소은 on 1/23/26. -// - -import Foundation - -import Data -import Domain -import Presentation - -protocol CollectionDetailFactory: CollectionRepositoryFactory, BookmarkFactory { - - // MARK: - UseCase - func makeCollectionDetailUseCase(collectionRepository: CollectionRepository) -> CollectionDetailUseCase - func makeCollectionDetailUseCase() -> CollectionDetailUseCase - - // MARK: - ViewModel - func makeCollectionDetailViewModel(collectionId: Int64) -> CollectionDetailViewModel - func makeCollectionDetailViewModel( - collectionId: Int64, - collectionDetailUseCase: CollectionDetailUseCase - ) -> CollectionDetailViewModel -} - -extension CollectionDetailFactory { - - // MARK: - UseCase - func makeCollectionDetailUseCase() -> CollectionDetailUseCase { - return makeCollectionDetailUseCase(collectionRepository: makeCollectionRepository()) - } - - func makeCollectionDetailUseCase(collectionRepository: CollectionRepository) -> CollectionDetailUseCase { - return DefaultCollectionDetailUseCase(collectionRepository: collectionRepository) - } - - // MARK: - ViewModel - func makeCollectionDetailViewModel(collectionId: Int64) -> CollectionDetailViewModel { - return makeCollectionDetailViewModel( - collectionId: collectionId, - collectionDetailUseCase: makeCollectionDetailUseCase() - ) - } - - func makeCollectionDetailViewModel( - collectionId: Int64, - collectionDetailUseCase: CollectionDetailUseCase - ) -> CollectionDetailViewModel { - return CollectionDetailViewModel( - collectionId: collectionId, - collectionDetailUseCase: collectionDetailUseCase, - fetchBookmarkedUserUseCase: makeFetchBookmarkedUserUseCase() - ) - } -} diff --git a/FLINT/FLINT/Dependency/Factory/CreateCollectionFactory.swift b/FLINT/FLINT/Dependency/Factory/CreateCollectionFactory.swift deleted file mode 100644 index 3868bace..00000000 --- a/FLINT/FLINT/Dependency/Factory/CreateCollectionFactory.swift +++ /dev/null @@ -1,41 +0,0 @@ -// -// CreateCollectionFactory.swift -// FLINT -// - -import Foundation -import Moya - -import Data -import Domain -import Presentation - -protocol CreateCollectionFactory: CollectionRepositoryFactory { - - // UseCase - func makeCreateCollectionUseCase() -> CreateCollectionUseCase - func makeCreateCollectionUseCase(collectionRepository: CollectionRepository) -> CreateCollectionUseCase - - // ViewModel - func makeCreateCollectionViewModel() -> CreateCollectionViewModel - func makeCreateCollectionViewModel(createCollectionUseCase: CreateCollectionUseCase) -> CreateCollectionViewModel -} - -extension CreateCollectionFactory { - - func makeCreateCollectionUseCase() -> CreateCollectionUseCase { - return makeCreateCollectionUseCase(collectionRepository: makeCollectionRepository()) - } - - func makeCreateCollectionUseCase(collectionRepository: CollectionRepository) -> CreateCollectionUseCase { - return DefaultCreateCollectionUseCase(collectionRepository: collectionRepository) - } - - func makeCreateCollectionViewModel() -> CreateCollectionViewModel { - return makeCreateCollectionViewModel(createCollectionUseCase: makeCreateCollectionUseCase()) - } - - func makeCreateCollectionViewModel(createCollectionUseCase: CreateCollectionUseCase) -> CreateCollectionViewModel { - return DefaultCreateCollectionViewModel(createCollectionUseCase: createCollectionUseCase) - } -} diff --git a/FLINT/FLINT/Dependency/Factory/HomeFactory.swift b/FLINT/FLINT/Dependency/Factory/HomeFactory.swift deleted file mode 100644 index e12126f1..00000000 --- a/FLINT/FLINT/Dependency/Factory/HomeFactory.swift +++ /dev/null @@ -1,112 +0,0 @@ -// -// HomeFactory.swift -// FLINT -// - -import Foundation -import Moya - -import Data -import Domain -import Presentation - -// MARK: - HomeFactory - -protocol HomeFactory: ProfileFactory, CreateCollectionFactory { - - // MARK: - Home (Recommended) - - // Root Dependency - func makeHomeAPIProvider() -> MoyaProvider - - // Service - func makeHomeService() -> HomeService - func makeHomeService(homeAPIProvider: MoyaProvider) -> HomeService - - // Repository - func makeHomeRepository() -> HomeRepository - func makeHomeRepository(homeService: HomeService) -> HomeRepository - - // UseCase - func makeHomeUseCase() -> HomeUseCase - func makeHomeUseCase(homeRepository: HomeRepository) -> HomeUseCase - - // MARK: - Watching Collections (Collection Swagger) - - // UseCase - func makeFetchWatchingCollectionsUseCase() -> FetchWatchingCollectionsUseCase - func makeFetchWatchingCollectionsUseCase(collectionRepository: CollectionRepository) -> FetchWatchingCollectionsUseCase - - // MARK: - ViewModel - - func makeHomeViewModel() -> HomeViewModel - func makeHomeViewModel( - homeUseCase: HomeUseCase, - userProfileUseCase: UserProfileUseCase, - fetchWatchingCollectionsUseCase: FetchWatchingCollectionsUseCase - ) -> HomeViewModel -} - -// MARK: - Default Implementations - -extension HomeFactory { - - // MARK: - Home (Recommended) - - func makeHomeService() -> HomeService { - makeHomeService(homeAPIProvider: makeHomeAPIProvider()) - } - - func makeHomeService(homeAPIProvider: MoyaProvider) -> HomeService { - DefaultHomeService(provider: homeAPIProvider) - } - - func makeHomeRepository() -> HomeRepository { - makeHomeRepository(homeService: makeHomeService()) - } - - func makeHomeRepository(homeService: HomeService) -> HomeRepository { - DefaultHomeRepository(homeService: homeService) - } - - func makeHomeUseCase() -> HomeUseCase { - makeHomeUseCase(homeRepository: makeHomeRepository()) - } - - func makeHomeUseCase(homeRepository: HomeRepository) -> HomeUseCase { - DefaultHomeUseCase(homeRepository: homeRepository) - } - - // MARK: - Watching Collections (Collection Swagger) - - func makeFetchWatchingCollectionsUseCase() -> FetchWatchingCollectionsUseCase { - makeFetchWatchingCollectionsUseCase(collectionRepository: makeCollectionRepository()) - } - - func makeFetchWatchingCollectionsUseCase(collectionRepository: CollectionRepository) -> FetchWatchingCollectionsUseCase { - DefaultFetchWatchingCollectionsUseCase(collectionRepository: collectionRepository) - } - - // MARK: - ViewModel - - func makeHomeViewModel() -> HomeViewModel { - makeHomeViewModel( - homeUseCase: makeHomeUseCase(), - userProfileUseCase: makeUserProfileUseCase(), - fetchWatchingCollectionsUseCase: makeFetchWatchingCollectionsUseCase() - ) - } - - func makeHomeViewModel( - homeUseCase: HomeUseCase, - userProfileUseCase: UserProfileUseCase, - fetchWatchingCollectionsUseCase: FetchWatchingCollectionsUseCase - ) -> HomeViewModel { - HomeViewModel( - homeUseCase: homeUseCase, - userProfileUseCase: userProfileUseCase, - fetchWatchingCollectionsUseCase: fetchWatchingCollectionsUseCase, - initialUserName: "얀비" - ) - } -} diff --git a/FLINT/FLINT/Dependency/Factory/ProfileFactory.swift b/FLINT/FLINT/Dependency/Factory/ProfileFactory.swift deleted file mode 100644 index e6ab9290..00000000 --- a/FLINT/FLINT/Dependency/Factory/ProfileFactory.swift +++ /dev/null @@ -1,53 +0,0 @@ -// -// ProfileFactory.swift -// FLINT -// -// Created by 진소은 on 1/22/26. -// -import Foundation - -import Moya - -import Data -import Domain -import Presentation - -protocol ProfileFactory: UserRepositoryFactory { - - // MARK: - UseCase - func makeUserProfileUseCase() -> UserProfileUseCase - func makeUserProfileUseCase(userRepository: UserRepository) -> UserProfileUseCase - - // MARK: - ViewModel - func makeProfileViewModel() -> ProfileViewModel - func makeProfileViewModel( - target: ProfileViewModel.Target - ) -> ProfileViewModel -} - -extension ProfileFactory { - - // MARK: - UseCase - func makeUserProfileUseCase() -> UserProfileUseCase { - return makeUserProfileUseCase(userRepository: makeUserRepository()) - } - - func makeUserProfileUseCase(userRepository: UserRepository) -> UserProfileUseCase { - return DefaultUserProfileUseCase(userRepository: userRepository) - } - - // MARK: - ViewModel - - func makeProfileViewModel() -> ProfileViewModel { - makeProfileViewModel(target: .me) - } - - func makeProfileViewModel( - target: ProfileViewModel.Target - ) -> ProfileViewModel { - ProfileViewModel( - target: target, - userProfileUseCase: makeUserProfileUseCase() - ) - } -} diff --git a/FLINT/FLINT/Dependency/Factory/Repository/AuthRepositoryFactory.swift b/FLINT/FLINT/Dependency/Factory/Repository/AuthRepositoryFactory.swift index 097f4e9c..2af43404 100644 --- a/FLINT/FLINT/Dependency/Factory/Repository/AuthRepositoryFactory.swift +++ b/FLINT/FLINT/Dependency/Factory/Repository/AuthRepositoryFactory.swift @@ -12,14 +12,10 @@ import Domain protocol AuthRepositoryFactory: AuthServiceFactory { func makeAuthRepository() -> AuthRepository - func makeAuthRepository(authService: AuthService) -> AuthRepository } extension AuthRepositoryFactory { func makeAuthRepository() -> AuthRepository { - return makeAuthRepository(authService: makeAuthService()) - } - func makeAuthRepository(authService: AuthService) -> AuthRepository { - return DefaultAuthRepository(authService: authService) + return DefaultAuthRepository(authService: makeAuthService()) } } diff --git a/FLINT/FLINT/Dependency/Factory/Repository/BookmarkRepositoryFactory.swift b/FLINT/FLINT/Dependency/Factory/Repository/BookmarkRepositoryFactory.swift index e2d25e69..9c17af2a 100644 --- a/FLINT/FLINT/Dependency/Factory/Repository/BookmarkRepositoryFactory.swift +++ b/FLINT/FLINT/Dependency/Factory/Repository/BookmarkRepositoryFactory.swift @@ -6,40 +6,16 @@ // import Foundation -import Moya import Data import Domain -protocol BookmarkRepositoryFactory { - func makeBookmarkAPIProvider() -> MoyaProvider - - // Service - func makeBookmarkService() -> BookmarkService - func makeBookmarkService(provider: MoyaProvider) -> BookmarkService - - // Repository +protocol BookmarkRepositoryFactory: BookmarkServiceFactory { func makeBookmarkRepository() -> BookmarkRepository - func makeBookmarkRepository(bookmarkService: BookmarkService) -> BookmarkRepository } extension BookmarkRepositoryFactory { - - // Service - func makeBookmarkService() -> BookmarkService { - return makeBookmarkService(provider: makeBookmarkAPIProvider()) - } - - func makeBookmarkService(provider: MoyaProvider) -> BookmarkService { - return DefaultBookmarkService(provider: provider) - } - - // Repository func makeBookmarkRepository() -> BookmarkRepository { - return makeBookmarkRepository(bookmarkService: makeBookmarkService()) - } - - func makeBookmarkRepository(bookmarkService: BookmarkService) -> BookmarkRepository { - return DefaultBookmarkRepository(bookmarkService: bookmarkService) + return DefaultBookmarkRepository(bookmarkService: makeBookmarkService()) } } diff --git a/FLINT/FLINT/Dependency/Factory/Repository/CollectionRepositoryFactory.swift b/FLINT/FLINT/Dependency/Factory/Repository/CollectionRepositoryFactory.swift index 75fb9cd5..1ca678cf 100644 --- a/FLINT/FLINT/Dependency/Factory/Repository/CollectionRepositoryFactory.swift +++ b/FLINT/FLINT/Dependency/Factory/Repository/CollectionRepositoryFactory.swift @@ -1,5 +1,5 @@ // -// File.swift +// CollectionRepositoryFactory.swift // FLINT // // Created by 김호성 on 2026.01.22. @@ -12,14 +12,10 @@ import Domain protocol CollectionRepositoryFactory: CollectionServiceFactory { func makeCollectionRepository() -> CollectionRepository - func makeCollectionRepository(collectionService: CollectionService) -> CollectionRepository } extension CollectionRepositoryFactory { func makeCollectionRepository() -> CollectionRepository { - return makeCollectionRepository(collectionService: makeCollectionService()) - } - func makeCollectionRepository(collectionService: CollectionService) -> CollectionRepository { - return DefaultCollectionRepository(collectionService: collectionService) + return DefaultCollectionRepository(collectionService: makeCollectionService()) } } diff --git a/FLINT/FLINT/Dependency/Factory/Repository/ContentRepositoryFactory.swift b/FLINT/FLINT/Dependency/Factory/Repository/ContentRepositoryFactory.swift new file mode 100644 index 00000000..a81c55c1 --- /dev/null +++ b/FLINT/FLINT/Dependency/Factory/Repository/ContentRepositoryFactory.swift @@ -0,0 +1,21 @@ +// +// ContentRepositoryFactory.swift +// FLINT +// +// Created by 김호성 on 2026.02.09. +// + +import Foundation + +import Data +import Domain + +protocol ContentRepositoryFactory: ContentServiceFactory { + func makeContentRepository() -> ContentRepository +} + +extension ContentRepositoryFactory { + func makeContentRepository() -> ContentRepository { + return DefaultContentRepository(contentService: makeContentService()) + } +} diff --git a/FLINT/FLINT/Dependency/Factory/Repository/HomeRepositoryFactory.swift b/FLINT/FLINT/Dependency/Factory/Repository/HomeRepositoryFactory.swift new file mode 100644 index 00000000..a606abde --- /dev/null +++ b/FLINT/FLINT/Dependency/Factory/Repository/HomeRepositoryFactory.swift @@ -0,0 +1,21 @@ +// +// HomeRepositoryFactory.swift +// FLINT +// +// Created by 김호성 on 2026.02.02. +// + +import Foundation + +import Data +import Domain + +protocol HomeRepositoryFactory: HomeServiceFactory { + func makeHomeRepository() -> HomeRepository +} + +extension HomeRepositoryFactory { + func makeHomeRepository() -> HomeRepository { + return DefaultHomeRepository(homeService: makeHomeService()) + } +} diff --git a/FLINT/FLINT/Dependency/Factory/Repository/SearchRepositoryFactory.swift b/FLINT/FLINT/Dependency/Factory/Repository/SearchRepositoryFactory.swift index 750d24da..55d53023 100644 --- a/FLINT/FLINT/Dependency/Factory/Repository/SearchRepositoryFactory.swift +++ b/FLINT/FLINT/Dependency/Factory/Repository/SearchRepositoryFactory.swift @@ -12,14 +12,10 @@ import Domain protocol SearchRepositoryFactory: SearchServiceFactory { func makeSearchRepository() -> SearchRepository - func makeSearchRepository(searchService: SearchService) -> SearchRepository } extension SearchRepositoryFactory { func makeSearchRepository() -> SearchRepository { - return makeSearchRepository(searchService: makeSearchService()) - } - func makeSearchRepository(searchService: SearchService) -> SearchRepository { - return DefaultSearchRepository(searchService: searchService) + return DefaultSearchRepository(searchService: makeSearchService()) } } diff --git a/FLINT/FLINT/Dependency/Factory/Repository/UserRepositoryFactory.swift b/FLINT/FLINT/Dependency/Factory/Repository/UserRepositoryFactory.swift index bc0d0a11..8419c9eb 100644 --- a/FLINT/FLINT/Dependency/Factory/Repository/UserRepositoryFactory.swift +++ b/FLINT/FLINT/Dependency/Factory/Repository/UserRepositoryFactory.swift @@ -1,5 +1,5 @@ // -// File.swift +// UserRepositoryFactory.swift // FLINT // // Created by 김호성 on 2026.01.22. @@ -12,14 +12,10 @@ import Domain protocol UserRepositoryFactory: UserServiceFactory { func makeUserRepository() -> UserRepository - func makeUserRepository(userService: UserService) -> UserRepository } extension UserRepositoryFactory { func makeUserRepository() -> UserRepository { - return makeUserRepository(userService: makeUserService()) - } - func makeUserRepository(userService: UserService) -> UserRepository { - return DefaultUserRepository(userService: userService) + return DefaultUserRepository(userService: makeUserService()) } } diff --git a/FLINT/FLINT/Dependency/Factory/Service/AuthServiceFactory.swift b/FLINT/FLINT/Dependency/Factory/Service/AuthServiceFactory.swift index 13c40c88..01b69ad3 100644 --- a/FLINT/FLINT/Dependency/Factory/Service/AuthServiceFactory.swift +++ b/FLINT/FLINT/Dependency/Factory/Service/AuthServiceFactory.swift @@ -7,20 +7,14 @@ import Foundation -import Moya - import Data -protocol AuthServiceFactory: AuthAPIFactory, TokenStorageFactory { +protocol AuthServiceFactory: AuthAPIProviderFactory, TokenStorageFactory { func makeAuthService() -> AuthService - func makeAuthService(tokenStorage: TokenStorage, authAPIProvider: MoyaProvider) -> AuthService } extension AuthServiceFactory { func makeAuthService() -> AuthService { - return makeAuthService(tokenStorage: makeTokenStorage(), authAPIProvider: makeAuthAPIProvider()) - } - func makeAuthService(tokenStorage: TokenStorage, authAPIProvider: MoyaProvider) -> AuthService { - return DefaultAuthService(tokenStorage: tokenStorage, authAPIProvider: authAPIProvider) + return DefaultAuthService(tokenStorage: makeTokenStorage(), authAPIProvider: makeAuthAPIProvider()) } } diff --git a/FLINT/FLINT/Dependency/Factory/Service/BookmarkServiceFactory.swift b/FLINT/FLINT/Dependency/Factory/Service/BookmarkServiceFactory.swift new file mode 100644 index 00000000..cef278dc --- /dev/null +++ b/FLINT/FLINT/Dependency/Factory/Service/BookmarkServiceFactory.swift @@ -0,0 +1,20 @@ +// +// BookmarkServiceFactory.swift +// FLINT +// +// Created by 김호성 on 2026.01.31. +// + +import Foundation + +import Data + +protocol BookmarkServiceFactory: BookmarkAPIProviderFactory { + func makeBookmarkService() -> BookmarkService +} + +extension BookmarkServiceFactory { + func makeBookmarkService() -> BookmarkService { + return DefaultBookmarkService(bookmarkAPIProvider: makeBookmarkAPIProvider()) + } +} diff --git a/FLINT/FLINT/Dependency/Factory/Service/CollectionServiceFactory.swift b/FLINT/FLINT/Dependency/Factory/Service/CollectionServiceFactory.swift index e4a471fd..2ae0ad7b 100644 --- a/FLINT/FLINT/Dependency/Factory/Service/CollectionServiceFactory.swift +++ b/FLINT/FLINT/Dependency/Factory/Service/CollectionServiceFactory.swift @@ -1,5 +1,5 @@ // -// File.swift +// CollectionServiceFactory.swift // FLINT // // Created by 김호성 on 2026.01.22. @@ -7,20 +7,14 @@ import Foundation -import Moya - import Data -protocol CollectionServiceFactory: CollectionAPIFactory { +protocol CollectionServiceFactory: CollectionAPIProviderFactory { func makeCollectionService() -> CollectionService - func makeCollectionService(exploreAPIProvider: MoyaProvider) -> CollectionService } extension CollectionServiceFactory { func makeCollectionService() -> CollectionService { - return makeCollectionService(exploreAPIProvider: makeCollectionAPIProvider()) - } - func makeCollectionService(exploreAPIProvider: MoyaProvider) -> CollectionService { - return DefaultCollectionService(provider: exploreAPIProvider) + return DefaultCollectionService(collectionAPIProvider: makeCollectionAPIProvider()) } } diff --git a/FLINT/FLINT/Dependency/Factory/Service/ContentServiceFactory.swift b/FLINT/FLINT/Dependency/Factory/Service/ContentServiceFactory.swift new file mode 100644 index 00000000..c2dfd6a4 --- /dev/null +++ b/FLINT/FLINT/Dependency/Factory/Service/ContentServiceFactory.swift @@ -0,0 +1,20 @@ +// +// ContentServiceFactory.swift +// FLINT +// +// Created by 김호성 on 2026.02.09. +// + +import Foundation + +import Data + +protocol ContentServiceFactory: ContentAPIProviderFactory { + func makeContentService() -> ContentService +} + +extension ContentServiceFactory { + func makeContentService() -> ContentService { + return DefaultContentService(contentAPIProvider: makeContentAPIProvider()) + } +} diff --git a/FLINT/FLINT/Dependency/Factory/Service/HomeServiceFactory.swift b/FLINT/FLINT/Dependency/Factory/Service/HomeServiceFactory.swift new file mode 100644 index 00000000..5ed6dc72 --- /dev/null +++ b/FLINT/FLINT/Dependency/Factory/Service/HomeServiceFactory.swift @@ -0,0 +1,20 @@ +// +// HomeServiceFactory.swift +// FLINT +// +// Created by 김호성 on 2026.01.31. +// + +import Foundation + +import Data + +protocol HomeServiceFactory: HomeAPIProviderFactory { + func makeHomeService() -> HomeService +} + +extension HomeServiceFactory { + func makeHomeService() -> HomeService { + return DefaultHomeService(homeAPIProvider: makeHomeAPIProvider()) + } +} diff --git a/FLINT/FLINT/Dependency/Factory/Service/SearchServiceFactory.swift b/FLINT/FLINT/Dependency/Factory/Service/SearchServiceFactory.swift index c11adef7..68571195 100644 --- a/FLINT/FLINT/Dependency/Factory/Service/SearchServiceFactory.swift +++ b/FLINT/FLINT/Dependency/Factory/Service/SearchServiceFactory.swift @@ -7,20 +7,14 @@ import Foundation -import Moya - import Data -protocol SearchServiceFactory: SearchAPIFactory { +protocol SearchServiceFactory: SearchAPIProviderFactory { func makeSearchService() -> SearchService - func makeSearchService(searchAPIProvider: MoyaProvider) -> SearchService } extension SearchServiceFactory { func makeSearchService() -> SearchService { - return makeSearchService(searchAPIProvider: makeSearchAPIProvider()) - } - func makeSearchService(searchAPIProvider: MoyaProvider) -> SearchService { - return DefaultSearchService(provider: searchAPIProvider) + return DefaultSearchService(searchAPIProvider: makeSearchAPIProvider()) } } diff --git a/FLINT/FLINT/Dependency/Factory/Service/UserServiceFactory.swift b/FLINT/FLINT/Dependency/Factory/Service/UserServiceFactory.swift index 88579ba1..24970990 100644 --- a/FLINT/FLINT/Dependency/Factory/Service/UserServiceFactory.swift +++ b/FLINT/FLINT/Dependency/Factory/Service/UserServiceFactory.swift @@ -1,5 +1,5 @@ // -// File.swift +// UserServiceFactory.swift // FLINT // // Created by 김호성 on 2026.01.22. @@ -7,20 +7,14 @@ import Foundation -import Moya - import Data -protocol UserServiceFactory: UserAPIFactory { +protocol UserServiceFactory: UserAPIProviderFactory { func makeUserService() -> UserService - func makeUserService(userAPIProvider: MoyaProvider) -> UserService } extension UserServiceFactory { func makeUserService() -> UserService { - return makeUserService(userAPIProvider: makeUserAPIProvider()) - } - func makeUserService(userAPIProvider: MoyaProvider) -> UserService { - return DefaultUserService(userAPIProvider: userAPIProvider) + return DefaultUserService(userAPIProvider: makeUserAPIProvider()) } } diff --git a/FLINT/FLINT/Dependency/Factory/TokenStorage/TokenStorageFactory.swift b/FLINT/FLINT/Dependency/Factory/TokenStorage/TokenStorageFactory.swift index 6bc916f5..66d70f7d 100644 --- a/FLINT/FLINT/Dependency/Factory/TokenStorage/TokenStorageFactory.swift +++ b/FLINT/FLINT/Dependency/Factory/TokenStorage/TokenStorageFactory.swift @@ -10,5 +10,13 @@ import Foundation import Data protocol TokenStorageFactory { + var tokenStorage: TokenStorage { get set } + func makeTokenStorage() -> TokenStorage } + +extension TokenStorageFactory { + func makeTokenStorage() -> TokenStorage { + return tokenStorage + } +} diff --git a/FLINT/FLINT/Dependency/Factory/UseCase/SignupUseCaseFactory.swift b/FLINT/FLINT/Dependency/Factory/UseCase/Auth/SignupUseCaseFactory.swift similarity index 50% rename from FLINT/FLINT/Dependency/Factory/UseCase/SignupUseCaseFactory.swift rename to FLINT/FLINT/Dependency/Factory/UseCase/Auth/SignupUseCaseFactory.swift index d7a9941d..67b7fac6 100644 --- a/FLINT/FLINT/Dependency/Factory/UseCase/SignupUseCaseFactory.swift +++ b/FLINT/FLINT/Dependency/Factory/UseCase/Auth/SignupUseCaseFactory.swift @@ -11,14 +11,10 @@ import Domain protocol SignupUseCaseFactory: AuthRepositoryFactory { func makeSignupUseCase() -> SignupUseCase - func makeSignupUseCase(authRepository: AuthRepository) -> SignupUseCase } extension SignupUseCaseFactory { func makeSignupUseCase() -> SignupUseCase { - return makeSignupUseCase(authRepository: makeAuthRepository()) - } - func makeSignupUseCase(authRepository: AuthRepository) -> SignupUseCase { - return DefaultSignupUseCase(authRepository: authRepository) + return DefaultSignupUseCase(authRepository: makeAuthRepository()) } } diff --git a/FLINT/FLINT/Dependency/Factory/UseCase/Auth/SocialVerifyUseCaseFactory.swift b/FLINT/FLINT/Dependency/Factory/UseCase/Auth/SocialVerifyUseCaseFactory.swift new file mode 100644 index 00000000..2fba9102 --- /dev/null +++ b/FLINT/FLINT/Dependency/Factory/UseCase/Auth/SocialVerifyUseCaseFactory.swift @@ -0,0 +1,20 @@ +// +// SocialVerifyUseCaseFactory.swift +// FLINT +// +// Created by 김호성 on 2026.01.23. +// + +import Foundation + +import Domain + +protocol SocialVerifyUseCaseFactory: AuthRepositoryFactory { + func makeSocialVerifyUseCase() -> SocialVerifyUseCase +} + +extension SocialVerifyUseCaseFactory { + func makeSocialVerifyUseCase() -> SocialVerifyUseCase { + return DefaultSocialVerifyUseCase(authRepository: makeAuthRepository()) + } +} diff --git a/FLINT/FLINT/Dependency/Factory/UseCase/Auth/WithDrawUseCaseFactory.swift b/FLINT/FLINT/Dependency/Factory/UseCase/Auth/WithDrawUseCaseFactory.swift new file mode 100644 index 00000000..28c225ff --- /dev/null +++ b/FLINT/FLINT/Dependency/Factory/UseCase/Auth/WithDrawUseCaseFactory.swift @@ -0,0 +1,20 @@ +// +// WithDrawUseCaseFactory.swift +// FLINT +// +// Created by 김호성 on 2026.02.09. +// + +import Foundation + +import Domain + +protocol WithDrawUseCaseFactory: AuthRepositoryFactory { + func makeWithDrawUseCase() -> WithDrawUseCase +} + +extension WithDrawUseCaseFactory { + func makeWithDrawUseCase() -> WithDrawUseCase { + return DefaultWithDrawUseCase(authRepository: makeAuthRepository()) + } +} diff --git a/FLINT/FLINT/Dependency/Factory/UseCase/Collection/CreateCollectionUseCaseFactory.swift b/FLINT/FLINT/Dependency/Factory/UseCase/Collection/CreateCollectionUseCaseFactory.swift new file mode 100644 index 00000000..51e2c3d3 --- /dev/null +++ b/FLINT/FLINT/Dependency/Factory/UseCase/Collection/CreateCollectionUseCaseFactory.swift @@ -0,0 +1,20 @@ +// +// CreateCollectionUseCaseFactory.swift +// FLINT +// +// Created by 김호성 on 2026.02.02. +// + +import Foundation + +import Domain + +protocol CreateCollectionUseCaseFactory: CollectionRepositoryFactory { + func makeCreateCollectionUseCase() -> CreateCollectionUseCase +} + +extension CreateCollectionUseCaseFactory { + func makeCreateCollectionUseCase() -> CreateCollectionUseCase { + return DefaultCreateCollectionUseCase(collectionRepository: makeCollectionRepository()) + } +} diff --git a/FLINT/FLINT/Dependency/Factory/UseCase/Collection/FetchBookmarkedCollectionsUseCaseFactory.swift b/FLINT/FLINT/Dependency/Factory/UseCase/Collection/FetchBookmarkedCollectionsUseCaseFactory.swift new file mode 100644 index 00000000..ddb9ac18 --- /dev/null +++ b/FLINT/FLINT/Dependency/Factory/UseCase/Collection/FetchBookmarkedCollectionsUseCaseFactory.swift @@ -0,0 +1,20 @@ +// +// FetchBookmarkedCollectionsUseCaseFactory.swift +// FLINT +// +// Created by 김호성 on 2026.02.09. +// + +import Foundation + +import Domain + +protocol FetchBookmarkedCollectionsUseCaseFactory: UserRepositoryFactory { + func makeFetchBookmarkedCollectionsUseCase() -> FetchBookmarkedCollectionsUseCase +} + +extension FetchBookmarkedCollectionsUseCaseFactory { + func makeFetchBookmarkedCollectionsUseCase() -> FetchBookmarkedCollectionsUseCase { + return DefaultFetchBookmarkedCollectionsUseCase(userRepository: makeUserRepository()) + } +} diff --git a/FLINT/FLINT/Dependency/Factory/UseCase/Collection/FetchCollectionBookmarkUsersUseCaseFactory.swift b/FLINT/FLINT/Dependency/Factory/UseCase/Collection/FetchCollectionBookmarkUsersUseCaseFactory.swift new file mode 100644 index 00000000..413c64e1 --- /dev/null +++ b/FLINT/FLINT/Dependency/Factory/UseCase/Collection/FetchCollectionBookmarkUsersUseCaseFactory.swift @@ -0,0 +1,20 @@ +// +// FetchCollectionBookmarkUsersUseCaseFactory.swift +// FLINT +// +// Created by 진소은 on 1/23/26. +// + +import Foundation + +import Domain + +protocol FetchCollectionBookmarkUsersUseCaseFactory: BookmarkRepositoryFactory { + func makeFetchCollectionBookmarkUsersUseCase() -> FetchCollectionBookmarkUsersUseCase +} + +extension FetchCollectionBookmarkUsersUseCaseFactory { + func makeFetchCollectionBookmarkUsersUseCase() -> FetchCollectionBookmarkUsersUseCase { + return DefaultFetchCollectionBookmarkUsersUseCase(bookmarkRepository: makeBookmarkRepository()) + } +} diff --git a/FLINT/FLINT/Dependency/Factory/UseCase/Collection/FetchCollectionDetailUseCaseFactory.swift b/FLINT/FLINT/Dependency/Factory/UseCase/Collection/FetchCollectionDetailUseCaseFactory.swift new file mode 100644 index 00000000..a5fb5886 --- /dev/null +++ b/FLINT/FLINT/Dependency/Factory/UseCase/Collection/FetchCollectionDetailUseCaseFactory.swift @@ -0,0 +1,20 @@ +// +// FetchCollectionDetailUseCaseFactory.swift +// FLINT +// +// Created by 김호성 on 2026.02.02. +// + +import Foundation + +import Domain + +protocol FetchCollectionDetailUseCaseFactory: CollectionRepositoryFactory { + func makeFetchCollectionDetailUseCase() -> FetchCollectionDetailUseCase +} + +extension FetchCollectionDetailUseCaseFactory { + func makeFetchCollectionDetailUseCase() -> FetchCollectionDetailUseCase { + return DefaultFetchCollectionDetailUseCase(collectionRepository: makeCollectionRepository()) + } +} diff --git a/FLINT/FLINT/Dependency/Factory/UseCase/Collection/FetchCreatedCollectionsUseCaseFactory.swift b/FLINT/FLINT/Dependency/Factory/UseCase/Collection/FetchCreatedCollectionsUseCaseFactory.swift new file mode 100644 index 00000000..f0e2fa50 --- /dev/null +++ b/FLINT/FLINT/Dependency/Factory/UseCase/Collection/FetchCreatedCollectionsUseCaseFactory.swift @@ -0,0 +1,20 @@ +// +// FetchCreatedCollectionsUseCaseFactory.swift +// FLINT +// +// Created by 김호성 on 2026.02.09. +// + +import Foundation + +import Domain + +protocol FetchCreatedCollectionsUseCaseFactory: UserRepositoryFactory { + func makeFetchCreatedCollectionsUseCase() -> FetchCreatedCollectionsUseCase +} + +extension FetchKeywordsUseCaseFactory { + func makeFetchCreatedCollectionsUseCase() -> FetchCreatedCollectionsUseCase { + return DefaultFetchCreatedCollectionsUseCase(userRepository: makeUserRepository()) + } +} diff --git a/FLINT/FLINT/Dependency/Factory/UseCase/Collection/FetchExploreCollectionsUseCaseFactory.swift b/FLINT/FLINT/Dependency/Factory/UseCase/Collection/FetchExploreCollectionsUseCaseFactory.swift new file mode 100644 index 00000000..23d7c2d9 --- /dev/null +++ b/FLINT/FLINT/Dependency/Factory/UseCase/Collection/FetchExploreCollectionsUseCaseFactory.swift @@ -0,0 +1,20 @@ +// +// FetchExploreCollectionsUseCaseFactory.swift +// FLINT +// +// Created by 김호성 on 2026.01.22. +// + +import Foundation + +import Domain + +protocol FetchExploreCollectionsUseCaseFactory: CollectionRepositoryFactory { + func makeFetchExploreCollectionsUseCase() -> FetchExploreCollectionsUseCase +} + +extension FetchExploreCollectionsUseCaseFactory { + func makeFetchExploreCollectionsUseCase() -> FetchExploreCollectionsUseCase { + return DefaultFetchExploreCollectionsUseCase(collectionRepository: makeCollectionRepository()) + } +} diff --git a/FLINT/FLINT/Dependency/Factory/UseCase/Collection/FetchRecentViewedCollectionsUseCaseFactory.swift b/FLINT/FLINT/Dependency/Factory/UseCase/Collection/FetchRecentViewedCollectionsUseCaseFactory.swift new file mode 100644 index 00000000..1be52cde --- /dev/null +++ b/FLINT/FLINT/Dependency/Factory/UseCase/Collection/FetchRecentViewedCollectionsUseCaseFactory.swift @@ -0,0 +1,20 @@ +// +// FetchRecentViewedCollectionsUseCaseFactory.swift +// FLINT +// +// Created by 김호성 on 2026.02.09. +// + +import Foundation + +import Domain + +protocol FetchRecentViewedCollectionsUseCaseFactory: CollectionRepositoryFactory { + func makeFetchRecentViewedCollectionsUseCase() -> FetchRecentViewedCollectionsUseCase +} + +extension FetchRecentViewedCollectionsUseCaseFactory { + func makeFetchRecentViewedCollectionsUseCase() -> FetchRecentViewedCollectionsUseCase { + return DefaultFetchRecentViewedCollectionsUseCase(collectionRepository: makeCollectionRepository()) + } +} diff --git a/FLINT/FLINT/Dependency/Factory/UseCase/Collection/FetchRecommendedCollectionsUseCaseFactory.swift b/FLINT/FLINT/Dependency/Factory/UseCase/Collection/FetchRecommendedCollectionsUseCaseFactory.swift new file mode 100644 index 00000000..dd630f28 --- /dev/null +++ b/FLINT/FLINT/Dependency/Factory/UseCase/Collection/FetchRecommendedCollectionsUseCaseFactory.swift @@ -0,0 +1,20 @@ +// +// FetchRecommendedCollectionsUseCaseFactory.swift +// FLINT +// +// Created by 김호성 on 2026.02.09. +// + +import Foundation + +import Domain + +protocol FetchRecommendedCollectionsUseCaseFactory: HomeRepositoryFactory { + func makeFetchRecommendedCollectionsUseCase() -> FetchRecommendedCollectionsUseCase +} + +extension FetchRecommendedCollectionsUseCaseFactory { + func makeFetchRecommendedCollectionsUseCase() -> FetchRecommendedCollectionsUseCase { + return DefaultFetchRecommendedCollectionsUseCase(homeRepository: makeHomeRepository()) + } +} diff --git a/FLINT/FLINT/Dependency/Factory/UseCase/Collection/ToggleCollectionBookmarkUseCaseFactory.swift b/FLINT/FLINT/Dependency/Factory/UseCase/Collection/ToggleCollectionBookmarkUseCaseFactory.swift new file mode 100644 index 00000000..4a391340 --- /dev/null +++ b/FLINT/FLINT/Dependency/Factory/UseCase/Collection/ToggleCollectionBookmarkUseCaseFactory.swift @@ -0,0 +1,20 @@ +// +// ToggleCollectionBookmarkUseCaseFactory.swift +// FLINT +// +// Created by 김호성 on 2026.02.09. +// + +import Foundation + +import Domain + +protocol ToggleCollectionBookmarkUseCaseFactory: BookmarkRepositoryFactory { + func makeToggleCollectionBookmarkUseCase() -> ToggleCollectionBookmarkUseCase +} + +extension ToggleCollectionBookmarkUseCaseFactory { + func makeToggleCollectionBookmarkUseCase() -> ToggleCollectionBookmarkUseCase { + return DefaultToggleCollectionBookmarkUseCase(bookmarkRepository: makeBookmarkRepository()) + } +} diff --git a/FLINT/FLINT/Dependency/Factory/UseCase/Content/FetchBookmarkedContentsUseCaseFactory.swift b/FLINT/FLINT/Dependency/Factory/UseCase/Content/FetchBookmarkedContentsUseCaseFactory.swift new file mode 100644 index 00000000..a4557744 --- /dev/null +++ b/FLINT/FLINT/Dependency/Factory/UseCase/Content/FetchBookmarkedContentsUseCaseFactory.swift @@ -0,0 +1,20 @@ +// +// FetchBookmarkedContentsUseCaseFactory.swift +// FLINT +// +// Created by 김호성 on 2026.02.09. +// + +import Foundation + +import Domain + +protocol FetchBookmarkedContentsUseCaseFactory: ContentRepositoryFactory, UserRepositoryFactory { + func makeFetchBookmarkedContentsUseCase() -> FetchBookmarkedContentsUseCase +} + +extension FetchBookmarkedContentsUseCaseFactory { + func makeFetchBookmarkedContentsUseCase() -> FetchBookmarkedContentsUseCase { + return DefaultFetchBookmarkedContentsUseCase(contentRepository: makeContentRepository(), userRepository: makeUserRepository()) + } +} diff --git a/FLINT/FLINT/Dependency/Factory/UseCase/Content/FetchOTTPlatformsForContentUseCaseFactory.swift b/FLINT/FLINT/Dependency/Factory/UseCase/Content/FetchOTTPlatformsForContentUseCaseFactory.swift new file mode 100644 index 00000000..485ed69a --- /dev/null +++ b/FLINT/FLINT/Dependency/Factory/UseCase/Content/FetchOTTPlatformsForContentUseCaseFactory.swift @@ -0,0 +1,20 @@ +// +// FetchOTTPlatformsForContentUseCaseFactory.swift +// FLINT +// +// Created by 김호성 on 2026.02.09. +// + +import Foundation + +import Domain + +protocol FetchOTTPlatformsForContentUseCaseFactory: ContentRepositoryFactory { + func makeFetchOTTPlatformsForContentUseCase() -> FetchOTTPlatformsForContentUseCase +} + +extension FetchOTTPlatformsForContentUseCaseFactory { + func makeFetchOTTPlatformsForContentUseCase() -> FetchOTTPlatformsForContentUseCase { + return DefaultFetchOTTPlatformsForContentUseCase(contentRepository: makeContentRepository()) + } +} diff --git a/FLINT/FLINT/Dependency/Factory/UseCase/Content/FetchPopularContentsUseCaseFactory.swift b/FLINT/FLINT/Dependency/Factory/UseCase/Content/FetchPopularContentsUseCaseFactory.swift new file mode 100644 index 00000000..96acb37e --- /dev/null +++ b/FLINT/FLINT/Dependency/Factory/UseCase/Content/FetchPopularContentsUseCaseFactory.swift @@ -0,0 +1,20 @@ +// +// FetchPopularContentsUseCaseFactory.swift +// FLINT +// +// Created by 김호성 on 2026.02.09. +// + +import Foundation + +import Domain + +protocol FetchPopularContentsUseCaseFactory: SearchRepositoryFactory { + func makeFetchPopularContentsUseCase() -> FetchPopularContentsUseCase +} + +extension FetchPopularContentsUseCaseFactory { + func makeFetchPopularContentsUseCase() -> FetchPopularContentsUseCase { + return DefaultFetchPopularContentsUseCase(searchRepository: makeSearchRepository()) + } +} diff --git a/FLINT/FLINT/Dependency/Factory/UseCase/Content/SearchContentsUseCaseFactory.swift b/FLINT/FLINT/Dependency/Factory/UseCase/Content/SearchContentsUseCaseFactory.swift new file mode 100644 index 00000000..ffb925db --- /dev/null +++ b/FLINT/FLINT/Dependency/Factory/UseCase/Content/SearchContentsUseCaseFactory.swift @@ -0,0 +1,20 @@ +// +// SearchContentsUseCaseFactory.swift +// FLINT +// +// Created by 김호성 on 2026.01.22. +// + +import Foundation + +import Domain + +protocol SearchContentsUseCaseFactory: SearchRepositoryFactory { + func makeSearchContentsUseCase() -> SearchContentsUseCase +} + +extension SearchContentsUseCaseFactory { + func makeSearchContentsUseCase() -> SearchContentsUseCase { + return DefaultSearchContentsUseCase(searchRepository: makeSearchRepository()) + } +} diff --git a/FLINT/FLINT/Dependency/Factory/UseCase/Content/ToggleContentBookmarkUseCaseFactory.swift b/FLINT/FLINT/Dependency/Factory/UseCase/Content/ToggleContentBookmarkUseCaseFactory.swift new file mode 100644 index 00000000..bd8f8beb --- /dev/null +++ b/FLINT/FLINT/Dependency/Factory/UseCase/Content/ToggleContentBookmarkUseCaseFactory.swift @@ -0,0 +1,20 @@ +// +// ToggleContentBookmarkUseCaseFactory.swift +// FLINT +// +// Created by 김호성 on 2026.02.09. +// + +import Foundation + +import Domain + +protocol ToggleContentBookmarkUseCaseFactory: BookmarkRepositoryFactory { + func makeToggleContentBookmarkUseCase() -> ToggleContentBookmarkUseCase +} + +extension ToggleContentBookmarkUseCaseFactory { + func makeToggleContentBookmarkUseCase() -> ToggleContentBookmarkUseCase { + return DefaultToggleContentBookmarkUseCase(bookmarkRepository: makeBookmarkRepository()) + } +} diff --git a/FLINT/FLINT/Dependency/Factory/UseCase/ContentsUseCaseFactory.swift b/FLINT/FLINT/Dependency/Factory/UseCase/ContentsUseCaseFactory.swift deleted file mode 100644 index 315451b5..00000000 --- a/FLINT/FLINT/Dependency/Factory/UseCase/ContentsUseCaseFactory.swift +++ /dev/null @@ -1,24 +0,0 @@ -// -// ContentsUseCase.swift -// FLINT -// -// Created by 김호성 on 2026.01.22. -// - -import Foundation - -import Domain - -protocol ContentsUseCaseFactory: SearchRepositoryFactory { - func makeContentsUseCase() -> ContentsUseCase - func makeContentsUseCase(searchRepository: SearchRepository) -> ContentsUseCase -} - -extension ContentsUseCaseFactory { - func makeContentsUseCase() -> ContentsUseCase { - return makeContentsUseCase(searchRepository: makeSearchRepository()) - } - func makeContentsUseCase(searchRepository: SearchRepository) -> ContentsUseCase { - return DefaultContentsUseCase(searchRepository: searchRepository) - } -} diff --git a/FLINT/FLINT/Dependency/Factory/UseCase/ExploreUseCaseFactory.swift b/FLINT/FLINT/Dependency/Factory/UseCase/ExploreUseCaseFactory.swift deleted file mode 100644 index 65766bf2..00000000 --- a/FLINT/FLINT/Dependency/Factory/UseCase/ExploreUseCaseFactory.swift +++ /dev/null @@ -1,24 +0,0 @@ -// -// File.swift -// FLINT -// -// Created by 김호성 on 2026.01.22. -// - -import Foundation - -import Domain - -protocol ExploreUseCaseFactory: CollectionRepositoryFactory { - func makeExploreUseCase() -> ExploreUseCase - func makeExploreUseCase(collectionRepository: CollectionRepository) -> ExploreUseCase -} - -extension ExploreUseCaseFactory { - func makeExploreUseCase() -> ExploreUseCase { - return makeExploreUseCase(collectionRepository: makeCollectionRepository()) - } - func makeExploreUseCase(collectionRepository: CollectionRepository) -> ExploreUseCase { - return DefaultExploreUseCase(collectionRepository: collectionRepository) - } -} diff --git a/FLINT/FLINT/Dependency/Factory/UseCase/NicknameUseCaseFactory.swift b/FLINT/FLINT/Dependency/Factory/UseCase/NicknameUseCaseFactory.swift deleted file mode 100644 index c3123495..00000000 --- a/FLINT/FLINT/Dependency/Factory/UseCase/NicknameUseCaseFactory.swift +++ /dev/null @@ -1,24 +0,0 @@ -// -// File.swift -// FLINT -// -// Created by 김호성 on 2026.01.22. -// - -import Foundation - -import Domain - -protocol NicknameUseCaseFactory: UserRepositoryFactory { - func makeNicknameUseCase() -> NicknameUseCase - func makeNicknameUseCase(userRepository: UserRepository) -> NicknameUseCase -} - -extension NicknameUseCaseFactory { - func makeNicknameUseCase() -> NicknameUseCase { - return makeNicknameUseCase(userRepository: makeUserRepository()) - } - func makeNicknameUseCase(userRepository: UserRepository) -> NicknameUseCase { - return DefaultNicknameUseCase(userRepository: userRepository) - } -} diff --git a/FLINT/FLINT/Dependency/Factory/UseCase/Profile/CheckNicknameUseCaseFactory.swift b/FLINT/FLINT/Dependency/Factory/UseCase/Profile/CheckNicknameUseCaseFactory.swift new file mode 100644 index 00000000..a3e877f5 --- /dev/null +++ b/FLINT/FLINT/Dependency/Factory/UseCase/Profile/CheckNicknameUseCaseFactory.swift @@ -0,0 +1,20 @@ +// +// CheckNicknameUseCaseFactory.swift +// FLINT +// +// Created by 김호성 on 2026.01.22. +// + +import Foundation + +import Domain + +protocol CheckNicknameUseCaseFactory: UserRepositoryFactory { + func makeCheckNicknameUseCase() -> CheckNicknameUseCase +} + +extension CheckNicknameUseCaseFactory { + func makeCheckNicknameUseCase() -> CheckNicknameUseCase { + return DefaultCheckNicknameUseCase(userRepository: makeUserRepository()) + } +} diff --git a/FLINT/FLINT/Dependency/Factory/UseCase/Profile/FetchKeywordsUseCaseFactory.swift b/FLINT/FLINT/Dependency/Factory/UseCase/Profile/FetchKeywordsUseCaseFactory.swift new file mode 100644 index 00000000..4eb81ce1 --- /dev/null +++ b/FLINT/FLINT/Dependency/Factory/UseCase/Profile/FetchKeywordsUseCaseFactory.swift @@ -0,0 +1,20 @@ +// +// FetchKeywordsUseCaseFactory.swift +// FLINT +// +// Created by 김호성 on 2026.02.09. +// + +import Foundation + +import Domain + +protocol FetchKeywordsUseCaseFactory: UserRepositoryFactory { + func makeFetchKeywordsUseCase() -> FetchKeywordsUseCase +} + +extension FetchKeywordsUseCaseFactory { + func makeFetchKeywordsUseCase() -> FetchKeywordsUseCase { + return DefaultFetchKeywordsUseCase(userRepository: makeUserRepository()) + } +} diff --git a/FLINT/FLINT/Dependency/Factory/UseCase/Profile/FetchProfileUseCaseFactory.swift b/FLINT/FLINT/Dependency/Factory/UseCase/Profile/FetchProfileUseCaseFactory.swift new file mode 100644 index 00000000..acf1fdfa --- /dev/null +++ b/FLINT/FLINT/Dependency/Factory/UseCase/Profile/FetchProfileUseCaseFactory.swift @@ -0,0 +1,20 @@ +// +// FetchProfileUseCaseFactory.swift +// FLINT +// +// Created by 김호성 on 2026.02.09. +// + +import Foundation + +import Domain + +protocol FetchProfileUseCaseFactory: UserRepositoryFactory { + func makeFetchProfileUseCase() -> FetchProfileUseCase +} + +extension FetchProfileUseCaseFactory { + func makeFetchProfileUseCase() -> FetchProfileUseCase { + return DefaultFetchProfileUseCase(userRepository: makeUserRepository()) + } +} diff --git a/FLINT/FLINT/Dependency/Factory/UseCase/SearchContentsUseCaseFactory.swift b/FLINT/FLINT/Dependency/Factory/UseCase/SearchContentsUseCaseFactory.swift deleted file mode 100644 index 428a920f..00000000 --- a/FLINT/FLINT/Dependency/Factory/UseCase/SearchContentsUseCaseFactory.swift +++ /dev/null @@ -1,24 +0,0 @@ -// -// ContentsUseCase.swift -// FLINT -// -// Created by 김호성 on 2026.01.22. -// - -import Foundation - -import Domain - -protocol SearchContentsUseCaseFactory: SearchRepositoryFactory { - func makeSearchContentsUseCase() -> SearchContentsUseCase - func makeSearchContentsUseCase(searchRepository: SearchRepository) -> SearchContentsUseCase -} - -extension SearchContentsUseCaseFactory { - func makeSearchContentsUseCase() -> SearchContentsUseCase { - return makeSearchContentsUseCase(searchRepository: makeSearchRepository()) - } - func makeSearchContentsUseCase(searchRepository: SearchRepository) -> SearchContentsUseCase { - return DefaultSearchContentsUseCase(searchRepository: searchRepository) - } -} diff --git a/FLINT/FLINT/Dependency/Factory/UseCase/SocialVerifyUseCaseFactory.swift b/FLINT/FLINT/Dependency/Factory/UseCase/SocialVerifyUseCaseFactory.swift deleted file mode 100644 index cead480b..00000000 --- a/FLINT/FLINT/Dependency/Factory/UseCase/SocialVerifyUseCaseFactory.swift +++ /dev/null @@ -1,24 +0,0 @@ -// -// SocialVerifyUseCaseFactory.swift -// FLINT -// -// Created by 김호성 on 2026.01.23. -// - -import Foundation - -import Domain - -protocol SocialVerifyUseCaseFactory: AuthRepositoryFactory { - func makeSocialVerifyUseCase() -> SocialVerifyUseCase - func makeSocialVerifyUseCase(authRepository: AuthRepository) -> SocialVerifyUseCase -} - -extension SignupUseCaseFactory { - func makeSocialVerifyUseCase() -> SocialVerifyUseCase { - return makeSocialVerifyUseCase(authRepository: makeAuthRepository()) - } - func makeSocialVerifyUseCase(authRepository: AuthRepository) -> SocialVerifyUseCase { - return DefaultSocialVerifyUseCase(authRepository: authRepository) - } -} diff --git a/FLINT/FLINT/Dependency/Factory/ViewController/AddContentSelectViewControllerFactory+.swift b/FLINT/FLINT/Dependency/Factory/ViewController/AddContentSelectViewControllerFactory+.swift new file mode 100644 index 00000000..4052eb7c --- /dev/null +++ b/FLINT/FLINT/Dependency/Factory/ViewController/AddContentSelectViewControllerFactory+.swift @@ -0,0 +1,17 @@ +// +// AddContentSelectViewControllerFactory+.swift +// FLINT +// +// Created by 김호성 on 2026.01.31. +// + +import Foundation + +import Presentation + +extension AddContentSelectViewControllerFactory where Self: AddContentSelectViewModelFactory & ViewControllerFactory { + func makeAddContentSelectViewController() -> AddContentSelectViewController { + let vm = makeAddContentSelectViewModel() + return AddContentSelectViewController(viewModel: vm, viewControllerFactory: self) + } +} diff --git a/FLINT/FLINT/Dependency/Factory/ViewController/CollectionDetailViewControllerFactory+.swift b/FLINT/FLINT/Dependency/Factory/ViewController/CollectionDetailViewControllerFactory+.swift new file mode 100644 index 00000000..40ee1c14 --- /dev/null +++ b/FLINT/FLINT/Dependency/Factory/ViewController/CollectionDetailViewControllerFactory+.swift @@ -0,0 +1,16 @@ +// +// CollectionDetailViewControllerFactory+.swift +// FLINT +// +// Created by 김호성 on 2026.01.31. +// + +import Foundation + +import Presentation + +extension CollectionDetailViewControllerFactory where Self: CollectionDetailViewModelFactory & ViewControllerFactory { + func makeCollectionDetailViewController(collectionId: Int64) -> CollectionDetailViewController { + return CollectionDetailViewController(viewModel: makeCollectionDetailViewModel(collectionId: collectionId), viewControllerFactory: self) + } +} diff --git a/FLINT/FLINT/Dependency/Factory/ViewController/CollectionFolderListViewControllerFactory+.swift b/FLINT/FLINT/Dependency/Factory/ViewController/CollectionFolderListViewControllerFactory+.swift new file mode 100644 index 00000000..adace326 --- /dev/null +++ b/FLINT/FLINT/Dependency/Factory/ViewController/CollectionFolderListViewControllerFactory+.swift @@ -0,0 +1,16 @@ +// +// CollectionFolderListViewControllerFactory+.swift +// FLINT +// +// Created by 김호성 on 2026.01.31. +// + +import Foundation + +import Presentation + +extension CollectionFolderListViewControllerFactory where Self: CollectionFolderListViewModelFactory & ViewControllerFactory { + func makeCollectionFolderListViewController() -> CollectionFolderListViewController { + return CollectionFolderListViewController(viewModel: makeCollectionFolderListViewModel(), viewControllerFactory: self) + } +} diff --git a/FLINT/FLINT/Dependency/Factory/ViewController/CreateCollectionViewControllerFactory+.swift b/FLINT/FLINT/Dependency/Factory/ViewController/CreateCollectionViewControllerFactory+.swift new file mode 100644 index 00000000..5a83079a --- /dev/null +++ b/FLINT/FLINT/Dependency/Factory/ViewController/CreateCollectionViewControllerFactory+.swift @@ -0,0 +1,17 @@ +// +// CreateCollectionViewControllerFactory+.swift +// FLINT +// +// Created by 김호성 on 2026.01.31. +// + +import Foundation + +import Presentation + +extension CreateCollectionViewControllerFactory where Self: CreateCollectionViewModelFactory & ViewControllerFactory { + func makeCreateCollectionViewController() -> CreateCollectionViewController { + let vm = makeCreateCollectionViewModel() + return CreateCollectionViewController(viewModel: vm, viewControllerFactory: self) + } +} diff --git a/FLINT/FLINT/Dependency/Factory/ViewController/ExploreViewControllerFactory+.swift b/FLINT/FLINT/Dependency/Factory/ViewController/ExploreViewControllerFactory+.swift new file mode 100644 index 00000000..86e55d61 --- /dev/null +++ b/FLINT/FLINT/Dependency/Factory/ViewController/ExploreViewControllerFactory+.swift @@ -0,0 +1,16 @@ +// +// ExploreViewControllerFactory+.swift +// FLINT +// +// Created by 김호성 on 2026.01.31. +// + +import Foundation + +import Presentation + +extension ExploreViewControllerFactory where Self: ExploreViewModelFactory & ViewControllerFactory { + func makeExploreViewController() -> ExploreViewController { + return ExploreViewController(exploreViewModel: makeExploreViewModel(), viewControllerFactory: self) + } +} diff --git a/FLINT/FLINT/Dependency/Factory/ViewController/FilmSelectViewControllerFactory+.swift b/FLINT/FLINT/Dependency/Factory/ViewController/FilmSelectViewControllerFactory+.swift new file mode 100644 index 00000000..80357d44 --- /dev/null +++ b/FLINT/FLINT/Dependency/Factory/ViewController/FilmSelectViewControllerFactory+.swift @@ -0,0 +1,16 @@ +// +// ContentSelectViewControllerFactory+.swift +// FLINT +// +// Created by 김호성 on 2026.01.30. +// + +import Foundation + +import Presentation + +extension ContentSelectViewControllerFactory where Self: ViewControllerFactory { + func makeContentSelectViewController(onboardingViewModel: OnboardingViewModel) -> ContentSelectViewController { + return ContentSelectViewController(onboardingViewModel: onboardingViewModel, viewControllerFactory: self) + } +} diff --git a/FLINT/FLINT/Dependency/Factory/ViewController/HomeViewControllerFactory+.swift b/FLINT/FLINT/Dependency/Factory/ViewController/HomeViewControllerFactory+.swift new file mode 100644 index 00000000..bcb7768c --- /dev/null +++ b/FLINT/FLINT/Dependency/Factory/ViewController/HomeViewControllerFactory+.swift @@ -0,0 +1,16 @@ +// +// HomeViewControllerFactory+.swift +// FLINT +// +// Created by 김호성 on 2026.01.31. +// + +import Foundation + +import Presentation + +extension HomeViewControllerFactory where Self: HomeViewModelFactory & ViewControllerFactory { + func makeHomeViewController() -> HomeViewController { + return HomeViewController(viewModel: makeHomeViewModel(), viewControllerFactory: self) + } +} diff --git a/FLINT/FLINT/Dependency/Factory/ViewController/LoginViewControllerFactory+.swift b/FLINT/FLINT/Dependency/Factory/ViewController/LoginViewControllerFactory+.swift new file mode 100644 index 00000000..1fc0dae4 --- /dev/null +++ b/FLINT/FLINT/Dependency/Factory/ViewController/LoginViewControllerFactory+.swift @@ -0,0 +1,16 @@ +// +// SplashViewControllerFactory.swift +// FLINT +// +// Created by 김호성 on 2026.01.30. +// + +import Foundation + +import Presentation + +extension LoginViewControllerFactory where Self: LoginViewModelFactory & ViewControllerFactory { + func makeLoginViewController() -> LoginViewController { + return LoginViewController(loginViewModel: makeLoginViewModel(), viewControllerFactory: self) + } +} diff --git a/FLINT/FLINT/Dependency/Factory/ViewController/NicknameViewControllerFactory+.swift b/FLINT/FLINT/Dependency/Factory/ViewController/NicknameViewControllerFactory+.swift new file mode 100644 index 00000000..89c8fcda --- /dev/null +++ b/FLINT/FLINT/Dependency/Factory/ViewController/NicknameViewControllerFactory+.swift @@ -0,0 +1,16 @@ +// +// NicknameViewControllerFactory+.swift +// FLINT +// +// Created by 김호성 on 2026.01.30. +// + +import Foundation + +import Presentation + +extension NicknameViewControllerFactory where Self: OnboardingViewModelFactory & ViewControllerFactory { + func makeNicknameViewController() -> NicknameViewController { + return NicknameViewController(onboardingViewModel: makeOnboardingViewModel(), viewControllerFactory: self) + } +} diff --git a/FLINT/FLINT/Dependency/Factory/ViewController/OnboardingDoneViewControllerFactory+.swift b/FLINT/FLINT/Dependency/Factory/ViewController/OnboardingDoneViewControllerFactory+.swift new file mode 100644 index 00000000..cde5b901 --- /dev/null +++ b/FLINT/FLINT/Dependency/Factory/ViewController/OnboardingDoneViewControllerFactory+.swift @@ -0,0 +1,16 @@ +// +// OnboardingDoneViewControllerFactory+.swift +// FLINT +// +// Created by 김호성 on 2026.01.30. +// + +import Foundation + +import Presentation + +extension OnboardingDoneViewControllerFactory where Self: ViewControllerFactory { + func makeOnboardingDoneViewController(onboardingViewModel: OnboardingViewModel) -> OnboardingDoneViewController { + return OnboardingDoneViewController(onboardingViewModel: onboardingViewModel, viewControllerFactory: self) + } +} diff --git a/FLINT/FLINT/Dependency/Factory/ViewController/OttSelectViewControllerFactory+.swift b/FLINT/FLINT/Dependency/Factory/ViewController/OttSelectViewControllerFactory+.swift new file mode 100644 index 00000000..44f393a6 --- /dev/null +++ b/FLINT/FLINT/Dependency/Factory/ViewController/OttSelectViewControllerFactory+.swift @@ -0,0 +1,16 @@ +// +// OttSelectViewControllerFactory+.swift +// FLINT +// +// Created by 김호성 on 2026.01.30. +// + +import Foundation + +import Presentation + +extension OttSelectViewControllerFactory where Self: ViewControllerFactory { + func makeOttSelectViewController(onboardingViewModel: OnboardingViewModel) -> OttSelectViewController { + return OttSelectViewController(onboardingViewModel: onboardingViewModel, viewControllerFactory: self) + } +} diff --git a/FLINT/FLINT/Dependency/Factory/ViewController/ProfileViewControllerFactory+.swift b/FLINT/FLINT/Dependency/Factory/ViewController/ProfileViewControllerFactory+.swift new file mode 100644 index 00000000..9b04e531 --- /dev/null +++ b/FLINT/FLINT/Dependency/Factory/ViewController/ProfileViewControllerFactory+.swift @@ -0,0 +1,26 @@ +// +// ProfileViewControllerFactory+.swift +// FLINT +// +// Created by 김호성 on 2026.01.31. +// + +import Foundation + +import Domain +import Presentation + +extension ProfileViewControllerFactory where Self: ProfileViewModelFactory & ViewControllerFactory { + func makeProfileViewController() -> ProfileViewController { + makeProfileViewController(target: .me) + } + + func makeProfileViewController( + target: UserTarget = .me + ) -> ProfileViewController { + return ProfileViewController( + profileViewModel: makeProfileViewModel(target: target), + viewControllerFactory: self + ) + } +} diff --git a/FLINT/FLINT/Dependency/Factory/ViewController/SplashViewControllerFactory+.swift b/FLINT/FLINT/Dependency/Factory/ViewController/SplashViewControllerFactory+.swift new file mode 100644 index 00000000..b72c0724 --- /dev/null +++ b/FLINT/FLINT/Dependency/Factory/ViewController/SplashViewControllerFactory+.swift @@ -0,0 +1,16 @@ +// +// SplashViewControllerFactory.swift +// FLINT +// +// Created by 김호성 on 2026.01.30. +// + +import Foundation + +import Presentation + +extension SplashViewControllerFactory where Self: ViewControllerFactory { + func makeSplashViewController() -> SplashViewController { + return SplashViewController(viewControllerFactory: self) + } +} diff --git a/FLINT/FLINT/Dependency/Factory/ViewController/TabBarViewControllerFactory+.swift b/FLINT/FLINT/Dependency/Factory/ViewController/TabBarViewControllerFactory+.swift new file mode 100644 index 00000000..8e6642f2 --- /dev/null +++ b/FLINT/FLINT/Dependency/Factory/ViewController/TabBarViewControllerFactory+.swift @@ -0,0 +1,16 @@ +// +// TabBarViewControllerFactory+.swift +// FLINT +// +// Created by 김호성 on 2026.01.31. +// + +import Foundation + +import Presentation + +extension TabBarViewControllerFactory where Self: ViewControllerFactory { + func makeTabBarViewController() -> TabBarViewController { + return TabBarViewController(viewControllerFactory: self) + } +} diff --git a/FLINT/FLINT/Dependency/Factory/ViewModel/AddContentSelectViewModelFactory.swift b/FLINT/FLINT/Dependency/Factory/ViewModel/AddContentSelectViewModelFactory.swift index e5db071b..037c94d1 100644 --- a/FLINT/FLINT/Dependency/Factory/ViewModel/AddContentSelectViewModelFactory.swift +++ b/FLINT/FLINT/Dependency/Factory/ViewModel/AddContentSelectViewModelFactory.swift @@ -7,33 +7,14 @@ import Foundation -import Domain import Presentation -protocol AddContentSelectViewModelFactory: SearchContentsUseCaseFactory, ContentsUseCaseFactory { +protocol AddContentSelectViewModelFactory: SearchContentsUseCaseFactory, FetchPopularContentsUseCaseFactory { func makeAddContentSelectViewModel() -> AddContentSelectViewModel - func makeAddContentSelectViewModel( - contentsUseCase: ContentsUseCase, - searchContentsUseCase: SearchContentsUseCase - ) -> AddContentSelectViewModel } extension AddContentSelectViewModelFactory { - func makeAddContentSelectViewModel() -> AddContentSelectViewModel { - return makeAddContentSelectViewModel( - contentsUseCase: makeContentsUseCase(), - searchContentsUseCase: makeSearchContentsUseCase() - ) - } - - func makeAddContentSelectViewModel( - contentsUseCase: ContentsUseCase, - searchContentsUseCase: SearchContentsUseCase - ) -> AddContentSelectViewModel { - return DefaultAddContentSelectViewModel( - contentsUseCase: contentsUseCase, - searchContentsUseCase: searchContentsUseCase - ) + return DefaultAddContentSelectViewModel(fetchPopularContentsUseCase: makeFetchPopularContentsUseCase(), searchContentsUseCase: makeSearchContentsUseCase()) } } diff --git a/FLINT/FLINT/Dependency/Factory/ViewModel/CollectionDetailViewModelFactory.swift b/FLINT/FLINT/Dependency/Factory/ViewModel/CollectionDetailViewModelFactory.swift new file mode 100644 index 00000000..e6a7eaf3 --- /dev/null +++ b/FLINT/FLINT/Dependency/Factory/ViewModel/CollectionDetailViewModelFactory.swift @@ -0,0 +1,20 @@ +// +// CollectionDetailViewModelFactory.swift +// FLINT +// +// Created by 김호성 on 2026.02.02. +// + +import Foundation + +import Presentation + +protocol CollectionDetailViewModelFactory: FetchCollectionDetailUseCaseFactory, FetchCollectionBookmarkUsersUseCaseFactory { + func makeCollectionDetailViewModel(collectionId: Int64) -> CollectionDetailViewModel +} + +extension CollectionDetailViewModelFactory { + func makeCollectionDetailViewModel(collectionId: Int64) -> CollectionDetailViewModel { + return CollectionDetailViewModel(collectionId: collectionId, fetchCollectionDetailUseCase: makeFetchCollectionDetailUseCase(), fetchCollectionBookmarkUsersUseCase: makeFetchCollectionBookmarkUsersUseCase()) + } +} diff --git a/FLINT/FLINT/Dependency/Factory/ViewModel/CollectionFolderListViewModel.swift b/FLINT/FLINT/Dependency/Factory/ViewModel/CollectionFolderListViewModel.swift deleted file mode 100644 index 92dac4b6..00000000 --- a/FLINT/FLINT/Dependency/Factory/ViewModel/CollectionFolderListViewModel.swift +++ /dev/null @@ -1,7 +0,0 @@ -// -// CollectionFolderListViewModel.swift -// FLINT -// -// Created by 소은 on 1/24/26. -// - diff --git a/FLINT/FLINT/Dependency/Factory/ViewModel/CollectionFolderListViewModelFactory.swift b/FLINT/FLINT/Dependency/Factory/ViewModel/CollectionFolderListViewModelFactory.swift new file mode 100644 index 00000000..36d3792c --- /dev/null +++ b/FLINT/FLINT/Dependency/Factory/ViewModel/CollectionFolderListViewModelFactory.swift @@ -0,0 +1,20 @@ +// +// CollectionFolderListViewModelFactory.swift +// FLINT +// +// Created by 김호성 on 2026.02.02. +// + +import Foundation + +import Presentation + +protocol CollectionFolderListViewModelFactory: FetchRecentViewedCollectionsUseCaseFactory { + func makeCollectionFolderListViewModel() -> CollectionFolderListViewModel +} + +extension CollectionFolderListViewModelFactory { + func makeCollectionFolderListViewModel() -> CollectionFolderListViewModel { + return CollectionFolderListViewModel(fetchRecentViewedCollectionsUseCase: makeFetchRecentViewedCollectionsUseCase()) + } +} diff --git a/FLINT/FLINT/Dependency/Factory/ViewModel/CreateCollectionViewModelFactory.swift b/FLINT/FLINT/Dependency/Factory/ViewModel/CreateCollectionViewModelFactory.swift new file mode 100644 index 00000000..ae523133 --- /dev/null +++ b/FLINT/FLINT/Dependency/Factory/ViewModel/CreateCollectionViewModelFactory.swift @@ -0,0 +1,20 @@ +// +// CreateCollectionViewModel.swift +// FLINT +// +// Created by 김호성 on 2026.02.02. +// + +import Foundation + +import Presentation + +protocol CreateCollectionViewModelFactory: CreateCollectionUseCaseFactory { + func makeCreateCollectionViewModel() -> CreateCollectionViewModel +} + +extension CreateCollectionViewModelFactory { + func makeCreateCollectionViewModel() -> CreateCollectionViewModel { + return DefaultCreateCollectionViewModel(createCollectionUseCase: makeCreateCollectionUseCase()) + } +} diff --git a/FLINT/FLINT/Dependency/Factory/ViewModel/ExploreViewModelFactory.swift b/FLINT/FLINT/Dependency/Factory/ViewModel/ExploreViewModelFactory.swift index d208d7ce..ba7ec64f 100644 --- a/FLINT/FLINT/Dependency/Factory/ViewModel/ExploreViewModelFactory.swift +++ b/FLINT/FLINT/Dependency/Factory/ViewModel/ExploreViewModelFactory.swift @@ -1,5 +1,5 @@ // -// File.swift +// ExploreViewModelFactory.swift // FLINT // // Created by 김호성 on 2026.01.22. @@ -7,19 +7,14 @@ import Foundation -import Domain import Presentation -protocol ExploreViewModelFactory: ExploreUseCaseFactory { +protocol ExploreViewModelFactory: FetchExploreCollectionsUseCaseFactory { func makeExploreViewModel() -> ExploreViewModel - func makeExploreViewModel(exploreUseCase: ExploreUseCase) -> ExploreViewModel } extension ExploreViewModelFactory { func makeExploreViewModel() -> ExploreViewModel { - return makeExploreViewModel(exploreUseCase: makeExploreUseCase()) - } - func makeExploreViewModel(exploreUseCase: ExploreUseCase) -> ExploreViewModel { - return DefaultExploreViewModel(exploreUseCase: exploreUseCase) + return DefaultExploreViewModel(fetchExploreCollectionsUseCase: makeFetchExploreCollectionsUseCase()) } } diff --git a/FLINT/FLINT/Dependency/Factory/ViewModel/HomeViewModelFactory.swift b/FLINT/FLINT/Dependency/Factory/ViewModel/HomeViewModelFactory.swift new file mode 100644 index 00000000..54fee029 --- /dev/null +++ b/FLINT/FLINT/Dependency/Factory/ViewModel/HomeViewModelFactory.swift @@ -0,0 +1,20 @@ +// +// HomeViewModelFactory.swift +// FLINT +// +// Created by 김호성 on 2026.02.02. +// + +import Foundation + +import Presentation + +protocol HomeViewModelFactory: FetchRecommendedCollectionsUseCaseFactory, FetchBookmarkedContentsUseCaseFactory, FetchProfileUseCaseFactory, FetchRecentViewedCollectionsUseCaseFactory { + func makeHomeViewModel() -> HomeViewModel +} + +extension HomeViewModelFactory { + func makeHomeViewModel() -> HomeViewModel { + return HomeViewModel(fetchRecommendedCollectionsUseCase: makeFetchRecommendedCollectionsUseCase(), fetchBookmarkedContentsUseCase: makeFetchBookmarkedContentsUseCase(), fetchProfileUseCase: makeFetchProfileUseCase(), fetchRecentViewedCollectionsUseCase: makeFetchRecentViewedCollectionsUseCase()) + } +} diff --git a/FLINT/FLINT/Dependency/Factory/ViewModel/LoginViewModelFactory.swift b/FLINT/FLINT/Dependency/Factory/ViewModel/LoginViewModelFactory.swift index 65b8bc53..2472b133 100644 --- a/FLINT/FLINT/Dependency/Factory/ViewModel/LoginViewModelFactory.swift +++ b/FLINT/FLINT/Dependency/Factory/ViewModel/LoginViewModelFactory.swift @@ -7,19 +7,14 @@ import Foundation -import Domain import Presentation protocol LoginViewModelFactory: SocialVerifyUseCaseFactory { func makeLoginViewModel() -> LoginViewModel - func makeLoginViewModel(socialVerifyUseCase: SocialVerifyUseCase) -> LoginViewModel } extension LoginViewModelFactory { func makeLoginViewModel() -> LoginViewModel { - return makeLoginViewModel(socialVerifyUseCase: makeSocialVerifyUseCase()) - } - func makeLoginViewModel(socialVerifyUseCase: SocialVerifyUseCase) -> LoginViewModel { - return DefaultLoginViewModel(socialVerifyUseCase: socialVerifyUseCase) + return DefaultLoginViewModel(socialVerifyUseCase: makeSocialVerifyUseCase()) } } diff --git a/FLINT/FLINT/Dependency/Factory/ViewModel/OnboardingViewModelFactory.swift b/FLINT/FLINT/Dependency/Factory/ViewModel/OnboardingViewModelFactory.swift index 5d1a9a7c..56d324bf 100644 --- a/FLINT/FLINT/Dependency/Factory/ViewModel/OnboardingViewModelFactory.swift +++ b/FLINT/FLINT/Dependency/Factory/ViewModel/OnboardingViewModelFactory.swift @@ -1,5 +1,5 @@ // -// File.swift +// OnboardingViewModelFactory.swift // FLINT // // Created by 김호성 on 2026.01.22. @@ -7,19 +7,14 @@ import Foundation -import Domain import Presentation -protocol OnboardingViewModelFactory: NicknameUseCaseFactory, SearchContentsUseCaseFactory, ContentsUseCaseFactory, SignupUseCaseFactory { +protocol OnboardingViewModelFactory: CheckNicknameUseCaseFactory, SearchContentsUseCaseFactory, FetchPopularContentsUseCaseFactory, SignupUseCaseFactory { func makeOnboardingViewModel() -> OnboardingViewModel - func makeOnboardingViewModel(nicknameUseCase: NicknameUseCase, contentsUseCase: ContentsUseCase, searchContentsUseCase: SearchContentsUseCase, signupUseCase: SignupUseCase) -> OnboardingViewModel } extension OnboardingViewModelFactory { func makeOnboardingViewModel() -> OnboardingViewModel { - return makeOnboardingViewModel(nicknameUseCase: makeNicknameUseCase(), contentsUseCase: makeContentsUseCase(), searchContentsUseCase: makeSearchContentsUseCase(), signupUseCase: makeSignupUseCase()) - } - func makeOnboardingViewModel(nicknameUseCase: NicknameUseCase, contentsUseCase: ContentsUseCase, searchContentsUseCase: SearchContentsUseCase, signupUseCase: SignupUseCase) -> OnboardingViewModel { - return DefaultOnboardingViewModel(nicknameUseCase: nicknameUseCase, contentsUseCase: contentsUseCase, searchContentsUseCase: searchContentsUseCase, signupUseCase: signupUseCase) + return DefaultOnboardingViewModel(checkNicknameUseCase: makeCheckNicknameUseCase(), fetchPopularContentsUseCase: makeFetchPopularContentsUseCase(), searchContentsUseCase: makeSearchContentsUseCase(), signupUseCase: makeSignupUseCase()) } } diff --git a/FLINT/FLINT/Dependency/Factory/ViewModel/ProfileViewModelFactory.swift b/FLINT/FLINT/Dependency/Factory/ViewModel/ProfileViewModelFactory.swift new file mode 100644 index 00000000..be70ecac --- /dev/null +++ b/FLINT/FLINT/Dependency/Factory/ViewModel/ProfileViewModelFactory.swift @@ -0,0 +1,21 @@ +// +// ProfileViewModelFactory.swift +// FLINT +// +// Created by 김호성 on 2026.02.02. +// + +import Foundation + +import Domain +import Presentation + +protocol ProfileViewModelFactory: FetchProfileUseCaseFactory, FetchKeywordsUseCaseFactory, FetchCreatedCollectionsUseCaseFactory, FetchBookmarkedCollectionsUseCaseFactory, FetchBookmarkedContentsUseCaseFactory { + func makeProfileViewModel(target: UserTarget) -> ProfileViewModel +} + +extension ProfileViewModelFactory { + func makeProfileViewModel(target: UserTarget) -> ProfileViewModel { + return ProfileViewModel(target: target, fetchProfileUseCase: makeFetchProfileUseCase(), fetchKeywordsUseCase: makeFetchKeywordsUseCase(), fetchCreatedCollectionsUseCase: makeFetchCreatedCollectionsUseCase(), fetchBookmarkedCollectionsUseCase: makeFetchBookmarkedCollectionsUseCase(), fetchBookmarkedContentsUseCase: makeFetchBookmarkedContentsUseCase()) + } +} diff --git a/FLINT/Presentation/Sources/View/Component/BottomSheet/BaseBottomSheetView.swift b/FLINT/Presentation/Sources/View/Component/BottomSheet/BaseBottomSheetView.swift index 611954c6..fcc52f2b 100644 --- a/FLINT/Presentation/Sources/View/Component/BottomSheet/BaseBottomSheetView.swift +++ b/FLINT/Presentation/Sources/View/Component/BottomSheet/BaseBottomSheetView.swift @@ -10,6 +10,8 @@ import UIKit import SnapKit import Then +import Domain + public enum BottomSheetContent { case ott(platforms: [OTTPlatform]) case savedUsers(users: [SavedUserRowItem]) diff --git a/FLINT/Presentation/Sources/View/Component/BottomSheet/OTTPlatformList/OTTBottomSheetView.swift b/FLINT/Presentation/Sources/View/Component/BottomSheet/OTTPlatformList/OTTBottomSheetView.swift index 9b71edb5..efdf6d6f 100644 --- a/FLINT/Presentation/Sources/View/Component/BottomSheet/OTTPlatformList/OTTBottomSheetView.swift +++ b/FLINT/Presentation/Sources/View/Component/BottomSheet/OTTPlatformList/OTTBottomSheetView.swift @@ -10,6 +10,8 @@ import UIKit import SnapKit import Then +import Domain + public final class OTTBottomSheetView: BaseView { // MARK: - Public Event diff --git a/FLINT/Presentation/Sources/View/Component/BottomSheet/OTTPlatformList/OTTListView.swift b/FLINT/Presentation/Sources/View/Component/BottomSheet/OTTPlatformList/OTTListView.swift index df4a393e..38a18162 100644 --- a/FLINT/Presentation/Sources/View/Component/BottomSheet/OTTPlatformList/OTTListView.swift +++ b/FLINT/Presentation/Sources/View/Component/BottomSheet/OTTPlatformList/OTTListView.swift @@ -10,6 +10,8 @@ import UIKit import SnapKit import Then +import Domain + public final class OTTListView: BaseView { public static let rowHeight: CGFloat = 48 diff --git a/FLINT/Presentation/Sources/View/Component/BottomSheet/OTTPlatformList/OTTPlatform+.swift b/FLINT/Presentation/Sources/View/Component/BottomSheet/OTTPlatformList/OTTPlatform+.swift new file mode 100644 index 00000000..4918cfe1 --- /dev/null +++ b/FLINT/Presentation/Sources/View/Component/BottomSheet/OTTPlatformList/OTTPlatform+.swift @@ -0,0 +1,23 @@ +// +// OTTPlatform+.swift +// Domain +// +// Created by 소은 on 1/12/26. +// + +import UIKit + +import Domain + +extension OTTPlatform { + public var icon: UIImage? { + switch self { + case .netflix: return UIImage.imgSmallNetflix1 + case .tving: return UIImage.imgSmallTving1 + case .wavve: return UIImage.imgSmallWavve1 + case .coupangPlay: return UIImage.imgSmallCoupang1 + case .watcha: return UIImage.imgSmallWatcha1 + case .disneyPlus: return UIImage.imgSmallDisney1 + } + } +} diff --git a/FLINT/Presentation/Sources/View/Component/BottomSheet/OTTPlatformList/OTTPlatformRowView.swift b/FLINT/Presentation/Sources/View/Component/BottomSheet/OTTPlatformList/OTTPlatformRowView.swift index 4f6f18f8..a1c20ff4 100644 --- a/FLINT/Presentation/Sources/View/Component/BottomSheet/OTTPlatformList/OTTPlatformRowView.swift +++ b/FLINT/Presentation/Sources/View/Component/BottomSheet/OTTPlatformList/OTTPlatformRowView.swift @@ -10,6 +10,8 @@ import UIKit import SnapKit import Then +import Domain + public final class OTTPlatformRowView: BaseView { // MARK: - Public Event diff --git a/FLINT/Presentation/Sources/View/Component/Cell/FilmPreviewCollectionViewCell.swift b/FLINT/Presentation/Sources/View/Component/Cell/SelectedContentCollectionViewCell.swift similarity index 89% rename from FLINT/Presentation/Sources/View/Component/Cell/FilmPreviewCollectionViewCell.swift rename to FLINT/Presentation/Sources/View/Component/Cell/SelectedContentCollectionViewCell.swift index 6b67b519..df4cf160 100644 --- a/FLINT/Presentation/Sources/View/Component/Cell/FilmPreviewCollectionViewCell.swift +++ b/FLINT/Presentation/Sources/View/Component/Cell/SelectedContentCollectionViewCell.swift @@ -1,5 +1,5 @@ // -// FilmPreviewCollectionViewCell.swift +// SelectedContentCollectionViewCell.swift // FLINT // // Created by 김호성 on 2026.01.10. @@ -10,7 +10,7 @@ import UIKit import SnapKit import Then -public final class FilmPreviewCollectionViewCell: BaseCollectionViewCell { +public final class SelectedContentCollectionViewCell: BaseCollectionViewCell { // MARK: - Component diff --git a/FLINT/Presentation/Sources/View/Component/MoreNoMoreCollection/MoreNoMoreCollectionItemCell.swift b/FLINT/Presentation/Sources/View/Component/MoreNoMoreCollection/MoreNoMoreCollectionItemCell.swift index 2cd927de..6c886eb3 100644 --- a/FLINT/Presentation/Sources/View/Component/MoreNoMoreCollection/MoreNoMoreCollectionItemCell.swift +++ b/FLINT/Presentation/Sources/View/Component/MoreNoMoreCollection/MoreNoMoreCollectionItemCell.swift @@ -113,7 +113,7 @@ public final class MoreNoMoreCollectionItemCell: BaseCollectionViewCell { public func configure(entity: CollectionEntity) { // 썸네일 - if let url = URL(string: entity.thumbnailUrl) { + if let url = entity.thumbnailUrl { posterImageView.kf.setImage( with: url, placeholder: UIImage(resource: .imgBackgroundGradiantMiddle) @@ -123,7 +123,7 @@ public final class MoreNoMoreCollectionItemCell: BaseCollectionViewCell { } // 프로필 이미지 - if let url = URL(string: entity.profileImageUrl) { + if let url = entity.user.profileImageUrl { profileImageView.kf.setImage( with: url, placeholder: UIImage(resource: .imgProfileGray) @@ -141,7 +141,7 @@ public final class MoreNoMoreCollectionItemCell: BaseCollectionViewCell { userNameLabel.attributedText = .pretendard( .caption1_r_12, - text: entity.nickname, + text: entity.user.nickname, color: .flintGray200 ) } diff --git a/FLINT/Presentation/Sources/View/Component/OTTLogoStripeView/CircleOTTPlatform+.swift b/FLINT/Presentation/Sources/View/Component/OTTLogoStripeView/CircleOTTPlatform+.swift new file mode 100644 index 00000000..93f8ca24 --- /dev/null +++ b/FLINT/Presentation/Sources/View/Component/OTTLogoStripeView/CircleOTTPlatform+.swift @@ -0,0 +1,23 @@ +// +// CircleOTTPlatform+.swift +// Domain +// +// Created by 소은 on 1/13/26. +// + +import UIKit + +import Domain + +extension CircleOTTPlatform { + public var smallLogoImage: UIImage? { + switch self { + case .netflix: return UIImage.imgSmallNetflix1 + case .tving: return UIImage.imgSmallTving1 + case .coupangPlay: return UIImage.imgSmallCoupang1 + case .wavve: return UIImage.imgSmallWavve1 + case .disneyPlus: return UIImage.imgSmallDisney1 + case .watcha: return UIImage.imgSmallWatcha1 + } + } +} diff --git a/FLINT/Presentation/Sources/View/Component/PreferenceKeyword/KeywordColor+.swift b/FLINT/Presentation/Sources/View/Component/PreferenceKeyword/KeywordColor+.swift new file mode 100644 index 00000000..1a012418 --- /dev/null +++ b/FLINT/Presentation/Sources/View/Component/PreferenceKeyword/KeywordColor+.swift @@ -0,0 +1,22 @@ +// +// KeywordColor+.swift +// FLINT +// +// Created by 진소은 on 1/18/26. +// + +import UIKit + +import Domain + +extension KeywordColor { + public var tagBackgroundImage: UIImage { + switch self { + case .pink: return UIImage(resource: .imgTagPink) + case .green: return UIImage(resource: .imgTagGreen) + case .orange: return UIImage(resource: .imgTagOrange) + case .yellow: return UIImage(resource: .imgTagYellow) + case .blue: return UIImage(resource: .imgTagBlue) + } + } +} diff --git a/FLINT/Presentation/Sources/View/Component/PreferenceKeyword/KeywordColor.swift b/FLINT/Presentation/Sources/View/Component/PreferenceKeyword/KeywordColor.swift deleted file mode 100644 index fed07294..00000000 --- a/FLINT/Presentation/Sources/View/Component/PreferenceKeyword/KeywordColor.swift +++ /dev/null @@ -1,45 +0,0 @@ -// -// KeywordColor.swift -// FLINT -// -// Created by 진소은 on 1/18/26. -// - -import Foundation -import UIKit - -public enum KeywordColor: String, Decodable { - case pink = "PINK" - case green = "GREEN" - case orange = "ORANGE" - case yellow = "YELLOW" - case blue = "BLUE" -} - -public struct KeywordDTO: Decodable { - public let color: KeywordColor - public let rank: Int - public let name: String - public let percentage: Int - public let imageUrl: String - - public init(color: KeywordColor, rank: Int, name: String, percentage: Int, imageUrl: String) { - self.color = color - self.rank = rank - self.name = name - self.percentage = percentage - self.imageUrl = imageUrl - } -} - -extension KeywordColor { - public var tagBackgroundImage: UIImage { - switch self { - case .pink: return UIImage(resource: .imgTagPink) - case .green: return UIImage(resource: .imgTagGreen) - case .orange: return UIImage(resource: .imgTagOrange) - case .yellow: return UIImage(resource: .imgTagYellow) - case .blue: return UIImage(resource: .imgTagBlue) - } - } -} diff --git a/FLINT/Presentation/Sources/View/Component/PreferenceKeyword/PreferenceChip.swift b/FLINT/Presentation/Sources/View/Component/PreferenceKeyword/PreferenceChip.swift index 4cd44f1a..c1fc4ba9 100644 --- a/FLINT/Presentation/Sources/View/Component/PreferenceKeyword/PreferenceChip.swift +++ b/FLINT/Presentation/Sources/View/Component/PreferenceKeyword/PreferenceChip.swift @@ -7,9 +7,11 @@ import UIKit +import Kingfisher import SnapKit import Then -import Kingfisher + +import Domain public final class PreferenceChip: BaseView { @@ -64,12 +66,12 @@ public final class PreferenceChip: BaseView { // MARK: - Public - public func configure(dto: KeywordDTO) { - style = PreferenceChipStyle.from(rank: dto.rank, color: dto.color) + public func configure(keyword: KeywordEntity) { + style = PreferenceChipStyle.from(rank: keyword.rank, color: keyword.color) - keywordLabel.attributedText = .pretendard(.head2_m_20, text: dto.name, color: .white) + keywordLabel.attributedText = .pretendard(.head2_m_20, text: keyword.name, color: .white) - applyResizableBackground(style.backgroundImage(for: dto.color)) + applyResizableBackground(style.backgroundImage(for: keyword.color)) contentStackView.spacing = style.spacing iconImageView.isHidden = (style.iconSize == 0) @@ -78,15 +80,11 @@ public final class PreferenceChip: BaseView { iconImageView.kf.cancelDownloadTask() iconImageView.image = nil } else { - if let url = URL(string: dto.imageUrl) { - iconImageView.kf.setImage( - with: url, - placeholder: nil, - options: [.transition(.fade(0.15)), .cacheOriginalImage] - ) - } else { - iconImageView.image = nil - } + iconImageView.kf.setImage( + with: keyword.imageUrl, + placeholder: nil, + options: [.transition(.fade(0.15)), .cacheOriginalImage] + ) } invalidateIntrinsicContentSize() diff --git a/FLINT/Presentation/Sources/View/Component/PreferenceKeyword/PreferenceChipStyle.swift b/FLINT/Presentation/Sources/View/Component/PreferenceKeyword/PreferenceChipStyle.swift index 02f341c4..4b4937f3 100644 --- a/FLINT/Presentation/Sources/View/Component/PreferenceKeyword/PreferenceChipStyle.swift +++ b/FLINT/Presentation/Sources/View/Component/PreferenceKeyword/PreferenceChipStyle.swift @@ -8,6 +8,8 @@ import Foundation import UIKit +import Domain + public enum PreferenceChipStyle { case colored(KeywordColor) case gray diff --git a/FLINT/Presentation/Sources/View/Component/PreferenceKeyword/PreferenceExampleView.swift b/FLINT/Presentation/Sources/View/Component/PreferenceKeyword/PreferenceExampleView.swift index 1e6aac4b..b422dbee 100644 --- a/FLINT/Presentation/Sources/View/Component/PreferenceKeyword/PreferenceExampleView.swift +++ b/FLINT/Presentation/Sources/View/Component/PreferenceKeyword/PreferenceExampleView.swift @@ -11,6 +11,8 @@ import Kingfisher import SnapKit import Then +import Domain + public final class PreferenceExampleView: BaseView { private let rankedView = PreferenceRankedChipView() @@ -26,13 +28,13 @@ public final class PreferenceExampleView: BaseView { $0.center.equalToSuperview() } - let dummyData: [KeywordDTO] = [ - .init(color: .blue, rank: 1, name: "영화", percentage: 0, imageUrl: "https://picsum.photos/seed/1/80"), - .init(color: .pink, rank: 2, name: "SF", percentage: 0, imageUrl: "https://picsum.photos/seed/2/80"), - .init(color: .green, rank: 3, name: "로맨스", percentage: 0, imageUrl: "https://picsum.photos/seed/3/80"), - .init(color: .orange, rank: 4, name: "공포", percentage: 0, imageUrl: "https://picsum.photos/seed/4/80"), - .init(color: .yellow, rank: 5, name: "액션", percentage: 0, imageUrl: "https://picsum.photos/seed/5/80"), - .init(color: .pink, rank: 6, name: "성장", percentage: 0, imageUrl: "https://picsum.photos/seed/6/80"), + let dummyData: [KeywordEntity] = [ + .init(color: .blue, rank: 1, name: "영화", percentage: 0, imageUrl: URL(string: "https://picsum.photos/seed/1/80")), + .init(color: .pink, rank: 2, name: "SF", percentage: 0, imageUrl: URL(string: "https://picsum.photos/seed/2/80")), + .init(color: .green, rank: 3, name: "로맨스", percentage: 0, imageUrl: URL(string: "https://picsum.photos/seed/3/80")), + .init(color: .orange, rank: 4, name: "공포", percentage: 0, imageUrl: URL(string: "https://picsum.photos/seed/4/80")), + .init(color: .yellow, rank: 5, name: "액션", percentage: 0, imageUrl: URL(string: "https://picsum.photos/seed/5/80")), + .init(color: .pink, rank: 6, name: "성장", percentage: 0, imageUrl: URL(string: "https://picsum.photos/seed/6/80")), ] rankedView.configure(keywords: dummyData) diff --git a/FLINT/Presentation/Sources/View/Component/PreferenceKeyword/PreferenceRankedChipView.swift b/FLINT/Presentation/Sources/View/Component/PreferenceKeyword/PreferenceRankedChipView.swift index f068bf28..5f670937 100644 --- a/FLINT/Presentation/Sources/View/Component/PreferenceKeyword/PreferenceRankedChipView.swift +++ b/FLINT/Presentation/Sources/View/Component/PreferenceKeyword/PreferenceRankedChipView.swift @@ -10,6 +10,8 @@ import UIKit import SnapKit import Then +import Domain + public final class PreferenceRankedChipView: BaseView { private let vStack = UIStackView().then { @@ -29,7 +31,7 @@ public final class PreferenceRankedChipView: BaseView { } } - public func configure(keywords: [KeywordDTO]) { + public func configure(keywords: [KeywordEntity]) { let byRank = Dictionary(uniqueKeysWithValues: keywords.map { ($0.rank, $0) }) let sumA = [1, 2, 4].compactMap { byRank[$0]?.name.count }.reduce(0, +) @@ -70,7 +72,7 @@ public final class PreferenceRankedChipView: BaseView { rankRow.forEach { r in guard let dto = byRank[r] else { return } let chip = PreferenceChip() - chip.configure(dto: dto) + chip.configure(keyword: dto) rowStack.addArrangedSubview(chip) } diff --git a/FLINT/Presentation/Sources/View/Component/ProfileImageSettingView.swift b/FLINT/Presentation/Sources/View/Component/ProfileImageSettingView.swift index 04ecbb16..898704ee 100644 --- a/FLINT/Presentation/Sources/View/Component/ProfileImageSettingView.swift +++ b/FLINT/Presentation/Sources/View/Component/ProfileImageSettingView.swift @@ -23,6 +23,7 @@ public final class ProfileImageSettingView: BaseView { public let settingButton = UIButton().then { $0.setImage(.icProfileChange, for: .normal) + // TODO: - Profile Image 설정 기능 구현 시 제거할 것!!!! $0.isHidden = true } diff --git a/FLINT/Presentation/Sources/View/Component/RecentSaved/RecentSavedContentItem.swift b/FLINT/Presentation/Sources/View/Component/RecentSaved/RecentSavedContentItem.swift index ff4b0f89..6602715b 100644 --- a/FLINT/Presentation/Sources/View/Component/RecentSaved/RecentSavedContentItem.swift +++ b/FLINT/Presentation/Sources/View/Component/RecentSaved/RecentSavedContentItem.swift @@ -7,6 +7,8 @@ import Foundation +import Domain + public struct RecentSavedContentItem: Hashable { public let id: UUID = UUID() public let posterImageName: String diff --git a/FLINT/Presentation/Sources/View/Scene/CollectionDetail/CollectionDetailFilmTableViewCell.swift b/FLINT/Presentation/Sources/View/Scene/CollectionDetail/CollectionDetailFilmTableViewCell.swift index 8cacdef7..0de866f3 100644 --- a/FLINT/Presentation/Sources/View/Scene/CollectionDetail/CollectionDetailFilmTableViewCell.swift +++ b/FLINT/Presentation/Sources/View/Scene/CollectionDetail/CollectionDetailFilmTableViewCell.swift @@ -280,7 +280,7 @@ extension UIButton { public extension CollectionDetailFilmTableViewCell { - func configure(item: CollectionContentEntity) { + func configure(item: CollectionDetailEntity.CollectionContentEntity) { // 이미지 if let url = item.imageUrl { poster.kf.setImage(with: url) diff --git a/FLINT/Presentation/Sources/View/Scene/CreateCollection/CollectionSearchVIew/AddContentSelectView.swift b/FLINT/Presentation/Sources/View/Scene/CreateCollection/CollectionSearchVIew/AddContentSelectView.swift index 3b3db8cb..069fe37e 100644 --- a/FLINT/Presentation/Sources/View/Scene/CreateCollection/CollectionSearchVIew/AddContentSelectView.swift +++ b/FLINT/Presentation/Sources/View/Scene/CreateCollection/CollectionSearchVIew/AddContentSelectView.swift @@ -33,7 +33,7 @@ public final class AddContentSelectView: BaseView { $0.showsHorizontalScrollIndicator = false $0.showsVerticalScrollIndicator = false $0.contentInset = .init(top: 0, left: 16, bottom: 0, right: 16) - $0.register(FilmPreviewCollectionViewCell.self) + $0.register(SelectedContentCollectionViewCell.self) $0.clipsToBounds = true } diff --git a/FLINT/Presentation/Sources/View/Scene/Explore/Cell/ExploreEmptyCollectionViewCell.swift b/FLINT/Presentation/Sources/View/Scene/Explore/Cell/ExploreEmptyCollectionViewCell.swift index 43f30624..a5809dd0 100644 --- a/FLINT/Presentation/Sources/View/Scene/Explore/Cell/ExploreEmptyCollectionViewCell.swift +++ b/FLINT/Presentation/Sources/View/Scene/Explore/Cell/ExploreEmptyCollectionViewCell.swift @@ -14,7 +14,7 @@ public final class ExploreEmptyCollectionViewCell: BaseCollectionViewCell { // MARK: - Component - public let collectionDetailButton = FlintButton(style: .able, title: "컬렉션 만들러 가기") + public let createCollectionButton = FlintButton(style: .able, title: "컬렉션 만들러 가기") public let wrapperView = UIView() @@ -64,7 +64,7 @@ public final class ExploreEmptyCollectionViewCell: BaseCollectionViewCell { public override func setHierarchy() { contentView.addSubviews( - collectionDetailButton, + createCollectionButton, wrapperView, ) wrapperView.addSubview(mainStackView) @@ -79,18 +79,22 @@ public final class ExploreEmptyCollectionViewCell: BaseCollectionViewCell { } public override func setLayout() { - collectionDetailButton.snp.makeConstraints { + createCollectionButton.snp.makeConstraints { $0.bottom.equalToSuperview().inset(32) $0.horizontalEdges.equalToSuperview().inset(16) $0.height.equalTo(48) } wrapperView.snp.makeConstraints { $0.top.horizontalEdges.equalToSuperview() - $0.bottom.equalTo(collectionDetailButton.snp.top) + $0.bottom.equalTo(createCollectionButton.snp.top) } mainStackView.snp.makeConstraints { $0.horizontalEdges.equalToSuperview().inset(16) $0.centerY.equalToSuperview() } } + + public override func prepare() { + createCollectionButton.removeTarget(nil, action: nil, for: .allEvents) + } } diff --git a/FLINT/Presentation/Sources/View/Scene/Onboarding/FilmSelect/Cell/OnboardingFilmCollectionViewCell.swift b/FLINT/Presentation/Sources/View/Scene/Onboarding/FilmSelect/Cell/OnboardingContentCollectionViewCell.swift similarity index 78% rename from FLINT/Presentation/Sources/View/Scene/Onboarding/FilmSelect/Cell/OnboardingFilmCollectionViewCell.swift rename to FLINT/Presentation/Sources/View/Scene/Onboarding/FilmSelect/Cell/OnboardingContentCollectionViewCell.swift index 7b7b823e..38e4b5c4 100644 --- a/FLINT/Presentation/Sources/View/Scene/Onboarding/FilmSelect/Cell/OnboardingFilmCollectionViewCell.swift +++ b/FLINT/Presentation/Sources/View/Scene/Onboarding/FilmSelect/Cell/OnboardingContentCollectionViewCell.swift @@ -1,5 +1,5 @@ // -// OnboardingFilmCollectionViewCell.swift +// OnboardingContentCollectionViewCell.swift // FLINT // // Created by 김호성 on 2026.01.17. @@ -10,13 +10,16 @@ import UIKit import SnapKit import Then -public final class OnboardingFilmCollectionViewCell: BaseCollectionViewCell { +import Domain + +public final class OnboardingContentCollectionViewCell: BaseCollectionViewCell { // MARK: - Component public let imageView = UIImageView().then { $0.backgroundColor = .flintGray100 $0.contentMode = .scaleAspectFill + $0.clipsToBounds = true } public let titleLabel = UILabel().then { @@ -95,4 +98,14 @@ public final class OnboardingFilmCollectionViewCell: BaseCollectionViewCell { $0.horizontalEdges.equalToSuperview().inset(32) } } + + // MARK: - Public Function + + public func configure(content: ContentEntity, isSelected: Bool) { + overlayView.isHidden = !isSelected + titleLabel.attributedText = .pretendard(.body1_r_16, text: content.title) + directorLabel.attributedText = .pretendard(.caption1_r_12, text: content.author) + yearLabel.attributedText = .pretendard(.caption1_r_12, text: "\(content.year)") + imageView.kf.setImage(with: content.posterUrl) + } } diff --git a/FLINT/Presentation/Sources/View/Scene/Onboarding/FilmSelect/FilmSelectView.swift b/FLINT/Presentation/Sources/View/Scene/Onboarding/FilmSelect/ContentSelectView.swift similarity index 93% rename from FLINT/Presentation/Sources/View/Scene/Onboarding/FilmSelect/FilmSelectView.swift rename to FLINT/Presentation/Sources/View/Scene/Onboarding/FilmSelect/ContentSelectView.swift index 6422842b..859e46b1 100644 --- a/FLINT/Presentation/Sources/View/Scene/Onboarding/FilmSelect/FilmSelectView.swift +++ b/FLINT/Presentation/Sources/View/Scene/Onboarding/FilmSelect/ContentSelectView.swift @@ -1,5 +1,5 @@ // -// FilmSelectView.swift +// ContentSelectView.swift // FLINT // // Created by 김호성 on 2026.01.14. @@ -10,7 +10,7 @@ import UIKit import SnapKit import Then -public final class FilmSelectView: BaseView { +public final class ContentSelectView: BaseView { // MARK: - Component @@ -55,7 +55,7 @@ public final class FilmSelectView: BaseView { $0.alignment = .fill $0.distribution = .fill } - public let filmPreviewCollectionView = UICollectionView( + public let selectedContentCollectionView = UICollectionView( frame: .zero, collectionViewLayout: UICollectionViewFlowLayout().then { $0.itemSize = CGSize(width: 92, height: 92) @@ -66,14 +66,14 @@ public final class FilmSelectView: BaseView { ).then { $0.isHidden = true $0.layer.applyShadow(alpha: 0.25, blur: 12, y: 12) - $0.register(FilmPreviewCollectionViewCell.self) + $0.register(SelectedContentCollectionViewCell.self) $0.backgroundColor = .flintBackground $0.showsHorizontalScrollIndicator = false $0.showsVerticalScrollIndicator = false $0.contentInset = .init(top: 0, left: 16, bottom: 16, right: 16) } - public let filmCollectionView: UICollectionView = { + public let contentCollectionView: UICollectionView = { let uselessHeight: CGFloat = 230 let item = NSCollectionLayoutItem( layoutSize: NSCollectionLayoutSize( @@ -102,7 +102,7 @@ public final class FilmSelectView: BaseView { collectionView.backgroundColor = .flintBackground collectionView.showsHorizontalScrollIndicator = false collectionView.showsVerticalScrollIndicator = false - collectionView.register(OnboardingFilmCollectionViewCell.self) + collectionView.register(OnboardingContentCollectionViewCell.self) return collectionView }() @@ -158,8 +158,8 @@ public final class FilmSelectView: BaseView { emptyView ) collectionViewStackView.addArrangedSubviews( - filmPreviewCollectionView, - filmCollectionView, + selectedContentCollectionView, + contentCollectionView, ) progressInfoView.addSubviews(progressView, progressLabel) foldableView.addSubview(titleLabel) @@ -220,7 +220,7 @@ public final class FilmSelectView: BaseView { $0.top.equalTo(searchView.snp.bottom) $0.horizontalEdges.equalToSuperview() } - filmPreviewCollectionView.snp.makeConstraints { + selectedContentCollectionView.snp.makeConstraints { $0.height.equalTo(108) } nextButton.snp.makeConstraints { @@ -230,7 +230,7 @@ public final class FilmSelectView: BaseView { $0.bottom.equalTo(safeAreaLayoutGuide) } emptyView.snp.makeConstraints { - $0.edges.equalTo(filmCollectionView) + $0.edges.equalTo(contentCollectionView) } emptyStackView.snp.makeConstraints { $0.center.equalToSuperview() diff --git a/FLINT/Presentation/Sources/View/Scene/Nickname/NicknameView.swift b/FLINT/Presentation/Sources/View/Scene/Onboarding/Nickname/NicknameView.swift similarity index 100% rename from FLINT/Presentation/Sources/View/Scene/Nickname/NicknameView.swift rename to FLINT/Presentation/Sources/View/Scene/Onboarding/Nickname/NicknameView.swift diff --git a/FLINT/Presentation/Sources/View/Scene/Onboarding/OttSelect/Cell/OnboardingOttCollectionViewCell.swift b/FLINT/Presentation/Sources/View/Scene/Onboarding/OttSelect/Cell/OnboardingOttCollectionViewCell.swift index adaec7a4..77932938 100644 --- a/FLINT/Presentation/Sources/View/Scene/Onboarding/OttSelect/Cell/OnboardingOttCollectionViewCell.swift +++ b/FLINT/Presentation/Sources/View/Scene/Onboarding/OttSelect/Cell/OnboardingOttCollectionViewCell.swift @@ -10,6 +10,8 @@ import UIKit import SnapKit import Then +import Domain + public final class OnboardingOttCollectionViewCell: BaseCollectionViewCell { // MARK: - Component @@ -75,4 +77,14 @@ public final class OnboardingOttCollectionViewCell: BaseCollectionViewCell { $0.horizontalEdges.equalToSuperview().inset(32) } } + + // MARK: - Public Function + + public func configure(ott: Ott, isSelected: Bool) { + overlayView.isHidden = !isSelected + titleLabel.textColor = isSelected ? DesignSystem.Color.gray300 : DesignSystem.Color.white + + imageView.image = ott.logo + titleLabel.attributedText = .pretendard(.body1_m_16, text: ott.korTitle, alignment: .center) + } } diff --git a/FLINT/Presentation/Sources/View/Scene/Profile/PreferenceRankedChipTableViewCell.swift b/FLINT/Presentation/Sources/View/Scene/Profile/PreferenceRankedChipTableViewCell.swift index a76b97ff..5ad51ee3 100644 --- a/FLINT/Presentation/Sources/View/Scene/Profile/PreferenceRankedChipTableViewCell.swift +++ b/FLINT/Presentation/Sources/View/Scene/Profile/PreferenceRankedChipTableViewCell.swift @@ -44,16 +44,7 @@ public final class PreferenceRankedChipTableViewCell: BaseTableViewCell { // public func configure(keywords: [KeywordDTO]) { // chipView.configure(keywords: keywords) // } - public func configure(entities: [KeywordEntity]) { - let keywords: [KeywordDTO] = entities.map { entity in - KeywordDTO( - color: KeywordColor(rawValue: entity.color) ?? .pink, // ⚠️ entity.color가 String이라고 가정 - rank: entity.rank, - name: entity.name, - percentage: entity.percentage, - imageUrl: entity.imageUrl - ) - } + public func configure(keywords: [KeywordEntity]) { chipView.configure(keywords: keywords) } } diff --git a/FLINT/Presentation/Sources/View/Scene/Profile/ProfileHeaderTableViewCell.swift b/FLINT/Presentation/Sources/View/Scene/Profile/ProfileHeaderTableViewCell.swift index 7a2deae3..db4fee91 100644 --- a/FLINT/Presentation/Sources/View/Scene/Profile/ProfileHeaderTableViewCell.swift +++ b/FLINT/Presentation/Sources/View/Scene/Profile/ProfileHeaderTableViewCell.swift @@ -88,14 +88,14 @@ public final class ProfileHeaderTableViewCell: BaseTableViewCell { public func configure( nickname: String = "", - profileImageUrl: String? = nil, + profileImageUrl: URL? = nil, isFliner: Bool = false ) { nameLabel.attributedText = .pretendard(.display2_m_28, text: nickname) verificationBadge.isHidden = !isFliner let placeholder = UIImage(resource: .imgProfileGray) - guard let urlString = profileImageUrl, let url = URL(string: urlString) else { + guard let url = profileImageUrl else { profileImageView.image = placeholder return } diff --git a/FLINT/Presentation/Sources/ViewController/Dependency/ViewControllerFactory.swift b/FLINT/Presentation/Sources/ViewController/Dependency/ViewControllerFactory.swift index aab113db..93999744 100644 --- a/FLINT/Presentation/Sources/ViewController/Dependency/ViewControllerFactory.swift +++ b/FLINT/Presentation/Sources/ViewController/Dependency/ViewControllerFactory.swift @@ -9,29 +9,30 @@ import UIKit import ViewModel -public protocol ViewControllerFactory { - func makeSplashViewController() -> SplashViewController - func makeLoginViewController() -> LoginViewController - - func makeNicknameViewController() -> NicknameViewController +public typealias ViewControllerFactory = - func makeFilmSelectViewController(onboardingViewModel: OnboardingViewModel) -> FilmSelectViewController - func makeOttSelectViewController(onboardingViewModel: OnboardingViewModel) -> OttSelectViewController - func makeOnboardingDoneViewController(onboardingViewModel: OnboardingViewModel) -> OnboardingDoneViewController + // MARK: - Splash / Login - func makeTabBarViewController() -> TabBarViewController + SplashViewControllerFactory & + LoginViewControllerFactory & - func makeHomeViewController() -> HomeViewController - func makeExploreViewController() -> ExploreViewController + // MARK: - Onboarding - func makeAddContentSelectViewController() -> AddContentSelectViewController - func makeCreateCollectionViewController() -> CreateCollectionViewController + NicknameViewControllerFactory & + ContentSelectViewControllerFactory & + OttSelectViewControllerFactory & + OnboardingDoneViewControllerFactory & - func makeProfileViewController() -> ProfileViewController - func makeProfileViewController(target: ProfileViewModel.Target) -> ProfileViewController - - func makeCollectionDetailViewController(collectionId: Int64) -> CollectionDetailViewController + // MARK: - Main - func makeCollectionFolderListViewController() -> CollectionFolderListViewController - -} + TabBarViewControllerFactory & + HomeViewControllerFactory & + ExploreViewControllerFactory & + ProfileViewControllerFactory & + + // MARK: - Collection + + CollectionFolderListViewControllerFactory & + CollectionDetailViewControllerFactory & + AddContentSelectViewControllerFactory & + CreateCollectionViewControllerFactory diff --git a/FLINT/Presentation/Sources/ViewController/Extension/UICollectionView+.swift b/FLINT/Presentation/Sources/ViewController/Extension/UICollectionView+.swift new file mode 100644 index 00000000..de4505e1 --- /dev/null +++ b/FLINT/Presentation/Sources/ViewController/Extension/UICollectionView+.swift @@ -0,0 +1,19 @@ +// +// UICollectionView+.swift +// Presentation +// +// Created by 김호성 on 2026.02.10. +// + +import UIKit + +import View + +extension UICollectionView { + public func dequeueReusableCell(_ cellType: T.Type, for indexPath: IndexPath) -> T { + guard let cell: T = dequeueReusableCell(withReuseIdentifier: cellType.reuseIdentifier, for: indexPath) as? T else { + fatalError("Failed to dequeue reusable cell of type \(cellType) with reuseIdentifier \(cellType.reuseIdentifier).") + } + return cell + } +} diff --git a/FLINT/Presentation/Sources/ViewController/Extension/UITableView+.swift b/FLINT/Presentation/Sources/ViewController/Extension/UITableView+.swift new file mode 100644 index 00000000..8d74370b --- /dev/null +++ b/FLINT/Presentation/Sources/ViewController/Extension/UITableView+.swift @@ -0,0 +1,19 @@ +// +// UITableView+.swift +// Presentation +// +// Created by 김호성 on 2026.02.14. +// + +import UIKit + +import View + +extension UITableView { + public func dequeueReusableCell(_ cellType: T.Type, for indexPath: IndexPath) -> T { + guard let cell: T = dequeueReusableCell(withIdentifier: cellType.reuseIdentifier, for: indexPath) as? T else { + fatalError("Failed to dequeue reusable cell of type \(cellType) with reuseIdentifier \(cellType.reuseIdentifier).") + } + return cell + } +} diff --git a/FLINT/Presentation/Sources/ViewController/Scene/CollectionDetail/CollectionDetailViewController.swift b/FLINT/Presentation/Sources/ViewController/Scene/CollectionDetail/CollectionDetailViewController.swift index bd225082..535f0559 100644 --- a/FLINT/Presentation/Sources/ViewController/Scene/CollectionDetail/CollectionDetailViewController.swift +++ b/FLINT/Presentation/Sources/ViewController/Scene/CollectionDetail/CollectionDetailViewController.swift @@ -14,6 +14,10 @@ import Entity import View import ViewModel +public protocol CollectionDetailViewControllerFactory { + func makeCollectionDetailViewController(collectionId: Int64) -> CollectionDetailViewController +} + public final class CollectionDetailViewController: BaseViewController { // MARK: - Enum @@ -115,7 +119,7 @@ public final class CollectionDetailViewController: BaseViewController CollectionFolderListViewController +} + public final class CollectionFolderListViewController: BaseViewController { // MARK: - Data @@ -105,17 +109,17 @@ extension CollectionFolderListViewController: UICollectionViewDataSource { let entity = viewModel.items[indexPath.item] - let firstURL = URL(string: entity.imageList.first ?? entity.thumbnailUrl) + let firstURL = entity.imageList.first ?? entity.thumbnailUrl let secondString = entity.imageList.count > 1 ? entity.imageList[1] : nil - let secondURL = secondString.flatMap(URL.init(string:)) - let profileURL = URL(string: entity.profileImageUrl) + let secondURL = entity.imageList[safe: 1] + let profileURL = entity.user.profileImageUrl cell.configure( .init( firstPosterURL: firstURL, secondPosterURL: secondURL, profileImageURL: profileURL, - name: entity.nickname, + name: entity.user.nickname, title: entity.title, description: entity.description, isBookmarked: entity.isBookmarked, diff --git a/FLINT/Presentation/Sources/ViewController/Scene/CreateCollection/CollectionSearchVIew/AddContentSelectViewController.swift b/FLINT/Presentation/Sources/ViewController/Scene/CreateCollection/CollectionSearchVIew/AddContentSelectViewController.swift index 74f7e9bd..b52e29ba 100644 --- a/FLINT/Presentation/Sources/ViewController/Scene/CreateCollection/CollectionSearchVIew/AddContentSelectViewController.swift +++ b/FLINT/Presentation/Sources/ViewController/Scene/CreateCollection/CollectionSearchVIew/AddContentSelectViewController.swift @@ -16,6 +16,10 @@ import Domain import View import ViewModel +public protocol AddContentSelectViewControllerFactory { + func makeAddContentSelectViewController() -> AddContentSelectViewController +} + public final class AddContentSelectViewController: BaseViewController { // MARK: - Output @@ -362,9 +366,9 @@ extension AddContentSelectViewController: UICollectionViewDataSource { ) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell( - withReuseIdentifier: FilmPreviewCollectionViewCell.reuseIdentifier, + withReuseIdentifier: SelectedContentCollectionViewCell.reuseIdentifier, for: indexPath - ) as! FilmPreviewCollectionViewCell + ) as! SelectedContentCollectionViewCell let vm = selectedViewModels[indexPath.item] diff --git a/FLINT/Presentation/Sources/ViewController/Scene/CreateCollection/CreateCollectionView/CreateCollectionViewController.swift b/FLINT/Presentation/Sources/ViewController/Scene/CreateCollection/CreateCollectionView/CreateCollectionViewController.swift index 9c84fc79..1c32bd15 100644 --- a/FLINT/Presentation/Sources/ViewController/Scene/CreateCollection/CreateCollectionView/CreateCollectionViewController.swift +++ b/FLINT/Presentation/Sources/ViewController/Scene/CreateCollection/CreateCollectionView/CreateCollectionViewController.swift @@ -12,6 +12,10 @@ import Domain import View import ViewModel +public protocol CreateCollectionViewControllerFactory { + func makeCreateCollectionViewController() -> CreateCollectionViewController +} + public final class CreateCollectionViewController: BaseViewController { // MARK: - Enum diff --git a/FLINT/Presentation/Sources/ViewController/Scene/Explore/ExploreViewController.swift b/FLINT/Presentation/Sources/ViewController/Scene/Explore/ExploreViewController.swift index 55730f54..10c475e9 100644 --- a/FLINT/Presentation/Sources/ViewController/Scene/Explore/ExploreViewController.swift +++ b/FLINT/Presentation/Sources/ViewController/Scene/Explore/ExploreViewController.swift @@ -16,10 +16,16 @@ import Domain import View import ViewModel +public protocol ExploreViewControllerFactory { + func makeExploreViewController() -> ExploreViewController +} + public final class ExploreViewController: BaseViewController { public let exploreViewModel: ExploreViewModel + private var mainCollectionViewDataSource: UICollectionViewDiffableDataSource? + // MARK: - Component private let gradientBackgroundView = FixedGradientView().then { @@ -45,20 +51,23 @@ public final class ExploreViewController: BaseViewController { super.viewDidLoad() setNavigationBar(.init(left: .logo)) - rootView.mainCollectionView.register(ExploreCollectionViewCell.self) - rootView.mainCollectionView.register(ExploreEmptyCollectionViewCell.self) - rootView.mainCollectionView.delegate = self - rootView.mainCollectionView.dataSource = self + setupMainCollectionView() } // MARK: - Setup public override func bind() { - exploreViewModel.collections.sink { [weak self] exploreInfoEntity in - Log.d(exploreInfoEntity) - self?.rootView.mainCollectionView.reloadData() + exploreViewModel.collections.sink { [weak self] exploreInfoEntities in + guard let self else { return } + mainCollectionViewDataSource?.apply(makeSnapshot(exploreInfoEntities: exploreInfoEntities, isCollectionsExhausted: exploreViewModel.cursor.value == nil), animatingDifferences: false) } .store(in: &cancellables) + + exploreViewModel.cursor.sink(receiveValue: { [weak self] cursor in + guard let self else { return } + mainCollectionViewDataSource?.apply(makeSnapshot(exploreInfoEntities: exploreViewModel.collections.value, isCollectionsExhausted: cursor == nil), animatingDifferences: false) + }) + .store(in: &cancellables) } public override func setBaseHierarchy() { @@ -74,39 +83,71 @@ public final class ExploreViewController: BaseViewController { } } -// MARK: - UICollectionViewDataSource +// MARK: - MainCollectionView -extension ExploreViewController: UICollectionViewDataSource { - public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { - return exploreViewModel.collections.value.count + 1 +extension ExploreViewController { + private enum MainCollectionViewSection: Int { + case main + case empty } - public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { - if indexPath.item == exploreViewModel.collections.value.count { - guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: ExploreEmptyCollectionViewCell.reuseIdentifier, for: indexPath) as? ExploreEmptyCollectionViewCell else { - return UICollectionViewCell() + private enum MainCollectionViewItem: Hashable, Sendable { + case collection(ExploreInfoEntity) + case empty + } + + private func setupMainCollectionView() { + rootView.mainCollectionView.register(ExploreCollectionViewCell.self) + rootView.mainCollectionView.register(ExploreEmptyCollectionViewCell.self) + rootView.mainCollectionView.delegate = self + rootView.mainCollectionView.dataSource = mainCollectionViewDataSource + + mainCollectionViewDataSource = UICollectionViewDiffableDataSource(collectionView: rootView.mainCollectionView, cellProvider: { [weak self] collectionView, indexPath, itemIdentifier in + guard let self else { return UICollectionViewCell() } + + switch itemIdentifier { + case let .collection(collection): + let cell = collectionView.dequeueReusableCell(ExploreCollectionViewCell.self, for: indexPath) + cell.collectionImageView.kf.setImage(with: collection.imageUrl) + cell.collectionTitleLabel.attributedText = .pretendard(.display2_m_28, text: collection.title) + cell.collectionDescriptionLabel.attributedText = .pretendard(.body1_r_16, text: collection.description) + cell.collectionDetailButton.addAction(UIAction(handler: { [weak self] _ in + self?.pushCollectionDetailViewController(collectionId: collection.collectionId) + }), for: .touchUpInside) + return cell + + case .empty: + let cell = collectionView.dequeueReusableCell(ExploreEmptyCollectionViewCell.self, for: indexPath) + cell.createCollectionButton.addAction(UIAction(handler: pushCreateCollectionViewController(_:)), for: .touchUpInside) + return cell } - return cell - } - guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: ExploreCollectionViewCell.reuseIdentifier, for: indexPath) as? ExploreCollectionViewCell else { - return UICollectionViewCell() + }) + mainCollectionViewDataSource?.apply(makeSnapshot(exploreInfoEntities: exploreViewModel.collections.value, isCollectionsExhausted: exploreViewModel.cursor.value == nil), animatingDifferences: false) + } + + private func makeSnapshot(exploreInfoEntities: [ExploreInfoEntity], isCollectionsExhausted: Bool) -> NSDiffableDataSourceSnapshot { + var snapshot = NSDiffableDataSourceSnapshot() + snapshot.appendSections([.main]) + snapshot.appendItems(exploreInfoEntities.map({ MainCollectionViewItem.collection($0) }), toSection: .main) + + if isCollectionsExhausted { + snapshot.appendSections([.empty]) + snapshot.appendItems([MainCollectionViewItem.empty], toSection: .empty) } - let collection = exploreViewModel.collections.value[indexPath.item] - cell.collectionImageView.kf.setImage(with: collection.imageUrl) - cell.collectionTitleLabel.attributedText = .pretendard(.display2_m_28, text: collection.title) - cell.collectionDescriptionLabel.attributedText = .pretendard(.body1_r_16, text: collection.description) - cell.collectionDetailButton.addAction(UIAction(handler: { [weak self] _ in - guard let id = Int64(collection.id) else { return } - guard let vc = self?.viewControllerFactory?.makeCollectionDetailViewController(collectionId: id) else { return } - self?.navigationController?.pushViewController(vc, animated: true) - - }), for: .touchUpInside) - return cell + return snapshot + } + + private func pushCollectionDetailViewController(collectionId: Int64) { + guard let vc = viewControllerFactory?.makeCollectionDetailViewController(collectionId: collectionId) else { return } + navigationController?.pushViewController(vc, animated: true) + } + + private func pushCreateCollectionViewController(_ action: UIAction) { + guard let vc = viewControllerFactory?.makeCreateCollectionViewController() else { return } + navigationController?.pushViewController(vc, animated: true) } } -// MARK: - UICollectionViewDelegateFlowLayout - extension ExploreViewController: UICollectionViewDelegateFlowLayout { public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { return collectionView.bounds.size @@ -117,8 +158,6 @@ extension ExploreViewController: UICollectionViewDelegateFlowLayout { } } -// MARK: - UIScrollViewDelegate - extension ExploreViewController: UIScrollViewDelegate { public func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { guard let collectionView = scrollView as? UICollectionView else { return } @@ -126,7 +165,7 @@ extension ExploreViewController: UIScrollViewDelegate { exploreViewModel.indexUpdated(indexPath.item) UIView.animate(withDuration: 0.25, animations: { [weak self] in guard let self else { return } - if indexPath.item == exploreViewModel.collections.value.count { + if indexPath.section == MainCollectionViewSection.empty.rawValue { setNavigationBar(.init(left: .logo, backgroundStyle: .clear)) } else { setNavigationBar(.init(left: .logo)) diff --git a/FLINT/Presentation/Sources/ViewController/Scene/Home/HomeViewController.swift b/FLINT/Presentation/Sources/ViewController/Scene/Home/HomeViewController.swift index 18fe7501..c9c83c6f 100644 --- a/FLINT/Presentation/Sources/ViewController/Scene/Home/HomeViewController.swift +++ b/FLINT/Presentation/Sources/ViewController/Scene/Home/HomeViewController.swift @@ -7,23 +7,28 @@ import UIKit +import Domain + import View import ViewModel -import Domain +public protocol HomeViewControllerFactory { + func makeHomeViewController() -> HomeViewController +} public final class HomeViewController: BaseViewController { private let viewModel: HomeViewModel - public init(viewModel: HomeViewModel, viewControllerFactory: ViewControllerFactory? = nil) { + public init(viewModel: HomeViewModel, viewControllerFactory: ViewControllerFactory) { self.viewModel = viewModel super.init(nibName: nil, bundle: nil) self.viewControllerFactory = viewControllerFactory } - @available(*, unavailable) - required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } // MARK: - Lifecycle @@ -136,18 +141,12 @@ extension HomeViewController: UITableViewDataSource { switch row { case .greeting(let userName): - let cell = tableView.dequeueReusableCell( - withIdentifier: HomeGreetingTableViewCell.reuseIdentifier, - for: indexPath - ) as! HomeGreetingTableViewCell + let cell = tableView.dequeueReusableCell(HomeGreetingTableViewCell.self, for: indexPath) cell.configure(userName: userName) return cell case .header(let style, let title, let subtitle): - let cell = tableView.dequeueReusableCell( - withIdentifier: TitleHeaderTableViewCell.reuseIdentifier, - for: indexPath - ) as! TitleHeaderTableViewCell + let cell = tableView.dequeueReusableCell(TitleHeaderTableViewCell.self, for: indexPath) cell.configure(style: map(style), title: title, subtitle: subtitle) @@ -170,35 +169,25 @@ extension HomeViewController: UITableViewDataSource { return cell case .fliner(let items): - let cell = tableView.dequeueReusableCell( - withIdentifier: MoreNoMoreCollectionTableViewCell.reuseIdentifier, - for: indexPath - ) as! MoreNoMoreCollectionTableViewCell + let cell = tableView.dequeueReusableCell(MoreNoMoreCollectionTableViewCell.self, for: indexPath) cell.configure(items: items) cell.onSelectItem = { [weak self] entity in - guard let self else { return } - - guard let collectionId = Int64(entity.id) else { - print("invalid collectionId:", entity.id) - return - } - - let factory = self.viewControllerFactory - ?? (self.parent as? TabBarViewController)?.viewControllerFactory - guard let factory else { return } + guard let self else { return } - let vc = factory.makeCollectionDetailViewController(collectionId: collectionId) - self.navigationController?.pushViewController(vc, animated: true) + guard let collectionId = Int64(entity.id) else { + print("invalid collectionId:", entity.id) + return } + guard let vc = viewControllerFactory?.makeCollectionDetailViewController(collectionId: collectionId) else { return } + self.navigationController?.pushViewController(vc, animated: true) + } + return cell case .ctaButton(let title): - let cell = tableView.dequeueReusableCell( - withIdentifier: HomeCTAButtonTableViewCell.reuseIdentifier, - for: indexPath - ) as! HomeCTAButtonTableViewCell + let cell = tableView.dequeueReusableCell(HomeCTAButtonTableViewCell.self, for: indexPath) cell.configure(title: title) diff --git a/FLINT/Presentation/Sources/ViewController/Scene/Login/LoginViewController.swift b/FLINT/Presentation/Sources/ViewController/Scene/Login/LoginViewController.swift index 76ad3e6f..72bb41ff 100644 --- a/FLINT/Presentation/Sources/ViewController/Scene/Login/LoginViewController.swift +++ b/FLINT/Presentation/Sources/ViewController/Scene/Login/LoginViewController.swift @@ -12,6 +12,10 @@ import Domain import View import ViewModel +public protocol LoginViewControllerFactory { + func makeLoginViewController() -> LoginViewController +} + public final class LoginViewController: BaseViewController { // MARK: - ViewModel @@ -37,7 +41,6 @@ public final class LoginViewController: BaseViewController { public override func bind() { loginViewModel.socialVerifyResultEntity.sink { [weak self] socialVerifyResultEntity in Log.d(socialVerifyResultEntity) - guard let socialVerifyResultEntity else { return } if !socialVerifyResultEntity.isRegistered { self?.register() } else { diff --git a/FLINT/Presentation/Sources/ViewController/Scene/MyViewController.swift b/FLINT/Presentation/Sources/ViewController/Scene/MyViewController.swift deleted file mode 100644 index 4947e5a8..00000000 --- a/FLINT/Presentation/Sources/ViewController/Scene/MyViewController.swift +++ /dev/null @@ -1,32 +0,0 @@ -// -// MyViewController.swift -// FLINT -// -// Created by 소은 on 1/6/26. -// - -import UIKit -import SnapKit -import Then - -public final class MyViewController: BaseViewController { - - private let titleLabel = UILabel().then { - $0.attributedText = .pretendard(.head1_sb_22, text: "My") - $0.textAlignment = .center - } - - public override func setUI() { - view.backgroundColor = .systemBackground - } - - public override func setHierarchy() { - view.addSubview(titleLabel) - } - - public override func setLayout() { - titleLabel.snp.makeConstraints { - $0.center.equalToSuperview() - } - } -} diff --git a/FLINT/Presentation/Sources/ViewController/Scene/Onboarding/FilmSelect/FilmSelectViewController.swift b/FLINT/Presentation/Sources/ViewController/Scene/Onboarding/ContentSelect/ContentSelectViewController.swift similarity index 59% rename from FLINT/Presentation/Sources/ViewController/Scene/Onboarding/FilmSelect/FilmSelectViewController.swift rename to FLINT/Presentation/Sources/ViewController/Scene/Onboarding/ContentSelect/ContentSelectViewController.swift index 019e4042..4e6122e0 100644 --- a/FLINT/Presentation/Sources/ViewController/Scene/Onboarding/FilmSelect/FilmSelectViewController.swift +++ b/FLINT/Presentation/Sources/ViewController/Scene/Onboarding/ContentSelect/ContentSelectViewController.swift @@ -1,5 +1,5 @@ // -// FilmSelectViewController.swift +// ContentSelectViewController.swift // FLINT // // Created by 김호성 on 2026.01.14. @@ -14,9 +14,13 @@ import Domain import View import ViewModel -// TODO: - shadow & select logic +public protocol ContentSelectViewControllerFactory { + func makeContentSelectViewController(onboardingViewModel: OnboardingViewModel) -> ContentSelectViewController +} + +// TODO: - shadow -public final class FilmSelectViewController: BaseViewController { +public final class ContentSelectViewController: BaseViewController { // MARK: - Enum @@ -60,28 +64,28 @@ public final class FilmSelectViewController: BaseViewController setNavigationBar(.init(left: .back, backgroundStyle: .solid(DesignSystem.Color.background))) hideKeyboardWhenTappedAround(activeOnAction: false) - onboardingViewModel.fetchContents() + onboardingViewModel.fetchPopularContents() rootView.searchTextField.searchAction = { [weak self] keyword in self?.onboardingViewModel.searchContents(keyword ?? "") } rootView.searchTextField.clearAction = { [weak self] in - self?.onboardingViewModel.fetchContents() + self?.onboardingViewModel.fetchPopularContents() } - rootView.progressLabel.attributedText = .pretendard(.caption1_m_12, text: "\(onboardingViewModel.selectedContents.value.count)/\(onboardingViewModel.filmSelectQuestions.count)") - rootView.progressView.progress = Float(onboardingViewModel.selectedContents.value.count) / Float(onboardingViewModel.filmSelectQuestions.count) + rootView.progressLabel.attributedText = .pretendard(.caption1_m_12, text: "\(onboardingViewModel.selectedContents.value.count)/\(onboardingViewModel.contentSelectQuestions.count)") + rootView.progressView.progress = Float(onboardingViewModel.selectedContents.value.count) / Float(onboardingViewModel.contentSelectQuestions.count) rootView.titleLabel.attributedText = .pretendard(.display2_m_28, text: "\(onboardingViewModel.nickname.value) 님이 좋아하는 작품 7개를 골라주세요", lineBreakMode: .byWordWrapping, lineBreakStrategy: .hangulWordPriority) - rootView.subtitleLabel.attributedText = .pretendard(.body2_r_14, text: onboardingViewModel.filmSelectQuestions[onboardingViewModel.selectedContents.value.count]) - rootView.filmPreviewCollectionView.dataSource = self - rootView.filmCollectionView.dataSource = self - rootView.filmCollectionView.delegate = self + rootView.subtitleLabel.attributedText = .pretendard(.body2_r_14, text: onboardingViewModel.contentSelectQuestions[onboardingViewModel.selectedContents.value.count]) + rootView.selectedContentCollectionView.dataSource = self + rootView.contentCollectionView.dataSource = self + rootView.contentCollectionView.delegate = self rootView.searchTextField.delegate = self rootView.layoutIfNeeded() - rootView.filmCollectionView.contentOffset.y = -rootView.filmCollectionView.contentInset.top + rootView.contentCollectionView.contentOffset.y = -rootView.contentCollectionView.contentInset.top - rootView.filmCollectionView.panGestureRecognizer.addTarget(self, action: #selector(filmCollectionViewPanGesture)) + rootView.contentCollectionView.panGestureRecognizer.addTarget(self, action: #selector(contentCollectionViewPanGesture)) rootView.nextButton.addAction(UIAction(handler: pushOttSelectViewController(_:)), for: .touchUpInside) } @@ -94,51 +98,49 @@ public final class FilmSelectViewController: BaseViewController onboardingViewModel.contents.sink { [weak self] contents in self?.rootView.emptyView.isHidden = !contents.isEmpty - self?.rootView.filmCollectionView.reloadData() + self?.rootView.contentCollectionView.reloadData() } .store(in: &cancellables) onboardingViewModel.selectedContents.sink { [weak self] selectedContents in guard let self else { return } UIView.animate(withDuration: 0.2, animations: { - self.rootView.filmPreviewCollectionView.isHidden = selectedContents.isEmpty + self.rootView.selectedContentCollectionView.isHidden = selectedContents.isEmpty }) - self.rootView.filmPreviewCollectionView.reloadData() - self.rootView.filmCollectionView.reloadData() - rootView.progressLabel.attributedText = .pretendard(.caption1_m_12, text: "\(selectedContents.count)/\(onboardingViewModel.filmSelectQuestions.count)") - rootView.progressView.progress = Float(selectedContents.count) / Float(onboardingViewModel.filmSelectQuestions.count) - rootView.subtitleLabel.attributedText = .pretendard(.body2_r_14, text: onboardingViewModel.filmSelectQuestions[min(selectedContents.count, onboardingViewModel.filmSelectQuestions.count-1)]) + self.rootView.selectedContentCollectionView.reloadData() + self.rootView.contentCollectionView.reloadData() + rootView.progressLabel.attributedText = .pretendard(.caption1_m_12, text: "\(selectedContents.count)/\(onboardingViewModel.contentSelectQuestions.count)") + rootView.progressView.progress = Float(selectedContents.count) / Float(onboardingViewModel.contentSelectQuestions.count) + rootView.subtitleLabel.attributedText = .pretendard(.body2_r_14, text: onboardingViewModel.contentSelectQuestions[min(selectedContents.count, onboardingViewModel.contentSelectQuestions.count-1)]) rootView.nextButton.isEnabled = selectedContents.count == 7 } .store(in: &cancellables) } - @objc public func filmCollectionViewPanGesture(_ sender: UIPanGestureRecognizer) { + @objc public func contentCollectionViewPanGesture(_ sender: UIPanGestureRecognizer) { // Adjust the accumulated scroll translation // so that the foldableView responds immediately when the scroll direction changes - let translationY = sender.translation(in: rootView.filmCollectionView).y - let velocityY = sender.velocity(in: rootView.filmCollectionView).y - - Log.d(translationY) + let translationY = sender.translation(in: rootView.contentCollectionView).y + let velocityY = sender.velocity(in: rootView.contentCollectionView).y let unclampedOffset = translationY - offsetCorrection // Update offsetCorrection value if unclampedOffset >= 0 { - // When topBarView is visible - // topBarViewOffsetY = translationY - offsetCorrection = 0 + // When foldableView is visible + // foldableViewYOffset = translationY - offsetCorrection = 0 offsetCorrection = translationY } if unclampedOffset <= -rootView.foldableView.bounds.height { - // When topBarView is hidden - // topBarViewOffsetY = translationY - offsetCorrection = -rootView.foldableView.bounds.height + // When foldableView is hidden + // foldableViewYOffset = translationY - offsetCorrection = -rootView.foldableView.bounds.height offsetCorrection = translationY + rootView.foldableView.bounds.height } let passedFoldableViewYOffset = foldableViewYOffset foldableViewYOffset = translationY - offsetCorrection rootView.updateFoldableViewYOffset(foldableViewYOffset) - rootView.filmCollectionView.contentOffset.y += foldableViewYOffset - passedFoldableViewYOffset + rootView.contentCollectionView.contentOffset.y += foldableViewYOffset - passedFoldableViewYOffset rootView.foldableView.alpha = 1 + foldableViewYOffset / rootView.foldableView.bounds.height // Magnetic snapping effect when the gesture ends @@ -147,15 +149,15 @@ public final class FilmSelectViewController: BaseViewController guard let self else { return } switch ScrollDirection(velocity: velocityY) { case .up: - foldableViewYOffset = 0 + foldableViewYOffset = .zero rootView.updateFoldableViewYOffset(foldableViewYOffset) - offsetCorrection = 0 + offsetCorrection = .zero rootView.foldableView.alpha = 1 case .down: foldableViewYOffset = -rootView.foldableView.bounds.height rootView.updateFoldableViewYOffset(foldableViewYOffset) offsetCorrection = rootView.foldableView.bounds.height - rootView.foldableView.alpha = 0 + rootView.foldableView.alpha = .zero case nil: break } @@ -172,43 +174,42 @@ public final class FilmSelectViewController: BaseViewController // MARK: - UICollectionView DataSource & Delegate -extension FilmSelectViewController: UICollectionViewDataSource { +extension ContentSelectViewController: UICollectionViewDataSource { public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { - if collectionView === rootView.filmPreviewCollectionView { - return filmPreviewCollectionView(collectionView, numberOfItemsInSection: section) - } else if collectionView === rootView.filmCollectionView { - return filmCollectionView(collectionView, numberOfItemsInSection: section) + if collectionView === rootView.selectedContentCollectionView { + return selectedContentCollectionView(collectionView, numberOfItemsInSection: section) + } else if collectionView === rootView.contentCollectionView { + return contentCollectionView(collectionView, numberOfItemsInSection: section) } return 0 } public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { - if collectionView === rootView.filmPreviewCollectionView { - return filmPreviewCollectionView(collectionView, cellForItemAt: indexPath) - } else if collectionView === rootView.filmCollectionView { - return filmCollectionView(collectionView, cellForItemAt: indexPath) + if collectionView === rootView.selectedContentCollectionView { + return selectedContentCollectionView(collectionView, cellForItemAt: indexPath) + } else if collectionView === rootView.contentCollectionView { + return contentCollectionView(collectionView, cellForItemAt: indexPath) } return UICollectionViewCell() } } -extension FilmSelectViewController: UICollectionViewDelegate { +extension ContentSelectViewController: UICollectionViewDelegate { public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { - filmCollectionView(collectionView, didSelectItemAt: indexPath) + contentCollectionView(collectionView, didSelectItemAt: indexPath) } } -// MARK: - FilmPreviewCollectionView DataSource +// MARK: - SelectedContentCollectionView DataSource -extension FilmSelectViewController { - public func filmPreviewCollectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { +extension ContentSelectViewController { + public func selectedContentCollectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return onboardingViewModel.selectedContents.value.count } - public func filmPreviewCollectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { - guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: FilmPreviewCollectionViewCell.reuseIdentifier, for: indexPath) as? FilmPreviewCollectionViewCell else { - return UICollectionViewCell() - } + public func selectedContentCollectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + let cell = collectionView.dequeueReusableCell(SelectedContentCollectionViewCell.self, for: indexPath) + let content = onboardingViewModel.selectedContents.value[indexPath.item] cell.imageView.kf.setImage(with: content.posterUrl) @@ -219,32 +220,27 @@ extension FilmSelectViewController { } } -// MARK: - FilmCollectionView DataSource & Delegate +// MARK: - ContentCollectionView DataSource & Delegate -extension FilmSelectViewController { - public func filmCollectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { +extension ContentSelectViewController { + public func contentCollectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return onboardingViewModel.contents.value.count } - public func filmCollectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { - guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: OnboardingFilmCollectionViewCell.reuseIdentifier, for: indexPath) as? OnboardingFilmCollectionViewCell else { - return UICollectionViewCell() - } - let content = onboardingViewModel.contents.value[indexPath.item] + public func contentCollectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + let cell = collectionView.dequeueReusableCell(OnboardingContentCollectionViewCell.self, for: indexPath) - cell.overlayView.isHidden = !onboardingViewModel.selectedContents.value.contains(where: { + let content = onboardingViewModel.contents.value[indexPath.item] + let isSelected = onboardingViewModel.selectedContents.value.contains(where: { $0 == content }) - cell.titleLabel.attributedText = .pretendard(.body1_r_16, text: content.title) - cell.directorLabel.attributedText = .pretendard(.caption1_r_12, text: content.author) - cell.yearLabel.attributedText = .pretendard(.caption1_r_12, text: "\(content.year)") - cell.imageView.kf.setImage(with: content.posterUrl) + cell.configure(content: content, isSelected: isSelected) return cell } } -extension FilmSelectViewController { - public func filmCollectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { +extension ContentSelectViewController { + public func contentCollectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { guard onboardingViewModel.selectedContents.value.count <= 6 else { return } @@ -252,7 +248,9 @@ extension FilmSelectViewController { } } -extension FilmSelectViewController: UITextFieldDelegate { +// MARK: - SearchTextField Delegate + +extension ContentSelectViewController: UITextFieldDelegate { public func textFieldShouldReturn(_ textField: UITextField) -> Bool { textField.resignFirstResponder() guard let text = textField.text else { return true } diff --git a/FLINT/Presentation/Sources/ViewController/Scene/Onboarding/Done/OnboardingDoneViewController.swift b/FLINT/Presentation/Sources/ViewController/Scene/Onboarding/Done/OnboardingDoneViewController.swift index c79df8e5..87fff128 100644 --- a/FLINT/Presentation/Sources/ViewController/Scene/Onboarding/Done/OnboardingDoneViewController.swift +++ b/FLINT/Presentation/Sources/ViewController/Scene/Onboarding/Done/OnboardingDoneViewController.swift @@ -12,6 +12,10 @@ import Domain import View import ViewModel +public protocol OnboardingDoneViewControllerFactory { + func makeOnboardingDoneViewController(onboardingViewModel: OnboardingViewModel) -> OnboardingDoneViewController +} + public final class OnboardingDoneViewController: BaseViewController { // MARK: - ViewModel diff --git a/FLINT/Presentation/Sources/ViewController/Scene/Nickname/NicknameViewController.swift b/FLINT/Presentation/Sources/ViewController/Scene/Onboarding/Nickname/NicknameViewController.swift similarity index 95% rename from FLINT/Presentation/Sources/ViewController/Scene/Nickname/NicknameViewController.swift rename to FLINT/Presentation/Sources/ViewController/Scene/Onboarding/Nickname/NicknameViewController.swift index fcccfef9..8bedc519 100644 --- a/FLINT/Presentation/Sources/ViewController/Scene/Nickname/NicknameViewController.swift +++ b/FLINT/Presentation/Sources/ViewController/Scene/Onboarding/Nickname/NicknameViewController.swift @@ -14,6 +14,10 @@ import Domain import View import ViewModel +public protocol NicknameViewControllerFactory { + func makeNicknameViewController() -> NicknameViewController +} + public final class NicknameViewController: BaseViewController { // MARK: - ViewModel @@ -161,8 +165,8 @@ public final class NicknameViewController: BaseViewController { private func nextButtonTapped(_ action: UIAction) { rootView.successToast.close(animated: false) rootView.failureToast.close(animated: false) - guard let filmSelectViewController = viewControllerFactory?.makeFilmSelectViewController(onboardingViewModel: onboardingViewModel) else { return } - navigationController?.pushViewController(filmSelectViewController, animated: true) + guard let contentSelectViewController = viewControllerFactory?.makeContentSelectViewController(onboardingViewModel: onboardingViewModel) else { return } + navigationController?.pushViewController(contentSelectViewController, animated: true) } } diff --git a/FLINT/Presentation/Sources/ViewController/Scene/Onboarding/OttSelect/OttSelectViewController.swift b/FLINT/Presentation/Sources/ViewController/Scene/Onboarding/OttSelect/OttSelectViewController.swift index 96df2419..7f0332e0 100644 --- a/FLINT/Presentation/Sources/ViewController/Scene/Onboarding/OttSelect/OttSelectViewController.swift +++ b/FLINT/Presentation/Sources/ViewController/Scene/Onboarding/OttSelect/OttSelectViewController.swift @@ -12,6 +12,10 @@ import Domain import View import ViewModel +public protocol OttSelectViewControllerFactory { + func makeOttSelectViewController(onboardingViewModel: OnboardingViewModel) -> OttSelectViewController +} + public class OttSelectViewController: BaseViewController { // MARK: - ViewModel @@ -67,22 +71,16 @@ extension OttSelectViewController: UICollectionViewDataSource { } public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { - guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: OnboardingOttCollectionViewCell.reuseIdentifier, for: indexPath) as? OnboardingOttCollectionViewCell else { - return UICollectionViewCell() - } + let cell = collectionView.dequeueReusableCell(OnboardingOttCollectionViewCell.self, for: indexPath) + guard let ott = Ott(rawValue: indexPath.item) else { return cell } - let isSelectedOtt = onboardingViewModel.selectedOtt.value.contains(where: { $0 == ott }) + cell.configure(ott: ott, isSelected: isSelectedOtt) - cell.overlayView.isHidden = !isSelectedOtt - cell.titleLabel.textColor = isSelectedOtt ? DesignSystem.Color.gray300 : DesignSystem.Color.white - - cell.imageView.image = ott.logo - cell.titleLabel.attributedText = .pretendard(.body1_m_16, text: ott.korTitle, alignment: .center) return cell } } diff --git a/FLINT/Presentation/Sources/ViewController/Scene/Profile/ProfileViewController.swift b/FLINT/Presentation/Sources/ViewController/Scene/Profile/ProfileViewController.swift index a97833ee..5a2f963c 100644 --- a/FLINT/Presentation/Sources/ViewController/Scene/Profile/ProfileViewController.swift +++ b/FLINT/Presentation/Sources/ViewController/Scene/Profile/ProfileViewController.swift @@ -5,20 +5,26 @@ // Created by 진소은 on 1/19/26. // -import UIKit import Combine +import UIKit import SnapKit import Then import Domain + import View import ViewModel +public protocol ProfileViewControllerFactory { + func makeProfileViewController() -> ProfileViewController + func makeProfileViewController(target: UserTarget) -> ProfileViewController +} + public final class ProfileViewController: BaseViewController { - private let profileViewModel: ProfileViewModel + public init( profileViewModel: ProfileViewModel, viewControllerFactory: ViewControllerFactory, @@ -27,10 +33,10 @@ public final class ProfileViewController: BaseViewController { super.init(nibName: nil, bundle: nil) self.viewControllerFactory = viewControllerFactory } - - @available(*, unavailable) - required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } public override func viewDidLoad() { super.viewDidLoad() @@ -51,26 +57,11 @@ public final class ProfileViewController: BaseViewController { tableView.dataSource = self tableView.delegate = self - tableView.register( - ProfileHeaderTableViewCell.self, - forCellReuseIdentifier: ProfileHeaderTableViewCell.reuseIdentifier - ) - tableView.register( - PreferenceRankedChipTableViewCell.self, - forCellReuseIdentifier: PreferenceRankedChipTableViewCell.reuseIdentifier - ) - tableView.register( - TitleHeaderTableViewCell.self, - forCellReuseIdentifier: TitleHeaderTableViewCell.reuseIdentifier - ) - tableView.register( - MoreNoMoreCollectionTableViewCell.self, - forCellReuseIdentifier: MoreNoMoreCollectionTableViewCell.reuseIdentifier - ) - tableView.register( - RecentSavedContentTableViewCell.self, - forCellReuseIdentifier: RecentSavedContentTableViewCell.reuseIdentifier - ) + tableView.register(ProfileHeaderTableViewCell.self) + tableView.register(PreferenceRankedChipTableViewCell.self) + tableView.register(TitleHeaderTableViewCell.self) + tableView.register(MoreNoMoreCollectionTableViewCell.self) + tableView.register(RecentSavedContentTableViewCell.self) } public override func bind() { @@ -141,63 +132,43 @@ extension ProfileViewController: UITableViewDataSource { switch row { case let .profileHeader(nickname, profileImageUrl, isFliner): - let cell = tableView.dequeueReusableCell( - withIdentifier: ProfileHeaderTableViewCell.reuseIdentifier, - for: indexPath - ) as! ProfileHeaderTableViewCell + let cell = tableView.dequeueReusableCell(ProfileHeaderTableViewCell.self, for: indexPath) cell.selectionStyle = .none cell.configure(nickname: nickname, profileImageUrl: profileImageUrl, isFliner: isFliner) return cell case let .preferenceChips(keywords): - let cell = tableView.dequeueReusableCell( - withIdentifier: PreferenceRankedChipTableViewCell.reuseIdentifier, - for: indexPath - ) as! PreferenceRankedChipTableViewCell + let cell = tableView.dequeueReusableCell(PreferenceRankedChipTableViewCell.self, for: indexPath) cell.selectionStyle = .none - cell.configure(entities: keywords) + cell.configure(keywords: keywords) return cell case let .titleHeader(style, title, subtitle): - let cell = tableView.dequeueReusableCell( - withIdentifier: TitleHeaderTableViewCell.reuseIdentifier, - for: indexPath - ) as! TitleHeaderTableViewCell + let cell = tableView.dequeueReusableCell(TitleHeaderTableViewCell.self, for: indexPath) cell.selectionStyle = .none cell.configure(style: map(style), title: title, subtitle: subtitle) return cell case let .myCollections(items): - let cell = tableView.dequeueReusableCell( - withIdentifier: MoreNoMoreCollectionTableViewCell.reuseIdentifier, - for: indexPath - ) as! MoreNoMoreCollectionTableViewCell + let cell = tableView.dequeueReusableCell(MoreNoMoreCollectionTableViewCell.self, for: indexPath) cell.selectionStyle = .none - cell.configure(items: items) - cell.onSelectItem = { entity in print("컬렉션 선택:", entity.id) } return cell case let .savedCollections(items): - let cell = tableView.dequeueReusableCell( - withIdentifier: MoreNoMoreCollectionTableViewCell.reuseIdentifier, - for: indexPath - ) as! MoreNoMoreCollectionTableViewCell + let cell = tableView.dequeueReusableCell(MoreNoMoreCollectionTableViewCell.self, for: indexPath) cell.selectionStyle = .none - cell.configure(items: items) - cell.onSelectItem = { entity in print("저장 컬렉션 선택:", entity.id) } return cell case let .savedContents(items): - let cell = tableView.dequeueReusableCell(withIdentifier: RecentSavedContentTableViewCell.reuseIdentifier, - for: indexPath) as! RecentSavedContentTableViewCell + let cell = tableView.dequeueReusableCell(RecentSavedContentTableViewCell.self, for: indexPath) cell.selectionStyle = .none cell.configure(items: items) cell.onTapItem = { [weak self] content in diff --git a/FLINT/Presentation/Sources/ViewController/Scene/Splash/SplashViewController.swift b/FLINT/Presentation/Sources/ViewController/Scene/Splash/SplashViewController.swift index 491eb0d4..d47f6743 100644 --- a/FLINT/Presentation/Sources/ViewController/Scene/Splash/SplashViewController.swift +++ b/FLINT/Presentation/Sources/ViewController/Scene/Splash/SplashViewController.swift @@ -5,13 +5,16 @@ // Created by 진소은 on 1/22/26. // - -import UIKit import Combine +import UIKit import View import ViewModel +public protocol SplashViewControllerFactory { + func makeSplashViewController() -> SplashViewController +} + public final class SplashViewController: BaseViewController { public init(viewControllerFactory: ViewControllerFactory) { diff --git a/FLINT/Presentation/Sources/ViewController/TabBar/TabBarViewController.swift b/FLINT/Presentation/Sources/ViewController/TabBar/TabBarViewController.swift index 37763eeb..48681779 100644 --- a/FLINT/Presentation/Sources/ViewController/TabBar/TabBarViewController.swift +++ b/FLINT/Presentation/Sources/ViewController/TabBar/TabBarViewController.swift @@ -12,6 +12,10 @@ import Then import View +public protocol TabBarViewControllerFactory { + func makeTabBarViewController() -> TabBarViewController +} + public class TabBarViewController: UIViewController { // MARK: - DI diff --git a/FLINT/Presentation/Sources/ViewModel/Extension/Publisher+.swift b/FLINT/Presentation/Sources/ViewModel/Extension/Publisher+Thread.swift similarity index 92% rename from FLINT/Presentation/Sources/ViewModel/Extension/Publisher+.swift rename to FLINT/Presentation/Sources/ViewModel/Extension/Publisher+Thread.swift index e61c0d85..babfed39 100644 --- a/FLINT/Presentation/Sources/ViewModel/Extension/Publisher+.swift +++ b/FLINT/Presentation/Sources/ViewModel/Extension/Publisher+Thread.swift @@ -1,5 +1,5 @@ // -// File.swift +// Publisher+Thread.swift // Presentation // // Created by 김호성 on 2026.01.20. diff --git a/FLINT/Presentation/Sources/ViewModel/Scene/CollectionDetail/CollectionDetailViewModel.swift b/FLINT/Presentation/Sources/ViewModel/Scene/CollectionDetail/CollectionDetailViewModel.swift index 684f5d20..fcd2833c 100644 --- a/FLINT/Presentation/Sources/ViewModel/Scene/CollectionDetail/CollectionDetailViewModel.swift +++ b/FLINT/Presentation/Sources/ViewModel/Scene/CollectionDetail/CollectionDetailViewModel.swift @@ -9,7 +9,6 @@ import Combine import Foundation import Domain -import Entity public final class CollectionDetailViewModel { @@ -51,8 +50,8 @@ public final class CollectionDetailViewModel { // MARK: - Dependency private let collectionId: Int64 - private let collectionDetailUseCase: CollectionDetailUseCase - private let fetchBookmarkedUserUseCase: FetchBookmarkedUserUseCase + private let fetchCollectionDetailUseCase: FetchCollectionDetailUseCase + private let fetchCollectionBookmarkUsersUseCase: FetchCollectionBookmarkUsersUseCase // MARK: - Private @@ -63,12 +62,12 @@ public final class CollectionDetailViewModel { public init( collectionId: Int64, - collectionDetailUseCase: CollectionDetailUseCase, - fetchBookmarkedUserUseCase: FetchBookmarkedUserUseCase + fetchCollectionDetailUseCase: FetchCollectionDetailUseCase, + fetchCollectionBookmarkUsersUseCase: FetchCollectionBookmarkUsersUseCase ) { self.collectionId = collectionId - self.collectionDetailUseCase = collectionDetailUseCase - self.fetchBookmarkedUserUseCase = fetchBookmarkedUserUseCase + self.fetchCollectionDetailUseCase = fetchCollectionDetailUseCase + self.fetchCollectionBookmarkUsersUseCase = fetchCollectionBookmarkUsersUseCase } // MARK: - Transform @@ -96,7 +95,7 @@ public final class CollectionDetailViewModel { private func fetch() { stateSubject.send(.loading) - collectionDetailUseCase.fetchCollectionDetail(collectionId: collectionId) + fetchCollectionDetailUseCase(collectionId: collectionId) .sink( receiveCompletion: { [weak self] completion in guard let self else { return } @@ -109,7 +108,7 @@ public final class CollectionDetailViewModel { self.stateSubject.send(.loaded(detail: detail, bookmarkedUsers: nil)) - self.fetchBookmarkedUserUseCase.execute(collectionId: self.collectionId) + self.fetchCollectionBookmarkUsersUseCase(collectionId: self.collectionId) .sink( receiveCompletion: { _ in }, receiveValue: { [weak self] users in diff --git a/FLINT/Presentation/Sources/ViewModel/Scene/CreateCollection/AddContentSelectViewModel.swift b/FLINT/Presentation/Sources/ViewModel/Scene/CreateCollection/AddContentSelectViewModel.swift index 1b18d5c4..e4229af7 100644 --- a/FLINT/Presentation/Sources/ViewModel/Scene/CreateCollection/AddContentSelectViewModel.swift +++ b/FLINT/Presentation/Sources/ViewModel/Scene/CreateCollection/AddContentSelectViewModel.swift @@ -26,7 +26,7 @@ public final class DefaultAddContentSelectViewModel: AddContentSelectViewModel { // MARK: - Dependency - private let contentsUseCase: ContentsUseCase + private let fetchPopularContentsUseCase: FetchPopularContentsUseCase private let searchContentsUseCase: SearchContentsUseCase // MARK: - Output @@ -42,10 +42,10 @@ public final class DefaultAddContentSelectViewModel: AddContentSelectViewModel { // MARK: - Init public init( - contentsUseCase: ContentsUseCase, + fetchPopularContentsUseCase: FetchPopularContentsUseCase, searchContentsUseCase: SearchContentsUseCase ) { - self.contentsUseCase = contentsUseCase + self.fetchPopularContentsUseCase = fetchPopularContentsUseCase self.searchContentsUseCase = searchContentsUseCase bind() } @@ -59,7 +59,7 @@ public final class DefaultAddContentSelectViewModel: AddContentSelectViewModel { public func fetchContents() { isSearching.send(false) - contentsUseCase.fetchContents() + fetchPopularContentsUseCase() .manageThread() .sinkHandledCompletion { [weak self] contents in self?.results.send(contents) @@ -89,7 +89,7 @@ public extension DefaultAddContentSelectViewModel { isSearching.send(true) - searchContentsUseCase.searchContents(keyword) + searchContentsUseCase(keyword: keyword) .manageThread() .sinkHandledCompletion { [weak self] contents in self?.results.send(contents) diff --git a/FLINT/Presentation/Sources/ViewModel/Scene/CreateCollection/CreateCollectionView/CreateCollectionViewModel.swift b/FLINT/Presentation/Sources/ViewModel/Scene/CreateCollection/CreateCollectionView/CreateCollectionViewModel.swift index cb2b2900..e1d5307a 100644 --- a/FLINT/Presentation/Sources/ViewModel/Scene/CreateCollection/CreateCollectionView/CreateCollectionViewModel.swift +++ b/FLINT/Presentation/Sources/ViewModel/Scene/CreateCollection/CreateCollectionView/CreateCollectionViewModel.swift @@ -73,9 +73,9 @@ public final class DefaultCreateCollectionViewModel: CreateCollectionViewModel { guard isDoneEnabled.value else { return } guard let entity = createEntity else { return } - createCollectionUseCase.createCollection(entity) + createCollectionUseCase(collectionInfo: entity) .manageThread() - .map { Result.success(()) } + .map { _ in Result.success(()) } .catch { Just(Result.failure($0)) } .sinkHandledCompletion { [weak self] result in switch result { diff --git a/FLINT/Presentation/Sources/ViewModel/Scene/Explore/ExploreViewModel.swift b/FLINT/Presentation/Sources/ViewModel/Scene/Explore/ExploreViewModel.swift index 1914ae00..cc1499be 100644 --- a/FLINT/Presentation/Sources/ViewModel/Scene/Explore/ExploreViewModel.swift +++ b/FLINT/Presentation/Sources/ViewModel/Scene/Explore/ExploreViewModel.swift @@ -1,5 +1,5 @@ // -// File.swift +// ExploreViewModel.swift // Presentation // // Created by 김호성 on 2026.01.22. @@ -17,23 +17,23 @@ public protocol ExploreViewModelInput { public protocol ExploreViewModelOutput { var index: CurrentValueSubject { get } var collections: CurrentValueSubject<[ExploreInfoEntity], Never> { get } - var cursor: UInt? { get set } + var cursor: CurrentValueSubject { get set } } public typealias ExploreViewModel = ExploreViewModelInput & ExploreViewModelOutput public final class DefaultExploreViewModel: ExploreViewModel { - private let exploreUseCase: ExploreUseCase + private let fetchExploreCollectionsUseCase: FetchExploreCollectionsUseCase public var index: CurrentValueSubject = .init(0) public var collections: CurrentValueSubject<[ExploreInfoEntity], Never> = .init([]) - public var cursor: UInt? + public var cursor: CurrentValueSubject = .init(nil) private var cancellables: Set = Set() - public init(exploreUseCase: ExploreUseCase) { - self.exploreUseCase = exploreUseCase + public init(fetchExploreCollectionsUseCase: FetchExploreCollectionsUseCase) { + self.fetchExploreCollectionsUseCase = fetchExploreCollectionsUseCase bind() fetchCollections() } @@ -44,8 +44,8 @@ public final class DefaultExploreViewModel: ExploreViewModel { private func bind() { index.sink { [weak self] index in - guard let self else { return } - if index > collections.value.count - 3 { + guard let self, let _ = cursor.value else { return } + if index > collections.value.count - 5 { fetchCollections() } } @@ -53,12 +53,12 @@ public final class DefaultExploreViewModel: ExploreViewModel { } private func fetchCollections() { - exploreUseCase.fetchExplore(cursor: cursor) + fetchExploreCollectionsUseCase(cursor: cursor.value) .manageThread() .sinkHandledCompletion { [weak self] collectionPagingEntity in guard let self else { return } collections.value.append(contentsOf: collectionPagingEntity.collections) - cursor = collectionPagingEntity.cursor + cursor.send(collectionPagingEntity.cursor) } .store(in: &cancellables) } diff --git a/FLINT/Presentation/Sources/ViewModel/Scene/Home/CollectionFolderListViewModel.swift b/FLINT/Presentation/Sources/ViewModel/Scene/Home/CollectionFolderListViewModel.swift index e743612c..3ec69eeb 100644 --- a/FLINT/Presentation/Sources/ViewModel/Scene/Home/CollectionFolderListViewModel.swift +++ b/FLINT/Presentation/Sources/ViewModel/Scene/Home/CollectionFolderListViewModel.swift @@ -17,15 +17,15 @@ public final class CollectionFolderListViewModel { @Published public private(set) var items: [CollectionEntity] = [] // MARK: - Dependency - private let fetchWatchingCollectionsUseCase: FetchWatchingCollectionsUseCase + private let fetchRecentViewedCollectionsUseCase: FetchRecentViewedCollectionsUseCase private var cancellables = Set() - public init(fetchWatchingCollectionsUseCase: FetchWatchingCollectionsUseCase) { - self.fetchWatchingCollectionsUseCase = fetchWatchingCollectionsUseCase + public init(fetchRecentViewedCollectionsUseCase: FetchRecentViewedCollectionsUseCase) { + self.fetchRecentViewedCollectionsUseCase = fetchRecentViewedCollectionsUseCase } public func load() { - fetchWatchingCollectionsUseCase.fetchWatchingCollections() + fetchRecentViewedCollectionsUseCase() .receive(on: DispatchQueue.main) .sink { completion in if case let .failure(error) = completion { @@ -50,10 +50,8 @@ public final class CollectionFolderListViewModel { description: old.description, imageList: old.imageList, bookmarkCount: old.bookmarkCount, - isBookmarked: isBookmarked, - userId: old.userId, - nickname: old.nickname, - profileImageUrl: old.profileImageUrl + isBookmarked: isBookmarked, + user: old.user ) } diff --git a/FLINT/Presentation/Sources/ViewModel/Scene/Home/HomeViewModel.swift b/FLINT/Presentation/Sources/ViewModel/Scene/Home/HomeViewModel.swift index 8030ac35..a4bb455e 100644 --- a/FLINT/Presentation/Sources/ViewModel/Scene/Home/HomeViewModel.swift +++ b/FLINT/Presentation/Sources/ViewModel/Scene/Home/HomeViewModel.swift @@ -5,21 +5,12 @@ // Created by 소은 on 2026.01.23. // -// -// HomeViewModel.swift -// Presentation -// -// Created by 소은 on 2026.01.23. -// - -import Foundation import Combine +import Foundation import Domain -import Entity public final class HomeViewModel { - // MARK: - Section / Row @@ -46,9 +37,10 @@ public final class HomeViewModel { // MARK: - Dependencies - private let homeUseCase: HomeUseCase - private let userProfileUseCase: UserProfileUseCase - private let fetchWatchingCollectionsUseCase: FetchWatchingCollectionsUseCase + private let fetchRecommendedCollectionsUseCase: FetchRecommendedCollectionsUseCase + private let fetchBookmarkedContentsUseCase: FetchBookmarkedContentsUseCase + private let fetchProfileUseCase: FetchProfileUseCase + private let fetchRecentViewedCollectionsUseCase: FetchRecentViewedCollectionsUseCase private var cancellables = Set() // MARK: - State @@ -61,14 +53,16 @@ public final class HomeViewModel { // MARK: - Init public init( - homeUseCase: HomeUseCase, - userProfileUseCase: UserProfileUseCase, - fetchWatchingCollectionsUseCase: FetchWatchingCollectionsUseCase, + fetchRecommendedCollectionsUseCase: FetchRecommendedCollectionsUseCase, + fetchBookmarkedContentsUseCase: FetchBookmarkedContentsUseCase, + fetchProfileUseCase: FetchProfileUseCase, + fetchRecentViewedCollectionsUseCase: FetchRecentViewedCollectionsUseCase, initialUserName: String = "얀비" ) { - self.homeUseCase = homeUseCase - self.userProfileUseCase = userProfileUseCase - self.fetchWatchingCollectionsUseCase = fetchWatchingCollectionsUseCase + self.fetchRecommendedCollectionsUseCase = fetchRecommendedCollectionsUseCase + self.fetchBookmarkedContentsUseCase = fetchBookmarkedContentsUseCase + self.fetchProfileUseCase = fetchProfileUseCase + self.fetchRecentViewedCollectionsUseCase = fetchRecentViewedCollectionsUseCase self.userName = initialUserName self.sections = makeSections() } @@ -77,8 +71,8 @@ public final class HomeViewModel { public func load() { - userProfileUseCase.fetchUserProfile(userId: 1) - .receive(on: DispatchQueue.main) + fetchProfileUseCase(for: .user(id: 1)) + .manageThread() .sink { completion in if case let .failure(error) = completion { print(" fetchUserProfile failed:", error) @@ -91,8 +85,8 @@ public final class HomeViewModel { .store(in: &cancellables) // 1) Fliner 추천 - homeUseCase.fetchRecommendedCollections() - .receive(on: DispatchQueue.main) + fetchRecommendedCollectionsUseCase() + .manageThread() .sink { completion in if case let .failure(error) = completion { print("fetchRecommendedCollections failed:", error) @@ -100,29 +94,15 @@ public final class HomeViewModel { } receiveValue: { [weak self] items in guard let self else { return } - self.flinerCollections = items.map { info in - CollectionEntity( - id: info.id ?? "", - thumbnailUrl: info.imageUrlString, - title: info.title, - description: "", - imageList: [], - bookmarkCount: 0, - isBookmarked: false, - userId: "", - nickname: info.userName, - profileImageUrl: info.profileImageUrlString - ) - - } + self.flinerCollections = items self.sections = self.makeSections() } .store(in: &cancellables) // 2) 최근 저장한 콘텐츠 - userProfileUseCase.fetchMyBookmarkedContents() - .receive(on: DispatchQueue.main) + fetchBookmarkedContentsUseCase(for: .me) + .manageThread() .sink { completion in if case let .failure(error) = completion { print("fetchMyBookmarkedContents failed:", error) @@ -134,8 +114,8 @@ public final class HomeViewModel { } .store(in: &cancellables) - fetchWatchingCollectionsUseCase.fetchWatchingCollections() - .receive(on: DispatchQueue.main) + fetchRecentViewedCollectionsUseCase() + .manageThread() .sink { completion in if case let .failure(error) = completion { print("fetchWatchingCollections failed:", error) @@ -146,8 +126,6 @@ public final class HomeViewModel { self.sections = self.makeSections() } .store(in: &cancellables) - - } // MARK: - Builder diff --git a/FLINT/Presentation/Sources/ViewModel/Scene/Login/LoginViewModel.swift b/FLINT/Presentation/Sources/ViewModel/Scene/Login/LoginViewModel.swift index a79baee5..f53f7cb0 100644 --- a/FLINT/Presentation/Sources/ViewModel/Scene/Login/LoginViewModel.swift +++ b/FLINT/Presentation/Sources/ViewModel/Scene/Login/LoginViewModel.swift @@ -18,7 +18,7 @@ public protocol LoginViewModelInput { } public protocol LoginViewModelOutput { - var socialVerifyResultEntity: CurrentValueSubject { get set } + var socialVerifyResultEntity: PassthroughSubject { get } } public typealias LoginViewModel = LoginViewModelInput & LoginViewModelOutput @@ -27,7 +27,7 @@ public final class DefaultLoginViewModel: LoginViewModel { private let socialVerifyUseCase: SocialVerifyUseCase - public var socialVerifyResultEntity: CurrentValueSubject = .init(nil) + public var socialVerifyResultEntity: PassthroughSubject = .init() private var cancellables: Set = Set() @@ -46,8 +46,8 @@ public final class DefaultLoginViewModel: LoginViewModel { return } if let accessToken = oauthToken?.accessToken { - socialVerifyUseCase.socialVerify( - socialVerifyEntity: SocialVerifyEntity( + socialVerifyUseCase( + socialAuthCredential: SocialVerifyEntity( provider: .kakao, accessToken: accessToken ) diff --git a/FLINT/Presentation/Sources/ViewModel/Scene/Onboarding/OnboardingViewModel.swift b/FLINT/Presentation/Sources/ViewModel/Scene/Onboarding/OnboardingViewModel.swift index 9c01d294..a7f83055 100644 --- a/FLINT/Presentation/Sources/ViewModel/Scene/Onboarding/OnboardingViewModel.swift +++ b/FLINT/Presentation/Sources/ViewModel/Scene/Onboarding/OnboardingViewModel.swift @@ -1,5 +1,5 @@ // -// File.swift +// OnboardingViewModel.swift // Presentation // // Created by 김호성 on 2026.01.20. @@ -14,11 +14,11 @@ public protocol OnboardingViewModelInput { // nickname func checkNickname(_ nickname: String) - // film select - func fetchContents() + // content select + func fetchPopularContents() func searchContents(_ keyword: String) func clickContent(_ content: ContentEntity) - func deleteContent(_ content: ContentEntity) + func deleteContent(_ content: ContentEntity) // ott select func clickOtt(_ ott: Ott) @@ -32,8 +32,8 @@ public protocol OnboardingViewModelOutput { var nickname: CurrentValueSubject { get } var nicknameValidState: CurrentValueSubject { get } - // film select - var filmSelectQuestions: [String] { get set } + // content select + var contentSelectQuestions: [String] { get set } var contents: CurrentValueSubject<[ContentEntity], Never> { get set } var selectedContents: CurrentValueSubject<[ContentEntity], Never> { get set } @@ -46,15 +46,15 @@ public typealias OnboardingViewModel = OnboardingViewModelInput & OnboardingView public final class DefaultOnboardingViewModel: OnboardingViewModel { - private let nicknameUseCase: NicknameUseCase - private let contentsUseCase: ContentsUseCase + private let checkNicknameUseCase: CheckNicknameUseCase + private let fetchPopularContentsUseCase: FetchPopularContentsUseCase private let searchContentsUseCase: SearchContentsUseCase private let signupUseCase: SignupUseCase public var nickname: CurrentValueSubject = .init("") public var nicknameValidState: CurrentValueSubject = .init(nil) - public var filmSelectQuestions: [String] = [ + public var contentSelectQuestions: [String] = [ "이번 달, 가장 재미있었던 작품은 무엇인가요?", "여러번 정주행 했던 작품은 무엇인가요?", "좋아하는 인물이 등장하는 작품은 무엇인가요?", @@ -72,13 +72,13 @@ public final class DefaultOnboardingViewModel: OnboardingViewModel { private var cancellables: Set = Set() public init( - nicknameUseCase: NicknameUseCase, - contentsUseCase: ContentsUseCase, + checkNicknameUseCase: CheckNicknameUseCase, + fetchPopularContentsUseCase: FetchPopularContentsUseCase, searchContentsUseCase: SearchContentsUseCase, - signupUseCase: SignupUseCase + signupUseCase: SignupUseCase, ) { - self.nicknameUseCase = nicknameUseCase - self.contentsUseCase = contentsUseCase + self.checkNicknameUseCase = checkNicknameUseCase + self.fetchPopularContentsUseCase = fetchPopularContentsUseCase self.searchContentsUseCase = searchContentsUseCase self.signupUseCase = signupUseCase } @@ -88,7 +88,7 @@ public final class DefaultOnboardingViewModel: OnboardingViewModel { nicknameValidState.send(.invalid) return } - nicknameUseCase.checkNickname(nickname) + checkNicknameUseCase(nickname) .manageThread() .sinkHandledCompletion(receiveValue: { [weak self] isValidNickname in self?.nicknameValidState.send(isValidNickname ? .valid : .duplicate) @@ -99,8 +99,8 @@ public final class DefaultOnboardingViewModel: OnboardingViewModel { .store(in: &cancellables) } - public func fetchContents() { - contentsUseCase.fetchContents() + public func fetchPopularContents() { + fetchPopularContentsUseCase() .manageThread() .sinkHandledCompletion { [weak self] contents in self?.contents.send(contents) @@ -109,7 +109,7 @@ public final class DefaultOnboardingViewModel: OnboardingViewModel { } public func searchContents(_ keyword: String) { - searchContentsUseCase.searchContents(keyword) + searchContentsUseCase(keyword: keyword) .manageThread() .sinkHandledCompletion { [weak self] contents in self?.contents.send(contents) @@ -140,8 +140,8 @@ public final class DefaultOnboardingViewModel: OnboardingViewModel { } public func signup() { - signupUseCase.signup( - SignupInfoEntity( + signupUseCase( + userInfo: SignupInfoEntity( nickname: nickname.value, favoriteContentIds: selectedContents.value.compactMap({ content in Int(content.id) diff --git a/FLINT/Presentation/Sources/ViewModel/Scene/Profile/ProfileViewModel.swift b/FLINT/Presentation/Sources/ViewModel/Scene/Profile/ProfileViewModel.swift index d5abb388..c30ee27d 100644 --- a/FLINT/Presentation/Sources/ViewModel/Scene/Profile/ProfileViewModel.swift +++ b/FLINT/Presentation/Sources/ViewModel/Scene/Profile/ProfileViewModel.swift @@ -5,23 +5,30 @@ // Created by 진소은 on 1/22/26. // -import Foundation import Combine +import Foundation import Domain -import Entity +//public protocol ProfileViewModelInput { +// +//} + +//public protocol ProfileViewModelOutput { +// var userProfileEntity: CurrentValueSubject { get set } +//} + +//public typealias ProfileViewModel = ProfileViewModelInput & ProfileViewModelOutput + +//public final class DefaultProfileViewModel: ProfileViewModel { public final class ProfileViewModel { +// public var userProfileEntity: CurrentValueSubject - public enum Target: Equatable { - case me - case user(userId: String) - } - private let target: Target + private let target: UserTarget public enum Row { - case profileHeader(nickname: String, profileImageUrl: String, isFliner: Bool) + case profileHeader(nickname: String, profileImageUrl: URL?, isFliner: Bool) case titleHeader(style: TitleHeaderStyle, title: String, subtitle: String) case preferenceChips(keywords: [KeywordEntity]) case myCollections(items: [CollectionEntity]) @@ -38,13 +45,17 @@ public final class ProfileViewModel { @Published public private(set) var rows: [Row] = [] // MARK: - Dependencies - private let userProfileUseCase: UserProfileUseCase + private let fetchProfileUseCase: FetchProfileUseCase + private let fetchKeywordsUseCase: FetchKeywordsUseCase + private let fetchCreatedCollectionsUseCase: FetchCreatedCollectionsUseCase + private let fetchBookmarkedCollectionsUseCase: FetchBookmarkedCollectionsUseCase + private let fetchBookmarkedContentsUseCase: FetchBookmarkedContentsUseCase private var cancellables = Set() // MARK: - State private var nickname: String private var isFliner: Bool - private var profileImageUrl: String? + private var profileImageUrl: URL? private var keywords: [KeywordEntity] = [] private var myCollections: [CollectionEntity] = [] @@ -52,169 +63,94 @@ public final class ProfileViewModel { private var savedContents: [ContentInfoEntity] = [] public init( - target: Target = .me, - userProfileUseCase: UserProfileUseCase, + target: UserTarget, + fetchProfileUseCase: FetchProfileUseCase, + fetchKeywordsUseCase: FetchKeywordsUseCase, + fetchCreatedCollectionsUseCase: FetchCreatedCollectionsUseCase, + fetchBookmarkedCollectionsUseCase: FetchBookmarkedCollectionsUseCase, + fetchBookmarkedContentsUseCase: FetchBookmarkedContentsUseCase, initialNickname: String = "플링", initialIsFliner: Bool = true ) { self.target = target - self.userProfileUseCase = userProfileUseCase + self.fetchProfileUseCase = fetchProfileUseCase + self.fetchKeywordsUseCase = fetchKeywordsUseCase + self.fetchCreatedCollectionsUseCase = fetchCreatedCollectionsUseCase + self.fetchBookmarkedCollectionsUseCase = fetchBookmarkedCollectionsUseCase + self.fetchBookmarkedContentsUseCase = fetchBookmarkedContentsUseCase self.nickname = initialNickname self.isFliner = initialIsFliner - self.profileImageUrl = "" self.rows = makeRows() } // MARK: - Input public func load() { - switch target { - case .me: - userProfileUseCase.fetchMyProfile() - .receive(on: DispatchQueue.main) - .sink { completion in - if case let .failure(error) = completion { - print("❌ fetchProfile failed:", error) - } - } receiveValue: { [weak self] profile in - guard let self else { return } - self.nickname = profile.nickname - self.isFliner = profile.isFliner - self.profileImageUrl = profile.profileImageUrl - self.rows = self.makeRows() - } - .store(in: &cancellables) - userProfileUseCase.fetchMyKeywords() - .receive(on: DispatchQueue.main) - .sink { completion in - if case let .failure(error) = completion { - print("❌ fetchKeywords failed:", error) - } - } receiveValue: { [weak self] keywords in - guard let self else { return } - self.keywords = keywords - self.rows = self.makeRows() - } - .store(in: &cancellables) - - userProfileUseCase.fetchMyCollections() - .receive(on: DispatchQueue.main) - .sink { completion in - if case let .failure(error) = completion { - print("❌ fetchMyCollections failed:", error) - } - } receiveValue: { [weak self] items in - guard let self else { return } - self.myCollections = items - self.rows = self.makeRows() - } - .store(in: &cancellables) - - userProfileUseCase.fetchMyBookmarkedCollections() - .receive(on: DispatchQueue.main) - .sink { completion in - if case let .failure(error) = completion { - print("❌ fetchSavedCollections failed:", error) - } - } receiveValue: { [weak self] items in - print("asdf", items.count) - guard let self else { return } - self.savedCollections = items - self.rows = self.makeRows() - } - .store(in: &cancellables) - - userProfileUseCase.fetchMyBookmarkedContents() - .receive(on: DispatchQueue.main) - .sink { completion in - if case let .failure(error) = completion { - print("❌ fetchSavedContents failed:", error) - } - } receiveValue: { [weak self] items in - guard let self else { return } - self.savedContents = items - self.rows = self.makeRows() + fetchProfileUseCase(for: target) + .manageThread() + .sinkHandledCompletion(receiveValue: { [weak self] userProfileEntity in + guard let self else { return } + nickname = userProfileEntity.nickname + isFliner = userProfileEntity.role == .fliner + profileImageUrl = userProfileEntity.profileImageUrl + rows = makeRows() + }) + .store(in: &cancellables) + + fetchKeywordsUseCase(for: target) + .manageThread() + .sink { completion in + if case let .failure(error) = completion { + print("❌ fetchKeywords failed:", error) } - .store(in: &cancellables) - - - - case .user(let userIdString): - guard let userId = Int64(userIdString) else { - print("❌ invalid userId:", userIdString) - return + } receiveValue: { [weak self] keywords in + guard let self else { return } + self.keywords = keywords + self.rows = self.makeRows() } - userProfileUseCase.fetchUserProfile(userId: userId) - .receive(on: DispatchQueue.main) - .sink { completion in - if case let .failure(error) = completion { - print("❌ fetchProfile failed:", error) - } - } receiveValue: { [weak self] profile in - guard let self else { return } - self.nickname = profile.nickname - self.isFliner = profile.isFliner - self.profileImageUrl = profile.profileImageUrl - self.rows = self.makeRows() - } - .store(in: &cancellables) - userProfileUseCase.fetchUserKeywords(userId: Int64(userId)) - .receive(on: DispatchQueue.main) - .sink { completion in - if case let .failure(error) = completion { - print("❌ fetchKeywords failed:", error) - } - } receiveValue: { [weak self] keywords in - guard let self else { return } - self.keywords = keywords - self.rows = self.makeRows() - } - .store(in: &cancellables) - - userProfileUseCase.fetchUserCollections(userId: userId) - .receive(on: DispatchQueue.main) - .sink { completion in - if case let .failure(error) = completion { - print("❌ fetchMyCollections failed:", error) - } - } receiveValue: { [weak self] items in - guard let self else { return } - self.myCollections = items - self.rows = self.makeRows() + .store(in: &cancellables) + + fetchCreatedCollectionsUseCase(for: target) + .manageThread() + .sink { completion in + if case let .failure(error) = completion { + print("❌ fetchMyCollections failed:", error) } - .store(in: &cancellables) - - userProfileUseCase.fetchBookmarkedCollections(userId: userId) - .receive(on: DispatchQueue.main) - .sink { completion in - if case let .failure(error) = completion { - print("❌ fetchSavedCollections failed:", error) - } - } receiveValue: { [weak self] items in - print("asdf", items.count) - guard let self else { return } - self.savedCollections = items - self.rows = self.makeRows() + } receiveValue: { [weak self] items in + guard let self else { return } + self.myCollections = items + self.rows = self.makeRows() + } + .store(in: &cancellables) + + fetchBookmarkedCollectionsUseCase(for: target) + .manageThread() + .sink { completion in + if case let .failure(error) = completion { + print("❌ fetchSavedCollections failed:", error) } - .store(in: &cancellables) - - userProfileUseCase.fetchBookmarkedContents(userId: userId) - .receive(on: DispatchQueue.main) - .sink { completion in - if case let .failure(error) = completion { - print("❌ fetchSavedContents failed:", error) - } - } receiveValue: { [weak self] items in - guard let self else { return } - self.savedContents = items - self.rows = self.makeRows() + } receiveValue: { [weak self] items in + print("asdf", items.count) + guard let self else { return } + self.savedCollections = items + self.rows = self.makeRows() + } + .store(in: &cancellables) + + fetchBookmarkedContentsUseCase(for: target) + .manageThread() + .sink { completion in + if case let .failure(error) = completion { + print("❌ fetchSavedContents failed:", error) } - .store(in: &cancellables) - } + } receiveValue: { [weak self] items in + guard let self else { return } + self.savedContents = items + self.rows = self.makeRows() + } + .store(in: &cancellables) } - // - // MARK: - Row builder private func makeRows() -> [Row] { var result: [Row] = [] @@ -223,7 +159,7 @@ public final class ProfileViewModel { result.append( .profileHeader( nickname: nickname, - profileImageUrl: profileImageUrl ?? "", + profileImageUrl: profileImageUrl, isFliner: isFliner ) ) diff --git a/FLINT/Presentation/Sources/ViewModel/Scene/Splash/SplashViewModel.swift b/FLINT/Presentation/Sources/ViewModel/Scene/Splash/SplashViewModel.swift deleted file mode 100644 index 3492ccd7..00000000 --- a/FLINT/Presentation/Sources/ViewModel/Scene/Splash/SplashViewModel.swift +++ /dev/null @@ -1,50 +0,0 @@ -// -// SplashViewModel.swift -// Presentation -// -// Created by 진소은 on 1/22/26. -// - - -import Combine - -public final class SplashViewModel: BaseViewModelType { - - public struct Input { - public let viewDidAppear: AnyPublisher - public let lottieFinished: AnyPublisher - - public init( - viewDidAppear: AnyPublisher, - lottieFinished: AnyPublisher - ) { - self.viewDidAppear = viewDidAppear - self.lottieFinished = lottieFinished - } - } - - public struct Output { - /// SplashViewController가 이 이벤트 받으면 rootView.play() 호출 - public let playLottie: AnyPublisher - - /// SplashViewController / Coordinator가 이 이벤트 받으면 Login으로 전환 - public let routeToLogin: AnyPublisher - } - - public init() {} - - public func transform(input: Input) -> Output { - let playLottie = input.viewDidAppear - .prefix(1) - .eraseToAnyPublisher() - - let routeToLogin = input.lottieFinished - .prefix(1) - .eraseToAnyPublisher() - - return Output( - playLottie: playLottie, - routeToLogin: routeToLogin - ) - } -}