From 46dd809bae45b12f5c2ea9cef6ab45ffca7cc472 Mon Sep 17 00:00:00 2001 From: duthd3 Date: Wed, 19 Nov 2025 21:55:56 +0900 Subject: [PATCH 1/2] feat/#269-BookmarkAPI --- .../CollectionListResponseDTO.swift | 12 +++++++ .../Endpoints/CollectionEndPoint.swift | 13 +++++++ .../CollectionAPIRepositoryImpl.swift | 35 +++++++++++++++++++ .../CreateCollectionListUseCaseImpl.swift | 15 ++++++++ .../FetchCollectionListUseCaseImpl.swift | 15 ++++++++ .../Collection/CollectionListResponse.swift | 13 +++++++ .../Repository/CollectionAPIRepository.swift | 10 ++++++ .../CreateCollectionListUseCase.swift | 5 +++ .../FetchCollectionListUseCase.swift | 5 +++ MLS/MLS/Application/AppDelegate.swift | 12 ++++++- .../AddCollection/AddCollectionReactor.swift | 9 +++-- .../CollectionList/CollectionListCell.swift | 33 ++++++++++++++--- .../CollectionListFactoryImpl.swift | 9 +++-- .../CollectionListReactor.swift | 27 +++++++++++--- .../CollectionListViewController.swift | 24 +++++++++---- .../Components/CollectionList.swift | 2 ++ .../DictionaryListViewController.swift | 1 + 17 files changed, 220 insertions(+), 20 deletions(-) create mode 100644 MLS/Data/Data/Network/DTO/CollectionDTO/CollectionListResponseDTO.swift create mode 100644 MLS/Data/Data/Network/Endpoints/CollectionEndPoint.swift create mode 100644 MLS/Data/Data/Repository/CollectionAPIRepositoryImpl.swift create mode 100644 MLS/Domain/Domain/UseCaseImpl/Collection/CreateCollectionListUseCaseImpl.swift create mode 100644 MLS/Domain/Domain/UseCaseImpl/Collection/FetchCollectionListUseCaseImpl.swift create mode 100644 MLS/Domain/DomainInterface/Entity/Collection/CollectionListResponse.swift create mode 100644 MLS/Domain/DomainInterface/Repository/CollectionAPIRepository.swift create mode 100644 MLS/Domain/DomainInterface/UseCase/Collection/CreateCollectionListUseCase.swift create mode 100644 MLS/Domain/DomainInterface/UseCase/Collection/FetchCollectionListUseCase.swift diff --git a/MLS/Data/Data/Network/DTO/CollectionDTO/CollectionListResponseDTO.swift b/MLS/Data/Data/Network/DTO/CollectionDTO/CollectionListResponseDTO.swift new file mode 100644 index 00000000..3c2e79eb --- /dev/null +++ b/MLS/Data/Data/Network/DTO/CollectionDTO/CollectionListResponseDTO.swift @@ -0,0 +1,12 @@ +import DomainInterface + +public struct CollectionListResponseDTO: Decodable { + public let collectionId: Int + public let name: String + public let createdAt: [Int] + public let recentBookmarks: [BookmarkDTO] + + public func toDomain() -> CollectionListResponse { + return CollectionListResponse(collectionId: collectionId, name: name, createdAt: createdAt, recentBookmarks: recentBookmarks.toDomain()) + } +} diff --git a/MLS/Data/Data/Network/Endpoints/CollectionEndPoint.swift b/MLS/Data/Data/Network/Endpoints/CollectionEndPoint.swift new file mode 100644 index 00000000..82d8d3e0 --- /dev/null +++ b/MLS/Data/Data/Network/Endpoints/CollectionEndPoint.swift @@ -0,0 +1,13 @@ +import DomainInterface + +public enum CollectionEndPoint { + static let base = "https://api.mapleland.kro.kr" + + public static func fetchCollectionList() -> ResponsableEndPoint<[CollectionListResponseDTO]> { + .init(baseURL: base, path: "/api/v1/collections", method: .GET) + } + + public static func createCollectionList(body: Encodable) -> EndPoint { + .init(baseURL: base, path: "/api/v1/collections", method: .POST, body: body) + } +} diff --git a/MLS/Data/Data/Repository/CollectionAPIRepositoryImpl.swift b/MLS/Data/Data/Repository/CollectionAPIRepositoryImpl.swift new file mode 100644 index 00000000..d6fa65a1 --- /dev/null +++ b/MLS/Data/Data/Repository/CollectionAPIRepositoryImpl.swift @@ -0,0 +1,35 @@ +import Foundation + +import DomainInterface + +import RxSwift + +public class CollectionAPIRepositoryImpl: CollectionAPIRepository { + private let provider: NetworkProvider + private let tokenInterceptor: Interceptor + + public init(provider: NetworkProvider, tokenInterceptor: Interceptor) { + self.provider = provider + self.tokenInterceptor = tokenInterceptor + } + + public func fetchCollectionList() -> Observable<[CollectionListResponse]> { + let endPoint = CollectionEndPoint.fetchCollectionList() + return provider.requestData(endPoint: endPoint, interceptor: tokenInterceptor).map { + $0.map {$0.toDomain()} + } + } + + public func createCollectionList(name: String) -> Completable { + let endPoint = CollectionEndPoint.createCollectionList(body: CreateCollectionRequestDTO(name: name)) + return provider.requestData(endPoint: endPoint, interceptor: tokenInterceptor) + + } +} + +private extension CollectionAPIRepositoryImpl { + struct CreateCollectionRequestDTO: Encodable { + let name: String + } + +} diff --git a/MLS/Domain/Domain/UseCaseImpl/Collection/CreateCollectionListUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/Collection/CreateCollectionListUseCaseImpl.swift new file mode 100644 index 00000000..16345da9 --- /dev/null +++ b/MLS/Domain/Domain/UseCaseImpl/Collection/CreateCollectionListUseCaseImpl.swift @@ -0,0 +1,15 @@ +import DomainInterface + +import RxSwift + +public final class CreateCollectionListUseCaseImpl: CreateCollectionListUseCase { + private let repository: CollectionAPIRepository + + public init(repository: CollectionAPIRepository) { + self.repository = repository + } + + public func execute(name: String) -> Completable { + return repository.createCollectionList(name: name) + } +} diff --git a/MLS/Domain/Domain/UseCaseImpl/Collection/FetchCollectionListUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/Collection/FetchCollectionListUseCaseImpl.swift new file mode 100644 index 00000000..3daeda96 --- /dev/null +++ b/MLS/Domain/Domain/UseCaseImpl/Collection/FetchCollectionListUseCaseImpl.swift @@ -0,0 +1,15 @@ +import DomainInterface + +import RxSwift + +public final class FetchCollectionListUseCaseImpl: FetchCollectionListUseCase { + private let repository: CollectionAPIRepository + + public init(repository: CollectionAPIRepository) { + self.repository = repository + } + + public func execute() -> Observable<[CollectionListResponse]> { + return repository.fetchCollectionList() + } +} diff --git a/MLS/Domain/DomainInterface/Entity/Collection/CollectionListResponse.swift b/MLS/Domain/DomainInterface/Entity/Collection/CollectionListResponse.swift new file mode 100644 index 00000000..696cc7a8 --- /dev/null +++ b/MLS/Domain/DomainInterface/Entity/Collection/CollectionListResponse.swift @@ -0,0 +1,13 @@ +public struct CollectionListResponse { + public let collectionId: Int + public let name: String + public let createdAt: [Int] + public let recentBookmarks: [BookmarkResponse] + + public init(collectionId: Int, name: String, createdAt: [Int], recentBookmarks: [BookmarkResponse]) { + self.collectionId = collectionId + self.name = name + self.createdAt = createdAt + self.recentBookmarks = recentBookmarks + } +} diff --git a/MLS/Domain/DomainInterface/Repository/CollectionAPIRepository.swift b/MLS/Domain/DomainInterface/Repository/CollectionAPIRepository.swift new file mode 100644 index 00000000..b074294b --- /dev/null +++ b/MLS/Domain/DomainInterface/Repository/CollectionAPIRepository.swift @@ -0,0 +1,10 @@ +import Foundation + +import RxSwift + +public protocol CollectionAPIRepository { + // 컬렉션 목록 조회 + func fetchCollectionList() -> Observable<[CollectionListResponse]> + // 컬렉션 목록 추가 + func createCollectionList(name: String) -> Completable +} diff --git a/MLS/Domain/DomainInterface/UseCase/Collection/CreateCollectionListUseCase.swift b/MLS/Domain/DomainInterface/UseCase/Collection/CreateCollectionListUseCase.swift new file mode 100644 index 00000000..1e2adbf8 --- /dev/null +++ b/MLS/Domain/DomainInterface/UseCase/Collection/CreateCollectionListUseCase.swift @@ -0,0 +1,5 @@ +import RxSwift + +public protocol CreateCollectionListUseCase { + func execute(name: String) -> Completable +} diff --git a/MLS/Domain/DomainInterface/UseCase/Collection/FetchCollectionListUseCase.swift b/MLS/Domain/DomainInterface/UseCase/Collection/FetchCollectionListUseCase.swift new file mode 100644 index 00000000..008f07d1 --- /dev/null +++ b/MLS/Domain/DomainInterface/UseCase/Collection/FetchCollectionListUseCase.swift @@ -0,0 +1,5 @@ +import RxSwift + +public protocol FetchCollectionListUseCase { + func execute() -> Observable<[CollectionListResponse]> +} diff --git a/MLS/MLS/Application/AppDelegate.swift b/MLS/MLS/Application/AppDelegate.swift index bfeb98e4..cd4b57ca 100644 --- a/MLS/MLS/Application/AppDelegate.swift +++ b/MLS/MLS/Application/AppDelegate.swift @@ -137,6 +137,10 @@ private extension AppDelegate { DIContainer.register(type: AlarmAPIRepository.self) { AlarmAPIRepositoryImpl(provider: DIContainer.resolve(type: NetworkProvider.self), interceptor: DIContainer.resolve(type: Interceptor.self)) } + DIContainer.register(type: CollectionAPIRepository.self) { + CollectionAPIRepositoryImpl(provider: DIContainer.resolve(type: NetworkProvider.self), + tokenInterceptor: DIContainer.resolve(type: Interceptor.self)) + } } func registerUseCase() { @@ -340,6 +344,12 @@ private extension AppDelegate { DIContainer.register(type: ParseItemFilterResultUseCase.self) { ParseItemFilterResultUseCaseImpl() } + DIContainer.register(type: FetchCollectionListUseCase.self) { + FetchCollectionListUseCaseImpl(repository: DIContainer.resolve(type: CollectionAPIRepository.self)) + } + DIContainer.register(type: CreateCollectionListUseCase.self) { + CreateCollectionListUseCaseImpl(repository: DIContainer.resolve(type: CollectionAPIRepository.self)) + } } func registerFactory() { @@ -478,7 +488,7 @@ private extension AppDelegate { BookmarkListFactoryImpl(itemFilterFactory: DIContainer.resolve(type: ItemFilterBottomSheetFactory.self), monsterFilterFactory: DIContainer.resolve(type: MonsterFilterBottomSheetFactory.self), sortedFactory: DIContainer.resolve(type: SortedBottomSheetFactory.self), bookmarkModalFactory: DIContainer.resolve(type: BookmarkModalFactory.self), loginFactory: DIContainer.resolve(type: LoginFactory.self), dictionaryDetailFactory: DIContainer.resolve(type: DictionaryDetailFactory.self), setBookmarkUseCase: DIContainer.resolve(type: SetBookmarkUseCase.self), checkLoginUseCase: DIContainer.resolve(type: CheckLoginUseCase.self), fetchBookmarkUseCase: DIContainer.resolve(type: FetchBookmarkUseCase.self), fetchMonsterBookmarkUseCase: DIContainer.resolve(type: FetchMonsterBookmarkUseCase.self), fetchItemBookmarkUseCase: DIContainer.resolve(type: FetchItemBookmarkUseCase.self), fetchNPCBookmarkUseCase: DIContainer.resolve(type: FetchNPCBookmarkUseCase.self), fetchQuestBookmarkUseCase: DIContainer.resolve(type: FetchQuestBookmarkUseCase.self), fetchMapBookmarkUseCase: DIContainer.resolve(type: FetchMapBookmarkUseCase.self), collectionEditFactory: DIContainer.resolve(type: CollectionEditFactory.self)) } DIContainer.register(type: CollectionListFactory.self) { - CollectionListFactoryImpl(addCollectionFactory: DIContainer.resolve(type: AddCollectionFactory.self), bookmarkDetailFactory: DIContainer.resolve(type: CollectionDetailFactory.self)) + CollectionListFactoryImpl(collectionListUseCase: DIContainer.resolve(type: FetchCollectionListUseCase.self), createCollectionListUseCase: DIContainer.resolve(type: CreateCollectionListUseCase.self), addCollectionFactory: DIContainer.resolve(type: AddCollectionFactory.self), bookmarkDetailFactory: DIContainer.resolve(type: CollectionDetailFactory.self)) } DIContainer.register(type: CollectionDetailFactory.self) { CollectionDetailFactoryImpl( diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/AddCollection/AddCollectionReactor.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/AddCollection/AddCollectionReactor.swift index 91023a59..5a6b1fc9 100644 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/AddCollection/AddCollectionReactor.swift +++ b/MLS/Presentation/BookmarkFeature/BookmarkFeature/AddCollection/AddCollectionReactor.swift @@ -82,10 +82,15 @@ public final class AddCollectionModalReactor: Reactor { newState.route = route case .addCollection(let title): var collection = newState.collection - collection?.title = title + // 기존 collection이 없으면 새로 생성 + if collection == nil { + collection = BookmarkCollection(id: -1, title: title, items: []) + } else { + collection?.title = title + } newState.route = .dismissWithSuccess(collection) } - + return newState } } diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionList/CollectionListCell.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionList/CollectionListCell.swift index 67af99b3..232e13df 100644 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionList/CollectionListCell.swift +++ b/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionList/CollectionListCell.swift @@ -1,4 +1,5 @@ import UIKit +import BaseFeature import DesignSystem @@ -39,18 +40,42 @@ public extension CollectionListCell { struct Input { let title: String let count: Int - let images: [UIImage?] + let images: [String?] - public init(title: String, count: Int, images: [UIImage?]) { + public init(title: String, count: Int, images: [String?]) { self.title = title self.count = count self.images = images } } - + func inject(input: Input) { - cellView.setImages(images: input.images) + loadImages(from: input.images) { [weak self] images in + print("이미지:\(images)") + self?.cellView.setImages(images: images) + } cellView.setTitle(text: input.title) cellView.setSubtitle(text: "\(String(input.count))개") } } + +private func loadImages(from urls: [String?], completion: @escaping ([UIImage?]) -> Void) { + + var results = Array(repeating: nil, count: urls.count) + let dispatchGroup = DispatchGroup() + + for (index, urlString) in urls.enumerated() { + dispatchGroup.enter() + + ImageLoader.shared.loadImage(stringURL: urlString) { image in + results[index] = image + dispatchGroup.leave() + } + } + + dispatchGroup.notify(queue: .main) { + completion(results) + } +} + + diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionList/CollectionListFactoryImpl.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionList/CollectionListFactoryImpl.swift index 7ad13ead..8fd68d44 100644 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionList/CollectionListFactoryImpl.swift +++ b/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionList/CollectionListFactoryImpl.swift @@ -1,17 +1,22 @@ import BaseFeature import BookmarkFeatureInterface +import DomainInterface public final class CollectionListFactoryImpl: CollectionListFactory { + private let collectionListUseCase: FetchCollectionListUseCase + private let createCollectionListUseCase: CreateCollectionListUseCase private let addCollectionFactory: AddCollectionFactory private let bookmarkDetailFactory: CollectionDetailFactory - public init(addCollectionFactory: AddCollectionFactory, bookmarkDetailFactory: CollectionDetailFactory) { + public init(collectionListUseCase: FetchCollectionListUseCase, createCollectionListUseCase: CreateCollectionListUseCase, addCollectionFactory: AddCollectionFactory, bookmarkDetailFactory: CollectionDetailFactory) { + self.collectionListUseCase = collectionListUseCase + self.createCollectionListUseCase = createCollectionListUseCase self.addCollectionFactory = addCollectionFactory self.bookmarkDetailFactory = bookmarkDetailFactory } public func make() -> BaseViewController { - let reactor = CollectionListReactor() + let reactor = CollectionListReactor(collectionListUseCase: collectionListUseCase, createCollectionListUseCase: createCollectionListUseCase) let viewController = CollectionListViewController(addCollectionFactory: addCollectionFactory, detailFactory: bookmarkDetailFactory) viewController.reactor = reactor return viewController diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionList/CollectionListReactor.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionList/CollectionListReactor.swift index 82ab21c1..7513c467 100644 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionList/CollectionListReactor.swift +++ b/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionList/CollectionListReactor.swift @@ -13,45 +13,64 @@ public final class CollectionListReactor: Reactor { public enum Action { case itemTapped(Int) + case viewWillAppear + case addCollection(String) } public enum Mutation { case navigateTo(Route) + case setListData([CollectionListResponse]) } public struct State { @Pulse var route: Route var collections: [BookmarkCollection] + var collectionListData: [CollectionListResponse] } // MARK: - Properties public var initialState: State private let disposeBag = DisposeBag() + + private let collectionListUseCase: FetchCollectionListUseCase + private let createCollectionListUseCase: CreateCollectionListUseCase - public init() { + public init( + collectionListUseCase: FetchCollectionListUseCase, + createCollectionListUseCase: CreateCollectionListUseCase + ) { + self.collectionListUseCase = collectionListUseCase + self.createCollectionListUseCase = createCollectionListUseCase self.initialState = State(route: .none, collections: [ - BookmarkCollection(id: 1, title: "1번", items: [ + BookmarkCollection(id: 1, title: "1000번", items: [ DictionaryItem(id: 1, type: .item, mainText: "1번 아이템", subText: "1번 설명", image: .add, isBookmarked: false), DictionaryItem(id: 2, type: .item, mainText: "2번 아이템", subText: "2번 설명", image: .add, isBookmarked: false) ]), - BookmarkCollection(id: 2, title: "2번", items: [ + BookmarkCollection(id: 2, title: "2000번", items: [ DictionaryItem(id: 3, type: .item, mainText: "3번 아이템", subText: "3번 설명", image: .add, isBookmarked: false), DictionaryItem(id: 4, type: .item, mainText: "4번 아이템", subText: "4번 설명", image: .add, isBookmarked: false) ]) - ]) + ], collectionListData: []) } public func mutate(action: Action) -> Observable { switch action { + case .viewWillAppear: + return collectionListUseCase.execute().map { .setListData($0) } case .itemTapped(let index): return .just(.navigateTo(.detail(currentState.collections[index]))) + case .addCollection(let collection): + return createCollectionListUseCase.execute(name: collection).andThen(collectionListUseCase.execute()) + .map {.setListData($0)} } } public func reduce(state: State, mutation: Mutation) -> State { var newState = state switch mutation { + case .setListData(let data): + newState.collectionListData = data case .navigateTo(let route): newState.route = route } diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionList/CollectionListViewController.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionList/CollectionListViewController.swift index 902cc963..e72bc4b7 100644 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionList/CollectionListViewController.swift +++ b/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionList/CollectionListViewController.swift @@ -61,6 +61,10 @@ private extension CollectionListViewController { addFloatingButton { [weak self] in guard let self = self else { return } let viewController = self.addCollectionFactory.make(collection: nil, onDismissWithMessage: { [weak self] collection in + if let collection = collection { + // Reactor에게 새로운 콜렉션 추가를 알림 + self?.reactor?.action.onNext(.addCollection(collection.title)) + } self?.onDismissWithMessage?(collection) }) self.present(viewController, animated: true) @@ -83,7 +87,12 @@ extension CollectionListViewController { bindViewState(reactor: reactor) } - func bindUserActions(reactor: Reactor) {} + func bindUserActions(reactor: Reactor) { + rx.viewWillAppear + .map { Reactor.Action.viewWillAppear } + .bind(to: reactor.action) + .disposed(by: disposeBag) + } func bindViewState(reactor: Reactor) { rx.viewDidAppear @@ -102,10 +111,11 @@ extension CollectionListViewController { .disposed(by: disposeBag) reactor.state - .map(\.collections) + .map(\.collectionListData) .withUnretained(self) - .subscribe { owner, collections in - owner.mainView.updateView(isEmptyData: collections.isEmpty) + .observe(on: MainScheduler.instance) + .subscribe { owner, collectionListData in + owner.mainView.updateView(isEmptyData: collectionListData.isEmpty) owner.mainView.listCollectionView.reloadData() } .disposed(by: disposeBag) @@ -115,7 +125,7 @@ extension CollectionListViewController { // MARK: - Delegate extension CollectionListViewController: UICollectionViewDelegate, UICollectionViewDataSource { public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { - reactor?.currentState.collections.count ?? 0 + reactor?.currentState.collectionListData.count ?? 0 } public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { @@ -124,11 +134,11 @@ extension CollectionListViewController: UICollectionViewDelegate, UICollectionVi withReuseIdentifier: CollectionListCell.identifier, for: indexPath ) as? CollectionListCell, - let item = reactor?.currentState.collections[indexPath.row] + let item = reactor?.currentState.collectionListData[indexPath.row] else { return UICollectionViewCell() } - cell.inject(input: CollectionListCell.Input(title: item.title, count: item.count, images: item.thumbnails)) + cell.inject(input: CollectionListCell.Input(title: item.name, count: item.recentBookmarks.count, images: item.recentBookmarks.map { $0.imageUrl })) return cell } diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Components/CollectionList.swift b/MLS/Presentation/DesignSystem/DesignSystem/Components/CollectionList.swift index 2b580db4..6aac4509 100644 --- a/MLS/Presentation/DesignSystem/DesignSystem/Components/CollectionList.swift +++ b/MLS/Presentation/DesignSystem/DesignSystem/Components/CollectionList.swift @@ -1,5 +1,6 @@ import UIKit + import SnapKit public final class CollectionList: UIView { @@ -136,6 +137,7 @@ public extension CollectionList { func setImages(images: [UIImage?]) { for (index, view) in imageViews.enumerated() { let imageView = view.subviews.compactMap { $0 as? UIImageView }.first + print("이미지 뷰 설정") imageView?.image = index < images.count ? images[index] : nil } } diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListViewController.swift index 9c827b39..069ac574 100644 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListViewController.swift +++ b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListViewController.swift @@ -148,6 +148,7 @@ extension DictionaryListViewController { .subscribe { owner, route in switch route { case .sort(let type): + print("sortsort실행~~~~~~~~~~~~~~~~~~~~~~~") let viewController = owner.sortedFactory.make( sortedOptions: type.bookmarkSortedFilter, selectedIndex: owner.selectedSortIndex From b9a07c450f4eb546fa67bb0256ef03999e5d7a15 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 23 Nov 2025 08:38:47 +0000 Subject: [PATCH 2/2] style/#269: Apply SwiftLint autocorrect --- .../CollectionDTO/CollectionListResponseDTO.swift | 2 +- .../Network/Endpoints/CollectionEndPoint.swift | 4 ++-- .../Repository/CollectionAPIRepositoryImpl.swift | 8 ++++---- .../CreateCollectionListUseCaseImpl.swift | 4 ++-- .../FetchCollectionListUseCaseImpl.swift | 4 ++-- .../Entity/Collection/CollectionListResponse.swift | 2 +- .../AddCollection/AddCollectionReactor.swift | 2 +- .../CollectionList/CollectionListCell.swift | 14 ++++++-------- .../CollectionList/CollectionListReactor.swift | 2 +- .../DesignSystem/Components/CollectionList.swift | 1 - 10 files changed, 20 insertions(+), 23 deletions(-) diff --git a/MLS/Data/Data/Network/DTO/CollectionDTO/CollectionListResponseDTO.swift b/MLS/Data/Data/Network/DTO/CollectionDTO/CollectionListResponseDTO.swift index 3c2e79eb..131b9b6c 100644 --- a/MLS/Data/Data/Network/DTO/CollectionDTO/CollectionListResponseDTO.swift +++ b/MLS/Data/Data/Network/DTO/CollectionDTO/CollectionListResponseDTO.swift @@ -5,7 +5,7 @@ public struct CollectionListResponseDTO: Decodable { public let name: String public let createdAt: [Int] public let recentBookmarks: [BookmarkDTO] - + public func toDomain() -> CollectionListResponse { return CollectionListResponse(collectionId: collectionId, name: name, createdAt: createdAt, recentBookmarks: recentBookmarks.toDomain()) } diff --git a/MLS/Data/Data/Network/Endpoints/CollectionEndPoint.swift b/MLS/Data/Data/Network/Endpoints/CollectionEndPoint.swift index 82d8d3e0..b1bd304c 100644 --- a/MLS/Data/Data/Network/Endpoints/CollectionEndPoint.swift +++ b/MLS/Data/Data/Network/Endpoints/CollectionEndPoint.swift @@ -2,11 +2,11 @@ import DomainInterface public enum CollectionEndPoint { static let base = "https://api.mapleland.kro.kr" - + public static func fetchCollectionList() -> ResponsableEndPoint<[CollectionListResponseDTO]> { .init(baseURL: base, path: "/api/v1/collections", method: .GET) } - + public static func createCollectionList(body: Encodable) -> EndPoint { .init(baseURL: base, path: "/api/v1/collections", method: .POST, body: body) } diff --git a/MLS/Data/Data/Repository/CollectionAPIRepositoryImpl.swift b/MLS/Data/Data/Repository/CollectionAPIRepositoryImpl.swift index d6fa65a1..7ba368e7 100644 --- a/MLS/Data/Data/Repository/CollectionAPIRepositoryImpl.swift +++ b/MLS/Data/Data/Repository/CollectionAPIRepositoryImpl.swift @@ -7,23 +7,23 @@ import RxSwift public class CollectionAPIRepositoryImpl: CollectionAPIRepository { private let provider: NetworkProvider private let tokenInterceptor: Interceptor - + public init(provider: NetworkProvider, tokenInterceptor: Interceptor) { self.provider = provider self.tokenInterceptor = tokenInterceptor } - + public func fetchCollectionList() -> Observable<[CollectionListResponse]> { let endPoint = CollectionEndPoint.fetchCollectionList() return provider.requestData(endPoint: endPoint, interceptor: tokenInterceptor).map { $0.map {$0.toDomain()} } } - + public func createCollectionList(name: String) -> Completable { let endPoint = CollectionEndPoint.createCollectionList(body: CreateCollectionRequestDTO(name: name)) return provider.requestData(endPoint: endPoint, interceptor: tokenInterceptor) - + } } diff --git a/MLS/Domain/Domain/UseCaseImpl/Collection/CreateCollectionListUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/Collection/CreateCollectionListUseCaseImpl.swift index 16345da9..5325ee16 100644 --- a/MLS/Domain/Domain/UseCaseImpl/Collection/CreateCollectionListUseCaseImpl.swift +++ b/MLS/Domain/Domain/UseCaseImpl/Collection/CreateCollectionListUseCaseImpl.swift @@ -4,11 +4,11 @@ import RxSwift public final class CreateCollectionListUseCaseImpl: CreateCollectionListUseCase { private let repository: CollectionAPIRepository - + public init(repository: CollectionAPIRepository) { self.repository = repository } - + public func execute(name: String) -> Completable { return repository.createCollectionList(name: name) } diff --git a/MLS/Domain/Domain/UseCaseImpl/Collection/FetchCollectionListUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/Collection/FetchCollectionListUseCaseImpl.swift index 3daeda96..10d586c6 100644 --- a/MLS/Domain/Domain/UseCaseImpl/Collection/FetchCollectionListUseCaseImpl.swift +++ b/MLS/Domain/Domain/UseCaseImpl/Collection/FetchCollectionListUseCaseImpl.swift @@ -4,11 +4,11 @@ import RxSwift public final class FetchCollectionListUseCaseImpl: FetchCollectionListUseCase { private let repository: CollectionAPIRepository - + public init(repository: CollectionAPIRepository) { self.repository = repository } - + public func execute() -> Observable<[CollectionListResponse]> { return repository.fetchCollectionList() } diff --git a/MLS/Domain/DomainInterface/Entity/Collection/CollectionListResponse.swift b/MLS/Domain/DomainInterface/Entity/Collection/CollectionListResponse.swift index 696cc7a8..f972b262 100644 --- a/MLS/Domain/DomainInterface/Entity/Collection/CollectionListResponse.swift +++ b/MLS/Domain/DomainInterface/Entity/Collection/CollectionListResponse.swift @@ -3,7 +3,7 @@ public struct CollectionListResponse { public let name: String public let createdAt: [Int] public let recentBookmarks: [BookmarkResponse] - + public init(collectionId: Int, name: String, createdAt: [Int], recentBookmarks: [BookmarkResponse]) { self.collectionId = collectionId self.name = name diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/AddCollection/AddCollectionReactor.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/AddCollection/AddCollectionReactor.swift index 5a6b1fc9..a21feece 100644 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/AddCollection/AddCollectionReactor.swift +++ b/MLS/Presentation/BookmarkFeature/BookmarkFeature/AddCollection/AddCollectionReactor.swift @@ -90,7 +90,7 @@ public final class AddCollectionModalReactor: Reactor { } newState.route = .dismissWithSuccess(collection) } - + return newState } } diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionList/CollectionListCell.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionList/CollectionListCell.swift index 232e13df..6a19c9cd 100644 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionList/CollectionListCell.swift +++ b/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionList/CollectionListCell.swift @@ -1,5 +1,5 @@ -import UIKit import BaseFeature +import UIKit import DesignSystem @@ -48,7 +48,7 @@ public extension CollectionListCell { self.images = images } } - + func inject(input: Input) { loadImages(from: input.images) { [weak self] images in print("이미지:\(images)") @@ -61,21 +61,19 @@ public extension CollectionListCell { private func loadImages(from urls: [String?], completion: @escaping ([UIImage?]) -> Void) { - var results = Array(repeating: nil, count: urls.count) + var results = [UIImage?](repeating: nil, count: urls.count) let dispatchGroup = DispatchGroup() - + for (index, urlString) in urls.enumerated() { dispatchGroup.enter() - + ImageLoader.shared.loadImage(stringURL: urlString) { image in results[index] = image dispatchGroup.leave() } } - + dispatchGroup.notify(queue: .main) { completion(results) } } - - diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionList/CollectionListReactor.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionList/CollectionListReactor.swift index 7513c467..0970ed54 100644 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionList/CollectionListReactor.swift +++ b/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionList/CollectionListReactor.swift @@ -32,7 +32,7 @@ public final class CollectionListReactor: Reactor { public var initialState: State private let disposeBag = DisposeBag() - + private let collectionListUseCase: FetchCollectionListUseCase private let createCollectionListUseCase: CreateCollectionListUseCase diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Components/CollectionList.swift b/MLS/Presentation/DesignSystem/DesignSystem/Components/CollectionList.swift index 6aac4509..b6543477 100644 --- a/MLS/Presentation/DesignSystem/DesignSystem/Components/CollectionList.swift +++ b/MLS/Presentation/DesignSystem/DesignSystem/Components/CollectionList.swift @@ -1,6 +1,5 @@ import UIKit - import SnapKit public final class CollectionList: UIView {