AddRelayView.swift (6268B)
1 // 2 // AddRelayView.swift 3 // damus 4 // 5 // Created by William Casarin on 2022-06-09. 6 // 7 8 import SwiftUI 9 10 struct AddRelayView: View { 11 let state: DamusState 12 @State var new_relay: String = "" 13 @State var relayAddErrorTitle: String? = nil 14 @State var relayAddErrorMessage: String? = nil 15 16 @Environment(\.dismiss) var dismiss 17 18 var body: some View { 19 VStack { 20 Text("Add relay", comment: "Title text to indicate user to an add a relay.") 21 .font(.system(size: 20, weight: .bold)) 22 .padding(.vertical) 23 24 Divider() 25 .padding(.bottom) 26 27 HStack { 28 Label("", image: "copy2") 29 .onTapGesture { 30 if let pastedrelay = UIPasteboard.general.string { 31 self.new_relay = pastedrelay 32 } 33 } 34 TextField(NSLocalizedString("wss://some.relay.com", comment: "Placeholder example for relay server address."), text: $new_relay) 35 .autocorrectionDisabled(true) 36 .textInputAutocapitalization(.never) 37 38 Label("", image: "close-circle") 39 .foregroundColor(.accentColor) 40 .opacity((new_relay == "") ? 0.0 : 1.0) 41 .onTapGesture { 42 self.new_relay = "" 43 } 44 } 45 .padding(10) 46 .background(.secondary.opacity(0.2)) 47 .cornerRadius(10) 48 49 if let errorMessage = relayAddErrorMessage { 50 VStack(spacing: 0) { 51 HStack(alignment: .top) { 52 Text(relayAddErrorTitle ?? "Error") 53 .bold() 54 .foregroundColor(DamusColors.dangerSecondary) 55 .padding(.leading) 56 Spacer() 57 Button(action: { 58 relayAddErrorTitle = nil // Clear error title 59 relayAddErrorMessage = nil // Clear error message 60 self.new_relay = "" 61 }, label: { 62 Image("close") 63 .frame(width: 20, height: 20) 64 .foregroundColor(DamusColors.dangerSecondary) 65 }) 66 .padding(.trailing) 67 } 68 69 Text(errorMessage) 70 .foregroundColor(DamusColors.dangerSecondary) 71 .padding(.top, 10) 72 } 73 .frame(minWidth: 300, maxWidth: .infinity, minHeight: 120, alignment: .center) 74 .background { 75 RoundedRectangle(cornerRadius: 12) 76 .fill(DamusColors.dangerBorder, strokeBorder: .gray.opacity(0.5), lineWidth: 1) 77 } 78 } 79 80 Button(action: { 81 if new_relay.starts(with: "wss://") == false && new_relay.starts(with: "ws://") == false { 82 new_relay = "wss://" + new_relay 83 } 84 85 guard let url = RelayURL(new_relay), 86 let ev = state.contacts.event, 87 let keypair = state.keypair.to_full() else { 88 return 89 } 90 91 let info = RelayInfo.rw 92 let descriptor = RelayDescriptor(url: url, info: info) 93 94 do { 95 try state.pool.add_relay(descriptor) 96 relayAddErrorTitle = nil // Clear error title 97 relayAddErrorMessage = nil // Clear error message 98 } catch RelayError.RelayAlreadyExists { 99 relayAddErrorTitle = NSLocalizedString("Duplicate relay", comment: "Title of the duplicate relay error message.") 100 relayAddErrorMessage = NSLocalizedString("The relay you are trying to add is already added.\nYou're all set!", comment: "An error message that appears when the user attempts to add a relay that has already been added.") 101 return 102 } catch { 103 return 104 } 105 106 state.pool.connect(to: [url]) 107 108 if let new_ev = add_relay(ev: ev, keypair: keypair, current_relays: state.pool.our_descriptors, relay: url, info: info) { 109 process_contact_event(state: state, ev: ev) 110 111 state.pool.send(.event(new_ev)) 112 } 113 114 if let relay_metadata = make_relay_metadata(relays: state.pool.our_descriptors, keypair: keypair) { 115 state.postbox.send(relay_metadata) 116 } 117 new_relay = "" 118 119 UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil) 120 121 dismiss() 122 }) { 123 HStack { 124 Text(verbatim: "Add relay") 125 .bold() 126 } 127 .frame(minWidth: 300, maxWidth: .infinity, alignment: .center) 128 } 129 .buttonStyle(GradientButtonStyle(padding: 10)) 130 //.disabled(!new_relay.isValidURL) <--- TODO 131 .padding(.vertical) 132 133 Spacer() 134 } 135 .padding() 136 } 137 } 138 139 // TODO 140 // This works sometimes, in certain cases where the relay is valid it won't allow the user to add it 141 // Needs improvement 142 extension String { 143 var isValidURL: Bool { 144 let detector = try! NSDataDetector(types: NSTextCheckingResult.CheckingType.link.rawValue) 145 if let match = detector.firstMatch(in: self, options: [], range: NSRange(location: 0, length: self.utf16.count)) { 146 // it is a link, if the match covers the whole string 147 return match.range.length == self.utf16.count 148 } else { 149 return false 150 } 151 } 152 } 153 154 struct AddRelayView_Previews: PreviewProvider { 155 @State static var relay: String = "" 156 157 static var previews: some View { 158 AddRelayView(state: test_damus_state) 159 } 160 }