Fix thread UI jumpiness
Since991a4a8, the `make_actionbar_model` function introduced an async call to populate the action bar data. This surfaced a pre-existing problem where the action bar model would reinstantiate in any SwiftUI render pass for the chat bubbles in `ChatroomThreadView`. This issue was not visible before because the whole computation happened directly on the main actor during the render, maintaining the illusion of a stable entity. Since the computation was moved to an async task (for performance and concurrency design reasons), it caused the action bar items to reload in each render pass, causing multiple re-renders and the jumpiness witnessed in the ticket. The issue was addressed by making the action bar model initialization happen within ChatEventView itself, and wrapping it on `StateObject` to make that entity stable across re-renders. This fixes an issue for an unreleased change, so no changelog entry is necessary. Changelog-None Fixes:991a4a8Closes: https://github.com/damus-io/damus/issues/3270 Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
This commit is contained in:
@@ -36,9 +36,24 @@ struct ChatEventView: View {
|
||||
@State var selected_emoji: Emoji?
|
||||
|
||||
@State private var isOnTopHalfOfScreen: Bool = false
|
||||
@ObservedObject var bar: ActionBarModel
|
||||
@StateObject private var bar: ActionBarModel
|
||||
@Environment(\.swipeViewGroupSelection) var swipeViewGroupSelection
|
||||
|
||||
init(event: NostrEvent, selected_event: NostrEvent, prev_ev: NostrEvent?, next_ev: NostrEvent?, damus_state: DamusState, thread: ThreadModel, scroll_to_event: ((_ id: NoteId) -> Void)?, focus_event: (() -> Void)?, highlight_bubble: Bool) {
|
||||
self.event = event
|
||||
self.selected_event = selected_event
|
||||
self.prev_ev = prev_ev
|
||||
self.next_ev = next_ev
|
||||
self.damus_state = damus_state
|
||||
self.thread = thread
|
||||
self.scroll_to_event = scroll_to_event
|
||||
self.focus_event = focus_event
|
||||
self.highlight_bubble = highlight_bubble
|
||||
|
||||
// Initialize @StateObject using wrappedValue
|
||||
_bar = StateObject(wrappedValue: make_actionbar_model(ev: event.id, damus: damus_state))
|
||||
}
|
||||
|
||||
enum PopoverState: String {
|
||||
case closed
|
||||
case open_emoji_selector
|
||||
@@ -340,21 +355,17 @@ struct ChatEventView: View {
|
||||
}
|
||||
|
||||
#Preview {
|
||||
let bar = make_actionbar_model(ev: test_note.id, damus: test_damus_state)
|
||||
return ChatEventView(event: test_note, selected_event: test_note, prev_ev: nil, next_ev: nil, damus_state: test_damus_state, thread: ThreadModel(event: test_note, damus_state: test_damus_state), scroll_to_event: nil, focus_event: nil, highlight_bubble: false, bar: bar)
|
||||
return ChatEventView(event: test_note, selected_event: test_note, prev_ev: nil, next_ev: nil, damus_state: test_damus_state, thread: ThreadModel(event: test_note, damus_state: test_damus_state), scroll_to_event: nil, focus_event: nil, highlight_bubble: false)
|
||||
}
|
||||
|
||||
#Preview {
|
||||
let bar = make_actionbar_model(ev: test_note.id, damus: test_damus_state)
|
||||
return ChatEventView(event: test_short_note, selected_event: test_note, prev_ev: nil, next_ev: nil, damus_state: test_damus_state, thread: ThreadModel(event: test_note, damus_state: test_damus_state), scroll_to_event: nil, focus_event: nil, highlight_bubble: false, bar: bar)
|
||||
return ChatEventView(event: test_short_note, selected_event: test_note, prev_ev: nil, next_ev: nil, damus_state: test_damus_state, thread: ThreadModel(event: test_note, damus_state: test_damus_state), scroll_to_event: nil, focus_event: nil, highlight_bubble: false)
|
||||
}
|
||||
|
||||
#Preview {
|
||||
let bar = make_actionbar_model(ev: test_note.id, damus: test_damus_state)
|
||||
return ChatEventView(event: test_short_note, selected_event: test_note, prev_ev: nil, next_ev: nil, damus_state: test_damus_state, thread: ThreadModel(event: test_note, damus_state: test_damus_state), scroll_to_event: nil, focus_event: nil, highlight_bubble: true, bar: bar)
|
||||
return ChatEventView(event: test_short_note, selected_event: test_note, prev_ev: nil, next_ev: nil, damus_state: test_damus_state, thread: ThreadModel(event: test_note, damus_state: test_damus_state), scroll_to_event: nil, focus_event: nil, highlight_bubble: true)
|
||||
}
|
||||
|
||||
#Preview {
|
||||
let bar = make_actionbar_model(ev: test_note.id, damus: test_damus_state)
|
||||
return ChatEventView(event: test_super_short_note, selected_event: test_note, prev_ev: nil, next_ev: nil, damus_state: test_damus_state, thread: ThreadModel(event: test_note, damus_state: test_damus_state), scroll_to_event: nil, focus_event: nil, highlight_bubble: false, bar: bar)
|
||||
return ChatEventView(event: test_super_short_note, selected_event: test_note, prev_ev: nil, next_ev: nil, damus_state: test_damus_state, thread: ThreadModel(event: test_note, damus_state: test_damus_state), scroll_to_event: nil, focus_event: nil, highlight_bubble: false)
|
||||
}
|
||||
|
||||
@@ -64,8 +64,7 @@ struct ChatroomThreadView: View {
|
||||
focus_event: {
|
||||
self.set_active_event(scroller: scroller, ev: ev)
|
||||
},
|
||||
highlight_bubble: highlighted_note_id == ev.id,
|
||||
bar: make_actionbar_model(ev: ev.id, damus: damus)
|
||||
highlight_bubble: highlighted_note_id == ev.id
|
||||
)
|
||||
.id(ev.id)
|
||||
.matchedGeometryEffect(id: ev.id.hex(), in: animation, anchor: .center)
|
||||
|
||||
Reference in New Issue
Block a user