Draft of the new navigation system
This commit is contained in:
parent
8dfb90ff06
commit
d123edf24b
|
@ -1,4 +1,4 @@
|
|||
// swift-tools-version: 5.6
|
||||
// swift-tools-version: 5.7
|
||||
// The swift-tools-version declares the minimum version of Swift required to build this package.
|
||||
|
||||
import PackageDescription
|
||||
|
@ -7,7 +7,7 @@ let package = Package(
|
|||
name: "modules",
|
||||
defaultLocalization: "en",
|
||||
platforms: [
|
||||
.iOS(.v15)
|
||||
.iOS(.v16)
|
||||
],
|
||||
products: [
|
||||
.library(name: "About", targets: ["About"]),
|
||||
|
|
|
@ -87,6 +87,7 @@ public struct BalancesView: View {
|
|||
.navigationBarTitleDisplayMode(.inline)
|
||||
.padding(.vertical, 1)
|
||||
.applyScreenBackground()
|
||||
.zashiBack()
|
||||
.alert(
|
||||
store: store.scope(
|
||||
state: \.$alert,
|
||||
|
|
|
@ -61,6 +61,12 @@ public struct Home {
|
|||
case updateTransactionList([TransactionState])
|
||||
case transactionList(TransactionList.Action)
|
||||
case walletBalances(WalletBalances.Action)
|
||||
|
||||
// primary actions
|
||||
case receiveTapped
|
||||
case sendTapped
|
||||
case scanTapped
|
||||
case moreTapped
|
||||
}
|
||||
|
||||
@Dependency(\.mainQueue) var mainQueue
|
||||
|
@ -105,6 +111,9 @@ public struct Home {
|
|||
.cancel(id: CancelStateId),
|
||||
.cancel(id: CancelEventId)
|
||||
)
|
||||
|
||||
case .receiveTapped, .sendTapped, .scanTapped, .moreTapped:
|
||||
return .none
|
||||
|
||||
case .resolveReviewRequest:
|
||||
if reviewRequest.canRequestReview() {
|
||||
|
|
|
@ -50,6 +50,40 @@ public struct HomeView: View {
|
|||
.padding(.bottom, 20)
|
||||
}
|
||||
|
||||
HStack(spacing: 8) {
|
||||
button(
|
||||
L10n.Tabs.receive,
|
||||
icon: Asset.Assets.Icons.received.image
|
||||
) {
|
||||
store.send(.receiveTapped)
|
||||
}
|
||||
|
||||
button(
|
||||
L10n.Tabs.send,
|
||||
icon: Asset.Assets.Icons.sent.image
|
||||
) {
|
||||
store.send(.sendTapped)
|
||||
}
|
||||
|
||||
button(
|
||||
"Scan",
|
||||
icon: Asset.Assets.Icons.scan.image
|
||||
) {
|
||||
store.send(.scanTapped)
|
||||
}
|
||||
|
||||
button(
|
||||
"More",
|
||||
icon: Asset.Assets.Icons.dotsMenu.image
|
||||
) {
|
||||
store.send(.moreTapped)
|
||||
}
|
||||
}
|
||||
.zFont(.medium, size: 12, style: Design.Text.primary)
|
||||
.padding(.top, 24)
|
||||
.padding(.bottom, 32)
|
||||
.screenHorizontalPadding()
|
||||
|
||||
VStack(spacing: 0) {
|
||||
if store.transactionListState.transactions.isEmpty && !store.transactionListState.isInvalidated {
|
||||
noTransactionsView()
|
||||
|
@ -172,6 +206,27 @@ public struct HomeView: View {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func button(_ title: String, icon: Image, action: @escaping () -> Void) -> some View {
|
||||
Button {
|
||||
action()
|
||||
} label: {
|
||||
VStack(spacing: 4) {
|
||||
icon
|
||||
.resizable()
|
||||
.renderingMode(.template)
|
||||
.frame(width: 24, height: 24)
|
||||
|
||||
Text(title)
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
.frame(height: 76)
|
||||
.background {
|
||||
RoundedRectangle(cornerRadius: 20)
|
||||
.fill(Design.Surfaces.bgSecondary.color(colorScheme))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Previews
|
||||
|
|
|
@ -158,6 +158,7 @@ public struct ReceiveView: View {
|
|||
}
|
||||
.padding(.horizontal, 4)
|
||||
.applyScreenBackground()
|
||||
.zashiBack()
|
||||
}
|
||||
|
||||
@ViewBuilder private func addressBlock(
|
||||
|
|
|
@ -16,9 +16,9 @@ import Pasteboard
|
|||
/// In this file is a collection of helpers that control all state and action related operations
|
||||
/// for the `Root` with a connection to the UI navigation.
|
||||
extension Root {
|
||||
public struct DebugState: Equatable { }
|
||||
public struct DebugState { }
|
||||
|
||||
public indirect enum DebugAction: Equatable {
|
||||
public indirect enum DebugAction {
|
||||
case cancelRescan
|
||||
case cantStartSync(ZcashError)
|
||||
case copySeedToPasteboard
|
||||
|
|
|
@ -17,8 +17,8 @@ import SwiftUI
|
|||
/// In this file is a collection of helpers that control all state and action related operations
|
||||
/// for the `Root` with a connection to the UI navigation.
|
||||
extension Root {
|
||||
public struct DestinationState: Equatable {
|
||||
public enum Destination: Equatable {
|
||||
public struct DestinationState {
|
||||
public enum Destination {
|
||||
case deeplinkWarning
|
||||
case notEnoughFreeSpace
|
||||
case onboarding
|
||||
|
@ -42,7 +42,7 @@ extension Root {
|
|||
}
|
||||
}
|
||||
|
||||
public enum DestinationAction: Equatable {
|
||||
public enum DestinationAction {
|
||||
case deeplink(URL)
|
||||
case deeplinkHome
|
||||
case deeplinkSend(Zatoshi, String, String)
|
||||
|
|
|
@ -22,7 +22,7 @@ extension Root {
|
|||
static let noAuthenticationWithinXMinutes = 15
|
||||
}
|
||||
|
||||
public enum InitializationAction: Equatable {
|
||||
public enum InitializationAction {
|
||||
case appDelegate(AppDelegateAction)
|
||||
case checkBackupPhraseValidation
|
||||
case checkRestoreWalletFlag(SyncStatus)
|
||||
|
|
|
@ -50,7 +50,7 @@ public struct Root {
|
|||
let CancelFlexaId = UUID()
|
||||
|
||||
@ObservableState
|
||||
public struct State: Equatable {
|
||||
public struct State {
|
||||
public var CancelEventId = UUID()
|
||||
public var CancelStateId = UUID()
|
||||
|
||||
|
@ -128,7 +128,7 @@ public struct Root {
|
|||
}
|
||||
}
|
||||
|
||||
public enum Action: Equatable {
|
||||
public enum Action {
|
||||
public enum ConfirmationDialog: Equatable {
|
||||
case fullRescan
|
||||
case quickRescan
|
||||
|
|
|
@ -24,14 +24,14 @@ import AddressBookClient
|
|||
|
||||
@Reducer
|
||||
public struct SendFlow {
|
||||
public enum Confirmation: Equatable {
|
||||
public enum Confirmation {
|
||||
case requestPayment
|
||||
case send
|
||||
}
|
||||
|
||||
@ObservableState
|
||||
public struct State: Equatable {
|
||||
public enum Destination: Equatable {
|
||||
public struct State {
|
||||
public enum Destination {
|
||||
case partialProposalError
|
||||
case scanQR
|
||||
}
|
||||
|
@ -194,7 +194,7 @@ public struct SendFlow {
|
|||
}
|
||||
}
|
||||
|
||||
public enum Action: Equatable {
|
||||
public enum Action {
|
||||
case addNewContactTapped(RedactableString)
|
||||
case addressBookTapped
|
||||
case addressUpdated(RedactableString)
|
||||
|
@ -248,7 +248,7 @@ public struct SendFlow {
|
|||
case .onAppear:
|
||||
state.scanState.checkers = [.zcashAddressScanChecker, .requestZecScanChecker]
|
||||
state.memoState.charLimit = zcashSDKEnvironment.memoCharLimit
|
||||
guard let account = state.zashiWalletAccount else {
|
||||
guard let _ = state.zashiWalletAccount else {
|
||||
return .send(.exchangeRateSetupChanged)
|
||||
}
|
||||
return .send(.exchangeRateSetupChanged)
|
||||
|
|
|
@ -214,6 +214,7 @@ public struct SendFlowView: View {
|
|||
}
|
||||
.padding(.vertical, 1)
|
||||
.applyScreenBackground()
|
||||
.zashiBack()
|
||||
.alert(store: store.scope(
|
||||
state: \.$alert,
|
||||
action: \.alert
|
||||
|
|
|
@ -36,8 +36,15 @@ import UserMetadataProvider
|
|||
|
||||
@Reducer
|
||||
public struct Tabs {
|
||||
@Reducer
|
||||
public enum Path {
|
||||
case sendFlow(SendFlow)
|
||||
}
|
||||
|
||||
@ObservableState
|
||||
public struct State: Equatable {
|
||||
public struct State {
|
||||
var path = StackState<Path.State>()
|
||||
|
||||
public enum Destination: Equatable {
|
||||
case addressDetails
|
||||
case currencyConversionSetup
|
||||
|
@ -84,19 +91,6 @@ public struct Tabs {
|
|||
case send
|
||||
case receive
|
||||
case balances
|
||||
|
||||
public var title: String {
|
||||
switch self {
|
||||
case .account:
|
||||
return L10n.Tabs.account
|
||||
case .send:
|
||||
return L10n.Tabs.send
|
||||
case .receive:
|
||||
return L10n.Tabs.receive
|
||||
case .balances:
|
||||
return L10n.Tabs.balances
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public var accountSwitchRequest = false
|
||||
|
@ -177,7 +171,7 @@ public struct Tabs {
|
|||
}
|
||||
}
|
||||
|
||||
public enum Action: BindableAction, Equatable {
|
||||
public enum Action: BindableAction {
|
||||
case accountSwitchTapped
|
||||
case addKeystoneHWWalletTapped
|
||||
case addKeystoneHWWallet(AddKeystoneHWWallet.Action)
|
||||
|
@ -191,6 +185,7 @@ public struct Tabs {
|
|||
case home(Home.Action)
|
||||
case keystoneBannerTapped
|
||||
case onAppear
|
||||
case path(StackActionOf<Path>)
|
||||
case presentKeystoneWeb
|
||||
case rateTooltipTapped
|
||||
case receive(Receive.Action)
|
||||
|
@ -236,9 +231,9 @@ public struct Tabs {
|
|||
Scan()
|
||||
}
|
||||
|
||||
Scope(state: \.sendState, action: \.send) {
|
||||
SendFlow()
|
||||
}
|
||||
// Scope(state: \.sendState, action: \.send) {
|
||||
// SendFlow()
|
||||
// }
|
||||
|
||||
Scope(state: \.sendConfirmationState, action: \.sendConfirmation) {
|
||||
SendConfirmation()
|
||||
|
@ -292,6 +287,9 @@ public struct Tabs {
|
|||
state.isRateEducationEnabled = userStoredPreferences.exchangeRate() == nil
|
||||
return .none
|
||||
|
||||
case .path:
|
||||
return .none
|
||||
|
||||
case .accountSwitchTapped:
|
||||
state.accountSwitchRequest.toggle()
|
||||
return .none
|
||||
|
@ -386,6 +384,18 @@ public struct Tabs {
|
|||
}
|
||||
return .send(.updateStackDestinationRequestPayment(.requestPaymentConfirmation))
|
||||
|
||||
case .home(.receiveTapped):
|
||||
print("__LD \(state.sendState.address)")
|
||||
state.selectedTab = .receive
|
||||
return .none
|
||||
|
||||
case .home(.sendTapped):
|
||||
var test = SendFlow.State()
|
||||
test.address = "aaa"
|
||||
state.path.append(.sendFlow(test))
|
||||
state.selectedTab = .send
|
||||
return .none
|
||||
|
||||
case .home(.seeAllTransactionsTapped):
|
||||
return .send(.updateStackDestinationTransactions(.manager))
|
||||
|
||||
|
@ -716,5 +726,6 @@ public struct Tabs {
|
|||
return .none
|
||||
}
|
||||
}
|
||||
.forEach(\.path, action: \.path)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,17 +46,363 @@ public struct TabsView: View {
|
|||
|
||||
public var body: some View {
|
||||
WithPerceptionTracking {
|
||||
ZStack {
|
||||
TabView(selection: $store.selectedTab) {
|
||||
HomeView(
|
||||
store: self.store.scope(
|
||||
state: \.homeState,
|
||||
action: \.home
|
||||
),
|
||||
tokenName: tokenName
|
||||
)
|
||||
.tag(Tabs.State.Tab.account)
|
||||
|
||||
NavigationStack(path: $store.scope(state: \.path, action: \.path)) {
|
||||
HomeView(
|
||||
store: self.store.scope(
|
||||
state: \.homeState,
|
||||
action: \.home
|
||||
),
|
||||
tokenName: tokenName
|
||||
)
|
||||
} destination: { store in
|
||||
switch store.case {
|
||||
case let .sendFlow(store):
|
||||
SendFlowView(store: store, tokenName: tokenName)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// public var body: some View {
|
||||
// WithPerceptionTracking {
|
||||
// accountView()
|
||||
// .navigationBarTitleDisplayMode(.inline)
|
||||
// .navigationBarItems(
|
||||
// leading:
|
||||
// walletAccountSwitcher()
|
||||
// )
|
||||
// .navigationBarItems(
|
||||
// trailing:
|
||||
// HStack(spacing: 0) {
|
||||
// if store.selectedTab != .receive {
|
||||
// hideBalancesButton()
|
||||
// }
|
||||
//
|
||||
// settingsButton()
|
||||
// }
|
||||
// .animation(nil, value: store.selectedTab)
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
|
||||
// public var body2: some View {
|
||||
// WithPerceptionTracking {
|
||||
// accountView()
|
||||
// .navigationLinkEmpty(
|
||||
// isActive: store.bindingFor(.sendConfirmation),
|
||||
// destination: {
|
||||
// SendConfirmationView(
|
||||
// store: store.sendConfirmationStore(),
|
||||
// tokenName: tokenName
|
||||
// )
|
||||
// }
|
||||
// )
|
||||
// .navigationLinkEmpty(
|
||||
// isActive: store.bindingFor(.sendConfirmationKeystone),
|
||||
// destination: {
|
||||
// SignWithKeystoneView(store: store.sendConfirmationStore(), tokenName: tokenName)
|
||||
// }
|
||||
// )
|
||||
// .navigationLinkEmpty(
|
||||
// isActive: store.bindingFor(.currencyConversionSetup),
|
||||
// destination: {
|
||||
// CurrencyConversionSetupView(
|
||||
// store: store.currencyConversionSetupStore()
|
||||
// )
|
||||
// }
|
||||
// )
|
||||
// .navigationLinkEmpty(
|
||||
// isActive: store.bindingFor(.addressDetails),
|
||||
// destination: {
|
||||
// AddressDetailsView(store: store.addressDetailsStore())
|
||||
// }
|
||||
// )
|
||||
// .navigationLinkEmpty(
|
||||
// isActive: store.bindingForStackAddKeystoneKWWallet(.addKeystoneHWWallet),
|
||||
// destination: {
|
||||
// AddKeystoneHWWalletView(
|
||||
// store: store.addKeystoneHWWalletStore()
|
||||
// )
|
||||
// .navigationLinkEmpty(
|
||||
// isActive: store.bindingForStackAddKeystoneKWWallet(.scan),
|
||||
// destination: {
|
||||
// ScanView(
|
||||
// store: store.scanStore()
|
||||
// )
|
||||
// .navigationLinkEmpty(
|
||||
// isActive: store.bindingForStackAddKeystoneKWWallet(.accountSelection),
|
||||
// destination: {
|
||||
// AccountsSelectionView(
|
||||
// store: store.addKeystoneHWWalletStore()
|
||||
// )
|
||||
// }
|
||||
// )
|
||||
// }
|
||||
// )
|
||||
// }
|
||||
// )
|
||||
// .navigationLinkEmpty(
|
||||
// isActive: store.bindingForStackMaxPrivacy(.zecKeyboard),
|
||||
// destination: {
|
||||
// ZecKeyboardView(
|
||||
// store: store.zecKeyboardStore(),
|
||||
// tokenName: tokenName
|
||||
// )
|
||||
// .navigationLinkEmpty(
|
||||
// isActive: store.bindingForStackMaxPrivacy(.requestZec),
|
||||
// destination: {
|
||||
// RequestZecView(
|
||||
// store: store.requestZecStore(),
|
||||
// tokenName: tokenName
|
||||
// )
|
||||
// .navigationLinkEmpty(
|
||||
// isActive: store.bindingForStackMaxPrivacy(.requestZecSummary),
|
||||
// destination: {
|
||||
// RequestZecSummaryView(
|
||||
// store: store.requestZecStore(),
|
||||
// tokenName: tokenName
|
||||
// )
|
||||
// }
|
||||
// )
|
||||
// }
|
||||
// )
|
||||
// }
|
||||
// )
|
||||
// .navigationLinkEmpty(
|
||||
// isActive: store.bindingForStackLowPrivacy(.zecKeyboard),
|
||||
// destination: {
|
||||
// ZecKeyboardView(
|
||||
// store: store.zecKeyboardStore(),
|
||||
// tokenName: tokenName
|
||||
// )
|
||||
// .navigationLinkEmpty(
|
||||
// isActive: store.bindingForStackLowPrivacy(.requestZecSummary),
|
||||
// destination: {
|
||||
// RequestZecSummaryView(
|
||||
// store: store.requestZecStore(),
|
||||
// tokenName: tokenName
|
||||
// )
|
||||
// }
|
||||
// )
|
||||
// }
|
||||
// )
|
||||
// .navigationLinkEmpty(
|
||||
// isActive: store.bindingForStackRequestPayment(.requestPaymentConfirmation),
|
||||
// destination: {
|
||||
// RequestPaymentConfirmationView(
|
||||
// store: store.sendConfirmationStore(),
|
||||
// tokenName: tokenName
|
||||
// )
|
||||
// .navigationLinkEmpty(
|
||||
// isActive: store.bindingForStackRequestPayment(.addressBookNewContact),
|
||||
// destination: {
|
||||
// AddressBookContactView(store: store.addressBookStore())
|
||||
// }
|
||||
// )
|
||||
// }
|
||||
// )
|
||||
// .navigationLinkEmpty(
|
||||
// isActive: store.bindingForStackTransactions(.manager),
|
||||
// destination: {
|
||||
// TransactionsManagerView(
|
||||
// store: store.transactionsManagerStore(),
|
||||
// tokenName: tokenName
|
||||
// )
|
||||
// .navigationLinkEmpty(
|
||||
// isActive: store.bindingForStackTransactions(.details),
|
||||
// destination: {
|
||||
// TransactionDetailsView(
|
||||
// store: store.transactionDetailsStore(),
|
||||
// tokenName: tokenName
|
||||
// )
|
||||
// .navigationLinkEmpty(
|
||||
// isActive: store.bindingForStackTransactions(.addressBook),
|
||||
// destination: {
|
||||
// AddressBookContactView(store: store.addressBookStore())
|
||||
// }
|
||||
// )
|
||||
// }
|
||||
// )
|
||||
// }
|
||||
// )
|
||||
// .navigationLinkEmpty(
|
||||
// isActive: store.bindingForStackTransactionsHP(.details),
|
||||
// destination: {
|
||||
// TransactionDetailsView(
|
||||
// store: store.transactionDetailsStore(),
|
||||
// tokenName: tokenName
|
||||
// )
|
||||
// .navigationLinkEmpty(
|
||||
// isActive: store.bindingForStackTransactionsHP(.addressBook),
|
||||
// destination: {
|
||||
// AddressBookContactView(store: store.addressBookStore())
|
||||
// }
|
||||
// )
|
||||
// }
|
||||
// )
|
||||
// .navigationBarTitleDisplayMode(.inline)
|
||||
// .navigationBarItems(
|
||||
// leading:
|
||||
// walletAccountSwitcher()
|
||||
// )
|
||||
// .navigationBarItems(
|
||||
// trailing:
|
||||
// HStack(spacing: 0) {
|
||||
// if store.selectedTab != .receive {
|
||||
// hideBalancesButton()
|
||||
// }
|
||||
//
|
||||
// settingsButton()
|
||||
// }
|
||||
// .animation(nil, value: store.selectedTab)
|
||||
// )
|
||||
// .walletStatusPanel()
|
||||
// .sheet(isPresented: $store.isInAppBrowserOn) {
|
||||
// if let url = URL(string: store.inAppBrowserURL) {
|
||||
// InAppBrowserView(url: url)
|
||||
// }
|
||||
// }
|
||||
// .sheet(isPresented: $store.accountSwitchRequest) {
|
||||
// accountSwitchContent()
|
||||
// }
|
||||
// .sheet(isPresented: $store.selectTextRequest) {
|
||||
// VStack(alignment: .leading) {
|
||||
// HStack {
|
||||
// Spacer()
|
||||
//
|
||||
// Button {
|
||||
// store.send(.dismissSelectTextEditor)
|
||||
// } label: {
|
||||
// Asset.Assets.buttonCloseX.image
|
||||
// .zImage(size: 24, style: Design.Btns.Tertiary.fg)
|
||||
// .padding(8)
|
||||
// .background {
|
||||
// RoundedRectangle(cornerRadius: 12)
|
||||
// .fill(Design.Btns.Tertiary.bg.color(colorScheme))
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// TextEditor(text: $store.textToSelect)
|
||||
// .colorBackground(Asset.Colors.background.color)
|
||||
// .background(Asset.Colors.background.color)
|
||||
// .zFont(size: 14, style: Design.Text.primary)
|
||||
// }
|
||||
// .padding()
|
||||
// .applyScreenBackground()
|
||||
// }
|
||||
// .overlayPreferenceValue(ExchangeRateStaleTooltipPreferenceKey.self) { preferences in
|
||||
// WithPerceptionTracking {
|
||||
// if store.isRateTooltipEnabled {
|
||||
// GeometryReader { geometry in
|
||||
// preferences.map {
|
||||
// Tooltip(
|
||||
// title: L10n.Tooltip.ExchangeRate.title,
|
||||
// desc: L10n.Tooltip.ExchangeRate.desc
|
||||
// ) {
|
||||
// store.send(.rateTooltipTapped)
|
||||
// }
|
||||
// .frame(width: geometry.size.width - 40)
|
||||
// .offset(x: 20, y: geometry[$0].minY + geometry[$0].height)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// .overlayPreferenceValue(ExchangeRateFeaturePreferenceKey.self) { preferences in
|
||||
// WithPerceptionTracking {
|
||||
// if store.isRateEducationEnabled && store.selectedTab != .receive {
|
||||
// GeometryReader { geometry in
|
||||
// preferences.map {
|
||||
// VStack(alignment: .leading, spacing: 0) {
|
||||
// HStack(alignment: .top, spacing: 0) {
|
||||
// Asset.Assets.coinsSwap.image
|
||||
// .zImage(size: 20, style: Design.Text.primary)
|
||||
// .padding(10)
|
||||
// .background {
|
||||
// Circle()
|
||||
// .fill(Design.Surfaces.bgTertiary.color(colorScheme))
|
||||
// }
|
||||
// .padding(.trailing, 16)
|
||||
//
|
||||
// VStack(alignment: .leading, spacing: 5) {
|
||||
// Text(L10n.CurrencyConversion.cardTitle)
|
||||
// .zFont(size: 14, style: Design.Text.tertiary)
|
||||
//
|
||||
// Text(L10n.CurrencyConversion.title)
|
||||
// .zFont(.semiBold, size: 16, style: Design.Text.primary)
|
||||
// .lineLimit(1)
|
||||
// .minimumScaleFactor(0.5)
|
||||
// }
|
||||
// .padding(.trailing, 16)
|
||||
//
|
||||
// Spacer(minLength: 0)
|
||||
//
|
||||
// Button {
|
||||
// store.send(.currencyConversionCloseTapped)
|
||||
// } label: {
|
||||
// Asset.Assets.buttonCloseX.image
|
||||
// .zImage(size: 20, style: Design.HintTooltips.defaultFg)
|
||||
// }
|
||||
// .padding(20)
|
||||
// .offset(x: 20, y: -20)
|
||||
// }
|
||||
//
|
||||
// Button {
|
||||
// store.send(.updateDestination(.currencyConversionSetup))
|
||||
// } label: {
|
||||
// Text(L10n.CurrencyConversion.cardButton)
|
||||
// .zFont(.semiBold, size: 16, style: Design.Btns.Tertiary.fg)
|
||||
// .frame(height: 24)
|
||||
// .frame(maxWidth: .infinity)
|
||||
// .padding(.vertical, 12)
|
||||
// .background {
|
||||
// RoundedRectangle(cornerRadius: 12)
|
||||
// .fill(Design.Btns.Tertiary.bg.color(colorScheme))
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// .padding(24)
|
||||
// .background {
|
||||
// RoundedRectangle(cornerRadius: 12)
|
||||
// .fill(Design.Surfaces.bgPrimary.color(colorScheme))
|
||||
// .background {
|
||||
// RoundedRectangle(cornerRadius: 12)
|
||||
// .stroke(Design.Surfaces.strokeSecondary.color(colorScheme))
|
||||
// }
|
||||
// }
|
||||
// .frame(width: geometry.size.width - 40)
|
||||
// .offset(x: 20, y: geometry[$0].minY + geometry[$0].height)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
extension TabsView {
|
||||
@ViewBuilder func accountView() -> some View {
|
||||
WithPerceptionTracking {
|
||||
// VStack {
|
||||
// HStack {
|
||||
// Button("send") { store.send(.selectedTabChanged(.send)) }
|
||||
// Button("receive") { store.send(.selectedTabChanged(.receive)) }
|
||||
// Button("balances") { store.send(.selectedTabChanged(.balances)) }
|
||||
// }
|
||||
HomeView(
|
||||
store: self.store.scope(
|
||||
state: \.homeState,
|
||||
action: \.home
|
||||
),
|
||||
tokenName: tokenName
|
||||
)
|
||||
// }
|
||||
.onAppear { store.send(.onAppear) }
|
||||
.navigationLinkEmpty(
|
||||
isActive: store.bindingTabFor(.send),
|
||||
destination: {
|
||||
SendFlowView(
|
||||
store: self.store.scope(
|
||||
state: \.sendState,
|
||||
|
@ -64,8 +410,11 @@ public struct TabsView: View {
|
|||
),
|
||||
tokenName: tokenName
|
||||
)
|
||||
.tag(Tabs.State.Tab.send)
|
||||
|
||||
}
|
||||
)
|
||||
.navigationLinkEmpty(
|
||||
isActive: store.bindingTabFor(.receive),
|
||||
destination: {
|
||||
ReceiveView(
|
||||
store: self.store.scope(
|
||||
state: \.receiveState,
|
||||
|
@ -73,8 +422,11 @@ public struct TabsView: View {
|
|||
),
|
||||
networkType: networkType
|
||||
)
|
||||
.tag(Tabs.State.Tab.receive)
|
||||
|
||||
}
|
||||
)
|
||||
.navigationLinkEmpty(
|
||||
isActive: store.bindingTabFor(.balances),
|
||||
destination: {
|
||||
BalancesView(
|
||||
store: self.store.scope(
|
||||
state: \.balanceBreakdownState,
|
||||
|
@ -82,341 +434,8 @@ public struct TabsView: View {
|
|||
),
|
||||
tokenName: tokenName
|
||||
)
|
||||
.tag(Tabs.State.Tab.balances)
|
||||
}
|
||||
.onAppear { store.send(.onAppear) }
|
||||
|
||||
VStack(spacing: 0) {
|
||||
Spacer()
|
||||
|
||||
HStack {
|
||||
ForEach((Tabs.State.Tab.allCases), id: \.self) { item in
|
||||
Button {
|
||||
store.send(.selectedTabChanged(item), animation: .easeInOut)
|
||||
} label: {
|
||||
VStack {
|
||||
WithPerceptionTracking {
|
||||
if store.selectedTab == item {
|
||||
Text("\(item.title)")
|
||||
.font(.custom(FontFamily.Inter.black.name, size: 12))
|
||||
.foregroundColor(Asset.Colors.primary.color)
|
||||
Rectangle()
|
||||
.frame(height: 2)
|
||||
.zForegroundColor(Design.Surfaces.brandBg)
|
||||
.matchedGeometryEffect(id: "Tabs", in: tabsID, properties: .frame)
|
||||
} else {
|
||||
Text("\(item.title)")
|
||||
.font(.custom(FontFamily.Inter.regular.name, size: 12))
|
||||
.foregroundColor(Asset.Colors.primary.color)
|
||||
Rectangle()
|
||||
.frame(height: 2)
|
||||
.foregroundColor(.clear)
|
||||
}
|
||||
}
|
||||
}
|
||||
.frame(minHeight: 50)
|
||||
}
|
||||
|
||||
if item.rawValue < Tabs.State.Tab.allCases.count-1 {
|
||||
Spacer()
|
||||
}
|
||||
}
|
||||
}
|
||||
.padding(.horizontal, 40)
|
||||
.background(Asset.Colors.background.color)
|
||||
}
|
||||
.ignoresSafeArea(.keyboard)
|
||||
.navigationLinkEmpty(
|
||||
isActive: store.bindingFor(.sendConfirmation),
|
||||
destination: {
|
||||
SendConfirmationView(
|
||||
store: store.sendConfirmationStore(),
|
||||
tokenName: tokenName
|
||||
)
|
||||
}
|
||||
)
|
||||
.navigationLinkEmpty(
|
||||
isActive: store.bindingFor(.sendConfirmationKeystone),
|
||||
destination: {
|
||||
SignWithKeystoneView(store: store.sendConfirmationStore(), tokenName: tokenName)
|
||||
}
|
||||
)
|
||||
.navigationLinkEmpty(
|
||||
isActive: store.bindingFor(.currencyConversionSetup),
|
||||
destination: {
|
||||
CurrencyConversionSetupView(
|
||||
store: store.currencyConversionSetupStore()
|
||||
)
|
||||
}
|
||||
)
|
||||
.navigationLinkEmpty(
|
||||
isActive: store.bindingFor(.addressDetails),
|
||||
destination: {
|
||||
AddressDetailsView(store: store.addressDetailsStore())
|
||||
}
|
||||
)
|
||||
.navigationLinkEmpty(
|
||||
isActive: store.bindingForStackAddKeystoneKWWallet(.addKeystoneHWWallet),
|
||||
destination: {
|
||||
AddKeystoneHWWalletView(
|
||||
store: store.addKeystoneHWWalletStore()
|
||||
)
|
||||
.navigationLinkEmpty(
|
||||
isActive: store.bindingForStackAddKeystoneKWWallet(.scan),
|
||||
destination: {
|
||||
ScanView(
|
||||
store: store.scanStore()
|
||||
)
|
||||
.navigationLinkEmpty(
|
||||
isActive: store.bindingForStackAddKeystoneKWWallet(.accountSelection),
|
||||
destination: {
|
||||
AccountsSelectionView(
|
||||
store: store.addKeystoneHWWalletStore()
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
.navigationLinkEmpty(
|
||||
isActive: store.bindingForStackMaxPrivacy(.zecKeyboard),
|
||||
destination: {
|
||||
ZecKeyboardView(
|
||||
store: store.zecKeyboardStore(),
|
||||
tokenName: tokenName
|
||||
)
|
||||
.navigationLinkEmpty(
|
||||
isActive: store.bindingForStackMaxPrivacy(.requestZec),
|
||||
destination: {
|
||||
RequestZecView(
|
||||
store: store.requestZecStore(),
|
||||
tokenName: tokenName
|
||||
)
|
||||
.navigationLinkEmpty(
|
||||
isActive: store.bindingForStackMaxPrivacy(.requestZecSummary),
|
||||
destination: {
|
||||
RequestZecSummaryView(
|
||||
store: store.requestZecStore(),
|
||||
tokenName: tokenName
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
.navigationLinkEmpty(
|
||||
isActive: store.bindingForStackLowPrivacy(.zecKeyboard),
|
||||
destination: {
|
||||
ZecKeyboardView(
|
||||
store: store.zecKeyboardStore(),
|
||||
tokenName: tokenName
|
||||
)
|
||||
.navigationLinkEmpty(
|
||||
isActive: store.bindingForStackLowPrivacy(.requestZecSummary),
|
||||
destination: {
|
||||
RequestZecSummaryView(
|
||||
store: store.requestZecStore(),
|
||||
tokenName: tokenName
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
.navigationLinkEmpty(
|
||||
isActive: store.bindingForStackRequestPayment(.requestPaymentConfirmation),
|
||||
destination: {
|
||||
RequestPaymentConfirmationView(
|
||||
store: store.sendConfirmationStore(),
|
||||
tokenName: tokenName
|
||||
)
|
||||
.navigationLinkEmpty(
|
||||
isActive: store.bindingForStackRequestPayment(.addressBookNewContact),
|
||||
destination: {
|
||||
AddressBookContactView(store: store.addressBookStore())
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
.navigationLinkEmpty(
|
||||
isActive: store.bindingForStackTransactions(.manager),
|
||||
destination: {
|
||||
TransactionsManagerView(
|
||||
store: store.transactionsManagerStore(),
|
||||
tokenName: tokenName
|
||||
)
|
||||
.navigationLinkEmpty(
|
||||
isActive: store.bindingForStackTransactions(.details),
|
||||
destination: {
|
||||
TransactionDetailsView(
|
||||
store: store.transactionDetailsStore(),
|
||||
tokenName: tokenName
|
||||
)
|
||||
.navigationLinkEmpty(
|
||||
isActive: store.bindingForStackTransactions(.addressBook),
|
||||
destination: {
|
||||
AddressBookContactView(store: store.addressBookStore())
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
.navigationLinkEmpty(
|
||||
isActive: store.bindingForStackTransactionsHP(.details),
|
||||
destination: {
|
||||
TransactionDetailsView(
|
||||
store: store.transactionDetailsStore(),
|
||||
tokenName: tokenName
|
||||
)
|
||||
.navigationLinkEmpty(
|
||||
isActive: store.bindingForStackTransactionsHP(.addressBook),
|
||||
destination: {
|
||||
AddressBookContactView(store: store.addressBookStore())
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.navigationBarItems(
|
||||
leading:
|
||||
walletAccountSwitcher()
|
||||
)
|
||||
.navigationBarItems(
|
||||
trailing:
|
||||
HStack(spacing: 0) {
|
||||
if store.selectedTab != .receive {
|
||||
hideBalancesButton()
|
||||
}
|
||||
|
||||
settingsButton()
|
||||
}
|
||||
.animation(nil, value: store.selectedTab)
|
||||
)
|
||||
.walletStatusPanel()
|
||||
.sheet(isPresented: $store.isInAppBrowserOn) {
|
||||
if let url = URL(string: store.inAppBrowserURL) {
|
||||
InAppBrowserView(url: url)
|
||||
}
|
||||
}
|
||||
.sheet(isPresented: $store.accountSwitchRequest) {
|
||||
accountSwitchContent()
|
||||
}
|
||||
.sheet(isPresented: $store.selectTextRequest) {
|
||||
VStack(alignment: .leading) {
|
||||
HStack {
|
||||
Spacer()
|
||||
|
||||
Button {
|
||||
store.send(.dismissSelectTextEditor)
|
||||
} label: {
|
||||
Asset.Assets.buttonCloseX.image
|
||||
.zImage(size: 24, style: Design.Btns.Tertiary.fg)
|
||||
.padding(8)
|
||||
.background {
|
||||
RoundedRectangle(cornerRadius: 12)
|
||||
.fill(Design.Btns.Tertiary.bg.color(colorScheme))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TextEditor(text: $store.textToSelect)
|
||||
.colorBackground(Asset.Colors.background.color)
|
||||
.background(Asset.Colors.background.color)
|
||||
.zFont(size: 14, style: Design.Text.primary)
|
||||
}
|
||||
.padding()
|
||||
.applyScreenBackground()
|
||||
}
|
||||
.overlayPreferenceValue(ExchangeRateStaleTooltipPreferenceKey.self) { preferences in
|
||||
WithPerceptionTracking {
|
||||
if store.isRateTooltipEnabled {
|
||||
GeometryReader { geometry in
|
||||
preferences.map {
|
||||
Tooltip(
|
||||
title: L10n.Tooltip.ExchangeRate.title,
|
||||
desc: L10n.Tooltip.ExchangeRate.desc
|
||||
) {
|
||||
store.send(.rateTooltipTapped)
|
||||
}
|
||||
.frame(width: geometry.size.width - 40)
|
||||
.offset(x: 20, y: geometry[$0].minY + geometry[$0].height)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.overlayPreferenceValue(ExchangeRateFeaturePreferenceKey.self) { preferences in
|
||||
WithPerceptionTracking {
|
||||
if store.isRateEducationEnabled && store.selectedTab != .receive {
|
||||
GeometryReader { geometry in
|
||||
preferences.map {
|
||||
VStack(alignment: .leading, spacing: 0) {
|
||||
HStack(alignment: .top, spacing: 0) {
|
||||
Asset.Assets.coinsSwap.image
|
||||
.zImage(size: 20, style: Design.Text.primary)
|
||||
.padding(10)
|
||||
.background {
|
||||
Circle()
|
||||
.fill(Design.Surfaces.bgTertiary.color(colorScheme))
|
||||
}
|
||||
.padding(.trailing, 16)
|
||||
|
||||
VStack(alignment: .leading, spacing: 5) {
|
||||
Text(L10n.CurrencyConversion.cardTitle)
|
||||
.zFont(size: 14, style: Design.Text.tertiary)
|
||||
|
||||
Text(L10n.CurrencyConversion.title)
|
||||
.zFont(.semiBold, size: 16, style: Design.Text.primary)
|
||||
.lineLimit(1)
|
||||
.minimumScaleFactor(0.5)
|
||||
}
|
||||
.padding(.trailing, 16)
|
||||
|
||||
Spacer(minLength: 0)
|
||||
|
||||
Button {
|
||||
store.send(.currencyConversionCloseTapped)
|
||||
} label: {
|
||||
Asset.Assets.buttonCloseX.image
|
||||
.zImage(size: 20, style: Design.HintTooltips.defaultFg)
|
||||
}
|
||||
.padding(20)
|
||||
.offset(x: 20, y: -20)
|
||||
}
|
||||
|
||||
Button {
|
||||
store.send(.updateDestination(.currencyConversionSetup))
|
||||
} label: {
|
||||
Text(L10n.CurrencyConversion.cardButton)
|
||||
.zFont(.semiBold, size: 16, style: Design.Btns.Tertiary.fg)
|
||||
.frame(height: 24)
|
||||
.frame(maxWidth: .infinity)
|
||||
.padding(.vertical, 12)
|
||||
.background {
|
||||
RoundedRectangle(cornerRadius: 12)
|
||||
.fill(Design.Btns.Tertiary.bg.color(colorScheme))
|
||||
}
|
||||
}
|
||||
}
|
||||
.padding(24)
|
||||
.background {
|
||||
RoundedRectangle(cornerRadius: 12)
|
||||
.fill(Design.Surfaces.bgPrimary.color(colorScheme))
|
||||
.background {
|
||||
RoundedRectangle(cornerRadius: 12)
|
||||
.stroke(Design.Surfaces.strokeSecondary.color(colorScheme))
|
||||
}
|
||||
}
|
||||
.frame(width: geometry.size.width - 40)
|
||||
.offset(x: 20, y: geometry[$0].minY + geometry[$0].height)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -526,6 +545,13 @@ extension StoreOf<Tabs> {
|
|||
)
|
||||
}
|
||||
|
||||
func bindingTabFor(_ selectedTab: Tabs.State.Tab) -> Binding<Bool> {
|
||||
Binding<Bool>(
|
||||
get: { self.selectedTab == selectedTab },
|
||||
set: { self.send(.selectedTabChanged($0 ? selectedTab : .account)) }
|
||||
)
|
||||
}
|
||||
|
||||
func bindingForStackAddKeystoneKWWallet(_ destination: Tabs.State.StackDestinationAddKeystoneHWWallet) -> Binding<Bool> {
|
||||
Binding<Bool>(
|
||||
get: {
|
||||
|
|
12
modules/Sources/Generated/Resources/Assets.xcassets/icons/scan.imageset/Contents.json
vendored
Normal file
12
modules/Sources/Generated/Resources/Assets.xcassets/icons/scan.imageset/Contents.json
vendored
Normal file
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "scan.png",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
BIN
modules/Sources/Generated/Resources/Assets.xcassets/icons/scan.imageset/scan.png
vendored
Normal file
BIN
modules/Sources/Generated/Resources/Assets.xcassets/icons/scan.imageset/scan.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.9 KiB |
|
@ -104,6 +104,7 @@ public enum Asset {
|
|||
public static let qr = ImageAsset(name: "qr")
|
||||
public static let received = ImageAsset(name: "received")
|
||||
public static let save = ImageAsset(name: "save")
|
||||
public static let scan = ImageAsset(name: "scan")
|
||||
public static let search = ImageAsset(name: "search")
|
||||
public static let sent = ImageAsset(name: "sent")
|
||||
public static let server = ImageAsset(name: "server")
|
||||
|
|
|
@ -2375,7 +2375,7 @@
|
|||
ENABLE_PREVIEWS = YES;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
||||
INFOPLIST_FILE = "zashi-internal-Info.plist";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 16.6;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
|
@ -2405,7 +2405,7 @@
|
|||
ENABLE_PREVIEWS = YES;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
||||
INFOPLIST_FILE = "zashi-internal-Info.plist";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 16.6;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
|
@ -2435,7 +2435,7 @@
|
|||
ENABLE_PREVIEWS = YES;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
||||
INFOPLIST_FILE = "zashi-internal-Info.plist";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 16.6;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
|
|
Loading…
Reference in New Issue