damus

nostr ios client
git clone git://jb55.com/damus
Log | Files | Refs | README | LICENSE

ConfigView.swift (11250B)


      1 //
      2 //  ConfigView.swift
      3 //  damus
      4 //
      5 //  Created by William Casarin on 2022-06-09.
      6 //
      7 import AVFoundation
      8 import Kingfisher
      9 import SwiftUI
     10 import LocalAuthentication
     11 import Combine
     12 
     13 struct ConfigView: View {
     14     let state: DamusState
     15     @Environment(\.colorScheme) var colorScheme
     16     @Environment(\.dismiss) var dismiss
     17     @State var confirm_logout: Bool = false
     18     @State var delete_account_warning: Bool = false
     19     @State var confirm_delete_account: Bool = false
     20     @State var delete_text: String = ""
     21     @State private var searchText: String = ""
     22 
     23     @ObservedObject var settings: UserSettingsStore
     24     
     25     // String constants
     26     private let DELETE_KEYWORD = "DELETE"
     27     private let keysTitle = NSLocalizedString("Keys", comment: "Settings section for managing keys")
     28     private let appearanceTitle = NSLocalizedString("Appearance and filters", comment: "Section header for text, appearance, and content filter settings")
     29     private let searchUniverseTitle = NSLocalizedString("Search / Universe", comment: "Section header for search/universe settings")
     30     private let notificationsTitle = NSLocalizedString("Notifications", comment: "Section header for Damus notifications")
     31     private let zapsTitle = NSLocalizedString("Zaps", comment: "Section header for zap settings")
     32     private let translationTitle = NSLocalizedString("Translation", comment: "Section header for text and appearance settings")
     33     private let reactionsTitle = NSLocalizedString("Reactions", comment: "Section header for reactions settings")
     34     private let developerTitle = NSLocalizedString("Developer", comment: "Section header for developer settings")
     35     private let firstAidTitle = NSLocalizedString("First Aid", comment: "Section header for first aid tools and settings")
     36     private let signOutTitle = NSLocalizedString("Sign out", comment: "Sidebar menu label to sign out of the account.")
     37     private let deleteAccountTitle = NSLocalizedString("Delete Account", comment: "Button to delete the user's account.")
     38     private let versionTitle = NSLocalizedString("Version", comment: "Section title for displaying the version number of the Damus app.")
     39     private let copyString = NSLocalizedString("Copy", comment: "Context menu option for copying the version of damus.")
     40     
     41     init(state: DamusState) {
     42         self.state = state
     43         _settings = ObservedObject(initialValue: state.settings)
     44     }
     45 
     46     func textColor() -> Color {
     47         colorScheme == .light ? DamusColors.black : DamusColors.white
     48     }
     49     
     50     func showSettingsButton(title : String)->Bool{
     51         return searchText.isEmpty || title.lowercased().contains(searchText.lowercased())
     52     }
     53     
     54     var body: some View {
     55         ZStack(alignment: .leading) {
     56             Form {
     57                 Section {
     58                     // Keys
     59                     if showSettingsButton(title: keysTitle){
     60                         NavigationLink(value:Route.KeySettings(keypair: state.keypair)){
     61                             IconLabel(keysTitle,img_name:"Key",color:.purple)
     62                         }
     63                     }
     64                     // Appearance and filters
     65                     if showSettingsButton(title: appearanceTitle){
     66                         NavigationLink(value:Route.AppearanceSettings(settings: settings)){
     67                             IconLabel(appearanceTitle,img_name:"eye",color:.red)
     68                         }
     69                     }
     70                     // Search/Universe
     71                     if showSettingsButton(title: searchUniverseTitle){
     72                         NavigationLink(value: Route.SearchSettings(settings: settings)){
     73                             IconLabel(searchUniverseTitle,img_name:"search",color:.red)
     74                         }
     75                     }
     76 
     77                     //Notifications
     78                     if showSettingsButton(title: notificationsTitle){
     79                         NavigationLink(value: Route.NotificationSettings(settings: settings)){
     80                             IconLabel(notificationsTitle,img_name:"notification-bell-on",color:.blue)
     81                         }
     82                     }
     83                     //Zaps
     84                     if showSettingsButton(title: zapsTitle){
     85                         NavigationLink(value: Route.ZapSettings(settings: settings)){
     86                             IconLabel(zapsTitle,img_name:"zap.fill",color:.orange)
     87                         }
     88                     }
     89                     //Translation
     90                     if showSettingsButton(title: translationTitle){
     91                         NavigationLink(value: Route.TranslationSettings(settings: settings)){
     92                             IconLabel(translationTitle,img_name:"globe",color:.green)
     93                         }
     94                     }
     95                     //Reactions
     96                     if showSettingsButton(title: reactionsTitle){
     97                         NavigationLink(value: Route.ReactionsSettings(settings: settings)){
     98                             IconLabel(reactionsTitle,img_name:"shaka.fill",color:.purple)
     99                         }
    100                     }
    101                     //Developer
    102                     if showSettingsButton(title: developerTitle){
    103                         NavigationLink(value: Route.DeveloperSettings(settings: settings)){
    104                             IconLabel(developerTitle,img_name:"magic-stick2.fill",color:DamusColors.adaptableBlack)
    105                         }
    106                     }
    107                     //First Aid
    108                     if showSettingsButton(title: firstAidTitle){
    109                         NavigationLink(value: Route.FirstAidSettings(settings: settings)){
    110                             IconLabel(firstAidTitle,img_name:"help2",color: .red)
    111                         }
    112                     }
    113                 }
    114                 //Sign out Section
    115                 if showSettingsButton(title: signOutTitle){
    116                     Section(signOutTitle){
    117                         Button(action: {
    118                             if state.keypair.privkey == nil {
    119                                 logout(state)
    120                             } else {
    121                                 confirm_logout = true
    122                             }
    123                         }, label: {
    124                             Label(signOutTitle, image: "logout")
    125                                 .foregroundColor(textColor())
    126                                 .frame(maxWidth: .infinity, alignment: .leading)
    127                         })
    128                     }
    129                 }
    130                 // Delete Account
    131                 if showSettingsButton(title: deleteAccountTitle){
    132                     if state.is_privkey_user {
    133                         Section(header: Text("Permanently Delete Account", comment: "Section title for deleting the user")) {
    134                             Button(action: {
    135                                 delete_account_warning = true
    136                             }, label: {
    137                                 Label(deleteAccountTitle, image: "delete")
    138                                     .frame(maxWidth: .infinity, alignment: .leading)
    139                                     .foregroundColor(.red)
    140                             })
    141                         }
    142                     }
    143                 }
    144                 // Version info
    145                 if showSettingsButton(title: versionTitle) {
    146                     Section(
    147                         header: Text(versionTitle),
    148                         footer: Text("").padding(.bottom, tabHeight + getSafeAreaBottom())
    149                     ) {
    150                         Text(verbatim: VersionInfo.version)
    151                             .contextMenu {
    152                                 Button {
    153                                     UIPasteboard.general.string = VersionInfo.version
    154                                 } label: {
    155                                     Label(copyString, image: "copy2")
    156                                 }
    157                             }
    158                     }
    159                 }
    160             }
    161         }
    162         .navigationTitle(NSLocalizedString("Settings", comment: "Navigation title for Settings view."))
    163         .navigationBarTitleDisplayMode(.large)
    164         .searchable(text: $searchText, prompt: NSLocalizedString("Search within settings", comment: "Text to prompt the user to search settings."))
    165         .alert(NSLocalizedString("WARNING:\n\nTHIS WILL SIGN AN EVENT THAT DELETES THIS ACCOUNT.\n\nYOU WILL NO LONGER BE ABLE TO LOG INTO DAMUS USING THIS ACCOUNT KEY.\n\n ARE YOU SURE YOU WANT TO CONTINUE?", comment: "Alert for deleting the users account."), isPresented: $delete_account_warning) {
    166 
    167             Button(NSLocalizedString("Cancel", comment: "Cancel deleting the user."), role: .cancel) {
    168                 delete_account_warning = false
    169             }
    170             Button(NSLocalizedString("Continue", comment: "Continue with deleting the user.")) {
    171                 confirm_delete_account = true
    172             }
    173         }
    174         .alert(NSLocalizedString("Permanently Delete Account", comment: "Alert for deleting the users account."), isPresented: $confirm_delete_account) {
    175             TextField(String(format: NSLocalizedString("Type %@ to delete", comment: "Text field prompt asking user to type DELETE in all caps to confirm that they want to proceed with deleting their account."), DELETE_KEYWORD), text: $delete_text)
    176             Button(NSLocalizedString("Cancel", comment: "Cancel deleting the user."), role: .cancel) {
    177                 confirm_delete_account = false
    178             }
    179             Button(NSLocalizedString("Delete", comment: "Button for deleting the users account."), role: .destructive) {
    180                 guard let keypair = state.keypair.to_full(),
    181                       delete_text == DELETE_KEYWORD,
    182                       let ev = created_deleted_account_profile(keypair: keypair) else {
    183                     return
    184                 }
    185                 state.nostrNetwork.postbox.send(ev)
    186                 logout(state)
    187             }
    188         }
    189         .alert(NSLocalizedString("Logout", comment: "Alert for logging out the user."), isPresented: $confirm_logout) {
    190             Button(NSLocalizedString("Cancel", comment: "Cancel out of logging out the user."), role: .cancel) {
    191                 confirm_logout = false
    192             }
    193             Button(NSLocalizedString("Logout", comment: "Button for logging out the user."), role: .destructive) {
    194                 logout(state)
    195             }
    196         } message: {
    197                 Text("Make sure your nsec account key is saved before you logout or you will lose access to this account", comment: "Reminder message in alert to get customer to verify that their private security account key is saved saved before logging out.")
    198         }
    199         .onReceive(handle_notify(.switched_timeline)) { _ in
    200             dismiss()
    201         }
    202     }
    203 }
    204 
    205 struct ConfigView_Previews: PreviewProvider {
    206     static var previews: some View {
    207         NavigationView {
    208             ConfigView(state: test_damus_state)
    209         }
    210     }
    211 }
    212 
    213 
    214 func handle_string_amount(new_value: String) -> Int? {
    215     let filtered = new_value.filter {
    216         $0.isNumber
    217     }
    218 
    219     if filtered == "" {
    220         return nil
    221     }
    222 
    223     guard let amt = NumberFormatter().number(from: filtered) as? Int else {
    224         return nil
    225     }
    226 
    227     return amt
    228 }