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 }