From c0dd6f80154d9344827bc5b0aa35f9f682cc96b3 Mon Sep 17 00:00:00 2001 From: Daniel Haight Date: Tue, 14 Dec 2021 00:50:52 +0000 Subject: [PATCH] Add Profile placeholder feature This feature is a very basic example of combining two existing features that can be navigated to. Aside from this it currently has no other functionality, and is intended to exist as yet another feature that can be navigated to. --- secant.xcodeproj/project.pbxproj | 24 ++++++ secant/Features/Home/HomeStore.swift | 31 +++++++ secant/Features/Home/Views/HomeView.swift | 3 + secant/Features/Profile/Profile.swift | 81 +++++++++++++++++++ .../Features/Profile/Views/ProfileView.swift | 46 +++++++++++ 5 files changed, 185 insertions(+) create mode 100644 secant/Features/Profile/Profile.swift create mode 100644 secant/Features/Profile/Views/ProfileView.swift diff --git a/secant.xcodeproj/project.pbxproj b/secant.xcodeproj/project.pbxproj index a09b16a..a46cb4f 100644 --- a/secant.xcodeproj/project.pbxproj +++ b/secant.xcodeproj/project.pbxproj @@ -107,6 +107,8 @@ F96B41E8273B501F0021B49A /* TransactionDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F96B41E5273B501F0021B49A /* TransactionDetailView.swift */; }; F96B41E9273B501F0021B49A /* TransactionHistoryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F96B41E6273B501F0021B49A /* TransactionHistoryView.swift */; }; F96B41EB273B50520021B49A /* Strings.swift in Sources */ = {isa = PBXBuildFile; fileRef = F96B41EA273B50520021B49A /* Strings.swift */; }; + F9971A5327680DD000A2DB75 /* Profile.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9971A5027680DD000A2DB75 /* Profile.swift */; }; + F9971A5427680DD000A2DB75 /* ProfileView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9971A5227680DD000A2DB75 /* ProfileView.swift */; }; F9971A5927680DDE00A2DB75 /* Request.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9971A5627680DDE00A2DB75 /* Request.swift */; }; F9971A5A27680DDE00A2DB75 /* RequestView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9971A5827680DDE00A2DB75 /* RequestView.swift */; }; F9971A5F27680DF600A2DB75 /* ScanView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9971A5D27680DF600A2DB75 /* ScanView.swift */; }; @@ -248,6 +250,8 @@ F96B41E5273B501F0021B49A /* TransactionDetailView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransactionDetailView.swift; sourceTree = ""; }; F96B41E6273B501F0021B49A /* TransactionHistoryView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransactionHistoryView.swift; sourceTree = ""; }; F96B41EA273B50520021B49A /* Strings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Strings.swift; sourceTree = ""; }; + F9971A5027680DD000A2DB75 /* Profile.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Profile.swift; sourceTree = ""; }; + F9971A5227680DD000A2DB75 /* ProfileView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProfileView.swift; sourceTree = ""; }; F9971A5627680DDE00A2DB75 /* Request.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Request.swift; sourceTree = ""; }; F9971A5827680DDE00A2DB75 /* RequestView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RequestView.swift; sourceTree = ""; }; F9971A5D27680DF600A2DB75 /* ScanView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScanView.swift; sourceTree = ""; }; @@ -712,6 +716,7 @@ isa = PBXGroup; children = ( F93874EC273C4DE200F0E875 /* Home */, + F9971A4F27680DD000A2DB75 /* Profile */, F9971A5527680DDE00A2DB75 /* Request */, F9971A5B27680DF600A2DB75 /* Scan */, F9C165B62740403600592F76 /* Send */, @@ -810,6 +815,23 @@ path = Views; sourceTree = ""; }; + F9971A4F27680DD000A2DB75 /* Profile */ = { + isa = PBXGroup; + children = ( + F9971A5027680DD000A2DB75 /* Profile.swift */, + F9971A5127680DD000A2DB75 /* Views */, + ); + path = Profile; + sourceTree = ""; + }; + F9971A5127680DD000A2DB75 /* Views */ = { + isa = PBXGroup; + children = ( + F9971A5227680DD000A2DB75 /* ProfileView.swift */, + ); + path = Views; + sourceTree = ""; + }; F9971A5527680DDE00A2DB75 /* Request */ = { isa = PBXGroup; children = ( @@ -1113,6 +1135,7 @@ 0D535FE2271F9476009A9E3E /* EnumeratedChip.swift in Sources */, 6654C73E2715A41300901167 /* OnboardingStore.swift in Sources */, 0D32281E26C5867D00262533 /* ScanQrScreen.swift in Sources */, + F9971A5327680DD000A2DB75 /* Profile.swift in Sources */, F93874F0273C4DE200F0E875 /* HomeStore.swift in Sources */, 669FDAEB272C23C2007B9422 /* CircularFrameBadge.swift in Sources */, 0D864A0E26E1583000A61879 /* LoadingScreen.swift in Sources */, @@ -1175,6 +1198,7 @@ F96B41EB273B50520021B49A /* Strings.swift in Sources */, 0D32283226C5877A00262533 /* BalanceScreen.swift in Sources */, 0D354A0A26D5A9D000315F45 /* KeyStoring.swift in Sources */, + F9971A5427680DD000A2DB75 /* ProfileView.swift in Sources */, 0DA13CA226C1955600E3B610 /* HomeScreenViewModel.swift in Sources */, 0D32282926C586E000262533 /* RequestZcashScreenViewModel.swift in Sources */, 0D32281926C5864B00262533 /* ProfileScreen.swift in Sources */, diff --git a/secant/Features/Home/HomeStore.swift b/secant/Features/Home/HomeStore.swift index 18d7872..d10eb2f 100644 --- a/secant/Features/Home/HomeStore.swift +++ b/secant/Features/Home/HomeStore.swift @@ -6,16 +6,19 @@ struct HomeState: Equatable { case history case send case recoveryPhraseDisplay + case profile case scan case request } var transactionHistoryState: TransactionHistoryState + var profileState: ProfileState var route: Route? } enum HomeAction: Equatable { case updateRoute(HomeState.Route?) case transactionHistory(TransactionHistoryAction) + case profile(ProfileAction) } // MARK: - HomeReducer @@ -33,6 +36,16 @@ extension HomeReducer { .default .run(&state.transactionHistoryState, transactionHistoryAction, ()) .map(HomeAction.transactionHistory) + case let .profile(profileAction): + return ProfileReducer + .default + .pullback( + state: \.profileState, + action: /HomeAction.profile, + environment: { _ in + return ProfileEnvironment() + }) + .run(&state, action, ()) } } } @@ -48,6 +61,14 @@ extension HomeStore { action: HomeAction.transactionHistory ) } + + func profileStore() -> ProfileStore { + self.scope( + state: \.profileState, + action: HomeAction.profile + ) + } + } // MARK: - HomeViewStore @@ -119,6 +140,15 @@ extension HomeViewStore { } ) } + + var showProfileBinding: Binding { + self.binding( + get: { $0.route == .profile }, + send: { isActive in + return .updateRoute(isActive ? .profile : nil) + } + ) + } } // MARK: PlaceHolders @@ -127,6 +157,7 @@ extension HomeState { static var placeholder: Self { .init( transactionHistoryState: .placeHolder, + profileState: .placeholder, route: nil ) } diff --git a/secant/Features/Home/Views/HomeView.swift b/secant/Features/Home/Views/HomeView.swift index c7fa138..abfa6c8 100644 --- a/secant/Features/Home/Views/HomeView.swift +++ b/secant/Features/Home/Views/HomeView.swift @@ -32,6 +32,8 @@ struct HomeView: View { RecoveryPhraseDisplayView(store: .demo) case .scan: ScanView() + case .profile: + ProfileView(store: store.profileStore()) case .request: RequestView() } @@ -91,6 +93,7 @@ extension HomeStore { HomeStore( initialState: HomeState( transactionHistoryState: .placeHolder, + profileState: .placeholder, route: nil ), reducer: .default.debug(), diff --git a/secant/Features/Profile/Profile.swift b/secant/Features/Profile/Profile.swift new file mode 100644 index 0000000..b3fbcfd --- /dev/null +++ b/secant/Features/Profile/Profile.swift @@ -0,0 +1,81 @@ +import ComposableArchitecture +import SwiftUI + +struct ProfileState: Equatable { + enum Route { + case settings + case walletInfo + } + + var walletInfoState: WalletInfoState + var settingsState: SettingsState + var route: Route? +} + +enum ProfileAction: Equatable { + case updateRoute(ProfileState.Route?) +} + +struct ProfileEnvironment { +} + +// MARK: - ProfileReducer + +typealias ProfileReducer = Reducer + +extension ProfileReducer { + static let `default` = ProfileReducer { state, action, environment in + switch action { + case let .updateRoute(route): + state.route = route + return .none + } + } +} + +// MARK: - ProfileStore + +typealias ProfileStore = Store + +extension ProfileStore { +} + +// MARK: - ProfileViewStore + +typealias ProfileViewStore = ViewStore + +extension ProfileViewStore { + var routeBinding: Binding { + self.binding( + get: \.route, + send: ProfileAction.updateRoute + ) + } + + var bindingForWalletInfo: Binding { + self.routeBinding.map( + extract: { $0 == .walletInfo }, + embed: { $0 ? .walletInfo : nil } + ) + } + + var bindingForSettings: Binding { + self.routeBinding.map( + extract: { $0 == .settings }, + embed: { $0 ? .settings : nil } + ) + } +} + +// MARK: PlaceHolders + +extension ProfileState { + static var placeholder: Self { + .init( + walletInfoState: .init(), + settingsState: .init(), + route: nil + ) + } +} + diff --git a/secant/Features/Profile/Views/ProfileView.swift b/secant/Features/Profile/Views/ProfileView.swift new file mode 100644 index 0000000..a0d573e --- /dev/null +++ b/secant/Features/Profile/Views/ProfileView.swift @@ -0,0 +1,46 @@ +import ComposableArchitecture +import SwiftUI + +struct ProfileView: View { + let store: ProfileStore + + var body: some View { + WithViewStore(store) { viewStore in + List { + Text("Go To Wallet Info") + .navigationLink( + isActive: viewStore.bindingForWalletInfo, + destination: { + Text("Wallet") + } + ) + + Text("Go To Settings") + .navigationLink( + isActive: viewStore.bindingForSettings, + destination: { + Text("Settings") + } + ) + } + .navigationTitle(Text("\(String(describing: Self.self))")) + } + } +} + +struct ProfileView_Previews: PreviewProvider { + static var previews: some View { + NavigationView { + ProfileView( + store: .init( + initialState: .init( + walletInfoState: .init(), + settingsState: .init() + ), + reducer: .default, + environment: .init() + ) + ) + } + } +}