taler-ios

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

TalerWallet1App.swift (4513B)


      1 /*
      2  * This file is part of GNU Taler, ©2022-26 Taler Systems S.A.
      3  * See LICENSE.md
      4  */
      5 /**
      6  * Main app entry point
      7  *
      8  * @author Jonathan Buchanan
      9  * @author Marc Stibane
     10  */
     11 import BackgroundTasks
     12 import SwiftUI
     13 import os.log
     14 import SymLog
     15 
     16 @main
     17 struct TalerWallet1App: App {
     18 #if TALER_NIGHTLY
     19     @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
     20 #endif
     21     private let symLog = SymLogV()
     22     @Environment(\.scenePhase) private var phase
     23     @StateObject private var viewState = ViewState.shared           // popToRootView()
     24     @StateObject private var viewState2 = ViewState2.shared         // popToRootView()
     25     @State private var soundPlayed = false
     26 
     27     private let walletCore = WalletCore.shared
     28     private let controller = Controller.shared
     29     private let model = WalletModel.shared
     30     private let debugViewC = DebugViewC.shared
     31     let logger = Logger(subsystem: "net.taler.gnu", category: "Main App")
     32     private let biometricService = BiometricService.shared
     33 
     34     func scheduleAppRefresh() {
     35         let request = BGAppRefreshTaskRequest(identifier: "net.taler.refresh")
     36         request.earliestBeginDate = .now.addingTimeInterval(4 * 3600)
     37         try? BGTaskScheduler.shared.submit(request)
     38     }
     39 
     40     var body: some Scene {
     41         let mainView = MainView(logger: logger, stack: CallStack("App"), soundPlayed: $soundPlayed)
     42                 .environmentObject(debugViewC)      // change viewID / sheetID
     43                 .environmentObject(viewState)       // popToRoot
     44                 .environmentObject(viewState2)      // popToRoot
     45                 .environmentObject(controller)
     46                 .environmentObject(model)
     47                 .environmentObject(biometricService)
     48                 .addKeyboardVisibilityToEnvironment()
     49                     /// external events are taler:// or payto:// URLs passed to this app
     50                     /// we handle them in .onOpenURL in MainView.swift
     51                 .handlesExternalEvents(preferring: ["*"], allowing: ["*"])
     52                 .task {
     53 #if DEBUG
     54                     let testing = true
     55 #else
     56                     let testing = false
     57 #endif
     58                     try! await controller.initWalletCore(model, setTesting: testing)     // will (and should) crash on failure
     59                 }
     60         if #available(iOS 16.4, *) {
     61             return WindowGroup {
     62                 mainView
     63             }
     64             .onChange(of: phase) { newPhase in
     65                 switch newPhase {
     66                     case .active:
     67                         logger.log("❗️.onChange() ==> Active")
     68                     case .background:
     69                         logger.log("❗️.onChange() ==> Background)")
     70 //                      scheduleAppRefresh()
     71                     default: break
     72                 }
     73             }
     74             .backgroundTask(.appRefresh("net.taler.refresh")) {
     75 //                symLog.log("backgroundTask running")
     76 //#if 0
     77 //                let request = URLRequest(url: URL(string: "your_backend")!)
     78 //                guard let data = try? await URLSession.shared.data(for: request).0 else {
     79 //                    return
     80 //                }
     81 //                
     82 //                let decoder = JSONDecoder()
     83 //                guard let products = try? decoder.decode([Product].self, from: data) else {
     84 //                    return
     85 //                }
     86 //                
     87 //                if !products.isEmpty && !Task.isCancelled {
     88 //                    await notifyUser(for: products)
     89 //                }
     90 //#endif
     91             }
     92         } else {
     93             // Fallback on earlier versions
     94             return WindowGroup {
     95                 mainView
     96             }
     97         }
     98 
     99     }
    100 }
    101 
    102 final class ViewState : ObservableObject {
    103     static let shared = ViewState()
    104     @Published var rootViewId = UUID()
    105     let logger = Logger(subsystem: "net.taler.gnu", category: "ViewState")
    106 
    107     public func popToRootView(_ stack: CallStack?) -> Void {
    108         logger.info("popToRootView")
    109         rootViewId = UUID() // setting a new ID will cause 1st NavStack popToRootView behaviour
    110     }
    111 
    112     private init() { }
    113 }
    114 
    115 final class ViewState2 : ObservableObject {
    116     static let shared = ViewState2()
    117     @Published var rootViewId = UUID()
    118     let logger = Logger(subsystem: "net.taler.gnu", category: "ViewState2")
    119 
    120     public func popToRootView(_ stack: CallStack?) -> Void {
    121         logger.info("popToRootView")
    122         rootViewId = UUID() // setting a new ID will cause 2nd NavStack popToRootView behaviour
    123     }
    124 
    125     private init() { }
    126 }