BroadcastToRelaysView.swift (5109B)
1 // 2 // BroadcastToRelaysView.swift 3 // damus 4 // 5 // Created by devandsev on 2/4/23. 6 // 7 8 import SwiftUI 9 10 extension BroadcastToRelaysView { 11 12 class ViewState: ObservableObject { 13 let damusState: DamusState 14 @Published var relayRows: [RowState] = [] 15 16 var hasExcludedRelays: Bool { relayRows.contains { !$0.isSelected } } 17 var selectedRelays: [RelayDescriptor] { relayRows.filter { $0.isSelected }.map { $0.relay } } 18 var limitingRelayIds: [String]? { 19 guard hasExcludedRelays else { 20 return nil 21 } 22 return selectedRelays.map { get_relay_id($0.url) } 23 } 24 25 init(state: DamusState) { 26 damusState = state 27 relayRows = state.pool.descriptors.map { RowState(relay: $0, isSelected: true) } 28 } 29 } 30 31 struct RowState: Equatable { 32 let relay: RelayDescriptor 33 var isSelected: Bool 34 } 35 } 36 37 /// A list of relays you can select to send your event to 38 /// 39 /// Can be presented in 2 modes: 40 /// - If `broadCastEvent` is nil, user selects relays, goes to the previous screen and the post/reply will be sent to selected relays only. Presented in this mode from `PostView` and `ReplyView` by tapping relays button. 41 /// - If `broadCastEvent` is not nil, there will be a "Broadcast" button in the navBar to broadcast this event to selected relays. Presented in this mode by long-pressing a post and choosing "Broadcast". 42 struct BroadcastToRelaysView: View { 43 @ObservedObject var state: ViewState 44 45 let broadCastEvent: NostrEvent? 46 47 @Environment(\.presentationMode) var presentationMode 48 49 func selectAll() { 50 $state.relayRows.forEach { $0.wrappedValue.isSelected = true } 51 } 52 53 func selectOne() { 54 guard let firstSelectedRow = $state.relayRows.first(where: { $0.wrappedValue.isSelected }) else { 55 $state.relayRows.forEach { $0.wrappedValue.isSelected = false } 56 $state.relayRows.first?.wrappedValue.isSelected = true 57 return 58 } 59 60 $state.relayRows.forEach { $0.wrappedValue.isSelected = false } 61 firstSelectedRow.wrappedValue.isSelected = true 62 } 63 64 func dismiss() { 65 self.presentationMode.wrappedValue.dismiss() 66 } 67 68 var body: some View { 69 NavigationView { 70 Form { 71 Section { 72 List(Array($state.relayRows), id: \.wrappedValue.relay.url) { $relayRow in 73 SelectableRowView(isSelected: $relayRow.isSelected, 74 shouldChangeSelection: { 75 return !relayRow.isSelected || $state.relayRows.filter { $0.wrappedValue.isSelected }.count > 1 76 77 } ) { 78 RelayView(state: state.damusState, relay: relayRow.relay.url.absoluteString) 79 } 80 } 81 } 82 header: { 83 HStack { 84 Text("Relays to send to", comment: "Section header text for relay server list. On this screen user can select to which specific relays the post should be sent.") 85 Spacer() 86 Button(NSLocalizedString("All", comment: "Button to select all relays in the list to which the post will be sent")) { 87 self.selectAll() 88 } 89 .disabled(!state.hasExcludedRelays) 90 Button(NSLocalizedString("One", comment: "Button to select only one relay from the list to which the post will be sent")) { 91 self.selectOne() 92 } 93 .disabled(state.selectedRelays.count == 1) 94 } 95 .buttonStyle(.bordered) 96 } 97 } 98 .toolbar { 99 ToolbarItem(placement: .navigationBarLeading) { 100 if broadCastEvent != nil { 101 Button(action: { 102 dismiss() 103 }) { 104 Text("Cancel", comment: "Navigation bar button to cancel broadcasting the user's note to all of the user's connected relay servers.") 105 }.foregroundColor(.primary) 106 } 107 } 108 ToolbarItem(placement: .navigationBarTrailing) { 109 if broadCastEvent != nil { 110 Button(action: { 111 if let broadCastEvent = broadCastEvent { 112 state.damusState.pool.send(.event(broadCastEvent), to: state.limitingRelayIds) 113 dismiss() 114 } 115 }) { 116 Text("Broadcast", comment: "Navigation bar button to confirm broadcasting the user's note to all of the user's connected relay servers.") 117 } 118 } 119 } 120 } 121 } 122 } 123 }