damus

nostr ios client
git clone git://jb55.com/damus
Log | Files | Refs | README | LICENSE

commit 9a70bcf280a1ca68505307bee3207e00c9e1e45f
parent 4f5c9b1bf7b6c2ea097cb3ff8ab30958ce53b33e
Author: William Casarin <jb55@jb55.com>
Date:   Thu, 30 Jun 2022 07:15:11 -0700

tabs: add blue dot to home view

Changelog-Added: Add blue dot notification to home tab
Changelog-Fixed: Clicking tabs now clear blue dots immediately
Signed-off-by: William Casarin <jb55@jb55.com>

Diffstat:
Mdamus/ContentView.swift | 19+++++++++----------
Mdamus/Models/HomeModel.swift | 43++++++++++++++++++++++++++++++++++++-------
Mdamus/Views/MainTabView.swift | 53+++++++++++++++++++++++------------------------------
3 files changed, 68 insertions(+), 47 deletions(-)

diff --git a/damus/ContentView.swift b/damus/ContentView.swift @@ -174,7 +174,7 @@ struct ContentView: View { .navigationViewStyle(.stack) } - TabBar(new_notifications: $home.new_notifications, selected: $selected_timeline, action: switch_timeline) + TabBar(new_events: $home.new_events, selected: $selected_timeline, action: switch_timeline) } .onAppear() { self.connect() @@ -305,9 +305,6 @@ struct ContentView: View { return } - if (timeline != .notifications && self.selected_timeline == .notifications) || timeline == .notifications { - home.new_notifications = false - } self.selected_timeline = timeline NotificationCenter.default.post(name: .switched_timeline, object: timeline) //self.selected_timeline = timeline @@ -413,9 +410,10 @@ struct LastNotification { let created_at: Int64 } -func get_last_notified() -> LastNotification? { - let last = UserDefaults.standard.string(forKey: "last_notification") - let last_created = UserDefaults.standard.string(forKey: "last_notification_time") +func get_last_event(_ timeline: Timeline) -> LastNotification? { + let str = timeline.rawValue + let last = UserDefaults.standard.string(forKey: "last_\(str)") + let last_created = UserDefaults.standard.string(forKey: "last_\(str)_time") .flatMap { Int64($0) } return last.flatMap { id in @@ -425,9 +423,10 @@ func get_last_notified() -> LastNotification? { } } -func save_last_notified(_ ev: NostrEvent) { - UserDefaults.standard.set(ev.id, forKey: "last_notification") - UserDefaults.standard.set(String(ev.created_at), forKey: "last_notification_time") +func save_last_event(_ ev: NostrEvent, timeline: Timeline) { + let str = timeline.rawValue + UserDefaults.standard.set(ev.id, forKey: "last_\(str)") + UserDefaults.standard.set(String(ev.created_at), forKey: "last_\(str)_time") } diff --git a/damus/Models/HomeModel.swift b/damus/Models/HomeModel.swift @@ -7,6 +7,27 @@ import Foundation +struct NewEventsBits { + let bits: Int + + init() { + bits = 0 + } + + init (prev: NewEventsBits, setting: Timeline) { + self.bits = prev.bits | timeline_bit(setting) + } + + init (prev: NewEventsBits, unsetting: Timeline) { + self.bits = prev.bits & ~timeline_bit(unsetting) + } + + func is_set(_ timeline: Timeline) -> Bool { + let notification_bit = timeline_bit(timeline) + return (bits & notification_bit) == notification_bit + } + +} class HomeModel: ObservableObject { var damus_state: DamusState @@ -18,9 +39,10 @@ class HomeModel: ObservableObject { let home_subid = UUID().description let contacts_subid = UUID().description let notifications_subid = UUID().description + let dms_subid = UUID().description let init_subid = UUID().description - @Published var new_notifications: Bool = false + @Published var new_events: NewEventsBits = NewEventsBits() @Published var notifications: [NostrEvent] = [] @Published var events: [NostrEvent] = [] @Published var loading: Bool = false @@ -261,21 +283,28 @@ class HomeModel: ObservableObject { return m[kind] } + func handle_last_event(ev: NostrEvent, timeline: Timeline) { + let last_ev = get_last_event(timeline) + + if last_ev == nil || last_ev!.created_at < ev.created_at { + save_last_event(ev, timeline: timeline) + new_events = NewEventsBits(prev: new_events, setting: timeline) + } + } + func handle_notification(ev: NostrEvent) { if !insert_uniq_sorted_event(events: &notifications, new_ev: ev, cmp: { $0.created_at > $1.created_at }) { return } - let last_notified = get_last_notified() - - if last_notified == nil || last_notified!.created_at < ev.created_at { - save_last_notified(ev) - new_notifications = true - } + handle_last_event(ev: ev, timeline: .notifications) } func insert_home_event(_ ev: NostrEvent) -> Bool { let ok = insert_uniq_sorted_event(events: &self.events, new_ev: ev, cmp: { $0.created_at > $1.created_at }) + if ok { + handle_last_event(ev: ev, timeline: .home) + } return ok } diff --git a/damus/Views/MainTabView.swift b/damus/Views/MainTabView.swift @@ -17,30 +17,30 @@ enum Timeline: String, CustomStringConvertible { } } - -struct MainTabView: View { - var body: some View { - Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/) - } -} - -struct MainTabView_Previews: PreviewProvider { - static var previews: some View { - MainTabView() +func timeline_bit(_ timeline: Timeline) -> Int { + switch timeline { + case .home: return 1 << 0 + case .notifications: return 1 << 1 + case .search: return 1 << 2 + case .dms: return 1 << 3 } } -struct NotificationsTab: View { - @Binding var new_notifications: Bool + +struct TabButton: View { + let timeline: Timeline + let img: String + @Binding var selected: Timeline? + @Binding var new_events: NewEventsBits let action: (Timeline) -> () var body: some View { ZStack(alignment: .center) { - TabButton(timeline: .notifications, img: "bell", selected: $selected, action: action) + Tab - if new_notifications { + if new_events.is_set(timeline) { Circle() .size(CGSize(width: 8, height: 8)) .frame(width: 10, height: 10, alignment: .topTrailing) @@ -50,19 +50,12 @@ struct NotificationsTab: View { } } } -} - - -struct TabButton: View { - let timeline: Timeline - let img: String - @Binding var selected: Timeline? - - let action: (Timeline) -> () - - var body: some View { - Button(action: {action(timeline)}) { + var Tab: some View { + Button(action: { + action(timeline) + new_events = NewEventsBits(prev: new_events, unsetting: timeline) + }) { Label("", systemImage: selected == timeline ? "\(img).fill" : img) .contentShape(Rectangle()) .frame(maxWidth: .infinity, minHeight: 30.0) @@ -73,7 +66,7 @@ struct TabButton: View { struct TabBar: View { - @Binding var new_notifications: Bool + @Binding var new_events: NewEventsBits @Binding var selected: Timeline? let action: (Timeline) -> () @@ -82,9 +75,9 @@ struct TabBar: View { VStack { Divider() HStack { - TabButton(timeline: .home, img: "house", selected: $selected, action: action) - TabButton(timeline: .search, img: "magnifyingglass.circle", selected: $selected, action: action) - NotificationsTab(new_notifications: $new_notifications, selected: $selected, action: action) + TabButton(timeline: .home, img: "house", selected: $selected, new_events: $new_events, action: action) + TabButton(timeline: .search, img: "magnifyingglass.circle", selected: $selected, new_events: $new_events, action: action) + TabButton(timeline: .notifications, img: "bell", selected: $selected, new_events: $new_events, action: action) } } }