taler-ios

iOS apps for GNU Taler (wallet)
Log | Files | Refs | README | LICENSE

commit 39767097234f31ced92e17e07f468cde0bb859a2
parent 3b59e23a40bd629f3da4eaf8e2c77f8f392152c5
Author: Marc Stibane <marc@taler.net>
Date:   Sun,  3 Nov 2024 08:35:55 +0100

Onboarding

Diffstat:
MTalerWallet1/Controllers/PublicConstants.swift | 13+++++++++++--
MTalerWallet1/Views/HelperViews/TabBarView.swift | 67++++++++++++++++++++++++++++++++++++++++++++-----------------------
MTalerWallet1/Views/Main/MainView.swift | 24+++++++++++-------------
MTalerWallet1/Views/Settings/AboutView.swift | 26++++++++++++++++++++++++--
4 files changed, 90 insertions(+), 40 deletions(-)

diff --git a/TalerWallet1/Controllers/PublicConstants.swift b/TalerWallet1/Controllers/PublicConstants.swift @@ -7,12 +7,21 @@ */ import Foundation -public let MAXRECENT = 4 +public let CHF_4217 = "CHF" // ISO-4217 Swiss Francs +public let EUR_4217 = "EUR" // ISO-4217 Euro +public let HUF_4217 = "HUF" // ISO-4217 Hungarian Forint + +public let TAPPED = 4 // how often you need to tap on the Actions button before it loses its label +public let DRAGGED = 2 // #times to drag to stop the auto-dragging +public let DRAGDELAY = 0.5 +public let DRAGDURATION = 0.25 +public let DRAGSPEED = 0.1 +public let MAXRECENT = 4 // # of rows in Recent Transactions + public let ICONLEADING = CGFloat(-8) public let HSPACING = CGFloat(10) // space between items in HStack public let LAUNCHDURATION: Double = 1.60 -public let SLIDEDURATION: Double = 0.45 public let ONEDAY: UInt = 1 // 1..3 public let SEVENDAYS: UInt = 7 // 3..9 diff --git a/TalerWallet1/Views/HelperViews/TabBarView.swift b/TalerWallet1/Views/HelperViews/TabBarView.swift @@ -9,6 +9,7 @@ import SwiftUI struct TabBarView: View { @Binding var selection: Tab + @Binding var userAction: Int @Binding var hidden: Int let onActionTab: () -> Void let onActionDrag: () -> Void @@ -16,15 +17,20 @@ struct TabBarView: View { @Environment(\.keyboardShowing) var keyboardShowing @AppStorage("minimalistic") var minimalistic: Bool = false + @AppStorage("tapped") var tapped: Int = 0 + @AppStorage("dragged") var dragged: Int = 0 @State private var offset = CGSize.zero @State private var didDrag = false private func tabBarItem(for tab: Tab) -> some View { VStack(spacing: 0) { - if tab == .actions { - let width = 72.0 - let height = 57.6 + let isActions = (tab == .actions) + let withText = isActions ? tapped < TAPPED + : tapped < TAPPED || !minimalistic + if isActions { + let width = withText ? 48 : 72.0 + let height = withText ? 36 : 57.6 tab.image .resizable() .scaledToFill() @@ -32,7 +38,7 @@ struct TabBarView: View { .clipped() // Crop the image to the frame size .padding(.bottom, 4) .offset(offset) - .opacity(1 - Double(abs(offset.height / 35))) +// .opacity(1 - Double(abs(offset.height / 35))) .gesture( DragGesture() .onChanged { gesture in @@ -42,6 +48,9 @@ struct TabBarView: View { offset = .zero didDrag = true onActionDrag() // switch to camera + if tapped >= TAPPED { + dragged += 1 + } } else { offset = trans } @@ -55,50 +64,62 @@ struct TabBarView: View { offset = .zero } ) - } else { - let size = minimalistic ? 36.0 : 24.0 + let size = withText ? 24.0 : 36.0 tab.image .resizable() .renderingMode(.template) .tint(.black) .aspectRatio(contentMode: .fit) .frame(width: size, height: size) - if !minimalistic { - Text(tab.title) - .lineLimit(1) - .talerFont(.body) - } } - } + if withText { + Text(tab.title) + .lineLimit(1) + .talerFont(.body) + } + }.id(tab) .foregroundColor(selection == tab ? .accentColor : .secondary) .padding(.vertical, 8) .accessibilityElement(children: .combine) .accessibility(label: Text(tab.title)) .accessibility(addTraits: [.isButton]) .accessibility(removeTraits: [.isImage]) + .frame(maxWidth: .infinity) + .contentShape(Rectangle()) } + private func userAction(_ newValue: Int) { + if tapped >= TAPPED && dragged < DRAGGED { + withAnimation(Animation.easeOut(duration: DRAGDURATION).delay(DRAGDELAY)) { + offset.height = -50 + } + withAnimation(Animation.easeOut(duration: DRAGSPEED).delay(DRAGDELAY + DRAGDURATION + DRAGSPEED)) { + offset.height = 0 + } + } + } var body: some View { Group { if keyboardShowing || hidden > 0 { EmptyView() } else { + let actionTab = tabBarItem(for: Tab.actions) + let balanceTab = tabBarItem(for: Tab.balances) + let settingsTab = tabBarItem(for: Tab.settings) HStack(alignment: .bottom) { - ForEach(Tab.allCases, id: \.self) { tab in - tabBarItem(for: tab) - .frame(maxWidth: .infinity) - .contentShape(Rectangle()) - .onTapGesture { - if tab == .actions { - onActionTab() - } else { - selection = tab - } - } + balanceTab.onTapGesture { selection = .balances; userAction += 1 } + actionTab.onTapGesture { + onActionTab() + tapped += 1 +// dragged = 0 } + settingsTab.onTapGesture { selection = .settings; userAction += 1 } } .background(WalletColors().backgroundColor.edgesIgnoringSafeArea(.bottom)) + .onChange(of: userAction) { newValue in + userAction(newValue) + } } } } diff --git a/TalerWallet1/Views/Main/MainView.swift b/TalerWallet1/Views/Main/MainView.swift @@ -46,6 +46,7 @@ struct MainView: View { // @State private var showCameraAlert: Bool = false @State private var qrButtonTapped = false @State private var innerHeight: CGFloat = .zero + @State private var userAction = 0 func sheetDismissed() -> Void { logger.info("sheet dismiss") @@ -65,12 +66,13 @@ struct MainView: View { #endif Group { if controller.backendState == .ready { - Content(logger: logger, stack: stack.push("Content"), - selectedBalance: $selectedBalance, - talerFontIndex: $talerFontIndex, - showActionSheet: $showActionSheet, - showScanner: $showScanner) - .onAppear() { + MainContent(logger: logger, stack: stack.push("Content"), + selectedBalance: $selectedBalance, + talerFontIndex: $talerFontIndex, + showActionSheet: $showActionSheet, + showScanner: $showScanner, + userAction: $userAction) + .onAppear() { #if DEBUG if playSoundsI != 0 && playSoundsB && !soundPlayed { controller.playSound(1008) // Startup chime @@ -211,13 +213,14 @@ extension MainView { } } - struct Content: View { + struct MainContent: View { let logger: Logger let stack: CallStack @Binding var selectedBalance: Balance? @Binding var talerFontIndex: Int @Binding var showActionSheet: Bool @Binding var showScanner: Bool + @Binding var userAction: Int #if DEBUG @AppStorage("developerMode") var developerMode: Bool = true @@ -304,12 +307,7 @@ extension MainView { let balancesTitle = Tab.balances.title // let actionTitle = Tab.actions.title let settingsTitle = Tab.settings.title - let tabBarView = TabBarView(selection: tabSelection(), hidden: $navModel.tabBarHidden) { - if selectedTab != .balances { - selectedTab = .balances - } - // TODO: check NavigationStack, pop only if necessary -// ViewState.shared.popToRootView(nil) either do this after any of the buttons was operated, or don't do it at all + let tabBarView = TabBarView(selection: tabSelection(), userAction: $userAction, hidden: $navModel.tabBarHidden) { showActionSheet = true } onActionDrag: { showScanner = true diff --git a/TalerWallet1/Views/Settings/AboutView.swift b/TalerWallet1/Views/Settings/AboutView.swift @@ -22,10 +22,13 @@ struct AboutView: View { #endif @AppStorage("myListStyle") var myListStyle: MyListStyle = .automatic @AppStorage("minimalistic") var minimalistic: Bool = false + @AppStorage("tapped") var tapped: Int = 0 + @AppStorage("dragged") var dragged: Int = 0 @State private var rotationEnabled = false @State private var showGitHash = false @State private var listID = UUID() + @State private var onboarding = false var body: some View { #if PRINT_CHANGES @@ -63,11 +66,27 @@ struct AboutView: View { } } } else { - SettingsItem(name: String(localized: "WalletCore Version"), id1: "wallet-coreV") { + SettingsItem(name: String(localized: "Wallet-Core Version"), id1: "wallet-coreV") { Text(verbatim: "\(walletCore.versionInfo?.implementationSemver ?? "unknown")") } } }.onTapGesture(count: 1) { showGitHash.toggle() } + SettingsToggle(name: String(localized: "Onboarding"), + value: $onboarding.onChange({ shouldOnboard in + if shouldOnboard { + tapped = 0 + dragged = 0 + } else { + tapped = TAPPED + dragged = DRAGGED + } + }), + id1: "onboarding", + description: minimalistic ? nil : String(localized: "Explain the Actions button")) +#if DEBUG + Text("Tapped: \(tapped), dragged: \(dragged)") +#endif + // SettingsItem(name: "Supported Exchange Versions", id1: "exchange") { // Text(verbatim: "\(walletCore.versionInfo?.exchange ?? "unknown")") // } @@ -82,6 +101,9 @@ struct AboutView: View { .listStyle(myListStyle.style).anyView } .navigationTitle(navTitle) + .task { + onboarding = (tapped < TAPPED || dragged < DRAGGED) + } .onAppear() { DebugViewC.shared.setViewID(VIEW_ABOUT, stack: stack.push()) } @@ -110,7 +132,7 @@ extension Bundle { } var releaseVersionNumberPretty: String { let release = releaseVersionNumber ?? "1.0.0" - return "v\(release) (\(buildVersionNumber))" + return release // "v\(release) (\(buildVersionNumber))" } } // MARK: -