taler-ios

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

ContactsView.swift (5428B)


      1 /*
      2  * This file is part of GNU Taler, ©2022-26 Taler Systems S.A.
      3  * See LICENSE.md
      4  */
      5 /**
      6  * @author Marc Stibane
      7  */
      8 import SwiftUI
      9 import taler_swift
     10 import SymLog
     11 
     12 // MARK: -
     13 struct ContactRowView: View {
     14     let stack: CallStack
     15     let contact: ContactEntry
     16     let talerURI: String?
     17     let subject: String?
     18 
     19     @EnvironmentObject private var model: WalletModel
     20 
     21     @State private var showAlert: Bool = false
     22 
     23     private var cancelButton: some View {
     24         Button("Cancel", role: .cancel) {
     25             showAlert = false
     26         }
     27     }
     28 
     29     private var sendNowButton: some View {
     30         Button(contact.petname.isEmpty ? "Send now" : "Send to \(contact.petname)") {
     31             showAlert = false
     32             if let talerURI {
     33                 Task {
     34                     try? await model.sendTalerUriMailboxMessage(talerURI,
     35 //                                                   subjectHint: subject ?? EMPTYSTRING,
     36                                                             to: contact)
     37                     dismissTop(stack.push())
     38                 }
     39             }
     40         }
     41     }
     42 
     43     var body: some View {
     44         let label = VStack(alignment: .leading) {
     45             if !contact.petname.isEmpty {
     46                 Text(contact.petname)
     47                     .talerFont(.title3)
     48             }
     49             Text(contact.alias)
     50                 .talerFont(.body)
     51         }
     52 
     53         if let talerURI {       // send this to the selected contact
     54             label
     55                 .contentShape(.rect)
     56                 .frame(maxWidth: .infinity, alignment: .leading)
     57                 .background {
     58                     Color.primary.opacity(showAlert ? 0.12 : INVISIBLE)
     59                 }
     60                 .onTapGesture { showAlert.toggle() }
     61                 .alert("Send to \(contact.petname)",
     62                        isPresented: $showAlert,
     63                        actions: {   sendNowButton
     64                                     cancelButton },
     65                        message: {   if let subject {
     66                                         Text(subject)
     67                                     } })
     68 
     69         } else {                // edit the selected contact
     70             NavigationLink {
     71                 let title = String(localized: "TitleEditContact",
     72                                 defaultValue: "Edit Contact", comment: "View Title, Button")
     73                 AddContactView(stack.push(), contact: contact, navTitle: title)
     74             } label: { label }
     75         }
     76     }
     77 }
     78 // MARK: -
     79 /// This view shows the list of contacts
     80 ///  called either from TalDir settings (without talerURI), or from CopyShare->TalDirButton (with talerURI)
     81 struct ContactsView: View {
     82     private let symLog = SymLogV(0)
     83     let stack: CallStack
     84     let talerURI: String?
     85     let subject: String?
     86 
     87     @EnvironmentObject private var model: WalletModel
     88     @EnvironmentObject private var controller: Controller
     89     @AppStorage("minimalistic") var minimalistic: Bool = false
     90     @AppStorage("myListStyle") var myListStyle: MyListStyle = .automatic
     91 
     92     @State private var contacts: [ContactEntry]? = nil
     93     @State private var showAddDialog: Bool = false
     94 
     95     var navTitle: String {
     96         String(localized: "TitleContacts", defaultValue: "Contacts")
     97     }
     98 
     99     var body: some View {
    100 #if PRINT_CHANGES
    101         let _ = Self._printChanges()
    102         let _ = symLog.vlog()       // just to get the # to compare it with .onAppear & onDisappear
    103 #endif
    104         let a11yLabelStr = String(localized: "Add contact", comment: "a11y for the + button")
    105         let plusButton = PlusButton(accessibilityLabelStr: a11yLabelStr) {
    106             showAddDialog = true
    107         }
    108         let addContactDest = AddContactView(stack.push())
    109         let actions = Group {
    110             NavLink($showAddDialog) { addContactDest }
    111         }
    112         let contacts = controller.contacts
    113         let ownEntries = contacts.filter({$0.isSelf == true })
    114         let otherEntries = contacts.filter({$0.isSelf != true })
    115         List {
    116             if !ownEntries.isEmpty {
    117                 Section(header: Text("Own contacts")) {
    118                     ForEachWithIndex(array: ownEntries) { index, contact in
    119                         ContactRowView(stack: stack.push(),
    120                                      contact: contact,
    121                                     talerURI: talerURI,
    122                                      subject: subject)
    123                     }
    124                 }
    125             }
    126             Section {
    127                 if otherEntries.isEmpty {
    128                     Text("No contacts yet...")
    129                 } else {
    130                     ForEachWithIndex(array: otherEntries) { index, contact in
    131                         ContactRowView(stack: stack.push(),
    132                                      contact: contact,
    133                                     talerURI: talerURI,
    134                                      subject: subject)
    135                     }
    136                 }
    137             }
    138         }
    139         .background(actions)
    140         .listStyle(myListStyle.style).anyView
    141 //        .task { await viewDidLoad() }
    142         .refreshable {
    143             controller.hapticNotification(.success)
    144             symLog.log("refreshing")
    145             await controller.loadContacts(stack.push())
    146         }
    147         .navigationTitle(navTitle)
    148         .navigationBarItems(trailing: plusButton)
    149         .onAppear() {
    150             DebugViewC.shared.setViewID(VIEW_CONTACTS, stack: stack.push())
    151         }
    152     } // body
    153 }