diff --git a/FLINT/Data/Sources/DTO/Collection/ToggleBookmarkResponseDTO.swift b/FLINT/Data/Sources/DTO/Collection/ToggleBookmarkResponseDTO.swift new file mode 100644 index 0000000..9d1526f --- /dev/null +++ b/FLINT/Data/Sources/DTO/Collection/ToggleBookmarkResponseDTO.swift @@ -0,0 +1,21 @@ +// +// ToggleBookmarkResponseDTO.swift +// Data +// +// Created by 소은 on 4/22/26. +// + + +import Foundation + +import Entity + +public struct ToggleBookmarkResponseDTO: Codable { + public let data: Bool? +} + +extension ToggleBookmarkResponseDTO { + public var entity: Bool { + return data ?? false + } +} diff --git a/FLINT/FLINT/Application/SceneDelegate.swift b/FLINT/FLINT/Application/SceneDelegate.swift index 05284ea..cd29ebd 100644 --- a/FLINT/FLINT/Application/SceneDelegate.swift +++ b/FLINT/FLINT/Application/SceneDelegate.swift @@ -23,8 +23,9 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { window = UIWindow(windowScene: windowScene) // let viewController = diContainer.makeSplashViewController() - let viewController = diContainer.makeNicknameViewController() -// let viewController = diContainer.makeTabBarViewController() +// let viewController = diContainer.makeNicknameViewController() + let viewController = diContainer.makeTabBarViewController() + let navigationController = UINavigationController(rootViewController: viewController).configured({ $0.navigationBar.isHidden = true }) diff --git a/FLINT/FLINT/Dependency/Factory/ViewModel/CollectionFolderListViewModelFactory.swift b/FLINT/FLINT/Dependency/Factory/ViewModel/CollectionFolderListViewModelFactory.swift index 36d3792..7e263db 100644 --- a/FLINT/FLINT/Dependency/Factory/ViewModel/CollectionFolderListViewModelFactory.swift +++ b/FLINT/FLINT/Dependency/Factory/ViewModel/CollectionFolderListViewModelFactory.swift @@ -9,12 +9,17 @@ import Foundation import Presentation -protocol CollectionFolderListViewModelFactory: FetchRecentViewedCollectionsUseCaseFactory { +protocol CollectionFolderListViewModelFactory: + FetchRecentViewedCollectionsUseCaseFactory & + ToggleCollectionBookmarkUseCaseFactory { func makeCollectionFolderListViewModel() -> CollectionFolderListViewModel } extension CollectionFolderListViewModelFactory { func makeCollectionFolderListViewModel() -> CollectionFolderListViewModel { - return CollectionFolderListViewModel(fetchRecentViewedCollectionsUseCase: makeFetchRecentViewedCollectionsUseCase()) + return CollectionFolderListViewModel( + fetchRecentViewedCollectionsUseCase: makeFetchRecentViewedCollectionsUseCase(), + toggleCollectionBookmarkUseCase: makeToggleCollectionBookmarkUseCase() + ) } } diff --git a/FLINT/Presentation/Sources/ViewController/Scene/CollectionFolder/CollectionFolderListViewController.swift b/FLINT/Presentation/Sources/ViewController/Scene/CollectionFolder/CollectionFolderListViewController.swift index 16d68ae..dcee74f 100644 --- a/FLINT/Presentation/Sources/ViewController/Scene/CollectionFolder/CollectionFolderListViewController.swift +++ b/FLINT/Presentation/Sources/ViewController/Scene/CollectionFolder/CollectionFolderListViewController.swift @@ -110,7 +110,6 @@ extension CollectionFolderListViewController: UICollectionViewDataSource { let entity = viewModel.items[indexPath.item] let firstURL = entity.imageList.first ?? entity.thumbnailUrl - let secondString = entity.imageList.count > 1 ? entity.imageList[1] : nil let secondURL = entity.imageList[safe: 1] let profileURL = entity.user.profileImageUrl @@ -220,98 +219,3 @@ extension CollectionFolderListViewController: UICollectionViewDelegateFlowLayout ) -> CGFloat { 24 } } -// MARK: - FolderItem (화면 전용 더미 모델) - -private extension CollectionFolderListViewController { - - struct FolderItem { - let firstPosterImage: UIImage? - let secondPosterImage: UIImage? - - let profileImage: UIImage? - let name: String - - let title: String - let description: String - - var isBookmarked: Bool - let bookmarkedCountText: String? - - static func mock() -> [FolderItem] { - return [ - .init( - firstPosterImage: nil, - secondPosterImage: nil, - profileImage: DesignSystem.Image.Common.profileBlue, - name: "닉네임", - title: "한번 보면 못 빠져나오는 사랑이야기", - description: "이 컬렉션은 세계최고 너무나도 멋진 컬렉션입니다", - isBookmarked: true, - bookmarkedCountText: "123" - ), - .init( - firstPosterImage: nil, - secondPosterImage: nil, - profileImage: DesignSystem.Image.Common.profileBlue, - name: "닉네임", - title: "한번 보면 못 빠져나오는 사랑이야기", - description: "이 컬렉션은 세계최고 너무나도 멋진 컬렉션입니다", - isBookmarked: true, - bookmarkedCountText: "123" - ), - .init( - firstPosterImage: nil, - secondPosterImage: nil, - profileImage: DesignSystem.Image.Common.profileBlue, - name: "닉네임", - title: "한번 보면 못 빠져나오는 사랑이야기", - description: "이 컬렉션은 세계최고 너무나도 멋진 컬렉션입니다", - isBookmarked: false, - bookmarkedCountText: "123" - ), - .init( - firstPosterImage: nil, - secondPosterImage: nil, - profileImage: nil, - name: "닉네임", - title: "한번 보면 못 빠져나오는 사랑이야기", - description: "이 컬렉션은 세계최고 너무나도 멋진 컬렉션입니다", - isBookmarked: true, - bookmarkedCountText: "123" - ), - .init( - firstPosterImage: nil, - secondPosterImage: nil, - profileImage: nil, - name: "닉네임", - title: "한번 보면 못 빠져나오는 사랑이야기", - description: "이 컬렉션은 세계최고 너무나도 멋진 컬렉션입니다", - isBookmarked: false, - bookmarkedCountText: "123" - ), - .init( - firstPosterImage: nil, - secondPosterImage: nil, - profileImage: nil, - name: "닉네임", - title: "한번 보면 못 빠져나오는 사랑이야기", - description: "이 컬렉션은 세계최고 너무나도 멋진 컬렉션입니다", - isBookmarked: true, - bookmarkedCountText: "123" - ), - .init( - firstPosterImage: nil, - secondPosterImage: nil, - profileImage: nil, - name: "닉네임", - title: "한번 보면 못 빠져나오는 사랑이야기", - description: "이 컬렉션은 세계최고 너무나도 멋진 컬렉션입니다", - isBookmarked: true, - bookmarkedCountText: "123" - ) - - ] - } - } -} - diff --git a/FLINT/Presentation/Sources/ViewModel/Scene/Home/CollectionFolderListViewModel.swift b/FLINT/Presentation/Sources/ViewModel/Scene/Home/CollectionFolderListViewModel.swift index 3ec69ee..286ba57 100644 --- a/FLINT/Presentation/Sources/ViewModel/Scene/Home/CollectionFolderListViewModel.swift +++ b/FLINT/Presentation/Sources/ViewModel/Scene/Home/CollectionFolderListViewModel.swift @@ -18,10 +18,15 @@ public final class CollectionFolderListViewModel { // MARK: - Dependency private let fetchRecentViewedCollectionsUseCase: FetchRecentViewedCollectionsUseCase + private let toggleCollectionBookmarkUseCase: ToggleCollectionBookmarkUseCase private var cancellables = Set() - public init(fetchRecentViewedCollectionsUseCase: FetchRecentViewedCollectionsUseCase) { + public init( + fetchRecentViewedCollectionsUseCase: FetchRecentViewedCollectionsUseCase, + toggleCollectionBookmarkUseCase: ToggleCollectionBookmarkUseCase + ) { self.fetchRecentViewedCollectionsUseCase = fetchRecentViewedCollectionsUseCase + self.toggleCollectionBookmarkUseCase = toggleCollectionBookmarkUseCase } public func load() { @@ -39,9 +44,13 @@ public final class CollectionFolderListViewModel { } public func updateBookmark(at index: Int, isBookmarked: Bool) { + guard items.indices.contains(index) else { return } let old = items[index] + + let collectionId = old.id + guard let collectionIdInt = Int64(collectionId) else { return } items[index] = CollectionEntity( id: old.id, @@ -49,10 +58,21 @@ public final class CollectionFolderListViewModel { title: old.title, description: old.description, imageList: old.imageList, - bookmarkCount: old.bookmarkCount, + bookmarkCount: isBookmarked ? old.bookmarkCount + 1 : max(old.bookmarkCount - 1, 0), isBookmarked: isBookmarked, user: old.user ) + + toggleCollectionBookmarkUseCase(collectionId: collectionIdInt) + .receive(on: DispatchQueue.main) + .sink { completion in + if case let .failure(error) = completion { + print("❌ toggleBookmark failed:", error) + } + } receiveValue: { isBookmarked in + print("✅ toggleBookmark success:", isBookmarked) + } + .store(in: &cancellables) } }