From 430d93576a10786efc40de405cb1c5adceccecfa Mon Sep 17 00:00:00 2001 From: yungu0010 Date: Wed, 2 Apr 2025 01:24:25 +0900 Subject: [PATCH 1/9] =?UTF-8?q?[Refactor]=20#529=20-=20HomeCalendarDetailV?= =?UTF-8?q?C=20=EB=A9=94=EB=AA=A8=EB=A6=AC=20=EB=88=84=EC=88=98=20?= =?UTF-8?q?=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CalendarDetailScene/VC/HomeCalendarDetailVC.swift | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/SOPT-iOS/Projects/Features/HomeFeature/Sources/CalendarDetailScene/VC/HomeCalendarDetailVC.swift b/SOPT-iOS/Projects/Features/HomeFeature/Sources/CalendarDetailScene/VC/HomeCalendarDetailVC.swift index 3625314a..8deb2634 100644 --- a/SOPT-iOS/Projects/Features/HomeFeature/Sources/CalendarDetailScene/VC/HomeCalendarDetailVC.swift +++ b/SOPT-iOS/Projects/Features/HomeFeature/Sources/CalendarDetailScene/VC/HomeCalendarDetailVC.swift @@ -26,8 +26,7 @@ final class HomeCalendarDetailVC: UIViewController, HomeCalendarDetailViewContro // MARK: UI Components - private lazy var naviBar = OPNavigationBar(self, - type: .oneLeftButton, + private lazy var naviBar = OPNavigationBar(type: .oneLeftButton, backgroundColor: DSKitAsset.Colors.semanticBackground.color) .addMiddleLabel(title: I18N.Home.CalendarDetail.navigationTitle, font: DSKitFontFamily.Suit.medium.font(size: 16)) @@ -142,7 +141,7 @@ extension HomeCalendarDetailVC { private func bindViewModels() { let input = HomeCalendarDetailViewModel.Input( viewDidLoad: Just(()).asDriver(), - naviBackButtonTap: self.naviBar.leftButtonTapped.asDriver(), + naviBackButtonTap: self.naviBar.leftButtonTapped, onAttendanceButtonTap: self.attendanceButton .publisher(for: .touchUpInside) .withUnretained(self) @@ -157,7 +156,7 @@ extension HomeCalendarDetailVC { .sink { owner, calendarDetailInfo in owner.calendarDetailInfo = calendarDetailInfo owner.collectionView.reloadData() - self.scrollToRecentSchedule() + owner.scrollToRecentSchedule() }.store(in: cancelBag) } From 9cffdfe3d17013ad90c8b366f8eca26b95aa3296 Mon Sep 17 00:00:00 2001 From: yungu0010 Date: Wed, 2 Apr 2025 01:46:48 +0900 Subject: [PATCH 2/9] =?UTF-8?q?[Refactor]=20#529=20-=20AppMyPageVC=20?= =?UTF-8?q?=EB=A9=94=EB=AA=A8=EB=A6=AC=20=EB=88=84=EC=88=98=20=ED=95=B4?= =?UTF-8?q?=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AppMyPageViewController.swift | 29 +++++++++---------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/SOPT-iOS/Projects/Features/AppMyPageFeature/Sources/AppMypageScene/AppMyPageViewController.swift b/SOPT-iOS/Projects/Features/AppMyPageFeature/Sources/AppMypageScene/AppMyPageViewController.swift index 8ee194d9..66fdcfad 100644 --- a/SOPT-iOS/Projects/Features/AppMyPageFeature/Sources/AppMypageScene/AppMyPageViewController.swift +++ b/SOPT-iOS/Projects/Features/AppMyPageFeature/Sources/AppMypageScene/AppMyPageViewController.swift @@ -49,7 +49,6 @@ public final class AppMyPageVC: UIViewController, MyPageViewControllable { // MARK: - Views private lazy var navigationBar = OPNavigationBar( - self, type: .oneLeftButton, backgroundColor: DSKitAsset.Colors.black100.color, ignoreLeftButtonAction: true @@ -227,27 +226,27 @@ extension AppMyPageVC { // TODO: - (@승호): 적절히 객체에 위임하기 private func addTabGestureOnListItems() { - self.servicePolicySectionGroup.addTapGestureRecognizer { - self.onPolicyItemTap?() + self.servicePolicySectionGroup.addTapGestureRecognizer { [weak self] in + self?.onPolicyItemTap?() } - self.termsOfUseListItem.addTapGestureRecognizer { - self.onTermsOfUseItemTap?() + self.termsOfUseListItem.addTapGestureRecognizer { [weak self] in + self?.onTermsOfUseItemTap?() } self.sendFeedbackListItem.addTapGestureRecognizer { openExternalLink(urlStr: ExternalURL.KakaoTalk.serviceProposal) } - self.alertListItem.addTapGestureRecognizer { - self.onAlertButtonTap?(UIApplication.openSettingsURLString) + self.alertListItem.addTapGestureRecognizer { [weak self] in + self?.onAlertButtonTap?(UIApplication.openSettingsURLString) } - self.editOnelineSentenceListItem.addTapGestureRecognizer { - self.onEditOnelineSentenceItemTap?() + self.editOnelineSentenceListItem.addTapGestureRecognizer { [weak self] in + self?.onEditOnelineSentenceItemTap?() } - self.resetStampListItem.addTapGestureRecognizer { + self.resetStampListItem.addTapGestureRecognizer { [weak self] in AlertUtils.presentAlertVC( type: .titleDescription, theme: .main, @@ -261,7 +260,7 @@ extension AppMyPageVC { ) } - self.logoutListItem.addTapGestureRecognizer { + self.logoutListItem.addTapGestureRecognizer { [weak self] in AlertUtils.presentAlertVC( type: .titleDescription, theme: .main, @@ -275,12 +274,12 @@ extension AppMyPageVC { ) } - self.withDrawalListItem.addTapGestureRecognizer { - self.onWithdrawalItemTap?(self.userType) + self.withDrawalListItem.addTapGestureRecognizer { [weak self] in + self?.onWithdrawalItemTap?(self?.userType ?? .visitor) } - self.loginListItem.addTapGestureRecognizer { - self.onShowLogin?() + self.loginListItem.addTapGestureRecognizer { [weak self] in + self?.onShowLogin?() } } } From 947cdcffdc919e71fc7d2085c5ebe3cf2386339c Mon Sep 17 00:00:00 2001 From: yungu0010 Date: Wed, 2 Apr 2025 02:53:48 +0900 Subject: [PATCH 3/9] =?UTF-8?q?[Refactor]=20#529=20-=20MissionListVC=20?= =?UTF-8?q?=ED=81=B4=EB=A1=9C=EC=A0=80=20=EB=A9=94=EB=AA=A8=EB=A6=AC=20?= =?UTF-8?q?=EB=88=84=EC=88=98=20=EB=B0=A9=EC=A7=80=20-=20menuItems=20?= =?UTF-8?q?=ED=81=B4=EB=A1=9C=EC=A0=80=EC=97=90=EC=84=9C=20self=20?= =?UTF-8?q?=EA=B0=95=ED=95=9C=EC=B0=B8=EC=A1=B0=20->=20[weak=20self]?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=80=EA=B2=BD=20-=20UICollectionViewCompositio?= =?UTF-8?q?nalLayout=EC=97=90=EC=84=9C=20self=20=EA=B0=95=ED=95=9C=20?= =?UTF-8?q?=EC=B0=B8=EC=A1=B0=20->=20[weak=20self]=EB=A1=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MissionListCompositionalLayout.swift | 6 +++--- .../MissionListScene/VC/MissionListVC.swift | 19 ++++++++++++++----- .../ViewModel/MissionListViewModel.swift | 2 +- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/SOPT-iOS/Projects/Features/StampFeature/Sources/MissionListScene/CollectionView/MissionListCompositionalLayout.swift b/SOPT-iOS/Projects/Features/StampFeature/Sources/MissionListScene/CollectionView/MissionListCompositionalLayout.swift index f402f89a..a4a87d7c 100644 --- a/SOPT-iOS/Projects/Features/StampFeature/Sources/MissionListScene/CollectionView/MissionListCompositionalLayout.swift +++ b/SOPT-iOS/Projects/Features/StampFeature/Sources/MissionListScene/CollectionView/MissionListCompositionalLayout.swift @@ -12,10 +12,10 @@ extension MissionListVC { static let standardWidth = UIScreen.main.bounds.width - 40.adjusted func createLayout() -> UICollectionViewLayout { - return UICollectionViewCompositionalLayout { (sectionIndex, layoutEnvironment) -> NSCollectionLayoutSection? in + return UICollectionViewCompositionalLayout { [weak self] (sectionIndex, layoutEnvironment) -> NSCollectionLayoutSection? in switch MissionListSection.type(sectionIndex) { - case .sentence: return self.createSentenceSection() - case .missionList: return self.createMissionListSection() + case .sentence: return self?.createSentenceSection() + case .missionList: return self?.createMissionListSection() } } } diff --git a/SOPT-iOS/Projects/Features/StampFeature/Sources/MissionListScene/VC/MissionListVC.swift b/SOPT-iOS/Projects/Features/StampFeature/Sources/MissionListScene/VC/MissionListVC.swift index 6ac29184..63a09de9 100644 --- a/SOPT-iOS/Projects/Features/StampFeature/Sources/MissionListScene/VC/MissionListVC.swift +++ b/SOPT-iOS/Projects/Features/StampFeature/Sources/MissionListScene/VC/MissionListVC.swift @@ -23,7 +23,7 @@ public class MissionListVC: UIViewController, MissionListViewControllable { // MARK: - Properties - public var viewModel: MissionListViewModel! + public var viewModel: MissionListViewModel public var sceneType: MissionListSceneType { return self.viewModel.missionListsceneType } @@ -69,11 +69,11 @@ public class MissionListVC: UIViewController, MissionListViewControllable { var menuItems: [UIAction] = [] [("전체 미션", MissionListFetchType.all), ("완료 미션", MissionListFetchType.complete), - ("미완료 미션", MissionListFetchType.incomplete)].forEach { menuTitle, fetchType in + ("미완료 미션", MissionListFetchType.incomplete)].forEach { [weak self] menuTitle, fetchType in menuItems.append(UIAction(title: menuTitle, - handler: { _ in - self.missionTypeMenuSelected.send(fetchType) - self.naviBar.setTitle(menuTitle) + handler: { [weak self] _ in + self?.missionTypeMenuSelected.send(fetchType) + self?.naviBar.setTitle(menuTitle) })) } return menuItems @@ -164,6 +164,15 @@ public class MissionListVC: UIViewController, MissionListViewControllable { self.viewWillAppear.send(()) self.navigationController?.interactivePopGestureRecognizer?.delegate = self } + + init(viewModel: MissionListViewModel) { + self.viewModel = viewModel + super.init(nibName: nil, bundle: nil) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } } // MARK: - UI & Layouts diff --git a/SOPT-iOS/Projects/Features/StampFeature/Sources/MissionListScene/ViewModel/MissionListViewModel.swift b/SOPT-iOS/Projects/Features/StampFeature/Sources/MissionListScene/ViewModel/MissionListViewModel.swift index eb8cdeb1..05678093 100644 --- a/SOPT-iOS/Projects/Features/StampFeature/Sources/MissionListScene/ViewModel/MissionListViewModel.swift +++ b/SOPT-iOS/Projects/Features/StampFeature/Sources/MissionListScene/ViewModel/MissionListViewModel.swift @@ -101,7 +101,7 @@ extension MissionListViewModel { .asDriver() .sink { usersActivateGenerationStatus in output.usersActivateGenerationStatus = usersActivateGenerationStatus - }.store(in: self.cancelBag) + }.store(in: cancelBag) self.useCase.errorOccurred .asDriver() From 2943246506f9e309290c3208bf1e679bc7f1551c Mon Sep 17 00:00:00 2001 From: yungu0010 Date: Wed, 2 Apr 2025 02:55:59 +0900 Subject: [PATCH 4/9] =?UTF-8?q?[Refactor]=20#529=20-=20missionListVC?= =?UTF-8?q?=EC=97=90=20viewModel=20=EC=83=9D=EC=84=B1=EC=9E=90=20=EC=A3=BC?= =?UTF-8?q?=EC=9E=85=20=EB=B0=A9=EC=8B=9D=EC=9C=BC=EB=A1=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../StampFeature/Sources/Coordinator/StampBuilder.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SOPT-iOS/Projects/Features/StampFeature/Sources/Coordinator/StampBuilder.swift b/SOPT-iOS/Projects/Features/StampFeature/Sources/Coordinator/StampBuilder.swift index e11c61de..acb1f921 100644 --- a/SOPT-iOS/Projects/Features/StampFeature/Sources/Coordinator/StampBuilder.swift +++ b/SOPT-iOS/Projects/Features/StampFeature/Sources/Coordinator/StampBuilder.swift @@ -23,7 +23,7 @@ extension StampBuilder: StampFeatureViewBuildable { public func makeMissionListVC(sceneType: MissionListSceneType) -> MissionListViewControllable { let useCase = DefaultMissionListUseCase(repository: missionListRepository) let viewModel = MissionListViewModel(useCase: useCase, sceneType: sceneType) - let missionListVC = MissionListVC() + let missionListVC = MissionListVC(viewModel: viewModel) missionListVC.viewModel = viewModel return missionListVC } From 6d3897ae1ee8b1bbef6972a6c2874925e61e7085 Mon Sep 17 00:00:00 2001 From: yungu0010 Date: Wed, 2 Apr 2025 03:04:16 +0900 Subject: [PATCH 5/9] =?UTF-8?q?[Fix]=20#529=20-=20OPNavigatoin=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1=EC=9E=90=20=EC=9B=90=EB=9E=98=EB=8C=80=EB=A1=9C=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../{AppMyPageViewController.swift => AppMyPageVC.swift} | 1 + .../Sources/CalendarDetailScene/VC/HomeCalendarDetailVC.swift | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) rename SOPT-iOS/Projects/Features/AppMyPageFeature/Sources/AppMypageScene/{AppMyPageViewController.swift => AppMyPageVC.swift} (99%) diff --git a/SOPT-iOS/Projects/Features/AppMyPageFeature/Sources/AppMypageScene/AppMyPageViewController.swift b/SOPT-iOS/Projects/Features/AppMyPageFeature/Sources/AppMypageScene/AppMyPageVC.swift similarity index 99% rename from SOPT-iOS/Projects/Features/AppMyPageFeature/Sources/AppMypageScene/AppMyPageViewController.swift rename to SOPT-iOS/Projects/Features/AppMyPageFeature/Sources/AppMypageScene/AppMyPageVC.swift index 66fdcfad..3800779f 100644 --- a/SOPT-iOS/Projects/Features/AppMyPageFeature/Sources/AppMypageScene/AppMyPageViewController.swift +++ b/SOPT-iOS/Projects/Features/AppMyPageFeature/Sources/AppMypageScene/AppMyPageVC.swift @@ -49,6 +49,7 @@ public final class AppMyPageVC: UIViewController, MyPageViewControllable { // MARK: - Views private lazy var navigationBar = OPNavigationBar( + self, type: .oneLeftButton, backgroundColor: DSKitAsset.Colors.black100.color, ignoreLeftButtonAction: true diff --git a/SOPT-iOS/Projects/Features/HomeFeature/Sources/CalendarDetailScene/VC/HomeCalendarDetailVC.swift b/SOPT-iOS/Projects/Features/HomeFeature/Sources/CalendarDetailScene/VC/HomeCalendarDetailVC.swift index 8deb2634..d28daac5 100644 --- a/SOPT-iOS/Projects/Features/HomeFeature/Sources/CalendarDetailScene/VC/HomeCalendarDetailVC.swift +++ b/SOPT-iOS/Projects/Features/HomeFeature/Sources/CalendarDetailScene/VC/HomeCalendarDetailVC.swift @@ -26,7 +26,7 @@ final class HomeCalendarDetailVC: UIViewController, HomeCalendarDetailViewContro // MARK: UI Components - private lazy var naviBar = OPNavigationBar(type: .oneLeftButton, + private lazy var naviBar = OPNavigationBar(self, type: .oneLeftButton, backgroundColor: DSKitAsset.Colors.semanticBackground.color) .addMiddleLabel(title: I18N.Home.CalendarDetail.navigationTitle, font: DSKitFontFamily.Suit.medium.font(size: 16)) From 30788f52668f7231bacaba7bcdf5c4ab8b15dd81 Mon Sep 17 00:00:00 2001 From: yungu0010 Date: Wed, 2 Apr 2025 03:08:19 +0900 Subject: [PATCH 6/9] =?UTF-8?q?[Del]=20#529=20-=20=EB=B6=88=ED=95=84?= =?UTF-8?q?=EC=9A=94=ED=95=9C=20import=EB=AC=B8=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../TabBarFeature/Sources/ViewModel/TabBarViewModel.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/SOPT-iOS/Projects/Features/TabBarFeature/Sources/ViewModel/TabBarViewModel.swift b/SOPT-iOS/Projects/Features/TabBarFeature/Sources/ViewModel/TabBarViewModel.swift index ee91021b..27fd39d7 100644 --- a/SOPT-iOS/Projects/Features/TabBarFeature/Sources/ViewModel/TabBarViewModel.swift +++ b/SOPT-iOS/Projects/Features/TabBarFeature/Sources/ViewModel/TabBarViewModel.swift @@ -10,7 +10,6 @@ import Foundation import Combine import Core -import TabBarFeatureInterface final public class TabBarViewModel: TabBarViewModelType { From ac9889a4ee86382d23c35b4bcaf1e9a366c4699b Mon Sep 17 00:00:00 2001 From: yungu0010 Date: Wed, 2 Apr 2025 03:12:09 +0900 Subject: [PATCH 7/9] =?UTF-8?q?[Chore]=20#529=20-=20missionListVC=20?= =?UTF-8?q?=ED=83=AD=20=EA=B0=84=EA=B2=A9=204=EB=A1=9C=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MissionListScene/VC/MissionListVC.swift | 806 +++++++++--------- 1 file changed, 403 insertions(+), 403 deletions(-) diff --git a/SOPT-iOS/Projects/Features/StampFeature/Sources/MissionListScene/VC/MissionListVC.swift b/SOPT-iOS/Projects/Features/StampFeature/Sources/MissionListScene/VC/MissionListVC.swift index 63a09de9..0e5b0fb7 100644 --- a/SOPT-iOS/Projects/Features/StampFeature/Sources/MissionListScene/VC/MissionListVC.swift +++ b/SOPT-iOS/Projects/Features/StampFeature/Sources/MissionListScene/VC/MissionListVC.swift @@ -20,150 +20,150 @@ import StampFeatureInterface import BaseFeatureDependency public class MissionListVC: UIViewController, MissionListViewControllable { - - // MARK: - Properties - - public var viewModel: MissionListViewModel - public var sceneType: MissionListSceneType { - return self.viewModel.missionListsceneType - } - private var cancelBag = CancelBag() - - private var missionTypeMenuSelected = CurrentValueSubject(.all) - private var viewWillAppear = PassthroughSubject() - private let swipeHandler = PassthroughSubject() - - lazy var dataSource: UICollectionViewDiffableDataSource! = nil - - // MARK: - MissionListCoordinatable - - public var onSwiped: (() -> Void)? - public var onNaviBackTap: (() -> Void)? - public var onPartRankingButtonTap: ((RankingViewType) -> Void)? - public var onCurrentGenerationRankingButtonTap: ((RankingViewType) -> Void)? - public var onGuideTap: (() -> Void)? - public var onCellTap: ((MissionListModel, String?) -> Void)? - public var onReportButtonTap: (() -> Void)? - - private var usersActiveGenerationStatus: UsersActiveGenerationStatusViewResponse? - - // MARK: - UI Components - - lazy var naviBar: STNavigationBar = { - switch sceneType { - case .default: - return STNavigationBar(type: .title) - .setTitle("전체 미션") - .setTitleTypoStyle(.SoptampFont.h2) - .setTitleButtonMenu(menuItems: self.menuItems) - .addLeftButtonToTitleMenu() - case .ranking(let username, _): - return STNavigationBar(type: .titleWithLeftButton) - .setTitle(username) - .setRightButton(.none) - .setTitleTypoStyle(.SoptampFont.h2) + + // MARK: - Properties + + public var viewModel: MissionListViewModel + public var sceneType: MissionListSceneType { + return self.viewModel.missionListsceneType } - }() - - private lazy var menuItems: [UIAction] = { - var menuItems: [UIAction] = [] - [("전체 미션", MissionListFetchType.all), - ("완료 미션", MissionListFetchType.complete), - ("미완료 미션", MissionListFetchType.incomplete)].forEach { [weak self] menuTitle, fetchType in - menuItems.append(UIAction(title: menuTitle, - handler: { [weak self] _ in - self?.missionTypeMenuSelected.send(fetchType) - self?.naviBar.setTitle(menuTitle) - })) + private var cancelBag = CancelBag() + + private var missionTypeMenuSelected = CurrentValueSubject(.all) + private var viewWillAppear = PassthroughSubject() + private let swipeHandler = PassthroughSubject() + + lazy var dataSource: UICollectionViewDiffableDataSource! = nil + + // MARK: - MissionListCoordinatable + + public var onSwiped: (() -> Void)? + public var onNaviBackTap: (() -> Void)? + public var onPartRankingButtonTap: ((RankingViewType) -> Void)? + public var onCurrentGenerationRankingButtonTap: ((RankingViewType) -> Void)? + public var onGuideTap: (() -> Void)? + public var onCellTap: ((MissionListModel, String?) -> Void)? + public var onReportButtonTap: (() -> Void)? + + private var usersActiveGenerationStatus: UsersActiveGenerationStatusViewResponse? + + // MARK: - UI Components + + lazy var naviBar: STNavigationBar = { + switch sceneType { + case .default: + return STNavigationBar(type: .title) + .setTitle("전체 미션") + .setTitleTypoStyle(.SoptampFont.h2) + .setTitleButtonMenu(menuItems: self.menuItems) + .addLeftButtonToTitleMenu() + case .ranking(let username, _): + return STNavigationBar(type: .titleWithLeftButton) + .setTitle(username) + .setRightButton(.none) + .setTitleTypoStyle(.SoptampFont.h2) + } + }() + + private lazy var menuItems: [UIAction] = { + var menuItems: [UIAction] = [] + [("전체 미션", MissionListFetchType.all), + ("완료 미션", MissionListFetchType.complete), + ("미완료 미션", MissionListFetchType.incomplete)].forEach { [weak self] menuTitle, fetchType in + menuItems.append(UIAction(title: menuTitle, + handler: { [weak self] _ in + self?.missionTypeMenuSelected.send(fetchType) + self?.naviBar.setTitle(menuTitle) + })) + } + return menuItems + }() + + private lazy var sentenceLabel: SentencePaddingLabel = { + let lb = SentencePaddingLabel() + if case let .ranking(_, sentence) = sceneType { + lb.text = sentence + } + lb.setTypoStyle(.SoptampFont.subtitle1) + lb.textColor = DSKitAsset.Colors.soptampGray900.color + lb.numberOfLines = 2 + lb.textAlignment = .center + lb.backgroundColor = DSKitAsset.Colors.soptampPurple100.color + lb.layer.cornerRadius = 9.adjustedH + lb.clipsToBounds = true + lb.setCharacterSpacing(0) + return lb + }() + + private lazy var missionListCollectionView: UICollectionView = { + let cv = UICollectionView(frame: .zero, collectionViewLayout: self.createLayout()) + cv.showsVerticalScrollIndicator = true + cv.backgroundColor = .white + cv.bounces = false + return cv + }() + + private let missionListEmptyView = MissionListEmptyView() + + private lazy var floatingButtonStackView = UIStackView(frame: self.view.frame).then { + $0.axis = .horizontal + $0.spacing = 0.f } - return menuItems - }() - - private lazy var sentenceLabel: SentencePaddingLabel = { - let lb = SentencePaddingLabel() - if case let .ranking(_, sentence) = sceneType { - lb.text = sentence + + private lazy var currentGenerationRankFloatingButton: UIButton = { + let bt = UIButton() + bt.layer.maskedCorners = [.layerMinXMinYCorner, .layerMinXMaxYCorner] + bt.layer.cornerRadius = 27.adjustedH + bt.setBackgroundColor(DSKitAsset.Colors.soptampPurple300.color, for: .normal) + bt.setBackgroundColor(DSKitAsset.Colors.soptampPurple300.color.withAlphaComponent(0.2), for: .selected) + bt.setImage(DSKitAsset.Assets.icTrophy.image.withRenderingMode(.alwaysTemplate), for: .normal) + bt.setImage(DSKitAsset.Assets.icTrophy.image.withRenderingMode(.alwaysTemplate), for: .highlighted) + bt.tintColor = .white + bt.titleLabel?.setTypoStyle(.SoptampFont.h2) + bt.contentEdgeInsets = UIEdgeInsets(top: 0, left: -15, bottom: 0, right: 0) + bt.titleEdgeInsets = UIEdgeInsets(top: 0, left: 10, bottom: 0, right: 0) + return bt + }() + + private lazy var partRankingFloatingButton: UIButton = { + let bt = UIButton() + bt.layer.maskedCorners = [.layerMaxXMinYCorner, .layerMaxXMaxYCorner] + bt.layer.cornerRadius = 27.adjustedH + bt.setBackgroundColor(DSKitAsset.Colors.soptampPink300.color, for: .normal) + bt.setBackgroundColor(DSKitAsset.Colors.soptampPink300.color.withAlphaComponent(0.2), for: .selected) + bt.setImage(DSKitAsset.Assets.icTrophy.image.withRenderingMode(.alwaysTemplate), for: .normal) + bt.setImage(DSKitAsset.Assets.icTrophy.image.withRenderingMode(.alwaysTemplate), for: .highlighted) + bt.tintColor = .white + bt.titleLabel?.setTypoStyle(.SoptampFont.h2) + let attributedStr = NSMutableAttributedString(string: "파트별 랭킹") + let style = NSMutableParagraphStyle() + attributedStr.addAttribute(NSAttributedString.Key.kern, value: 0, range: NSMakeRange(0, attributedStr.length)) + attributedStr.addAttribute(NSAttributedString.Key.foregroundColor, value: UIColor.white, range: NSMakeRange(0, attributedStr.length)) + bt.setAttributedTitle(attributedStr, for: .normal) + bt.contentEdgeInsets = UIEdgeInsets(top: 0, left: -15, bottom: 0, right: 0) + bt.titleEdgeInsets = UIEdgeInsets(top: 0, left: 10, bottom: 0, right: 0) + return bt + }() + + // MARK: - View Life Cycle + + public override func viewDidLoad() { + super.viewDidLoad() + self.setUI() + self.setLayout() + self.setDelegate() + self.setGesture() + self.registerCells() + self.setDataSource() + self.bindViews() + self.bindViewModels() + } + + public override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + self.viewWillAppear.send(()) + self.navigationController?.interactivePopGestureRecognizer?.delegate = self } - lb.setTypoStyle(.SoptampFont.subtitle1) - lb.textColor = DSKitAsset.Colors.soptampGray900.color - lb.numberOfLines = 2 - lb.textAlignment = .center - lb.backgroundColor = DSKitAsset.Colors.soptampPurple100.color - lb.layer.cornerRadius = 9.adjustedH - lb.clipsToBounds = true - lb.setCharacterSpacing(0) - return lb - }() - - private lazy var missionListCollectionView: UICollectionView = { - let cv = UICollectionView(frame: .zero, collectionViewLayout: self.createLayout()) - cv.showsVerticalScrollIndicator = true - cv.backgroundColor = .white - cv.bounces = false - return cv - }() - - private let missionListEmptyView = MissionListEmptyView() - - private lazy var floatingButtonStackView = UIStackView(frame: self.view.frame).then { - $0.axis = .horizontal - $0.spacing = 0.f - } - - private lazy var currentGenerationRankFloatingButton: UIButton = { - let bt = UIButton() - bt.layer.maskedCorners = [.layerMinXMinYCorner, .layerMinXMaxYCorner] - bt.layer.cornerRadius = 27.adjustedH - bt.setBackgroundColor(DSKitAsset.Colors.soptampPurple300.color, for: .normal) - bt.setBackgroundColor(DSKitAsset.Colors.soptampPurple300.color.withAlphaComponent(0.2), for: .selected) - bt.setImage(DSKitAsset.Assets.icTrophy.image.withRenderingMode(.alwaysTemplate), for: .normal) - bt.setImage(DSKitAsset.Assets.icTrophy.image.withRenderingMode(.alwaysTemplate), for: .highlighted) - bt.tintColor = .white - bt.titleLabel?.setTypoStyle(.SoptampFont.h2) - bt.contentEdgeInsets = UIEdgeInsets(top: 0, left: -15, bottom: 0, right: 0) - bt.titleEdgeInsets = UIEdgeInsets(top: 0, left: 10, bottom: 0, right: 0) - return bt - }() - - private lazy var partRankingFloatingButton: UIButton = { - let bt = UIButton() - bt.layer.maskedCorners = [.layerMaxXMinYCorner, .layerMaxXMaxYCorner] - bt.layer.cornerRadius = 27.adjustedH - bt.setBackgroundColor(DSKitAsset.Colors.soptampPink300.color, for: .normal) - bt.setBackgroundColor(DSKitAsset.Colors.soptampPink300.color.withAlphaComponent(0.2), for: .selected) - bt.setImage(DSKitAsset.Assets.icTrophy.image.withRenderingMode(.alwaysTemplate), for: .normal) - bt.setImage(DSKitAsset.Assets.icTrophy.image.withRenderingMode(.alwaysTemplate), for: .highlighted) - bt.tintColor = .white - bt.titleLabel?.setTypoStyle(.SoptampFont.h2) - let attributedStr = NSMutableAttributedString(string: "파트별 랭킹") - let style = NSMutableParagraphStyle() - attributedStr.addAttribute(NSAttributedString.Key.kern, value: 0, range: NSMakeRange(0, attributedStr.length)) - attributedStr.addAttribute(NSAttributedString.Key.foregroundColor, value: UIColor.white, range: NSMakeRange(0, attributedStr.length)) - bt.setAttributedTitle(attributedStr, for: .normal) - bt.contentEdgeInsets = UIEdgeInsets(top: 0, left: -15, bottom: 0, right: 0) - bt.titleEdgeInsets = UIEdgeInsets(top: 0, left: 10, bottom: 0, right: 0) - return bt - }() - - // MARK: - View Life Cycle - - public override func viewDidLoad() { - super.viewDidLoad() - self.setUI() - self.setLayout() - self.setDelegate() - self.setGesture() - self.registerCells() - self.setDataSource() - self.bindViews() - self.bindViewModels() - } - - public override func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) - self.viewWillAppear.send(()) - self.navigationController?.interactivePopGestureRecognizer?.delegate = self - } init(viewModel: MissionListViewModel) { self.viewModel = viewModel @@ -178,290 +178,290 @@ public class MissionListVC: UIViewController, MissionListViewControllable { // MARK: - UI & Layouts extension MissionListVC { - - private func setUI() { - self.view.backgroundColor = .white - self.navigationController?.isNavigationBarHidden = true - } - - private func setLayout() { - self.view.addSubviews(naviBar, missionListCollectionView) - - naviBar.snp.makeConstraints { make in - make.leading.top.trailing.equalTo(view.safeAreaLayoutGuide) - } - - missionListCollectionView.snp.makeConstraints { make in - make.top.equalTo(naviBar.snp.bottom).offset(20.adjustedH) - make.leading.trailing.equalToSuperview() - make.bottom.equalToSuperview() + + private func setUI() { + self.view.backgroundColor = .white + self.navigationController?.isNavigationBarHidden = true } - - switch sceneType { - case .default: - self.view.addSubview(self.floatingButtonStackView) - - self.floatingButtonStackView.snp.makeConstraints { make in - make.bottom.equalTo(view.safeAreaLayoutGuide).offset(-18.adjustedH) - make.centerX.equalToSuperview() - } - - self.partRankingFloatingButton.snp.makeConstraints { - $0.width.equalTo(143.adjusted) - $0.height.equalTo(54.adjustedH) - } - - self.currentGenerationRankFloatingButton.snp.makeConstraints { - $0.width.equalTo(143.adjusted) - $0.height.equalTo(54.adjustedH) - } - - case .ranking: - self.view.addSubview(sentenceLabel) - - sentenceLabel.snp.makeConstraints { make in - make.top.equalTo(naviBar.snp.bottom).offset(10.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() - } + + private func setLayout() { + self.view.addSubviews(naviBar, missionListCollectionView) + + naviBar.snp.makeConstraints { make in + make.leading.top.trailing.equalTo(view.safeAreaLayoutGuide) + } + + missionListCollectionView.snp.makeConstraints { make in + make.top.equalTo(naviBar.snp.bottom).offset(20.adjustedH) + make.leading.trailing.equalToSuperview() + make.bottom.equalToSuperview() + } + + switch sceneType { + case .default: + self.view.addSubview(self.floatingButtonStackView) + + self.floatingButtonStackView.snp.makeConstraints { make in + make.bottom.equalTo(view.safeAreaLayoutGuide).offset(-18.adjustedH) + make.centerX.equalToSuperview() + } + + self.partRankingFloatingButton.snp.makeConstraints { + $0.width.equalTo(143.adjusted) + $0.height.equalTo(54.adjustedH) + } + + self.currentGenerationRankFloatingButton.snp.makeConstraints { + $0.width.equalTo(143.adjusted) + $0.height.equalTo(54.adjustedH) + } + + case .ranking: + self.view.addSubview(sentenceLabel) + + sentenceLabel.snp.makeConstraints { make in + make.top.equalTo(naviBar.snp.bottom).offset(10.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() + } + } } - } } // MARK: - Methods extension MissionListVC { - private func bindViews() { - - naviBar.rightButtonTapped - .asDriver() - .withUnretained(self) - .sink { owner, _ in - owner.onGuideTap?() - }.store(in: self.cancelBag) - - naviBar.leftButtonTapped - .withUnretained(self) - .sink { owner, _ in - owner.onNaviBackTap?() - }.store(in: self.cancelBag) - - partRankingFloatingButton.publisher(for: .touchUpInside) - .withUnretained(self) - .sink { owner, _ in - owner.onPartRankingButtonTap?(.partRanking) - }.store(in: self.cancelBag) - - currentGenerationRankFloatingButton.publisher(for: .touchUpInside) - .withUnretained(self) - .sink { owner, _ in - guard let usersActiveGenerationStatus = owner.usersActiveGenerationStatus else { return } - - owner.onCurrentGenerationRankingButtonTap?(.currentGeneration(info: usersActiveGenerationStatus)) - }.store(in: self.cancelBag) - - swipeHandler - .first() - .withUnretained(self) - .sink { owner, _ in - owner.onSwiped?() - }.store(in: self.cancelBag) - } - - private func bindViewModels() { - let input = MissionListViewModel.Input( - viewDidLoad: Driver.just(()), - viewWillAppear: viewWillAppear.asDriver(), - missionTypeSelected: missionTypeMenuSelected - ) - - let output = self.viewModel.transform(from: input, cancelBag: self.cancelBag) - - naviBar.reportButtonTapped - .withUnretained(self) - .sink { owner, _ in - owner.onReportButtonTap?() - }.store(in: cancelBag) - - output.$missionListModel - .compactMap { $0 } - .sink { [weak self] model in - self?.setCollectionView(model: model) - }.store(in: self.cancelBag) - - output.$usersActivateGenerationStatus - .compactMap { $0 } - .sink { [weak self] generationStatus in - guard generationStatus.status == .ACTIVE else { return } - - self?.usersActiveGenerationStatus = generationStatus - self?.remakeButtonConstraint() - self?.configureCurrentGenerationButton(with: String(describing: generationStatus.currentGeneration)) - }.store(in: self.cancelBag) - - output.needNetworkAlert - .withUnretained(self) - .sink { owner, _ in - owner.showNetworkAlert() - }.store(in: self.cancelBag) - } + private func bindViews() { + + naviBar.rightButtonTapped + .asDriver() + .withUnretained(self) + .sink { owner, _ in + owner.onGuideTap?() + }.store(in: self.cancelBag) + + naviBar.leftButtonTapped + .withUnretained(self) + .sink { owner, _ in + owner.onNaviBackTap?() + }.store(in: self.cancelBag) + + partRankingFloatingButton.publisher(for: .touchUpInside) + .withUnretained(self) + .sink { owner, _ in + owner.onPartRankingButtonTap?(.partRanking) + }.store(in: self.cancelBag) + + currentGenerationRankFloatingButton.publisher(for: .touchUpInside) + .withUnretained(self) + .sink { owner, _ in + guard let usersActiveGenerationStatus = owner.usersActiveGenerationStatus else { return } + + owner.onCurrentGenerationRankingButtonTap?(.currentGeneration(info: usersActiveGenerationStatus)) + }.store(in: self.cancelBag) + + swipeHandler + .first() + .withUnretained(self) + .sink { owner, _ in + owner.onSwiped?() + }.store(in: self.cancelBag) + } + + private func bindViewModels() { + let input = MissionListViewModel.Input( + viewDidLoad: Driver.just(()), + viewWillAppear: viewWillAppear.asDriver(), + missionTypeSelected: missionTypeMenuSelected + ) + + let output = self.viewModel.transform(from: input, cancelBag: self.cancelBag) + + naviBar.reportButtonTapped + .withUnretained(self) + .sink { owner, _ in + owner.onReportButtonTap?() + }.store(in: cancelBag) + + output.$missionListModel + .compactMap { $0 } + .sink { [weak self] model in + self?.setCollectionView(model: model) + }.store(in: self.cancelBag) + + output.$usersActivateGenerationStatus + .compactMap { $0 } + .sink { [weak self] generationStatus in + guard generationStatus.status == .ACTIVE else { return } + + self?.usersActiveGenerationStatus = generationStatus + self?.remakeButtonConstraint() + self?.configureCurrentGenerationButton(with: String(describing: generationStatus.currentGeneration)) + }.store(in: self.cancelBag) + + output.needNetworkAlert + .withUnretained(self) + .sink { owner, _ in + owner.showNetworkAlert() + }.store(in: self.cancelBag) + } } extension MissionListVC { - - private func setDelegate() { - missionListCollectionView.delegate = self - } - - private func setGesture() { - self.setGesture(to: missionListCollectionView) - self.setGesture(to: missionListEmptyView) - } - - private func setGesture(to view: UIView) { - let swipeGesture = UIPanGestureRecognizer(target: self, action: #selector(swipeBack(_:))) - swipeGesture.delegate = self - view.addGestureRecognizer(swipeGesture) - } - - @objc - private func swipeBack(_ sender: UIPanGestureRecognizer) { - let velocity = sender.velocity(in: self.view) - let velocityMinimum: CGFloat = 1000 - guard let navigation = self.navigationController else { return } - let isScrollY: Bool = abs(velocity.x) > abs(velocity.y) + 200 - let isNotRootView = navigation.viewControllers.count >= 2 - if velocity.x >= velocityMinimum - && isNotRootView - && isScrollY { - self.missionListCollectionView.isScrollEnabled = false - swipeHandler.send(()) + + private func setDelegate() { + missionListCollectionView.delegate = self } - } - - private func registerCells() { - MissionListCVC.register(target: missionListCollectionView) - } - - private func setDataSource() { - dataSource = UICollectionViewDiffableDataSource(collectionView: missionListCollectionView, cellProvider: { collectionView, indexPath, itemIdentifier in - switch MissionListSection.type(indexPath.section) { - case .sentence: - guard let sentenceCell = collectionView.dequeueReusableCell(withReuseIdentifier: MissionListCVC.className, for: indexPath) as? MissionListCVC else { return UICollectionViewCell() } - return sentenceCell - - case .missionList: - guard let missionListCell = collectionView.dequeueReusableCell(withReuseIdentifier: MissionListCVC.className, for: indexPath) as? MissionListCVC else { return UICollectionViewCell() } - let missionListModel = itemIdentifier - missionListCell.initCellType = missionListModel.toCellType() - missionListCell.setData(model: missionListModel) - return missionListCell - } - }) - } - - func setCollectionView(model: [MissionListModel]) { - if model.isEmpty { - self.missionListCollectionView.isHidden = true - self.missionListEmptyView.isHidden = false - self.setEmptyView() - } else { - self.missionListCollectionView.isHidden = false - self.missionListEmptyView.isHidden = true - self.applySnapshot(model: model) + + private func setGesture() { + self.setGesture(to: missionListCollectionView) + self.setGesture(to: missionListEmptyView) } - } - - private func setEmptyView() { - missionListEmptyView.snp.removeConstraints() - missionListEmptyView.removeFromSuperview() - self.view.addSubviews(missionListEmptyView) - missionListEmptyView.snp.makeConstraints { make in - make.top.equalTo(naviBar.snp.bottom).offset(145.adjustedH) - make.centerX.equalToSuperview() - make.width.equalToSuperview() - make.bottom.equalToSuperview().priority(.low) + + private func setGesture(to view: UIView) { + let swipeGesture = UIPanGestureRecognizer(target: self, action: #selector(swipeBack(_:))) + swipeGesture.delegate = self + view.addGestureRecognizer(swipeGesture) } - bringRankingFloatingButtonToFront() - } - - private func bringRankingFloatingButtonToFront() { - self.view.subviews.forEach { view in - if view == self.partRankingFloatingButton { - self.view.bringSubviewToFront(partRankingFloatingButton) - } + + @objc + private func swipeBack(_ sender: UIPanGestureRecognizer) { + let velocity = sender.velocity(in: self.view) + let velocityMinimum: CGFloat = 1000 + guard let navigation = self.navigationController else { return } + let isScrollY: Bool = abs(velocity.x) > abs(velocity.y) + 200 + let isNotRootView = navigation.viewControllers.count >= 2 + if velocity.x >= velocityMinimum + && isNotRootView + && isScrollY { + self.missionListCollectionView.isScrollEnabled = false + swipeHandler.send(()) + } + } + + private func registerCells() { + MissionListCVC.register(target: missionListCollectionView) + } + + private func setDataSource() { + dataSource = UICollectionViewDiffableDataSource(collectionView: missionListCollectionView, cellProvider: { collectionView, indexPath, itemIdentifier in + switch MissionListSection.type(indexPath.section) { + case .sentence: + guard let sentenceCell = collectionView.dequeueReusableCell(withReuseIdentifier: MissionListCVC.className, for: indexPath) as? MissionListCVC else { return UICollectionViewCell() } + return sentenceCell + + case .missionList: + guard let missionListCell = collectionView.dequeueReusableCell(withReuseIdentifier: MissionListCVC.className, for: indexPath) as? MissionListCVC else { return UICollectionViewCell() } + let missionListModel = itemIdentifier + missionListCell.initCellType = missionListModel.toCellType() + missionListCell.setData(model: missionListModel) + return missionListCell + } + }) + } + + func setCollectionView(model: [MissionListModel]) { + if model.isEmpty { + self.missionListCollectionView.isHidden = true + self.missionListEmptyView.isHidden = false + self.setEmptyView() + } else { + self.missionListCollectionView.isHidden = false + self.missionListEmptyView.isHidden = true + self.applySnapshot(model: model) + } + } + + private func setEmptyView() { + missionListEmptyView.snp.removeConstraints() + missionListEmptyView.removeFromSuperview() + self.view.addSubviews(missionListEmptyView) + missionListEmptyView.snp.makeConstraints { make in + make.top.equalTo(naviBar.snp.bottom).offset(145.adjustedH) + make.centerX.equalToSuperview() + make.width.equalToSuperview() + make.bottom.equalToSuperview().priority(.low) + } + bringRankingFloatingButtonToFront() + } + + private func bringRankingFloatingButtonToFront() { + self.view.subviews.forEach { view in + if view == self.partRankingFloatingButton { + self.view.bringSubviewToFront(partRankingFloatingButton) + } + } + } + + private func applySnapshot(model: [MissionListModel]) { + var snapshot = NSDiffableDataSourceSnapshot() + snapshot.appendSections([.sentence, .missionList]) + snapshot.appendItems(model, toSection: .missionList) + dataSource.apply(snapshot, animatingDifferences: false) + self.view.setNeedsLayout() + } + + private func remakeButtonConstraint() { + self.floatingButtonStackView.addArrangedSubviews(self.currentGenerationRankFloatingButton, self.partRankingFloatingButton) + } + + private func configureCurrentGenerationButton(with generation: String) { + let attributedStr = NSMutableAttributedString(string: "\(generation)기 랭킹") + let style = NSMutableParagraphStyle() + attributedStr.addAttribute(NSAttributedString.Key.kern, value: 0, range: NSMakeRange(0, attributedStr.length)) + attributedStr.addAttribute(NSAttributedString.Key.foregroundColor, value: UIColor.white, range: NSMakeRange(0, attributedStr.length)) + self.currentGenerationRankFloatingButton.setAttributedTitle(attributedStr, for: .normal) + } + + private func showNetworkAlert() { + AlertUtils.presentNetworkAlertVC( + theme: .soptamp, + animated: true + ) } - } - - private func applySnapshot(model: [MissionListModel]) { - var snapshot = NSDiffableDataSourceSnapshot() - snapshot.appendSections([.sentence, .missionList]) - snapshot.appendItems(model, toSection: .missionList) - dataSource.apply(snapshot, animatingDifferences: false) - self.view.setNeedsLayout() - } - - private func remakeButtonConstraint() { - self.floatingButtonStackView.addArrangedSubviews(self.currentGenerationRankFloatingButton, self.partRankingFloatingButton) - } - - private func configureCurrentGenerationButton(with generation: String) { - let attributedStr = NSMutableAttributedString(string: "\(generation)기 랭킹") - let style = NSMutableParagraphStyle() - attributedStr.addAttribute(NSAttributedString.Key.kern, value: 0, range: NSMakeRange(0, attributedStr.length)) - attributedStr.addAttribute(NSAttributedString.Key.foregroundColor, value: UIColor.white, range: NSMakeRange(0, attributedStr.length)) - self.currentGenerationRankFloatingButton.setAttributedTitle(attributedStr, for: .normal) - } - - private func showNetworkAlert() { - AlertUtils.presentNetworkAlertVC( - theme: .soptamp, - animated: true - ) - } } // 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 true - } - default: - return false + 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 true + } + default: + return false + } } - } - - public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { - switch indexPath.section { - case 0: - return - case 1: - guard let tappedCell = collectionView.cellForItem(at: indexPath) as? MissionListCVC, - let model = tappedCell.model else { return } - onCellTap?(model, sceneType.usrename) - default: - return + + public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { + switch indexPath.section { + case 0: + return + case 1: + guard let tappedCell = collectionView.cellForItem(at: indexPath) as? MissionListCVC, + let model = tappedCell.model else { return } + onCellTap?(model, sceneType.usrename) + default: + return + } } - } } extension MissionListVC: UIGestureRecognizerDelegate { - public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool { - return true - } + public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool { + return true + } } From 45983d9dcd75beb0fb25455356b10978480dfff7 Mon Sep 17 00:00:00 2001 From: yungu0010 Date: Wed, 2 Apr 2025 03:36:13 +0900 Subject: [PATCH 8/9] =?UTF-8?q?[Refactor]=20#529=20-=20PokeMainVC=EC=99=80?= =?UTF-8?q?=20PokeCoordinator=20=EA=B0=84=20=EC=88=9C=ED=99=98=EC=B0=B8?= =?UTF-8?q?=EC=A1=B0=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Sources/Coordinator/PokeCoordinator.swift | 6 +++--- .../Sources/PokeMainScene/VC/PokeMainVC.swift | 17 +++++++++-------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/SOPT-iOS/Projects/Features/PokeFeature/Sources/Coordinator/PokeCoordinator.swift b/SOPT-iOS/Projects/Features/PokeFeature/Sources/Coordinator/PokeCoordinator.swift index cd787fc1..5b51c721 100644 --- a/SOPT-iOS/Projects/Features/PokeFeature/Sources/Coordinator/PokeCoordinator.swift +++ b/SOPT-iOS/Projects/Features/PokeFeature/Sources/Coordinator/PokeCoordinator.swift @@ -57,21 +57,21 @@ final class PokeCoordinator: DefaultCoordinator { pokeMain.vm.onPokeButtonTapped = { [weak self] userModel in guard let self else { return .empty() } - return self.showMessageBottomSheet(userModel: userModel, on: pokeMain.vc.viewController) + return self.showMessageBottomSheet(userModel: userModel, on: self.rootController) } pokeMain.vm.onNewFriendMade = { [weak self] friendName in guard let self else { return } let pokeMakingFriendCompletedVC = self.factory.makePokeMakingFriendCompleted(friendName: friendName).viewController pokeMakingFriendCompletedVC.modalPresentationStyle = .overFullScreen - pokeMain.vc.viewController.present(pokeMakingFriendCompletedVC, animated: false) + self.rootController?.present(pokeMakingFriendCompletedVC, animated: false) } pokeMain.vm.onAnonymousFriendUpgrade = { [weak self] user in guard let self else { return } let pokeAnonymousFriendUpgradeVC = self.factory.makePokeAnonymousFriendUpgrade(user: user).viewController pokeAnonymousFriendUpgradeVC.modalPresentationStyle = .overFullScreen - pokeMain.vc.viewController.present(pokeAnonymousFriendUpgradeVC, animated: false) + self.rootController?.present(pokeAnonymousFriendUpgradeVC, animated: false) } pokeMain.vm.switchToOnboarding = { [weak self] in diff --git a/SOPT-iOS/Projects/Features/PokeFeature/Sources/PokeMainScene/VC/PokeMainVC.swift b/SOPT-iOS/Projects/Features/PokeFeature/Sources/PokeMainScene/VC/PokeMainVC.swift index ac13017b..95a34473 100644 --- a/SOPT-iOS/Projects/Features/PokeFeature/Sources/PokeMainScene/VC/PokeMainVC.swift +++ b/SOPT-iOS/Projects/Features/PokeFeature/Sources/PokeMainScene/VC/PokeMainVC.swift @@ -103,11 +103,11 @@ public final class PokeMainVC: UIViewController, PokeMainViewControllable { public override func viewDidLoad() { super.viewDidLoad() - self.setUI() - self.setDelegate() - self.setStackView() - self.setLayout() - self.bindViewModel() + setUI() + setDelegate() + setStackView() + setLayout() + bindViewModel() } } @@ -298,8 +298,9 @@ extension PokeMainVC { }.store(in: cancelBag) output.isLoading - .sink { [weak self] isLoading in - isLoading ? self?.showLoading() : self?.stopLoading() - }.store(in: self.cancelBag) + .withUnretained(self) + .sink { owner, isLoading in + isLoading ? owner.showLoading() : owner.stopLoading() + }.store(in: cancelBag) } } From 25823f84e40484c050bd80e9e36d6d5ab7413fca Mon Sep 17 00:00:00 2001 From: yungu0010 Date: Wed, 2 Apr 2025 03:39:14 +0900 Subject: [PATCH 9/9] =?UTF-8?q?[Del]=20#529=20-=20STNavigationBar=EC=97=90?= =?UTF-8?q?=EC=84=9C=20=EC=82=AC=EC=9A=A9=ED=95=98=EC=A7=80=20=EC=95=8A?= =?UTF-8?q?=EB=8A=94=20=ED=94=84=EB=A1=9C=ED=8D=BC=ED=8B=B0=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Sources/Components/SoptampComponents/STNavigationBar.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/SOPT-iOS/Projects/Modules/DSKit/Sources/Components/SoptampComponents/STNavigationBar.swift b/SOPT-iOS/Projects/Modules/DSKit/Sources/Components/SoptampComponents/STNavigationBar.swift index 007dd456..6a895242 100644 --- a/SOPT-iOS/Projects/Modules/DSKit/Sources/Components/SoptampComponents/STNavigationBar.swift +++ b/SOPT-iOS/Projects/Modules/DSKit/Sources/Components/SoptampComponents/STNavigationBar.swift @@ -29,7 +29,6 @@ public class STNavigationBar: UIView { // MARK: - UI Component - private var vc: UIViewController? private let titleLabel = UILabel() private let titleButton = UIButton() private let leftButton = UIButton()