Snapshot phone entry list during redraw

This commit is contained in:
Joe Julian
2026-04-03 08:28:58 -07:00
parent b4f7ca3002
commit 49e3beee55
2 changed files with 37 additions and 4 deletions
+12 -4
View File
@@ -650,6 +650,13 @@ func (u *ui) filter() {
}
}
func (u *ui) visibleEntrySnapshot() ([]entry, []widget.Clickable) {
visible := append([]entry(nil), u.visible...)
clicks := make([]widget.Clickable, len(visible))
copy(clicks, u.entryClicks)
return visible, clicks
}
func defaultStatePaths(stateDir string) statePaths {
baseDir := strings.TrimSpace(stateDir)
if baseDir == "" {
@@ -4145,7 +4152,8 @@ func (u *ui) listPanel(gtx layout.Context) layout.Dimensions {
u.ensureNavClickables()
if u.mode == "phone" {
return panel(gtx, func(gtx layout.Context) layout.Dimensions {
rows := make([]layout.Widget, 0, 16+len(u.visible))
visibleEntries, entryClicks := u.visibleEntrySnapshot()
rows := make([]layout.Widget, 0, 16+len(visibleEntries))
rows = append(rows, func(gtx layout.Context) layout.Dimensions {
gtx.Constraints.Min.X = gtx.Constraints.Max.X
return u.outlinedFieldState(gtx, u.isFocused(focusSearch), func(gtx layout.Context) layout.Dimensions {
@@ -4209,15 +4217,15 @@ func (u *ui) listPanel(gtx layout.Context) layout.Dimensions {
rows = append(rows, u.apiTokenListPanel)
case u.state.Section == appstate.SectionAPIAudit:
rows = append(rows, u.apiAuditListPanel)
case len(u.visible) == 0:
case len(visibleEntries) == 0:
rows = append(rows, func(gtx layout.Context) layout.Dimensions {
return emptyStatePanel(gtx, u.theme, u.listEmptyState())
})
default:
for i := range u.visible {
for i := range visibleEntries {
idx := i
rows = append(rows, func(gtx layout.Context) layout.Dimensions {
return u.entryRow(gtx, &u.entryClicks[idx], idx, u.visible[idx])
return u.entryRow(gtx, &entryClicks[idx], idx, visibleEntries[idx])
})
}
}
+25
View File
@@ -821,6 +821,31 @@ func TestUIPhoneListPanelWithExpandedGroupControlsAndEntriesDoesNotPanic(t *test
_ = u.listPanel(gtx)
}
func TestUIVisibleEntrySnapshotIsStableAfterVisibleMutation(t *testing.T) {
t.Parallel()
u := newUIWithModel("phone", vault.Model{
Entries: []vault.Entry{
{ID: "1", Title: "Alpha", Path: []string{"Crew", "Internet"}},
{ID: "2", Title: "Beta", Path: []string{"Crew", "Internet"}},
},
})
u.state.NavigateToPath([]string{"Crew", "Internet"})
u.filter()
visible, clicks := u.visibleEntrySnapshot()
if len(visible) != 2 || len(clicks) != 2 {
t.Fatalf("snapshot lengths = (%d, %d), want (2, 2)", len(visible), len(clicks))
}
u.visible = u.visible[:1]
u.entryClicks = u.entryClicks[:1]
if got := visible[1].Title; got != "Beta" {
t.Fatalf("visible snapshot second title = %q, want Beta", got)
}
}
func TestUIPhoneBackReturnsFromSubscreenToEntries(t *testing.T) {
t.Parallel()