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() + ) + ) + } + } +}