Make phone entry pane fully scrollable
This commit is contained in:
@@ -245,6 +245,7 @@ type ui struct {
|
|||||||
detailList widget.List
|
detailList widget.List
|
||||||
apiPolicyList widget.List
|
apiPolicyList widget.List
|
||||||
lifecycleList widget.List
|
lifecycleList widget.List
|
||||||
|
phonePanelList widget.List
|
||||||
recentVaultListState widget.List
|
recentVaultListState widget.List
|
||||||
recentRemoteListState widget.List
|
recentRemoteListState widget.List
|
||||||
copyUser widget.Clickable
|
copyUser widget.Clickable
|
||||||
@@ -556,6 +557,9 @@ func newUIWithState(mode string, sess appstate.CurrentSession, paths statePaths)
|
|||||||
lifecycleList: widget.List{
|
lifecycleList: widget.List{
|
||||||
List: layout.List{Axis: layout.Vertical},
|
List: layout.List{Axis: layout.Vertical},
|
||||||
},
|
},
|
||||||
|
phonePanelList: widget.List{
|
||||||
|
List: layout.List{Axis: layout.Vertical},
|
||||||
|
},
|
||||||
recentVaultListState: widget.List{
|
recentVaultListState: widget.List{
|
||||||
List: layout.List{Axis: layout.Vertical},
|
List: layout.List{Axis: layout.Vertical},
|
||||||
},
|
},
|
||||||
@@ -4026,6 +4030,87 @@ func (u *ui) listPanel(gtx layout.Context) layout.Dimensions {
|
|||||||
panel = compactCard
|
panel = compactCard
|
||||||
}
|
}
|
||||||
u.ensureNavClickables()
|
u.ensureNavClickables()
|
||||||
|
if u.mode == "phone" {
|
||||||
|
return panel(gtx, func(gtx layout.Context) layout.Dimensions {
|
||||||
|
rows := make([]layout.Widget, 0, 16+len(u.visible))
|
||||||
|
if !u.isVaultLocked() {
|
||||||
|
rows = append(rows, u.navigationHeader)
|
||||||
|
rows = append(rows, func(gtx layout.Context) layout.Dimensions {
|
||||||
|
return layout.Spacer{Height: spacing}.Layout(gtx)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if !u.isVaultLocked() && u.state.Section == appstate.SectionRecycleBin {
|
||||||
|
rows = append(rows, u.recycleBinSectionNotice)
|
||||||
|
rows = append(rows, func(gtx layout.Context) layout.Dimensions {
|
||||||
|
return layout.Spacer{Height: spacing}.Layout(gtx)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if !u.isVaultLocked() && (u.state.Section == appstate.SectionEntries || u.state.Section == appstate.SectionRecycleBin) {
|
||||||
|
rows = append(rows, u.pathBar)
|
||||||
|
rows = append(rows, func(gtx layout.Context) layout.Dimensions {
|
||||||
|
return layout.Spacer{Height: spacing}.Layout(gtx)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if !u.isVaultLocked() && u.state.Section == appstate.SectionEntries {
|
||||||
|
rows = append(rows, u.groupBar)
|
||||||
|
rows = append(rows, func(gtx layout.Context) layout.Dimensions {
|
||||||
|
return layout.Spacer{Height: spacing}.Layout(gtx)
|
||||||
|
})
|
||||||
|
rows = append(rows, u.groupControlsSection)
|
||||||
|
rows = append(rows, func(gtx layout.Context) layout.Dimensions {
|
||||||
|
return layout.Spacer{Height: spacing}.Layout(gtx)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
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 {
|
||||||
|
editor := material.Editor(u.theme, &u.search, "Search vault")
|
||||||
|
editor.Color = u.theme.Palette.Fg
|
||||||
|
editor.HintColor = mutedColor
|
||||||
|
return layout.UniformInset(unit.Dp(10)).Layout(gtx, editor.Layout)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
rows = append(rows, func(gtx layout.Context) layout.Dimensions {
|
||||||
|
return layout.Spacer{Height: spacing}.Layout(gtx)
|
||||||
|
})
|
||||||
|
if !u.isVaultLocked() {
|
||||||
|
rows = append(rows, func(gtx layout.Context) layout.Dimensions {
|
||||||
|
switch u.state.Section {
|
||||||
|
case appstate.SectionEntries:
|
||||||
|
btn := material.Button(u.theme, &u.addEntry, "+ Add Entry")
|
||||||
|
return btn.Layout(gtx)
|
||||||
|
case appstate.SectionAPITokens:
|
||||||
|
return tonedButton(gtx, u.theme, &u.issueAPIToken, "Issue API Token")
|
||||||
|
default:
|
||||||
|
return layout.Dimensions{}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
rows = append(rows, func(gtx layout.Context) layout.Dimensions {
|
||||||
|
return layout.Spacer{Height: spacing}.Layout(gtx)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
switch {
|
||||||
|
case u.state.Section == appstate.SectionAPITokens:
|
||||||
|
rows = append(rows, u.apiTokenListPanel)
|
||||||
|
case u.state.Section == appstate.SectionAPIAudit:
|
||||||
|
rows = append(rows, u.apiAuditListPanel)
|
||||||
|
case len(u.visible) == 0:
|
||||||
|
rows = append(rows, func(gtx layout.Context) layout.Dimensions {
|
||||||
|
return emptyStatePanel(gtx, u.theme, u.listEmptyState())
|
||||||
|
})
|
||||||
|
default:
|
||||||
|
for i := range u.visible {
|
||||||
|
idx := i
|
||||||
|
rows = append(rows, func(gtx layout.Context) layout.Dimensions {
|
||||||
|
return u.entryRow(gtx, &u.entryClicks[idx], idx, u.visible[idx])
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return material.List(u.theme, &u.phonePanelList).Layout(gtx, len(rows), func(gtx layout.Context, i int) layout.Dimensions {
|
||||||
|
return rows[i](gtx)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
return panel(gtx, func(gtx layout.Context) layout.Dimensions {
|
return panel(gtx, func(gtx layout.Context) layout.Dimensions {
|
||||||
return layout.Flex{Axis: layout.Vertical}.Layout(gtx,
|
return layout.Flex{Axis: layout.Vertical}.Layout(gtx,
|
||||||
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
||||||
|
|||||||
@@ -774,6 +774,38 @@ func TestUIPhoneGroupBrowserToggleDoesNotChangeCurrentGroupToolsState(t *testing
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestUIPhoneListPanelWithExpandedGroupControlsAndEntriesDoesNotPanic(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
u := newUIWithModel("phone", vault.Model{
|
||||||
|
Groups: [][]string{
|
||||||
|
{"Crew"},
|
||||||
|
{"Crew", "Internet"},
|
||||||
|
{"Crew", "eMail"},
|
||||||
|
},
|
||||||
|
Entries: []vault.Entry{
|
||||||
|
{ID: "amazon", Title: "Amazon", Username: "joe", Path: []string{"Crew", "Internet"}},
|
||||||
|
{ID: "mail", Title: "Mail", Username: "joe", Path: []string{"Crew", "eMail"}},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
u.groupControlsHidden = false
|
||||||
|
u.setCurrentPath([]string{"Crew"})
|
||||||
|
u.filter()
|
||||||
|
|
||||||
|
ops := new(op.Ops)
|
||||||
|
gtx := layout.Context{
|
||||||
|
Ops: ops,
|
||||||
|
Constraints: layout.Exact(image.Pt(1080, 900)),
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
t.Fatalf("listPanel() panicked on phone with groups, controls, and entries: %v", r)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
_ = u.listPanel(gtx)
|
||||||
|
}
|
||||||
|
|
||||||
func TestUIAPIAuditSectionShowsRecordedEvents(t *testing.T) {
|
func TestUIAPIAuditSectionShowsRecordedEvents(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user