secant-ios-wallet/modules/Sources/Features/BalanceBreakdown/BalancesView.swift

216 lines
6.9 KiB
Swift

//
// BalancesView.swift
// Zashi
//
// Created by Lukáš Korba on 04.08.2022.
//
import SwiftUI
import ComposableArchitecture
import ZcashLightClientKit
import Generated
import PartialProposalError
import UIComponents
import Utils
import Models
import BalanceFormatter
import WalletBalances
import Combine
public struct BalancesView: View {
@Environment(\.colorScheme) private var colorScheme
@Perception.Bindable var store: StoreOf<Balances>
let tokenName: String
@Shared(.appStorage(.sensitiveContent)) var isSensitiveContentHidden = false
@Shared(.inMemory(.walletStatus)) public var walletStatus: WalletStatus = .none
public init(store: StoreOf<Balances>, tokenName: String) {
self.store = store
self.tokenName = tokenName
}
public var body: some View {
WithPerceptionTracking {
VStack(spacing: 0) {
Text(L10n.Balances.SpendableBalance.title)
.zFont(.semiBold, size: 24, style: Design.Text.primary)
.padding(.top, 40)
if store.spendability == .everything || store.isPendingInProcess {
Text(
store.spendability == .everything
? L10n.Balances.everythingDone
: store.isPendingTransaction
? L10n.Balances.infoPending
: L10n.Balances.infoSyncing
)
.zFont(size: 16, style: Design.Text.tertiary)
.frame(maxWidth: .infinity, alignment: .leading)
.fixedSize(horizontal: false, vertical: true)
.padding(.top, 8)
}
if store.isShieldableBalanceAvailable {
Text(L10n.Balances.infoShielding("\(L10n.General.feeShort(store.feeStr)) \(tokenName)"))
.zFont(size: 16, style: Design.Text.tertiary)
.frame(maxWidth: .infinity, alignment: .leading)
.fixedSize(horizontal: false, vertical: true)
.padding(.top, 24)
}
balancesBlock()
.padding(.top, 32)
.padding(.bottom, store.isShieldableBalanceAvailable ? 0: 32)
if store.isShieldableBalanceAvailable {
transparentBlock()
.padding(.vertical, 32)
}
ZashiButton(L10n.Balances.dismiss) {
store.send(.dismissTapped)
}
.padding(.bottom, 24)
}
.heightChangePreference { value in
store.send(.sheetHeightUpdated(value))
}
.screenHorizontalPadding()
.applyScreenBackground()
.onAppear { store.send(.onAppear) }
.onDisappear { store.send(.onDisappear) }
}
}
}
extension BalancesView {
@ViewBuilder func balancesBlock() -> some View {
VStack(spacing: 20) {
HStack(spacing: 0) {
Text(L10n.Balances.spendableBalance)
.zFont(size: 14, style: Design.Text.tertiary)
Spacer()
Asset.Assets.shield.image
.zImage(width: 11, height: 14, color: Asset.Colors.primary.color)
.padding(.trailing, 10)
ZatoshiText(store.shieldedBalance, .expanded, tokenName)
.zFont(.medium, size: 14, style: Design.Text.primary)
}
if store.isPendingInProcess {
HStack(spacing: 0) {
Text(L10n.Balances.pending)
.zFont(size: 14, style: Design.Text.tertiary)
Spacer()
progressViewLooping()
.padding(.trailing, 10)
ZatoshiText(
store.changePending + store.pendingTransactions, .expanded, tokenName
)
.zFont(.medium, size: 14, style: Design.Text.tertiary)
}
}
}
}
@ViewBuilder func transparentBlock() -> some View {
HStack(spacing: 0) {
VStack(alignment: .leading, spacing: 0) {
HStack(spacing: 0) {
Text(L10n.SmartBanner.Help.Shield.transparent)
.zFont(.medium, size: 16, style: Design.Text.primary)
.padding(.trailing, 4)
Asset.Assets.Icons.shieldOff.image
.zImage(size: 16, style: Design.Text.primary)
}
.padding(.bottom, 4)
ZatoshiText(store.transparentBalance, .expanded, tokenName)
.zFont(.semiBold, size: 20, style: Design.Text.primary)
}
Spacer()
ZashiButton(
L10n.SmartBanner.Content.Shield.button,
infinityWidth: false
) {
store.send(.shieldFundsTapped)
}
.disabled(store.isShielding)
}
.frame(maxWidth: .infinity)
.padding(.vertical, 12)
.padding(.horizontal, 20)
.background {
RoundedRectangle(cornerRadius: Design.Radius._2xl)
.fill(Design.Surfaces.bgSecondary.color(colorScheme))
.background {
RoundedRectangle(cornerRadius: Design.Radius._2xl)
.stroke(Design.Surfaces.strokeSecondary.color(colorScheme))
}
}
}
@ViewBuilder func progressViewLooping() -> some View {
ProgressView()
.scaleEffect(0.7)
.frame(width: 11, height: 14)
}
}
// MARK: - Previews
#Preview {
NavigationView {
BalancesView(
store: StoreOf<Balances>(
initialState: Balances.State(
autoShieldingThreshold: Zatoshi(1_000_000),
changePending: Zatoshi(25_234_000),
isShielding: true,
pendingTransactions: Zatoshi(25_234_000)
)
) {
Balances()
},
tokenName: "ZEC"
)
}
.navigationViewStyle(.stack)
}
// MARK: - Placeholders
extension Balances.State {
public static let placeholder = Balances.State(
autoShieldingThreshold: .zero,
changePending: .zero,
isShielding: false,
pendingTransactions: .zero
)
public static let initial = Balances.State(
autoShieldingThreshold: .zero,
changePending: .zero,
isShielding: false,
pendingTransactions: .zero
)
}
extension StoreOf<Balances> {
public static let placeholder = StoreOf<Balances>(
initialState: .placeholder
) {
Balances()
}
}