From 873436edce0ce0ddd4996881a0f97d83f4bc4e15 Mon Sep 17 00:00:00 2001 From: L-j-h-c Date: Tue, 20 Dec 2022 15:03:10 +0900 Subject: [PATCH 1/6] =?UTF-8?q?[Feat]=20#28=20-=20=EB=9E=AD=ED=82=B9=20?= =?UTF-8?q?=EB=AF=B8=EC=85=98=20=EB=A6=AC=EC=8A=A4=ED=8A=B8=20=ED=95=9C?= =?UTF-8?q?=EB=A7=88=EB=94=94=20=EB=9D=BC=EB=B2=A8=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MissionListScene/VC/MissionListVC.swift | 34 +++++++++++++++++-- .../ViewModel/MissionListViewModel.swift | 2 +- 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/SOPT-Stamp-iOS/Projects/Presentation/Sources/MissionListScene/VC/MissionListVC.swift b/SOPT-Stamp-iOS/Projects/Presentation/Sources/MissionListScene/VC/MissionListVC.swift index e226988a..c9a6a16a 100644 --- a/SOPT-Stamp-iOS/Projects/Presentation/Sources/MissionListScene/VC/MissionListVC.swift +++ b/SOPT-Stamp-iOS/Projects/Presentation/Sources/MissionListScene/VC/MissionListVC.swift @@ -36,7 +36,7 @@ public class MissionListVC: UIViewController { return CustomNavigationBar(self, type: .title) .setTitle("전체 미션") .setTitleTypoStyle(.h2) - case .ranking(let username): + case .ranking(let username, _): return CustomNavigationBar(self, type: .titleWithLeftButton) .setTitle(username) .setRightButton(.none) @@ -44,6 +44,21 @@ public class MissionListVC: UIViewController { } }() + private lazy var sentenceLabel: UILabel = { + let lb = UILabel() + if case let .ranking(_, sentence) = sceneType { + lb.text = sentence + } + lb.setTypoStyle(.subtitle2) + lb.textColor = DSKitAsset.Colors.gray900.color + lb.numberOfLines = 2 + lb.textAlignment = .center + lb.backgroundColor = DSKitAsset.Colors.purple100.color + lb.layer.cornerRadius = 9.adjustedH + lb.clipsToBounds = true + return lb + }() + private lazy var missionListCollectionView: UICollectionView = { let cv = UICollectionView(frame: .zero, collectionViewLayout: self.createLayout()) cv.showsVerticalScrollIndicator = true @@ -100,7 +115,8 @@ extension MissionListVC { make.bottom.equalToSuperview() } - if case .default = sceneType { + switch sceneType { + case .default: self.view.addSubview(rankingFloatingButton) rankingFloatingButton.snp.makeConstraints { make in @@ -109,6 +125,20 @@ extension MissionListVC { make.bottom.equalTo(view.safeAreaLayoutGuide) make.centerX.equalToSuperview() } + case .ranking: + self.view.addSubview(sentenceLabel) + + sentenceLabel.snp.makeConstraints { make in + make.top.equalTo(naviBar.snp.bottom).offset(16.adjustedH) + make.leading.trailing.equalToSuperview().inset(20.adjusted) + make.height.equalTo(64.adjustedH) + } + + missionListCollectionView.snp.remakeConstraints { make in + make.top.equalTo(sentenceLabel.snp.bottom).offset(16.adjustedH) + make.leading.trailing.equalToSuperview() + make.bottom.equalToSuperview() + } } } } diff --git a/SOPT-Stamp-iOS/Projects/Presentation/Sources/MissionListScene/ViewModel/MissionListViewModel.swift b/SOPT-Stamp-iOS/Projects/Presentation/Sources/MissionListScene/ViewModel/MissionListViewModel.swift index 95603bef..27308e71 100644 --- a/SOPT-Stamp-iOS/Projects/Presentation/Sources/MissionListScene/ViewModel/MissionListViewModel.swift +++ b/SOPT-Stamp-iOS/Projects/Presentation/Sources/MissionListScene/ViewModel/MissionListViewModel.swift @@ -14,7 +14,7 @@ import Domain @frozen public enum MissionListSceneType { case `default` - case ranking(userName: String) + case ranking(userName: String, sentence: String) } public class MissionListViewModel: ViewModelType { From 9870d71a124bbc755f18b377ef4b7d64d9cd1203 Mon Sep 17 00:00:00 2001 From: L-j-h-c Date: Tue, 20 Dec 2022 16:11:41 +0900 Subject: [PATCH 2/6] =?UTF-8?q?[Feat]=20#28=20-=20MissionListAPI=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Network/Sources/API/MissionAPI.swift | 40 +++++++++++++------ .../Sources/Entity/MissionListEntity.swift | 10 ++++- .../Network/Sources/Foundation/BaseAPI.swift | 39 ++++++++++++++---- .../Sources/Foundation/BaseService.swift | 2 +- .../Sources/Service/MissionService.swift | 14 ++++++- .../Sources/Application/SceneDelegate.swift | 2 +- 6 files changed, 83 insertions(+), 24 deletions(-) diff --git a/SOPT-Stamp-iOS/Projects/Modules/Network/Sources/API/MissionAPI.swift b/SOPT-Stamp-iOS/Projects/Modules/Network/Sources/API/MissionAPI.swift index 2994a5c8..ee71b046 100644 --- a/SOPT-Stamp-iOS/Projects/Modules/Network/Sources/API/MissionAPI.swift +++ b/SOPT-Stamp-iOS/Projects/Modules/Network/Sources/API/MissionAPI.swift @@ -12,26 +12,35 @@ import Alamofire import Moya public enum MissionAPI { - case sample(provider: String) + case fetchMissionList(type: MissionListFetchType, userId: Int) } extension MissionAPI: BaseAPI { - public static var apiType: APIType = .auth + public static var apiType: APIType = .mission + + // MARK: - Header + public var headers: [String : String]? { + switch self { + case .fetchMissionList(_, let userId): + return HeaderType.userId(userId: userId).value + default: return HeaderType.json.value + } + } // MARK: - Path public var path: String { switch self { - case .sample: - return "" + case .fetchMissionList(let type, _): + return "/\(type.path)" + default: return "" } } // MARK: - Method public var method: Moya.Method { switch self { - case .sample: - return .post + default: return .get } } @@ -39,16 +48,13 @@ extension MissionAPI: BaseAPI { private var bodyParameters: Parameters? { var params: Parameters = [:] switch self { - case .sample(let provider): - params["platform"] = provider + default: break } return params } private var parameterEncoding: ParameterEncoding { switch self { - case .sample: - return URLEncoding.init(destination: .queryString, arrayEncoding: .noBrackets, boolEncoding: .literal) default: return JSONEncoding.default } @@ -56,10 +62,20 @@ extension MissionAPI: BaseAPI { public var task: Task { switch self { - case .sample: - return .requestParameters(parameters: bodyParameters ?? [:], encoding: parameterEncoding) default: return .requestPlain } } } + +extension MissionAPI { + public enum MissionListFetchType: String { + case all + case complete + case incomplete + + public var path: String { + return self.rawValue + } + } +} diff --git a/SOPT-Stamp-iOS/Projects/Modules/Network/Sources/Entity/MissionListEntity.swift b/SOPT-Stamp-iOS/Projects/Modules/Network/Sources/Entity/MissionListEntity.swift index 03ed84f3..889bac20 100644 --- a/SOPT-Stamp-iOS/Projects/Modules/Network/Sources/Entity/MissionListEntity.swift +++ b/SOPT-Stamp-iOS/Projects/Modules/Network/Sources/Entity/MissionListEntity.swift @@ -8,6 +8,12 @@ import Foundation -public struct MissionListEntity { - +public struct MissionListEntityElement: Codable { + public let id: Int + public let title: String + public let level: Int + public let profileImage: [String]? + public let isCompleted: Bool } + +public typealias MissionListEntity = [MissionListEntityElement] diff --git a/SOPT-Stamp-iOS/Projects/Modules/Network/Sources/Foundation/BaseAPI.swift b/SOPT-Stamp-iOS/Projects/Modules/Network/Sources/Foundation/BaseAPI.swift index 7cc33f8c..89857008 100644 --- a/SOPT-Stamp-iOS/Projects/Modules/Network/Sources/Foundation/BaseAPI.swift +++ b/SOPT-Stamp-iOS/Projects/Modules/Network/Sources/Foundation/BaseAPI.swift @@ -11,9 +11,11 @@ import Moya import Foundation public enum APIType { - case notice case auth - case alert + case mission + case rank + case stamp + case user } public protocol BaseAPI: TargetType { @@ -25,17 +27,22 @@ extension BaseAPI { var base = Config.Network.baseURL switch Self.apiType { - case .alert: - base += "alert" - case .notice: - base += "notice" case .auth: - base += "auth" + base += "/auth" + case .mission: + base += "/mission" + case .rank: + base += "/rank" + case .stamp: + base += "/stamp" + case .user: + base += "/user" } guard let url = URL(string: base) else { fatalError("baseURL could not be configured") } + return url } @@ -43,3 +50,21 @@ extension BaseAPI { return ["Content-Type": "application/json"] } } + +public enum HeaderType { + case json + case jsonUserId(userId: Int) + case userId(userId: Int) + + public var value: [String: String] { + switch self { + case .json: + return ["Content-Type": "application/json"] + case .jsonUserId(let userId): + return ["Content-Type": "application/json", + "userId": String(userId)] + case .userId(let userId): + return ["userId": String(userId)] + } + } +} diff --git a/SOPT-Stamp-iOS/Projects/Modules/Network/Sources/Foundation/BaseService.swift b/SOPT-Stamp-iOS/Projects/Modules/Network/Sources/Foundation/BaseService.swift index 2738269e..e8396ef0 100644 --- a/SOPT-Stamp-iOS/Projects/Modules/Network/Sources/Foundation/BaseService.swift +++ b/SOPT-Stamp-iOS/Projects/Modules/Network/Sources/Foundation/BaseService.swift @@ -66,7 +66,7 @@ public extension BaseService { // MARK: - MakeRequests extension BaseService { - func requestObjectInCombine(_ target: API) -> AnyPublisher { + func requestObjectInCombine(_ target: API) -> AnyPublisher { return Future { promise in self.provider.request(target) { response in switch response { diff --git a/SOPT-Stamp-iOS/Projects/Modules/Network/Sources/Service/MissionService.swift b/SOPT-Stamp-iOS/Projects/Modules/Network/Sources/Service/MissionService.swift index c12ce7dc..12d71019 100644 --- a/SOPT-Stamp-iOS/Projects/Modules/Network/Sources/Service/MissionService.swift +++ b/SOPT-Stamp-iOS/Projects/Modules/Network/Sources/Service/MissionService.swift @@ -15,9 +15,21 @@ import Moya public typealias DefaultMissionService = BaseService public protocol MissionService { - + func fetchAllMissionList(userId: Int) -> AnyPublisher + func fetchCompleteMissionList(userId: Int) -> AnyPublisher + func fetchIncompleteMissionList(userId: Int) -> AnyPublisher } extension DefaultMissionService: MissionService { + public func fetchAllMissionList(userId: Int) -> AnyPublisher { + requestObjectInCombine(MissionAPI.fetchMissionList(type: .all, userId: userId)) + } + + public func fetchCompleteMissionList(userId: Int) -> AnyPublisher { + requestObjectInCombine(MissionAPI.fetchMissionList(type: .complete, userId: userId)) + } + public func fetchIncompleteMissionList(userId: Int) -> AnyPublisher { + requestObjectInCombine(MissionAPI.fetchMissionList(type: .incomplete, userId: userId)) + } } diff --git a/SOPT-Stamp-iOS/Projects/SOPT-Stamp-iOS/Sources/Application/SceneDelegate.swift b/SOPT-Stamp-iOS/Projects/SOPT-Stamp-iOS/Sources/Application/SceneDelegate.swift index a2e8eaae..9f19c8c0 100644 --- a/SOPT-Stamp-iOS/Projects/SOPT-Stamp-iOS/Sources/Application/SceneDelegate.swift +++ b/SOPT-Stamp-iOS/Projects/SOPT-Stamp-iOS/Sources/Application/SceneDelegate.swift @@ -20,7 +20,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { window = UIWindow(frame: scene.coordinateSpace.bounds) window?.windowScene = scene - let rootVC = ModuleFactory.shared.makeMissionListVC(sceneType: .default) + let rootVC = ModuleFactory.shared.makeMissionListVC(sceneType: .ranking(userName: "솝트", sentence: "나는 잘해볼게")) window?.rootViewController = UINavigationController(rootViewController: rootVC) window?.makeKeyAndVisible() } From 44dc175237eef9d13ec5d165d0cf3c112e2e649a Mon Sep 17 00:00:00 2001 From: L-j-h-c Date: Wed, 21 Dec 2022 18:56:32 +0900 Subject: [PATCH 3/6] =?UTF-8?q?[Feat]=20#28=20-=20MissionList=20Fetch=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Sources/Enum/MissionListFetchType.swift | 19 +++++++ .../Repository/MissionListRepository.swift | 24 +++++++-- .../Transform/MissionListTransform.swift | 21 ++++++++ .../Transform/SampleDataTransform.swift | 16 ------ .../Sources/Model/MissionListModel.swift | 15 ++++-- .../Domain/Sources/Model/SampleModel.swift | 16 ------ .../MissionListRepositoryInterface.swift | 4 +- .../Sources/UseCase/MissionListUseCase.swift | 18 +++++-- .../Network/Sources/API/MissionAPI.swift | 16 ++---- .../Cells/MissionListCVC.swift | 14 ++++- .../MissionListScene/VC/MissionListVC.swift | 51 +++++++++---------- .../ViewModel/MissionListViewModel.swift | 32 ++++++++---- 12 files changed, 149 insertions(+), 97 deletions(-) create mode 100644 SOPT-Stamp-iOS/Projects/Core/Sources/Enum/MissionListFetchType.swift create mode 100644 SOPT-Stamp-iOS/Projects/Data/Sources/Transform/MissionListTransform.swift delete mode 100644 SOPT-Stamp-iOS/Projects/Data/Sources/Transform/SampleDataTransform.swift delete mode 100644 SOPT-Stamp-iOS/Projects/Domain/Sources/Model/SampleModel.swift diff --git a/SOPT-Stamp-iOS/Projects/Core/Sources/Enum/MissionListFetchType.swift b/SOPT-Stamp-iOS/Projects/Core/Sources/Enum/MissionListFetchType.swift new file mode 100644 index 00000000..eb927643 --- /dev/null +++ b/SOPT-Stamp-iOS/Projects/Core/Sources/Enum/MissionListFetchType.swift @@ -0,0 +1,19 @@ +// +// MissionListFetchType.swift +// Core +// +// Created by Junho Lee on 2022/12/21. +// Copyright © 2022 SOPT-Stamp-iOS. All rights reserved. +// + +import Foundation + +public enum MissionListFetchType: String { + case all + case complete + case incomplete + + public var path: String { + return self.rawValue + } +} diff --git a/SOPT-Stamp-iOS/Projects/Data/Sources/Repository/MissionListRepository.swift b/SOPT-Stamp-iOS/Projects/Data/Sources/Repository/MissionListRepository.swift index f02537b5..aa2907d1 100644 --- a/SOPT-Stamp-iOS/Projects/Data/Sources/Repository/MissionListRepository.swift +++ b/SOPT-Stamp-iOS/Projects/Data/Sources/Repository/MissionListRepository.swift @@ -8,19 +8,35 @@ import Combine +import Core import Domain import Network public class MissionListRepository { - private let networkService: MissionService - private let cancelBag = Set() + private let missionService: MissionService + private let cancelBag = CancelBag() public init(service: MissionService) { - self.networkService = service + self.missionService = service } } extension MissionListRepository: MissionListRepositoryInterface { - + public func fetchMissionList(type: MissionListFetchType) -> AnyPublisher<[MissionListModel], Error> { + switch type { + case .all: + return missionService.fetchAllMissionList(userId: 1) + .map { $0.toDomain() } + .eraseToAnyPublisher() + case .complete: + return missionService.fetchCompleteMissionList(userId: 1) + .map { $0.toDomain() } + .eraseToAnyPublisher() + case .incomplete: + return missionService.fetchIncompleteMissionList(userId: 1) + .map { $0.toDomain() } + .eraseToAnyPublisher() + } + } } diff --git a/SOPT-Stamp-iOS/Projects/Data/Sources/Transform/MissionListTransform.swift b/SOPT-Stamp-iOS/Projects/Data/Sources/Transform/MissionListTransform.swift new file mode 100644 index 00000000..e89eb865 --- /dev/null +++ b/SOPT-Stamp-iOS/Projects/Data/Sources/Transform/MissionListTransform.swift @@ -0,0 +1,21 @@ +// +// MissionListTransform.swift +// Data +// +// Created by Junho Lee on 2022/12/20. +// Copyright © 2022 SOPT-Stamp-iOS. All rights reserved. +// + +import Foundation + +import Domain +import Network + +public extension MissionListEntity { + func toDomain() -> [MissionListModel] { + return self.map { .init(id: $0.id, + title: $0.title, + level: $0.level, + isCompleted: $0.isCompleted) } + } +} diff --git a/SOPT-Stamp-iOS/Projects/Data/Sources/Transform/SampleDataTransform.swift b/SOPT-Stamp-iOS/Projects/Data/Sources/Transform/SampleDataTransform.swift deleted file mode 100644 index 3231a054..00000000 --- a/SOPT-Stamp-iOS/Projects/Data/Sources/Transform/SampleDataTransform.swift +++ /dev/null @@ -1,16 +0,0 @@ -// -// SampleRepository.swift -// Network -// -// Created by Junho Lee on 2022/11/09. -// Copyright © 2022 SOPT-Stamp-iOS. All rights reserved. -// - -import Domain -import Network - -extension SampleEntity { - public func toDomain() -> SampleModel { - return SampleModel() - } -} diff --git a/SOPT-Stamp-iOS/Projects/Domain/Sources/Model/MissionListModel.swift b/SOPT-Stamp-iOS/Projects/Domain/Sources/Model/MissionListModel.swift index e66fefdc..a6189822 100644 --- a/SOPT-Stamp-iOS/Projects/Domain/Sources/Model/MissionListModel.swift +++ b/SOPT-Stamp-iOS/Projects/Domain/Sources/Model/MissionListModel.swift @@ -8,9 +8,16 @@ import Foundation -public struct MissionListModel { - - public init() { - +public struct MissionListModel: Codable, Hashable { + public let id: Int + public let title: String + public let level: Int + public let isCompleted: Bool + + public init(id: Int, title: String, level: Int, isCompleted: Bool) { + self.id = id + self.title = title + self.level = level + self.isCompleted = isCompleted } } diff --git a/SOPT-Stamp-iOS/Projects/Domain/Sources/Model/SampleModel.swift b/SOPT-Stamp-iOS/Projects/Domain/Sources/Model/SampleModel.swift deleted file mode 100644 index 989add87..00000000 --- a/SOPT-Stamp-iOS/Projects/Domain/Sources/Model/SampleModel.swift +++ /dev/null @@ -1,16 +0,0 @@ -// -// SampleModel.swift -// Network -// -// Created by Junho Lee on 2022/11/09. -// Copyright © 2022 SOPT-Stamp-iOS. All rights reserved. -// - -import Foundation - -public struct SampleModel { - - public init() { - - } -} diff --git a/SOPT-Stamp-iOS/Projects/Domain/Sources/RepositoryInterface/MissionListRepositoryInterface.swift b/SOPT-Stamp-iOS/Projects/Domain/Sources/RepositoryInterface/MissionListRepositoryInterface.swift index 3683f4b6..26ff86ef 100644 --- a/SOPT-Stamp-iOS/Projects/Domain/Sources/RepositoryInterface/MissionListRepositoryInterface.swift +++ b/SOPT-Stamp-iOS/Projects/Domain/Sources/RepositoryInterface/MissionListRepositoryInterface.swift @@ -8,6 +8,8 @@ import Combine +import Core + public protocol MissionListRepositoryInterface { - + func fetchMissionList(type: MissionListFetchType) -> AnyPublisher<[MissionListModel], Error> } diff --git a/SOPT-Stamp-iOS/Projects/Domain/Sources/UseCase/MissionListUseCase.swift b/SOPT-Stamp-iOS/Projects/Domain/Sources/UseCase/MissionListUseCase.swift index 32e0be78..c79f9c7d 100644 --- a/SOPT-Stamp-iOS/Projects/Domain/Sources/UseCase/MissionListUseCase.swift +++ b/SOPT-Stamp-iOS/Projects/Domain/Sources/UseCase/MissionListUseCase.swift @@ -8,14 +8,18 @@ import Combine -public protocol MissionListUseCase { +import Core +public protocol MissionListUseCase { + func fetchMissionList(type: MissionListFetchType) + var missionListModelsFetched: PassthroughSubject<[MissionListModel], Error> { get set } } public class DefaultMissionListUseCase { private let repository: MissionListRepositoryInterface - private var cancelBag = Set() + private var cancelBag = CancelBag() + public var missionListModelsFetched = PassthroughSubject<[MissionListModel], Error>() public init(repository: MissionListRepositoryInterface) { self.repository = repository @@ -23,5 +27,13 @@ public class DefaultMissionListUseCase { } extension DefaultMissionListUseCase: MissionListUseCase { - + public func fetchMissionList(type: MissionListFetchType) { + repository.fetchMissionList(type: type) + .sink(receiveCompletion: { event in + print("completion: \(event)") + }, receiveValue: { model in + self.missionListModelsFetched.send(model) + }) + .store(in: cancelBag) + } } diff --git a/SOPT-Stamp-iOS/Projects/Modules/Network/Sources/API/MissionAPI.swift b/SOPT-Stamp-iOS/Projects/Modules/Network/Sources/API/MissionAPI.swift index ee71b046..4715d053 100644 --- a/SOPT-Stamp-iOS/Projects/Modules/Network/Sources/API/MissionAPI.swift +++ b/SOPT-Stamp-iOS/Projects/Modules/Network/Sources/API/MissionAPI.swift @@ -8,6 +8,8 @@ import Foundation +import Core + import Alamofire import Moya @@ -20,7 +22,7 @@ extension MissionAPI: BaseAPI { public static var apiType: APIType = .mission // MARK: - Header - public var headers: [String : String]? { + public var headers: [String: String]? { switch self { case .fetchMissionList(_, let userId): return HeaderType.userId(userId: userId).value @@ -67,15 +69,3 @@ extension MissionAPI: BaseAPI { } } } - -extension MissionAPI { - public enum MissionListFetchType: String { - case all - case complete - case incomplete - - public var path: String { - return self.rawValue - } - } -} diff --git a/SOPT-Stamp-iOS/Projects/Presentation/Sources/MissionListScene/Cells/MissionListCVC.swift b/SOPT-Stamp-iOS/Projects/Presentation/Sources/MissionListScene/Cells/MissionListCVC.swift index 7d716bee..8d9f2bfd 100644 --- a/SOPT-Stamp-iOS/Projects/Presentation/Sources/MissionListScene/Cells/MissionListCVC.swift +++ b/SOPT-Stamp-iOS/Projects/Presentation/Sources/MissionListScene/Cells/MissionListCVC.swift @@ -95,6 +95,16 @@ extension MissionListCellType { } } +extension MissionListModel { + func toCellType() -> MissionListCellType { + switch self.level { + case 1: return .levelOne(completed: self.isCompleted) + case 2: return .levelTwo(completed: self.isCompleted) + default: return .levelThree(completed: self.isCompleted) + } + } +} + // MARK: MissionListCVC final class MissionListCVC: UICollectionViewCell, UICollectionViewRegisterable { @@ -246,7 +256,7 @@ extension MissionListCVC { extension MissionListCVC { - public func setData(model: String) { - + public func setData(model: MissionListModel) { + self.purposeLabel.text = model.title } } diff --git a/SOPT-Stamp-iOS/Projects/Presentation/Sources/MissionListScene/VC/MissionListVC.swift b/SOPT-Stamp-iOS/Projects/Presentation/Sources/MissionListScene/VC/MissionListVC.swift index c9a6a16a..26143395 100644 --- a/SOPT-Stamp-iOS/Projects/Presentation/Sources/MissionListScene/VC/MissionListVC.swift +++ b/SOPT-Stamp-iOS/Projects/Presentation/Sources/MissionListScene/VC/MissionListVC.swift @@ -9,6 +9,7 @@ import UIKit import Core +import Domain import DSKit import Combine @@ -26,7 +27,7 @@ public class MissionListVC: UIViewController { } private var cancelBag = CancelBag() - lazy var dataSource: UICollectionViewDiffableDataSource! = nil + lazy var dataSource: UICollectionViewDiffableDataSource! = nil // MARK: - UI Components @@ -87,9 +88,9 @@ public class MissionListVC: UIViewController { self.setLayout() self.setDelegate() self.registerCells() - self.bindViewModels() self.setDataSource() - self.applySnapshot() + self.bindViews() + self.bindViewModels() } } @@ -146,16 +147,26 @@ extension MissionListVC { // MARK: - Methods extension MissionListVC { - - private func bindViewModels() { + private func bindViews() { naviBar.rightButtonTapped .asDriver() .sink { _ in self.pushToSettingVC() }.store(in: self.cancelBag) + } + + private func bindViewModels() { + + let input = MissionListViewModel.Input(viewDidLoad: Driver.just(()), + viewWillAppear: Driver.just(())) - let input = MissionListViewModel.Input() let output = self.viewModel.transform(from: input, cancelBag: self.cancelBag) + + output.$missionListModel + .compactMap { $0 } + .sink { model in + self.applySnapshot(model: model) + }.store(in: self.cancelBag) } private func setDelegate() { @@ -177,34 +188,18 @@ extension MissionListVC { case .missionList: guard let missionListCell = collectionView.dequeueReusableCell(withReuseIdentifier: MissionListCVC.className, for: indexPath) as? MissionListCVC else { return UICollectionViewCell() } - guard let index = itemIdentifier as? Int else { return UICollectionViewCell() } - switch index % 6 { - case 0: - missionListCell.initCellType = .levelOne(completed: true) - case 1: - missionListCell.initCellType = .levelOne(completed: false) - case 2: - missionListCell.initCellType = .levelTwo(completed: false) - case 3: - missionListCell.initCellType = .levelTwo(completed: true) - case 4: - missionListCell.initCellType = .levelThree(completed: true) - default: - missionListCell.initCellType = .levelThree(completed: false) - } + let missionListModel = itemIdentifier + missionListCell.initCellType = missionListModel.toCellType() + missionListCell.setData(model: missionListModel) return missionListCell } }) } - func applySnapshot() { - var snapshot = NSDiffableDataSourceSnapshot() + func applySnapshot(model: [MissionListModel]) { + var snapshot = NSDiffableDataSourceSnapshot() snapshot.appendSections([.sentence, .missionList]) - var tempItems: [Int] = [] - for i in 0..<50 { - tempItems.append(i) - } - snapshot.appendItems(tempItems, toSection: .missionList) + snapshot.appendItems(model, toSection: .missionList) dataSource.apply(snapshot, animatingDifferences: false) self.view.setNeedsLayout() } diff --git a/SOPT-Stamp-iOS/Projects/Presentation/Sources/MissionListScene/ViewModel/MissionListViewModel.swift b/SOPT-Stamp-iOS/Projects/Presentation/Sources/MissionListScene/ViewModel/MissionListViewModel.swift index 27308e71..f8c11fbb 100644 --- a/SOPT-Stamp-iOS/Projects/Presentation/Sources/MissionListScene/ViewModel/MissionListViewModel.swift +++ b/SOPT-Stamp-iOS/Projects/Presentation/Sources/MissionListScene/ViewModel/MissionListViewModel.swift @@ -7,6 +7,7 @@ // import Combine +import Foundation import Core import Domain @@ -18,25 +19,26 @@ public enum MissionListSceneType { } public class MissionListViewModel: ViewModelType { - + private let useCase: MissionListUseCase private var cancelBag = CancelBag() public var missionListsceneType: MissionListSceneType! - + // MARK: - Inputs public struct Input { - + let viewDidLoad: Driver + let viewWillAppear: Driver } // MARK: - Outputs - public struct Output { - + public class Output: NSObject { + @Published var missionListModel: [MissionListModel]? } // MARK: - init - + public init(useCase: MissionListUseCase, sceneType: MissionListSceneType) { self.useCase = useCase self.missionListsceneType = sceneType @@ -47,12 +49,22 @@ extension MissionListViewModel { public func transform(from input: Input, cancelBag: CancelBag) -> Output { let output = Output() self.bindOutput(output: output, cancelBag: cancelBag) - // input,output 상관관계 작성 - + + input.viewDidLoad + .sink { + self.useCase.fetchMissionList(type: .all) + }.store(in: cancelBag) + return output } - - private func bindOutput(output: Output, cancelBag: CancelBag) { + private func bindOutput(output: Output, cancelBag: CancelBag) { + let fetchedMissionList = self.useCase.missionListModelsFetched + + fetchedMissionList.asDriver() + .sink(receiveValue: { model in + output.missionListModel = model + }) + .store(in: self.cancelBag) } } From eb5b2a96a15a0c6014a3b2cc09fffe7cc0e8a3fe Mon Sep 17 00:00:00 2001 From: L-j-h-c Date: Wed, 21 Dec 2022 19:33:42 +0900 Subject: [PATCH 4/6] =?UTF-8?q?[Feat]=20#28=20-=20Mission=20Detail?= =?UTF-8?q?=EB=A1=9C=20=ED=99=94=EB=A9=B4=EC=A0=84=ED=99=98=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Core/Sources/Enum/StarViewLevel.swift | 8 +-- .../Cells/MissionListCVC.swift | 7 +++ .../MissionListScene/VC/MissionListVC.swift | 54 ++++++++++++------- 3 files changed, 46 insertions(+), 23 deletions(-) diff --git a/SOPT-Stamp-iOS/Projects/Core/Sources/Enum/StarViewLevel.swift b/SOPT-Stamp-iOS/Projects/Core/Sources/Enum/StarViewLevel.swift index d29fa871..e728d556 100644 --- a/SOPT-Stamp-iOS/Projects/Core/Sources/Enum/StarViewLevel.swift +++ b/SOPT-Stamp-iOS/Projects/Core/Sources/Enum/StarViewLevel.swift @@ -8,8 +8,8 @@ import Foundation -public enum StarViewLevel { - case levelOne - case levelTwo - case levelThree +public enum StarViewLevel: Int { + case levelOne = 1 + case levelTwo = 2 + case levelThree = 3 } diff --git a/SOPT-Stamp-iOS/Projects/Presentation/Sources/MissionListScene/Cells/MissionListCVC.swift b/SOPT-Stamp-iOS/Projects/Presentation/Sources/MissionListScene/Cells/MissionListCVC.swift index 8d9f2bfd..5acbdb5a 100644 --- a/SOPT-Stamp-iOS/Projects/Presentation/Sources/MissionListScene/Cells/MissionListCVC.swift +++ b/SOPT-Stamp-iOS/Projects/Presentation/Sources/MissionListScene/Cells/MissionListCVC.swift @@ -103,6 +103,10 @@ extension MissionListModel { default: return .levelThree(completed: self.isCompleted) } } + + func toListDetailSceneType() -> ListDetailSceneType { + return (self.isCompleted == true) ? .edit : .none + } } // MARK: MissionListCVC @@ -112,6 +116,8 @@ final class MissionListCVC: UICollectionViewCell, UICollectionViewRegisterable { // MARK: - Properties static var isFromNib: Bool = false + + public var model: MissionListModel? private var cellType: MissionListCellType = .levelOne(completed: false) public var initCellType: MissionListCellType { get { return self.cellType } @@ -258,5 +264,6 @@ extension MissionListCVC { public func setData(model: MissionListModel) { self.purposeLabel.text = model.title + self.model = model } } diff --git a/SOPT-Stamp-iOS/Projects/Presentation/Sources/MissionListScene/VC/MissionListVC.swift b/SOPT-Stamp-iOS/Projects/Presentation/Sources/MissionListScene/VC/MissionListVC.swift index 26143395..52803324 100644 --- a/SOPT-Stamp-iOS/Projects/Presentation/Sources/MissionListScene/VC/MissionListVC.swift +++ b/SOPT-Stamp-iOS/Projects/Presentation/Sources/MissionListScene/VC/MissionListVC.swift @@ -153,6 +153,12 @@ extension MissionListVC { .sink { _ in self.pushToSettingVC() }.store(in: self.cancelBag) + + rankingFloatingButton.publisher(for: .touchUpInside) + .withUnretained(self) + .sink { owner, _ in + owner.pushToRankingVC() + }.store(in: self.cancelBag) } private func bindViewModels() { @@ -168,6 +174,19 @@ extension MissionListVC { self.applySnapshot(model: model) }.store(in: self.cancelBag) } + + private func pushToSettingVC() { + let settingVC = self.factory.makeSettingVC() + self.navigationController?.pushViewController(settingVC, animated: true) + } + + private func pushToRankingVC() { + let rankingVC = self.factory.makeRankingVC() + self.navigationController?.pushViewController(rankingVC, animated: true) + } +} + +extension MissionListVC { private func setDelegate() { missionListCollectionView.delegate = self @@ -203,31 +222,28 @@ extension MissionListVC { dataSource.apply(snapshot, animatingDifferences: false) self.view.setNeedsLayout() } - - private func pushToSettingVC() { - let settingVC = self.factory.makeSettingVC() - self.navigationController?.pushViewController(settingVC, animated: true) - } } // MARK: - UICollectionViewDelegate extension MissionListVC: UICollectionViewDelegate { public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { - - // TODO: - 확인용 - var sceneType: ListDetailSceneType = .none - var level: StarViewLevel = .levelOne - if indexPath.item % 2 == 0 { - sceneType = .completed - } - - if indexPath.item % 3 == 0 { - level = .levelTwo - } else if indexPath.item % 3 == 1 { - level = .levelThree + switch indexPath.section { + case 0: + return + case 1: + guard let tappedCell = collectionView.cellForItem(at: indexPath) as? MissionListCVC, + let model = tappedCell.model, + let starLevel = StarViewLevel.init(rawValue: model.level)else { return } + let sceneType = model.toListDetailSceneType() + + let detailVC = factory.makeListDetailVC(sceneType: sceneType, + starLevel: starLevel, + missionId: model.id, + missionTitle: model.title) + self.navigationController?.pushViewController(detailVC, animated: true) + default: + return } - let detailVC = factory.makeListDetailVC(sceneType: sceneType, starLevel: level, missionId: 3, missionTitle: "타이틀도 주세요 ..") - self.navigationController?.pushViewController(detailVC, animated: true) } } From 31404ded23eba796586b5d20e8c870fc8fc58550 Mon Sep 17 00:00:00 2001 From: L-j-h-c Date: Wed, 21 Dec 2022 20:09:18 +0900 Subject: [PATCH 5/6] =?UTF-8?q?[Feat]=20#28=20-=20=EB=AF=B8=EC=85=98=20?= =?UTF-8?q?=EB=A6=AC=EC=8A=A4=ED=8A=B8=20=EB=B0=8F=20=EB=9E=AD=ED=82=B9=20?= =?UTF-8?q?=EB=AF=B8=EC=85=98=20=EB=A6=AC=EC=8A=A4=ED=8A=B8=20=EB=B6=84?= =?UTF-8?q?=EA=B8=B0=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Repository/MissionListRepository.swift | 11 ++++++---- .../MissionListRepositoryInterface.swift | 2 +- .../Sources/UseCase/MissionListUseCase.swift | 13 +++++++++++- .../MissionListScene/VC/MissionListVC.swift | 20 +++++++++++++++++-- .../ViewModel/MissionListViewModel.swift | 12 ++++++++--- .../Sources/RankingScene/VC/RankingVC.swift | 14 +++++++++++-- 6 files changed, 59 insertions(+), 13 deletions(-) diff --git a/SOPT-Stamp-iOS/Projects/Data/Sources/Repository/MissionListRepository.swift b/SOPT-Stamp-iOS/Projects/Data/Sources/Repository/MissionListRepository.swift index aa2907d1..b4217b2a 100644 --- a/SOPT-Stamp-iOS/Projects/Data/Sources/Repository/MissionListRepository.swift +++ b/SOPT-Stamp-iOS/Projects/Data/Sources/Repository/MissionListRepository.swift @@ -23,18 +23,21 @@ public class MissionListRepository { } extension MissionListRepository: MissionListRepositoryInterface { - public func fetchMissionList(type: MissionListFetchType) -> AnyPublisher<[MissionListModel], Error> { + public func fetchMissionList(type: MissionListFetchType, userId: Int?) -> AnyPublisher<[MissionListModel], Error> { + let userId: Int = (userId != nil) + ? userId! + : 1 switch type { case .all: - return missionService.fetchAllMissionList(userId: 1) + return missionService.fetchAllMissionList(userId: userId) .map { $0.toDomain() } .eraseToAnyPublisher() case .complete: - return missionService.fetchCompleteMissionList(userId: 1) + return missionService.fetchCompleteMissionList(userId: userId) .map { $0.toDomain() } .eraseToAnyPublisher() case .incomplete: - return missionService.fetchIncompleteMissionList(userId: 1) + return missionService.fetchIncompleteMissionList(userId: userId) .map { $0.toDomain() } .eraseToAnyPublisher() } diff --git a/SOPT-Stamp-iOS/Projects/Domain/Sources/RepositoryInterface/MissionListRepositoryInterface.swift b/SOPT-Stamp-iOS/Projects/Domain/Sources/RepositoryInterface/MissionListRepositoryInterface.swift index 26ff86ef..13a995e3 100644 --- a/SOPT-Stamp-iOS/Projects/Domain/Sources/RepositoryInterface/MissionListRepositoryInterface.swift +++ b/SOPT-Stamp-iOS/Projects/Domain/Sources/RepositoryInterface/MissionListRepositoryInterface.swift @@ -11,5 +11,5 @@ import Combine import Core public protocol MissionListRepositoryInterface { - func fetchMissionList(type: MissionListFetchType) -> AnyPublisher<[MissionListModel], Error> + func fetchMissionList(type: MissionListFetchType, userId: Int?) -> AnyPublisher<[MissionListModel], Error> } diff --git a/SOPT-Stamp-iOS/Projects/Domain/Sources/UseCase/MissionListUseCase.swift b/SOPT-Stamp-iOS/Projects/Domain/Sources/UseCase/MissionListUseCase.swift index c79f9c7d..7a687561 100644 --- a/SOPT-Stamp-iOS/Projects/Domain/Sources/UseCase/MissionListUseCase.swift +++ b/SOPT-Stamp-iOS/Projects/Domain/Sources/UseCase/MissionListUseCase.swift @@ -12,6 +12,7 @@ import Core public protocol MissionListUseCase { func fetchMissionList(type: MissionListFetchType) + func fetchOtherUserMissionList(type: MissionListFetchType, userId: Int) var missionListModelsFetched: PassthroughSubject<[MissionListModel], Error> { get set } } @@ -27,8 +28,18 @@ public class DefaultMissionListUseCase { } extension DefaultMissionListUseCase: MissionListUseCase { + public func fetchOtherUserMissionList(type: MissionListFetchType, userId: Int) { + repository.fetchMissionList(type: type, userId: userId) + .sink(receiveCompletion: { event in + print("completion: \(event)") + }, receiveValue: { model in + self.missionListModelsFetched.send(model) + }) + .store(in: cancelBag) + } + public func fetchMissionList(type: MissionListFetchType) { - repository.fetchMissionList(type: type) + repository.fetchMissionList(type: type, userId: nil) .sink(receiveCompletion: { event in print("completion: \(event)") }, receiveValue: { model in diff --git a/SOPT-Stamp-iOS/Projects/Presentation/Sources/MissionListScene/VC/MissionListVC.swift b/SOPT-Stamp-iOS/Projects/Presentation/Sources/MissionListScene/VC/MissionListVC.swift index 52803324..15335bf5 100644 --- a/SOPT-Stamp-iOS/Projects/Presentation/Sources/MissionListScene/VC/MissionListVC.swift +++ b/SOPT-Stamp-iOS/Projects/Presentation/Sources/MissionListScene/VC/MissionListVC.swift @@ -37,7 +37,7 @@ public class MissionListVC: UIViewController { return CustomNavigationBar(self, type: .title) .setTitle("전체 미션") .setTitleTypoStyle(.h2) - case .ranking(let username, _): + case .ranking(let username, _, _): return CustomNavigationBar(self, type: .titleWithLeftButton) .setTitle(username) .setRightButton(.none) @@ -47,7 +47,7 @@ public class MissionListVC: UIViewController { private lazy var sentenceLabel: UILabel = { let lb = UILabel() - if case let .ranking(_, sentence) = sceneType { + if case let .ranking(_, sentence, _) = sceneType { lb.text = sentence } lb.setTypoStyle(.subtitle2) @@ -227,6 +227,22 @@ extension MissionListVC { // MARK: - UICollectionViewDelegate extension MissionListVC: UICollectionViewDelegate { + public func collectionView(_ collectionView: UICollectionView, shouldSelectItemAt indexPath: IndexPath) -> Bool { + switch indexPath.section { + case 0: + return false + case 1: + switch self.sceneType { + case .default: + return true + case .ranking: + return false + } + default: + return false + } + } + public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { switch indexPath.section { case 0: diff --git a/SOPT-Stamp-iOS/Projects/Presentation/Sources/MissionListScene/ViewModel/MissionListViewModel.swift b/SOPT-Stamp-iOS/Projects/Presentation/Sources/MissionListScene/ViewModel/MissionListViewModel.swift index f8c11fbb..516d02b8 100644 --- a/SOPT-Stamp-iOS/Projects/Presentation/Sources/MissionListScene/ViewModel/MissionListViewModel.swift +++ b/SOPT-Stamp-iOS/Projects/Presentation/Sources/MissionListScene/ViewModel/MissionListViewModel.swift @@ -15,7 +15,7 @@ import Domain @frozen public enum MissionListSceneType { case `default` - case ranking(userName: String, sentence: String) + case ranking(userName: String, sentence: String, userId: Int) } public class MissionListViewModel: ViewModelType { @@ -51,8 +51,14 @@ extension MissionListViewModel { self.bindOutput(output: output, cancelBag: cancelBag) input.viewDidLoad - .sink { - self.useCase.fetchMissionList(type: .all) + .withUnretained(self) + .sink { owner, _ in + switch owner.missionListsceneType { + case .ranking(_, _, let userId): + owner.useCase.fetchOtherUserMissionList(type: .all, userId: userId) + default: + owner.useCase.fetchMissionList(type: .all) + } }.store(in: cancelBag) return output diff --git a/SOPT-Stamp-iOS/Projects/Presentation/Sources/RankingScene/VC/RankingVC.swift b/SOPT-Stamp-iOS/Projects/Presentation/Sources/RankingScene/VC/RankingVC.swift index 4855f707..2790f4f7 100644 --- a/SOPT-Stamp-iOS/Projects/Presentation/Sources/RankingScene/VC/RankingVC.swift +++ b/SOPT-Stamp-iOS/Projects/Presentation/Sources/RankingScene/VC/RankingVC.swift @@ -87,7 +87,7 @@ extension RankingVC { // MARK: - Methods extension RankingVC { - + private func bindViewModels() { let input = RankingViewModel.Input() let output = self.viewModel.transform(from: input, cancelBag: self.cancelBag) @@ -142,5 +142,15 @@ extension RankingVC { } extension RankingVC: UICollectionViewDelegate { - + public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { +// guard let tappedCell = collectionView.cellForItem(at: indexPath) as? MissionListCVC, +// let model = tappedCell.model, +// let starLevel = StarViewLevel.init(rawValue: model.level)else { return } +// let sceneType = model.toListDetailSceneType() + + let otherUserMissionListVC = factory.makeMissionListVC(sceneType: .ranking(userName: "유저", + sentence: "한마디입니다", + userId: 2)) + self.navigationController?.pushViewController(otherUserMissionListVC, animated: true) + } } From f4e2298b512a4b40766fe240185636edc58a26f1 Mon Sep 17 00:00:00 2001 From: L-j-h-c Date: Wed, 21 Dec 2022 21:10:25 +0900 Subject: [PATCH 6/6] =?UTF-8?q?[Feat]=20#28=20-=20Mission=20List=20?= =?UTF-8?q?=EB=A9=94=EB=89=B4=20=EB=B2=84=ED=8A=BC=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Components/CustomNavigationBar.swift | 11 ++++++ .../MissionListScene/VC/MissionListVC.swift | 37 +++++++++++++++++-- .../ViewModel/MissionListViewModel.swift | 12 ++++++ 3 files changed, 56 insertions(+), 4 deletions(-) diff --git a/SOPT-Stamp-iOS/Projects/Modules/DSKit/Sources/Components/CustomNavigationBar.swift b/SOPT-Stamp-iOS/Projects/Modules/DSKit/Sources/Components/CustomNavigationBar.swift index 690d5973..63e1c5cd 100644 --- a/SOPT-Stamp-iOS/Projects/Modules/DSKit/Sources/Components/CustomNavigationBar.swift +++ b/SOPT-Stamp-iOS/Projects/Modules/DSKit/Sources/Components/CustomNavigationBar.swift @@ -139,6 +139,17 @@ extension CustomNavigationBar { titleLabel.setTypoStyle(font) return self } + + @discardableResult + public func setTitleButtonMenu(menuItems: [UIAction]) -> Self { + titleButton.menu = UIMenu(title: "", + image: nil, + identifier: nil, + options: [.displayInline], + children: menuItems) + titleButton.showsMenuAsPrimaryAction = true + return self + } } // MARK: - @objc diff --git a/SOPT-Stamp-iOS/Projects/Presentation/Sources/MissionListScene/VC/MissionListVC.swift b/SOPT-Stamp-iOS/Projects/Presentation/Sources/MissionListScene/VC/MissionListVC.swift index 15335bf5..f4372970 100644 --- a/SOPT-Stamp-iOS/Projects/Presentation/Sources/MissionListScene/VC/MissionListVC.swift +++ b/SOPT-Stamp-iOS/Projects/Presentation/Sources/MissionListScene/VC/MissionListVC.swift @@ -27,6 +27,8 @@ public class MissionListVC: UIViewController { } private var cancelBag = CancelBag() + private var missionTypeMenuSelected = CurrentValueSubject(.all) + lazy var dataSource: UICollectionViewDiffableDataSource! = nil // MARK: - UI Components @@ -37,6 +39,7 @@ public class MissionListVC: UIViewController { return CustomNavigationBar(self, type: .title) .setTitle("전체 미션") .setTitleTypoStyle(.h2) + .setTitleButtonMenu(menuItems: self.menuItems) case .ranking(let username, _, _): return CustomNavigationBar(self, type: .titleWithLeftButton) .setTitle(username) @@ -45,6 +48,20 @@ public class MissionListVC: UIViewController { } }() + private lazy var menuItems: [UIAction] = { + var menuItems: [UIAction] = [] + [("전체 미션", MissionListFetchType.all), + ("완료 미션", MissionListFetchType.complete), + ("미완료 미션", MissionListFetchType.incomplete)].forEach { menuTitle, fetchType in + menuItems.append(UIAction(title: menuTitle, + handler: { _ in + self.missionTypeMenuSelected.send(fetchType) + self.naviBar.setTitle(menuTitle) + })) + } + return menuItems + }() + private lazy var sentenceLabel: UILabel = { let lb = UILabel() if case let .ranking(_, sentence, _) = sceneType { @@ -148,10 +165,21 @@ extension MissionListVC { extension MissionListVC { private func bindViews() { + + if case MissionListSceneType.ranking = sceneType { + naviBar.rightButtonTapped + .asDriver() + .withUnretained(self) + .sink { owner, _ in + owner.pushToSettingVC() + }.store(in: self.cancelBag) + } + naviBar.rightButtonTapped .asDriver() - .sink { _ in - self.pushToSettingVC() + .withUnretained(self) + .sink { owner, _ in + owner.pushToSettingVC() }.store(in: self.cancelBag) rankingFloatingButton.publisher(for: .touchUpInside) @@ -164,7 +192,8 @@ extension MissionListVC { private func bindViewModels() { let input = MissionListViewModel.Input(viewDidLoad: Driver.just(()), - viewWillAppear: Driver.just(())) + viewWillAppear: Driver.just(()), + missionTypeSelected: missionTypeMenuSelected.asDriver()) let output = self.viewModel.transform(from: input, cancelBag: self.cancelBag) @@ -174,7 +203,7 @@ extension MissionListVC { self.applySnapshot(model: model) }.store(in: self.cancelBag) } - + private func pushToSettingVC() { let settingVC = self.factory.makeSettingVC() self.navigationController?.pushViewController(settingVC, animated: true) diff --git a/SOPT-Stamp-iOS/Projects/Presentation/Sources/MissionListScene/ViewModel/MissionListViewModel.swift b/SOPT-Stamp-iOS/Projects/Presentation/Sources/MissionListScene/ViewModel/MissionListViewModel.swift index 516d02b8..02c0b5f3 100644 --- a/SOPT-Stamp-iOS/Projects/Presentation/Sources/MissionListScene/ViewModel/MissionListViewModel.swift +++ b/SOPT-Stamp-iOS/Projects/Presentation/Sources/MissionListScene/ViewModel/MissionListViewModel.swift @@ -29,6 +29,7 @@ public class MissionListViewModel: ViewModelType { public struct Input { let viewDidLoad: Driver let viewWillAppear: Driver + let missionTypeSelected: Driver } // MARK: - Outputs @@ -61,6 +62,17 @@ extension MissionListViewModel { } }.store(in: cancelBag) + input.missionTypeSelected + .withUnretained(self) + .sink { owner, fetchType in + switch owner.missionListsceneType { + case .ranking(_, _, let userId): + owner.useCase.fetchOtherUserMissionList(type: fetchType, userId: userId) + default: + owner.useCase.fetchMissionList(type: fetchType) + } + }.store(in: cancelBag) + return output }