Search hashtags automatically

Changelog-Changed: Search hashtags automatically
This commit is contained in:
William Casarin
2023-05-02 08:22:36 -07:00
parent 4f459d128a
commit 8eb013f1f7
2 changed files with 123 additions and 58 deletions

View File

@@ -87,6 +87,8 @@ class SearchModel: ObservableObject {
return return
} }
self.loading = false
if sub_id == self.sub_id { if sub_id == self.sub_id {
load_profiles(profiles_subid: self.profiles_subid, relay_id: relay_id, load: .from_events(self.events.all_events), damus_state: state) load_profiles(profiles_subid: self.profiles_subid, relay_id: relay_id, load: .from_events(self.events.all_events), damus_state: state)
} }

View File

@@ -7,82 +7,132 @@
import SwiftUI import SwiftUI
enum Search { struct MultiSearch {
let hashtag: String
let profiles: [SearchedUser]
}
enum Search: Identifiable {
case profiles([SearchedUser]) case profiles([SearchedUser])
case hashtag(String) case hashtag(String)
case profile(String) case profile(String)
case note(String) case note(String)
case nip05(String) case nip05(String)
case hex(String) case hex(String)
case multi(MultiSearch)
var id: String {
switch self {
case .profiles: return "profiles"
case .hashtag: return "hashtag"
case .profile: return "profile"
case .note: return "note"
case .nip05: return "nip05"
case .hex: return "hex"
case .multi: return "multi"
}
}
} }
struct SearchResultsView: View { struct AnySearchResultsView: View {
let damus_state: DamusState let damus_state: DamusState
@Binding var search: String let searches: [Search]
@State var result: Search? = nil var body: some View {
VStack {
ForEach(searches) { r in
InnerSearchResults(damus_state: damus_state, search: r)
}
}
}
}
struct InnerSearchResults: View {
let damus_state: DamusState
let search: Search?
func ProfileSearchResult(pk: String) -> some View { func ProfileSearchResult(pk: String) -> some View {
FollowUserView(target: .pubkey(pk), damus_state: damus_state) FollowUserView(target: .pubkey(pk), damus_state: damus_state)
} }
var MainContent: some View { func HashtagSearch(_ ht: String) -> some View {
ScrollView { let search_model = SearchModel(state: damus_state, search: .filter_hashtag([ht]))
Group { let dst = SearchView(appstate: damus_state, search: search_model)
switch result { return NavigationLink(destination: dst) {
case .profiles(let results): Text("Search hashtag: #\(ht)", comment: "Navigation link to search hashtag.")
LazyVStack { }
ForEach(results) { prof in }
ProfileSearchResult(pk: prof.pubkey)
}
}
case .hashtag(let ht):
let search_model = SearchModel(state: damus_state, search: .filter_hashtag([ht]))
let dst = SearchView(appstate: damus_state, search: search_model)
NavigationLink(destination: dst) {
Text("Search hashtag: #\(ht)", comment: "Navigation link to search hashtag.")
}
case .nip05(let addr): func ProfilesSearch(_ results: [SearchedUser]) -> some View {
SearchingEventView(state: damus_state, evid: addr, search_type: .nip05) return LazyVStack {
ForEach(results) { prof in
case .profile(let prof): ProfileSearchResult(pk: prof.pubkey)
let decoded = try? bech32_decode(prof)
let hex = hex_encode(decoded!.data)
SearchingEventView(state: damus_state, evid: hex, search_type: .profile)
case .hex(let h):
//let prof_view = ProfileView(damus_state: damus_state, pubkey: h)
//let ev_view = ThreadView(damus: damus_state, event_id: h)
VStack(spacing: 10) {
SearchingEventView(state: damus_state, evid: h, search_type: .event)
SearchingEventView(state: damus_state, evid: h, search_type: .profile)
}
case .note(let nid):
let decoded = try? bech32_decode(nid)
let hex = hex_encode(decoded!.data)
SearchingEventView(state: damus_state, evid: hex, search_type: .event)
case .none:
Text("none", comment: "No search results.")
}
} }
.padding()
} }
} }
var body: some View { var body: some View {
MainContent Group {
.frame(maxHeight: .infinity) switch search {
.onAppear { case .profiles(let results):
self.result = search_for_string(profiles: damus_state.profiles, search) ProfilesSearch(results)
}
.onChange(of: search) { new in case .hashtag(let ht):
self.result = search_for_string(profiles: damus_state.profiles, new) HashtagSearch(ht)
case .nip05(let addr):
SearchingEventView(state: damus_state, evid: addr, search_type: .nip05)
case .profile(let prof):
let decoded = try? bech32_decode(prof)
let hex = hex_encode(decoded!.data)
SearchingEventView(state: damus_state, evid: hex, search_type: .profile)
case .hex(let h):
//let prof_view = ProfileView(damus_state: damus_state, pubkey: h)
//let ev_view = ThreadView(damus: damus_state, event_id: h)
VStack(spacing: 10) {
SearchingEventView(state: damus_state, evid: h, search_type: .event)
SearchingEventView(state: damus_state, evid: h, search_type: .profile)
}
case .note(let nid):
let decoded = try? bech32_decode(nid)
let hex = hex_encode(decoded!.data)
SearchingEventView(state: damus_state, evid: hex, search_type: .event)
case .multi(let multi):
VStack {
HashtagSearch(multi.hashtag)
ProfilesSearch(multi.profiles)
}
case .none:
Text("none", comment: "No search results.")
} }
}
}
}
struct SearchResultsView: View {
let damus_state: DamusState
@Binding var search: String
@State var result: Search? = nil
var body: some View {
ScrollView {
InnerSearchResults(damus_state: damus_state, search: result)
.padding()
}
.frame(maxHeight: .infinity)
.onAppear {
self.result = search_for_string(profiles: damus_state.profiles, search)
}
.onChange(of: search) { new in
self.result = search_for_string(profiles: damus_state.profiles, new)
}
} }
} }
@@ -107,8 +157,7 @@ func search_for_string(profiles: Profiles, _ new: String) -> Search? {
} }
if new.first! == "#" { if new.first! == "#" {
let ht = String(new.dropFirst().filter{$0 != " "}) return .hashtag(make_hashtagable(new))
return .hashtag(ht)
} }
if hex_decode(new) != nil, new.count == 64 { if hex_decode(new) != nil, new.count == 64 {
@@ -127,7 +176,21 @@ func search_for_string(profiles: Profiles, _ new: String) -> Search? {
} }
} }
return .profiles(search_profiles(profiles: profiles, search: new)) let multisearch = MultiSearch(hashtag: make_hashtagable(new), profiles: search_profiles(profiles: profiles, search: new))
return .multi(multisearch)
}
func make_hashtagable(_ str: String) -> String {
var new = str
guard str.utf8.count > 0 else {
return str
}
if new.hasPrefix("#") {
new = String(new.dropFirst())
}
return String(new.filter{$0 != " "})
} }
func search_profiles(profiles: Profiles, search: String) -> [SearchedUser] { func search_profiles(profiles: Profiles, search: String) -> [SearchedUser] {