damus

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

FirstAidSettingsView.swift (8095B)


      1 //
      2 //  FirstAidSettingsView.swift
      3 //  damus
      4 //
      5 //  Created by Daniel D’Aquino on 2024-04-19.
      6 //
      7 
      8 import SwiftUI
      9 
     10 struct FirstAidSettingsView: View {
     11     let damus_state: DamusState
     12     @ObservedObject var settings: UserSettingsStore
     13     @State var contactListInitiallyPresent: Bool = true
     14     @State var relayListInitiallyPresent: Bool = true
     15     
     16     var body: some View {
     17         Form {
     18             if !contactListInitiallyPresent {
     19                 ItemResetSection(
     20                     damus_state: self.damus_state,
     21                     settings: self.settings,
     22                     itemName: NSLocalizedString("Contact list", comment: "Section title for Contact list first aid tools"),
     23                     hintMessage: NSLocalizedString(
     24                         "No contact list was found. You might experience issues using the app. If you suspect you have permanently lost your contact list (or if you never had one), you can fix this by resetting it",
     25                         comment: "Section footer for Contact list first aid tools"
     26                     ),
     27                     resetButtonLabel: NSLocalizedString("Reset contact list", comment: "Button to reset contact list."),
     28                     warningMessage: NSLocalizedString(
     29                         "WARNING:\n\nThis will reset your contact list, including the list of everyone you follow and potentially the list of all relays you usually connect to. ONLY PROCEED IF YOU ARE SURE YOU HAVE LOST YOUR CONTACT LIST BEYOND RECOVERABILITY.",
     30                         comment: "Alert for resetting the user's contact list."),
     31                     successMessage: NSLocalizedString("Contact list has been reset", comment: "Message indicating that the contact list was successfully reset."),
     32                     performOperation: {
     33                         try await self.resetContactList()
     34                     }
     35                 )
     36             }
     37             
     38             if !relayListInitiallyPresent {
     39                 ItemResetSection(
     40                     damus_state: self.damus_state,
     41                     settings: self.settings,
     42                     itemName: NSLocalizedString("Relay list", comment: "Section title for Relay list first aid tools"),
     43                     hintMessage: NSLocalizedString(
     44                         "No relay list was found. You might experience issues using the app. If you suspect you have permanently lost your relay list (or if you never had one), you can fix this by resetting it",
     45                         comment: "Section footer for relay list first aid tools"
     46                     ),
     47                     resetButtonLabel: NSLocalizedString("Repair relay list", comment: "Button to repair relay list."),
     48                     warningMessage: NSLocalizedString("WARNING:\n\nThis will attempt to repair your relay list based on other information we have. You may lose any relays you have added manually. Only proceed if you have lost your relay list beyond recoverability or if you are ok with losing any manually added relays.", comment: "Alert for repairing the user's relay list."),
     49                     successMessage: NSLocalizedString("Relay list has been repaired", comment: "Message indicating that the relay list was successfully repaired."),
     50                     performOperation: {
     51                         try await self.resetRelayList()
     52                     }
     53                 )
     54             }
     55             
     56             if contactListInitiallyPresent && contactListInitiallyPresent {
     57                 Text("We did not detect any issues that we can automatically fix for you. If you are having issues, please contact Damus support: [support@damus.io](mailto:support@damus.io)", comment: "Message indicating that no First Aid actions are available.")
     58             }
     59         }
     60         .navigationTitle(NSLocalizedString("First Aid", comment: "Navigation title for first aid settings and tools"))
     61         .onAppear {
     62             self.contactListInitiallyPresent = damus_state.contacts.event != nil
     63             self.relayListInitiallyPresent = damus_state.nostrNetwork.userRelayList.getUserCurrentRelayList() != nil
     64         }
     65     }
     66     
     67     func resetContactList() async throws {
     68         guard let new_contact_list_event = make_first_contact_event(keypair: damus_state.keypair) else {
     69             throw FirstAidError.cannotMakeFirstContactEvent
     70         }
     71         damus_state.nostrNetwork.pool.send(.event(new_contact_list_event))
     72         damus_state.settings.latest_contact_event_id_hex = new_contact_list_event.id.hex()
     73     }
     74     
     75     func resetRelayList() async throws {
     76         let bestEffortRelayList = damus_state.nostrNetwork.userRelayList.getBestEffortRelayList()
     77         try damus_state.nostrNetwork.userRelayList.set(userRelayList: bestEffortRelayList)
     78     }
     79     
     80     enum FirstAidError: Error {
     81         case cannotMakeFirstContactEvent
     82     }
     83 }
     84 
     85 extension FirstAidSettingsView {
     86     struct ItemResetSection: View {
     87         let damus_state: DamusState
     88         @ObservedObject var settings: UserSettingsStore
     89         @State var reset_item_state: ItemResetState = .not_started
     90         
     91         let itemName: String
     92         let hintMessage: String
     93         let resetButtonLabel: String
     94         let warningMessage: String
     95         let successMessage: String
     96         var performOperation: () async throws -> Void
     97         
     98         enum ItemResetState: Equatable {
     99             case not_started
    100             case confirming_with_user
    101             case error(String)
    102             case in_progress
    103             case completed
    104         }
    105         
    106         var body: some View {
    107             Section(
    108                 header: Text(itemName),
    109                 footer: Text(hintMessage)
    110             ) {
    111                 Button(action: {
    112                     reset_item_state = .confirming_with_user
    113                 }, label: {
    114                     HStack(spacing: 6) {
    115                         switch reset_item_state {
    116                         case .not_started, .error:
    117                             Label(resetButtonLabel, image: "broom")
    118                                 .frame(maxWidth: .infinity, alignment: .leading)
    119                                 .foregroundColor(.red)
    120                         case .confirming_with_user, .in_progress:
    121                             ProgressView()
    122                             Text(NSLocalizedString("In progress…", comment: "Loading message indicating that a first aid operation is in progress."))
    123                         case .completed:
    124                             Image(systemName: "checkmark.circle.fill")
    125                                 .foregroundColor(.green)
    126                             Text(successMessage)
    127                         }
    128                     }
    129                 })
    130                 .disabled(reset_item_state == .in_progress || reset_item_state == .completed)
    131                 
    132                 if case let .error(error_message) = reset_item_state {
    133                     Text(error_message)
    134                         .foregroundStyle(.red)
    135                 }
    136             }
    137             .alert(warningMessage, isPresented: Binding(get: { reset_item_state == .confirming_with_user }, set: { _ in return })
    138             ) {
    139                 Button(NSLocalizedString("Cancel", comment: "Cancel the user-requested operation."), role: .cancel) {
    140                     reset_item_state = .not_started
    141                 }
    142                 Button(NSLocalizedString("Continue", comment: "Continue with the user-requested operation.")) {
    143                     Task {
    144                         do {
    145                             try await performOperation()
    146                             reset_item_state = .completed
    147                         }
    148                         catch {
    149                             reset_item_state = .error(NSLocalizedString("An unexpected error happened while trying to perform this action. Please contact support.", comment: "Error message for a failed reset/repair operation"))
    150                         }
    151                     }
    152                 }
    153             }
    154         }
    155     }
    156 }
    157 
    158 #Preview {
    159     FirstAidSettingsView(damus_state: test_damus_state, settings: test_damus_state.settings)
    160 }