commit 8eb013f1f70b686e146edfa2efb053de0b996cd7
parent 4f459d128a5761143c4ec71af63b56091c95a46b
Author: William Casarin <jb55@jb55.com>
Date: Tue, 2 May 2023 08:22:36 -0700
Search hashtags automatically
Changelog-Changed: Search hashtags automatically
Diffstat:
2 files changed, 122 insertions(+), 57 deletions(-)
diff --git a/damus/Models/SearchModel.swift b/damus/Models/SearchModel.swift
@@ -87,6 +87,8 @@ class SearchModel: ObservableObject {
return
}
+ self.loading = false
+
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)
}
diff --git a/damus/Views/SearchResultsView.swift b/damus/Views/SearchResultsView.swift
@@ -7,82 +7,132 @@
import SwiftUI
-enum Search {
+struct MultiSearch {
+ let hashtag: String
+ let profiles: [SearchedUser]
+}
+
+enum Search: Identifiable {
case profiles([SearchedUser])
case hashtag(String)
case profile(String)
case note(String)
case nip05(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
- @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 {
FollowUserView(target: .pubkey(pk), damus_state: damus_state)
}
- var MainContent: some View {
- ScrollView {
- Group {
- switch result {
- case .profiles(let results):
- 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):
- 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)
+ func HashtagSearch(_ ht: String) -> some View {
+ let search_model = SearchModel(state: damus_state, search: .filter_hashtag([ht]))
+ let dst = SearchView(appstate: damus_state, search: search_model)
+ return NavigationLink(destination: dst) {
+ Text("Search hashtag: #\(ht)", comment: "Navigation link to search hashtag.")
+ }
+ }
+
+ func ProfilesSearch(_ results: [SearchedUser]) -> some View {
+ return LazyVStack {
+ ForEach(results) { prof in
+ ProfileSearchResult(pk: prof.pubkey)
+ }
+ }
+ }
+
+ var body: some View {
+ Group {
+ switch search {
+ case .profiles(let results):
+ ProfilesSearch(results)
+
+ case .hashtag(let ht):
+ 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: hex, search_type: .event)
- case .none:
- Text("none", comment: "No search results.")
+ 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.")
}
- .padding()
}
}
+}
+
+struct SearchResultsView: View {
+ let damus_state: DamusState
+ @Binding var search: String
+ @State var result: Search? = nil
var body: some View {
- MainContent
- .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)
- }
+ 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! == "#" {
- let ht = String(new.dropFirst().filter{$0 != " "})
- return .hashtag(ht)
+ return .hashtag(make_hashtagable(new))
}
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] {