commit 4bf8a68c9c13e4af3548a55e7f40a92476a13d4e
parent 0a9ac9cb0db4c04f591c21f7823155ea81fab87e
Author: William Casarin <jb55@jb55.com>
Date: Sun, 3 Dec 2023 22:13:46 -0800
search: add damus search ui
Diffstat:
4 files changed, 120 insertions(+), 13 deletions(-)
diff --git a/damus.xcodeproj/project.pbxproj b/damus.xcodeproj/project.pbxproj
@@ -260,6 +260,7 @@
4C9B0DF32A65C46800CBDA21 /* ProfileEditButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C9B0DF22A65C46800CBDA21 /* ProfileEditButton.swift */; };
4C9BB83129C0ED4F00FC4E37 /* DisplayName.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C9BB83029C0ED4F00FC4E37 /* DisplayName.swift */; };
4C9BB83429C12D9900FC4E37 /* EventProfileName.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C9BB83329C12D9900FC4E37 /* EventProfileName.swift */; };
+ 4C9D6D1B2B1D35D7004E5CD9 /* PullDownSearch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C9D6D1A2B1D35D7004E5CD9 /* PullDownSearch.swift */; };
4C9F18E229AA9B6C008C55EC /* CustomizeZapView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C9F18E129AA9B6C008C55EC /* CustomizeZapView.swift */; };
4C9F18E429ABDE6D008C55EC /* MaybeAnonPfpView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C9F18E329ABDE6D008C55EC /* MaybeAnonPfpView.swift */; };
4CA2EFA0280E37AC0044ACD8 /* TimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CA2EF9F280E37AC0044ACD8 /* TimelineView.swift */; };
@@ -1057,6 +1058,7 @@
4C9B0DF22A65C46800CBDA21 /* ProfileEditButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileEditButton.swift; sourceTree = "<group>"; };
4C9BB83029C0ED4F00FC4E37 /* DisplayName.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DisplayName.swift; sourceTree = "<group>"; };
4C9BB83329C12D9900FC4E37 /* EventProfileName.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventProfileName.swift; sourceTree = "<group>"; };
+ 4C9D6D1A2B1D35D7004E5CD9 /* PullDownSearch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PullDownSearch.swift; sourceTree = "<group>"; };
4C9F18E129AA9B6C008C55EC /* CustomizeZapView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomizeZapView.swift; sourceTree = "<group>"; };
4C9F18E329ABDE6D008C55EC /* MaybeAnonPfpView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MaybeAnonPfpView.swift; sourceTree = "<group>"; };
4CA2EF9F280E37AC0044ACD8 /* TimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineView.swift; sourceTree = "<group>"; };
@@ -2188,6 +2190,7 @@
children = (
4CCEB7AD29B53D260078AA28 /* SearchingEventView.swift */,
4CCEB7AF29B5415A0078AA28 /* SearchingProfileView.swift */,
+ 4C9D6D1A2B1D35D7004E5CD9 /* PullDownSearch.swift */,
);
path = Search;
sourceTree = "<group>";
@@ -2867,7 +2870,6 @@
4C32B9582A9AD44700DC3548 /* VeriferOptions.swift in Sources */,
4CA2EFA0280E37AC0044ACD8 /* TimelineView.swift in Sources */,
4C30AC7629A5770900E2BD5A /* NotificationItemView.swift in Sources */,
- BA3759972ABCCF360018D73B /* CameraPreview.swift in Sources */,
4C86F7C42A76C44C00EC0817 /* ZappingNotify.swift in Sources */,
4C363A8428233689006E126D /* Parser.swift in Sources */,
3AAA95CA298DF87B00F3D526 /* TranslationService.swift in Sources */,
@@ -2952,6 +2954,7 @@
4CACA9DC280C38C000D9BBE8 /* Profiles.swift in Sources */,
4CE879582996C45300F758CC /* ZapsView.swift in Sources */,
4C30AC7429A5680900E2BD5A /* EventGroupView.swift in Sources */,
+ 4C9D6D1B2B1D35D7004E5CD9 /* PullDownSearch.swift in Sources */,
4C633352283D419F00B1C9C3 /* SignalModel.swift in Sources */,
4CFF8F6D29CD022E008DB934 /* WideEventView.swift in Sources */,
9609F058296E220800069BF3 /* BannerImageView.swift in Sources */,
diff --git a/damus/ContentView.swift b/damus/ContentView.swift
@@ -67,7 +67,7 @@ struct ContentView: View {
@Environment(\.scenePhase) var scenePhase
@State var active_sheet: Sheets? = nil
- @State var damus_state: DamusState? = nil
+ @State var damus_state: DamusState!
@SceneStorage("ContentView.selected_timeline") var selected_timeline: Timeline = .home
@State var muting: Pubkey? = nil
@State var confirm_mute: Bool = false
@@ -133,10 +133,8 @@ struct ContentView: View {
}
func contentTimelineView(filter: (@escaping (NostrEvent) -> Bool)) -> some View {
- ZStack {
- if let damus = self.damus_state {
- TimelineView<AnyView>(events: home.events, loading: .constant(false), damus: damus, show_friend_icon: false, filter: filter)
- }
+ TimelineView(events: home.events, loading: .constant(false), damus: damus_state, show_friend_icon: false, filter: filter) {
+ PullDownSearchView(state: damus_state, on_cancel: {})
}
}
@@ -202,12 +200,8 @@ struct ContentView: View {
func MaybeReportView(target: ReportTarget) -> some View {
Group {
- if let damus_state {
- if let keypair = damus_state.keypair.to_full() {
- ReportView(postbox: damus_state.postbox, target: target, keypair: keypair)
- } else {
- EmptyView()
- }
+ if let keypair = damus_state.keypair.to_full() {
+ ReportView(postbox: damus_state.postbox, target: target, keypair: keypair)
} else {
EmptyView()
}
diff --git a/damus/Views/Search/PullDownSearch.swift b/damus/Views/Search/PullDownSearch.swift
@@ -0,0 +1,110 @@
+//
+// PullDownSearch.swift
+// damus
+//
+// Created by William Casarin on 2023-12-03.
+//
+
+import Foundation
+
+import SwiftUI
+
+struct PullDownSearchView: View {
+ @State private var search_text = ""
+ @State private var results: [NostrEvent] = []
+ @State private var is_active: Bool = false
+ let state: DamusState
+ let on_cancel: () -> Void
+
+ var body: some View {
+ VStack(alignment: .leading) {
+ HStack {
+ TextField("Search", text: $search_text)
+ .textFieldStyle(RoundedBorderTextFieldStyle())
+ .onChange(of: search_text) { newValue in
+ Task.detached {
+ let note_keys = state.ndb.text_search(query: newValue, limit: 16)
+ var res = [NostrEvent]()
+ // TODO: fix duplicate results from search
+ var keyset = Set<NoteKey>()
+ do {
+ let txn = NdbTxn(ndb: state.ndb)
+ for note_key in note_keys {
+ guard let note = state.ndb.lookup_note_by_key_with_txn(note_key, txn: txn) else {
+ continue
+ }
+
+ if !keyset.contains(note_key) {
+ let owned_note = note.to_owned()
+ res.append(owned_note)
+ keyset.insert(note_key)
+ }
+ }
+ }
+
+ let res_ = res
+
+ Task { @MainActor [res_] in
+ results = res_
+ }
+ }
+ }
+ .onTapGesture {
+ is_active = true
+ }
+
+ if is_active {
+ Button(action: {
+ search_text = ""
+ end_editing()
+ on_cancel()
+ }, label: {
+ Text("Cancel")
+ })
+ }
+ }
+ .padding()
+
+ if results.count > 0 {
+ HStack {
+ Image("search")
+ Text(NSLocalizedString("Top hits", comment: "A label indicating that the notes being displayed below it are all top note search results"))
+ Spacer()
+ }
+ .padding(.horizontal)
+ .foregroundColor(.secondary)
+
+ ForEach(results, id: \.self) { note in
+ EventView(damus: state, event: note)
+ .onTapGesture {
+ let event = note.get_inner_event(cache: state.events) ?? note
+ let thread = ThreadModel(event: event, damus_state: state)
+ state.nav.push(route: Route.Thread(thread: thread))
+ }
+ }
+
+ HStack {
+ Image("notes.fill")
+ Text(NSLocalizedString("Notes", comment: "A label indicating that the notes being displayed below it are from a timeline, not search results"))
+ Spacer()
+ }
+ .foregroundColor(.secondary)
+ .padding(.horizontal)
+ } else if results.count == 0 && !search_text.isEmpty {
+ HStack {
+ Image("search")
+ Text(NSLocalizedString("No results", comment: "A label indicating that note search resulted in no results"))
+ Spacer()
+ }
+ .padding(.horizontal)
+ .foregroundColor(.secondary)
+ }
+ }
+ }
+}
+
+struct PullDownSearchView_Previews: PreviewProvider {
+ static var previews: some View {
+ PullDownSearchView(state: test_damus_state, on_cancel: {})
+ }
+}
diff --git a/damus/Views/SearchHomeView.swift b/damus/Views/SearchHomeView.swift
@@ -79,7 +79,7 @@ struct SearchHomeView: View {
AnyView(VStack {
SuggestedHashtagsView(damus_state: damus_state, max_items: 5, events: model.events)
HStack {
- Image(systemName: "bubble.fill")
+ Image("notes.fill")
Text(NSLocalizedString("All recent notes", comment: "A label indicating that the notes being displayed below it are all recent notes"))
Spacer()
}