reduce ContentView redraws

Remove observability from the home model, and use inner models for
updating specific parts of the UI, such as notification dots on the tab
bar.
This commit is contained in:
William Casarin 2023-06-23 10:01:30 +02:00
parent e885f38c54
commit 337c4de337
5 changed files with 38 additions and 22 deletions

View File

@ -171,6 +171,7 @@
4C90BD1C283AC38E008EE7EF /* Bech32Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C90BD1B283AC38E008EE7EF /* Bech32Tests.swift */; };
4C987B57283FD07F0042CE38 /* FollowersModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C987B56283FD07F0042CE38 /* FollowersModel.swift */; };
4C9AA1482A44442E003F49FD /* CustomizeZapModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C9AA1472A44442E003F49FD /* CustomizeZapModel.swift */; };
4C9AA14A2A4587A6003F49FD /* NotificationStatusModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C9AA1492A4587A6003F49FD /* NotificationStatusModel.swift */; };
4C9BB83129C0ED4F00FC4E37 /* DisplayName.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C9BB83029C0ED4F00FC4E37 /* DisplayName.swift */; };
4C9BB83429C12D9900FC4E37 /* EventProfileName.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C9BB83329C12D9900FC4E37 /* EventProfileName.swift */; };
4C9F18E229AA9B6C008C55EC /* CustomizeZapView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C9F18E129AA9B6C008C55EC /* CustomizeZapView.swift */; };
@ -615,6 +616,7 @@
4C90BD1B283AC38E008EE7EF /* Bech32Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Bech32Tests.swift; sourceTree = "<group>"; };
4C987B56283FD07F0042CE38 /* FollowersModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FollowersModel.swift; sourceTree = "<group>"; };
4C9AA1472A44442E003F49FD /* CustomizeZapModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomizeZapModel.swift; sourceTree = "<group>"; };
4C9AA1492A4587A6003F49FD /* NotificationStatusModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationStatusModel.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>"; };
4C9F18E129AA9B6C008C55EC /* CustomizeZapView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomizeZapView.swift; sourceTree = "<group>"; };
@ -976,6 +978,7 @@
children = (
4C54AA0929A55429003E4487 /* EventGroup.swift */,
4C54AA0B29A5543C003E4487 /* ZapGroup.swift */,
4C9AA1492A4587A6003F49FD /* NotificationStatusModel.swift */,
);
path = Notifications;
sourceTree = "<group>";
@ -1933,6 +1936,7 @@
4C1A9A1F29DDD24B00516EAC /* AppearanceSettingsView.swift in Sources */,
3AA59D1D2999B0400061C48E /* DraftsModel.swift in Sources */,
3169CAED294FCCFC00EE4006 /* Constants.swift in Sources */,
4C9AA14A2A4587A6003F49FD /* NotificationStatusModel.swift in Sources */,
4CB9D4A72992D02B00A9A7E4 /* ProfileNameView.swift in Sources */,
4CE4F0F429D779B5005914DB /* PostBox.swift in Sources */,
4C2859622A12A7F0004746F7 /* GoldSupportGradient.swift in Sources */,

View File

@ -75,7 +75,7 @@ struct ContentView: View {
@State var confirm_overwrite_mutelist: Bool = false
@SceneStorage("ContentView.filter_state") var filter_state : FilterState = .posts_and_replies
@State private var isSideBarOpened = false
@StateObject var home: HomeModel = HomeModel()
var home: HomeModel = HomeModel()
let sub_id = UUID().description
@ -128,7 +128,7 @@ struct ContentView: View {
func contentTimelineView(filter: (@escaping (NostrEvent) -> Bool)) -> some View {
ZStack {
if let damus = self.damus_state {
TimelineView(events: home.events, loading: $home.loading, damus: damus, show_friend_icon: false, filter: filter)
TimelineView(events: home.events, loading: .constant(false), damus: damus, show_friend_icon: false, filter: filter)
}
}
}
@ -308,7 +308,7 @@ struct ContentView: View {
}
.navigationViewStyle(.stack)
TabBar(new_events: $home.new_events, selected: $selected_timeline, settings: damus.settings, action: switch_timeline)
TabBar(nstatus: home.notification_status, selected: $selected_timeline, settings: damus.settings, action: switch_timeline)
.padding([.bottom], 8)
.background(Color(uiColor: .systemBackground).ignoresSafeArea())
}

View File

@ -23,7 +23,7 @@ struct NewEventsBits: OptionSet {
static let notifications: NewEventsBits = [.zaps, .likes, .reposts, .mentions]
}
class HomeModel: ObservableObject {
class HomeModel {
// Don't trigger a user notification for events older than a certain age
static let event_max_age_for_notification: TimeInterval = 12 * 60 * 60
@ -49,9 +49,9 @@ class HomeModel: ObservableObject {
var signal = SignalModel()
@Published var new_events: NewEventsBits = NewEventsBits()
@Published var notifications = NotificationsModel()
@Published var events: EventHolder = EventHolder()
var notifications = NotificationsModel()
var notification_status = NotificationStatusModel()
var events: EventHolder = EventHolder()
init() {
self.damus_state = DamusState.empty
@ -176,7 +176,7 @@ class HomeModel: ObservableObject {
return
}
guard let new_bits = handle_last_events(new_events: self.new_events, ev: ev, timeline: .notifications, shouldNotify: true) else {
guard let new_bits = handle_last_events(new_events: self.notification_status.new_events, ev: ev, timeline: .notifications, shouldNotify: true) else {
return
}
@ -195,7 +195,7 @@ class HomeModel: ObservableObject {
}
}
self.new_events = new_bits
self.notification_status.new_events = new_bits
}
}
@ -523,8 +523,8 @@ class HomeModel: ObservableObject {
@discardableResult
func handle_last_event(ev: NostrEvent, timeline: Timeline, shouldNotify: Bool = true) -> Bool {
if let new_bits = handle_last_events(new_events: self.new_events, ev: ev, timeline: timeline, shouldNotify: shouldNotify) {
new_events = new_bits
if let new_bits = handle_last_events(new_events: self.notification_status.new_events, ev: ev, timeline: timeline, shouldNotify: shouldNotify) {
self.notification_status.new_events = new_bits
return true
} else {
return false
@ -556,7 +556,7 @@ class HomeModel: ObservableObject {
}
func got_new_dm(notifs: NewEventsBits, ev: NostrEvent) {
self.new_events = notifs
notification_status.new_events = notifs
if damus_state.settings.dm_notification && ev.age < HomeModel.event_max_age_for_notification {
let convo = ev.decrypted(privkey: self.damus_state.keypair.privkey) ?? NSLocalizedString("New encrypted direct message", comment: "Notification that the user has received a new direct message")
@ -574,7 +574,7 @@ class HomeModel: ObservableObject {
if !should_debounce_dms {
self.incoming_dms.append(ev)
if let notifs = handle_incoming_dms(prev_events: self.new_events, dms: self.dms, our_pubkey: self.damus_state.pubkey, evs: self.incoming_dms) {
if let notifs = handle_incoming_dms(prev_events: notification_status.new_events, dms: self.dms, our_pubkey: self.damus_state.pubkey, evs: self.incoming_dms) {
got_new_dm(notifs: notifs, ev: ev)
}
self.incoming_dms = []
@ -584,7 +584,7 @@ class HomeModel: ObservableObject {
incoming_dms.append(ev)
dm_debouncer.debounce { [self] in
if let notifs = handle_incoming_dms(prev_events: self.new_events, dms: self.dms, our_pubkey: self.damus_state.pubkey, evs: self.incoming_dms) {
if let notifs = handle_incoming_dms(prev_events: notification_status.new_events, dms: self.dms, our_pubkey: self.damus_state.pubkey, evs: self.incoming_dms) {
got_new_dm(notifs: notifs, ev: ev)
}
self.incoming_dms = []

View File

@ -0,0 +1,12 @@
//
// NotificationStatusModel.swift
// damus
//
// Created by William Casarin on 2023-06-23.
//
import Foundation
class NotificationStatusModel: ObservableObject {
@Published var new_events: NewEventsBits = NewEventsBits()
}

View File

@ -29,7 +29,7 @@ struct TabButton: View {
let timeline: Timeline
let img: String
@Binding var selected: Timeline
@Binding var new_events: NewEventsBits
@ObservedObject var nstatus: NotificationStatusModel
let settings: UserSettingsStore
let action: (Timeline) -> ()
@ -38,7 +38,7 @@ struct TabButton: View {
ZStack(alignment: .center) {
Tab
if show_indicator(timeline: timeline, current: new_events, indicator_setting: settings.notification_indicators) {
if show_indicator(timeline: timeline, current: nstatus.new_events, indicator_setting: settings.notification_indicators) {
Circle()
.size(CGSize(width: 8, height: 8))
.frame(width: 10, height: 10, alignment: .topTrailing)
@ -53,7 +53,7 @@ struct TabButton: View {
Button(action: {
action(timeline)
let bits = timeline_to_notification_bits(timeline, ev: nil)
new_events = NewEventsBits(rawValue: new_events.rawValue & ~bits.rawValue)
nstatus.new_events = NewEventsBits(rawValue: nstatus.new_events.rawValue & ~bits.rawValue)
}) {
Image(selected != timeline ? img : "\(img).fill")
.contentShape(Rectangle())
@ -65,7 +65,7 @@ struct TabButton: View {
struct TabBar: View {
@Binding var new_events: NewEventsBits
var nstatus: NotificationStatusModel
@Binding var selected: Timeline
let settings: UserSettingsStore
@ -75,10 +75,10 @@ struct TabBar: View {
VStack {
Divider()
HStack {
TabButton(timeline: .home, img: "home", selected: $selected, new_events: $new_events, settings: settings, action: action).keyboardShortcut("1")
TabButton(timeline: .dms, img: "messages", selected: $selected, new_events: $new_events, settings: settings, action: action).keyboardShortcut("2")
TabButton(timeline: .search, img: "search", selected: $selected, new_events: $new_events, settings: settings, action: action).keyboardShortcut("3")
TabButton(timeline: .notifications, img: "notification-bell", selected: $selected, new_events: $new_events, settings: settings, action: action).keyboardShortcut("4")
TabButton(timeline: .home, img: "home", selected: $selected, nstatus: nstatus, settings: settings, action: action).keyboardShortcut("1")
TabButton(timeline: .dms, img: "messages", selected: $selected, nstatus: nstatus, settings: settings, action: action).keyboardShortcut("2")
TabButton(timeline: .search, img: "search", selected: $selected, nstatus: nstatus, settings: settings, action: action).keyboardShortcut("3")
TabButton(timeline: .notifications, img: "notification-bell", selected: $selected, nstatus: nstatus, settings: settings, action: action).keyboardShortcut("4")
}
}
}