SearchView.swift (5700B)
1 // 2 // SearchView.swift 3 // damus 4 // 5 // Created by William Casarin on 2022-05-09. 6 // 7 8 import SwiftUI 9 10 struct SearchView: View { 11 let appstate: DamusState 12 @ObservedObject var search: SearchModel 13 @Environment(\.dismiss) var dismiss 14 @State var is_hashtag_muted: Bool = false 15 16 var content_filter: (NostrEvent) -> Bool { 17 let filters = ContentFilters.defaults(damus_state: self.appstate) 18 return ContentFilters(filters: filters).filter 19 } 20 21 let height: CGFloat = 250.0 22 23 var body: some View { 24 TimelineView(events: search.events, loading: $search.loading, damus: appstate, show_friend_icon: true, filter: content_filter) { 25 ZStack(alignment: .leading) { 26 DamusBackground(maxHeight: height) 27 .mask(LinearGradient(gradient: Gradient(colors: [.black, .black, .black, .clear]), startPoint: .top, endPoint: .bottom)) 28 SearchHeaderView(state: appstate, described: described_search) 29 .padding(.leading, 30) 30 .padding(.top, 100) 31 } 32 } 33 .ignoresSafeArea() 34 .onReceive(handle_notify(.switched_timeline)) { obj in 35 dismiss() 36 } 37 .onAppear() { 38 search.subscribe() 39 } 40 .onDisappear() { 41 search.unsubscribe() 42 } 43 .onReceive(handle_notify(.new_mutes)) { notif in 44 search.filter_muted() 45 46 if let hashtag_string = search.search.hashtag?.first, 47 notif.contains(MuteItem.hashtag(Hashtag(hashtag: hashtag_string), nil)) { 48 is_hashtag_muted = true 49 } 50 } 51 .onReceive(handle_notify(.new_unmutes)) { unmutes in 52 if let hashtag_string = search.search.hashtag?.first, 53 unmutes.contains(MuteItem.hashtag(Hashtag(hashtag: hashtag_string), nil)) { 54 is_hashtag_muted = false 55 } 56 } 57 .toolbar { 58 if let hashtag = search.search.hashtag?.first { 59 ToolbarItem(placement: .topBarTrailing) { 60 Menu { 61 if is_hashtag_muted { 62 Button { 63 guard 64 let full_keypair = appstate.keypair.to_full(), 65 let existing_mutelist = appstate.mutelist_manager.event, 66 let mutelist = remove_from_mutelist(keypair: full_keypair, prev: existing_mutelist, to_remove: .hashtag(Hashtag(hashtag: hashtag), nil)) 67 else { 68 return 69 } 70 71 appstate.mutelist_manager.set_mutelist(mutelist) 72 appstate.postbox.send(mutelist) 73 } label: { 74 Text("Unmute Hashtag", comment: "Label represnting a button that the user can tap to unmute a given hashtag so they start seeing it in their feed again.") 75 } 76 } else { 77 MuteDurationMenu { duration in 78 mute_hashtag(hashtag_string: hashtag, expiration_time: duration?.date_from_now) 79 } label: { 80 Text("Mute Hashtag", comment: "Label represnting a button that the user can tap to mute a given hashtag so they don't see it in their feed anymore.") 81 } 82 } 83 } label: { 84 Image(systemName: "ellipsis") 85 } 86 } 87 } 88 } 89 .onAppear { 90 if let hashtag_string = search.search.hashtag?.first { 91 is_hashtag_muted = (appstate.mutelist_manager.event?.mute_list ?? []).contains(MuteItem.hashtag(Hashtag(hashtag: hashtag_string), nil)) 92 } 93 } 94 } 95 96 func mute_hashtag(hashtag_string: String, expiration_time: Date?) { 97 let existing_mutelist = appstate.mutelist_manager.event 98 99 guard 100 let full_keypair = appstate.keypair.to_full(), 101 let mutelist = create_or_update_mutelist(keypair: full_keypair, mprev: existing_mutelist, to_add: .hashtag(Hashtag(hashtag: hashtag_string), expiration_time)) 102 else { 103 return 104 } 105 106 appstate.mutelist_manager.set_mutelist(mutelist) 107 appstate.postbox.send(mutelist) 108 } 109 110 var described_search: DescribedSearch { 111 return describe_search(search.search) 112 } 113 } 114 115 enum DescribedSearch: CustomStringConvertible { 116 case hashtag(String) 117 case unknown 118 119 var is_hashtag: String? { 120 switch self { 121 case .hashtag(let ht): 122 return ht 123 case .unknown: 124 return nil 125 } 126 } 127 128 var description: String { 129 switch self { 130 case .hashtag(let s): 131 return "#" + s 132 case .unknown: 133 return NSLocalizedString("Search", comment: "Default title for the search screen when it is in an unknown state.") 134 } 135 } 136 } 137 138 func describe_search(_ filter: NostrFilter) -> DescribedSearch { 139 if let hashtags = filter.hashtag { 140 if hashtags.count >= 1 { 141 return .hashtag(hashtags[0]) 142 } 143 } 144 145 return .unknown 146 } 147 148 struct SearchView_Previews: PreviewProvider { 149 static var previews: some View { 150 let test_state = test_damus_state 151 let filter = NostrFilter(hashtag: ["bitcoin"]) 152 153 let model = SearchModel(state: test_state, search: filter) 154 155 SearchView(appstate: test_state, search: model) 156 } 157 }