Align desktop entries pane order with phone
This commit is contained in:
@@ -76,6 +76,17 @@ const (
|
|||||||
autofillNoticeSuppressed autofillNoticeMode = "suppressed"
|
autofillNoticeSuppressed autofillNoticeMode = "suppressed"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type listPanelTopSection string
|
||||||
|
|
||||||
|
const (
|
||||||
|
listPanelTopSearch listPanelTopSection = "search"
|
||||||
|
listPanelTopNavigation listPanelTopSection = "navigation"
|
||||||
|
listPanelTopPath listPanelTopSection = "path"
|
||||||
|
listPanelTopGroup listPanelTopSection = "group"
|
||||||
|
listPanelTopGroupTools listPanelTopSection = "group_tools"
|
||||||
|
listPanelTopPrimary listPanelTopSection = "primary"
|
||||||
|
)
|
||||||
|
|
||||||
type bannerKind string
|
type bannerKind string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -5917,6 +5928,63 @@ func (u *ui) entryRowMetrics() (unit.Dp, unit.Sp, unit.Sp, unit.Sp, unit.Sp, uni
|
|||||||
return inset, titleSize, metaSize, urlSize, pathSize, dividerGap
|
return inset, titleSize, metaSize, urlSize, pathSize, dividerGap
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *ui) listPanelTopSections() []listPanelTopSection {
|
||||||
|
sections := make([]listPanelTopSection, 0, 6)
|
||||||
|
if u.state.Section != appstate.SectionAbout {
|
||||||
|
sections = append(sections, listPanelTopSearch)
|
||||||
|
}
|
||||||
|
if !u.isVaultLocked() {
|
||||||
|
sections = append(sections, listPanelTopNavigation)
|
||||||
|
}
|
||||||
|
if !u.isVaultLocked() && (u.state.Section == appstate.SectionEntries || u.state.Section == appstate.SectionRecycleBin) {
|
||||||
|
sections = append(sections, listPanelTopPath)
|
||||||
|
}
|
||||||
|
if !u.isVaultLocked() && u.state.Section == appstate.SectionEntries {
|
||||||
|
sections = append(sections, listPanelTopGroup, listPanelTopGroupTools)
|
||||||
|
}
|
||||||
|
if !u.isVaultLocked() {
|
||||||
|
sections = append(sections, listPanelTopPrimary)
|
||||||
|
}
|
||||||
|
return sections
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *ui) listPanelSearchRow(gtx layout.Context) layout.Dimensions {
|
||||||
|
if u.state.Section == appstate.SectionAbout {
|
||||||
|
return layout.Dimensions{}
|
||||||
|
}
|
||||||
|
if u.mode == "phone" {
|
||||||
|
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, u.searchPlaceholder())
|
||||||
|
editor.Color = u.theme.Palette.Fg
|
||||||
|
editor.HintColor = mutedColor
|
||||||
|
return layout.UniformInset(unit.Dp(10)).Layout(gtx, editor.Layout)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *ui) listPanelPrimaryActionRow(gtx layout.Context) layout.Dimensions {
|
||||||
|
if u.state.Section == appstate.SectionAbout {
|
||||||
|
return layout.Dimensions{}
|
||||||
|
}
|
||||||
|
if u.isVaultLocked() {
|
||||||
|
return layout.Dimensions{}
|
||||||
|
}
|
||||||
|
switch u.state.Section {
|
||||||
|
case appstate.SectionEntries:
|
||||||
|
label := "Add Entry"
|
||||||
|
if u.mode == "phone" {
|
||||||
|
label = "+ " + label
|
||||||
|
}
|
||||||
|
btn := material.Button(u.theme, &u.addEntry, label)
|
||||||
|
return btn.Layout(gtx)
|
||||||
|
case appstate.SectionAPITokens:
|
||||||
|
return tonedButton(gtx, u.theme, &u.issueAPIToken, "Issue API Token")
|
||||||
|
default:
|
||||||
|
return layout.Dimensions{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (u *ui) listPanel(gtx layout.Context) layout.Dimensions {
|
func (u *ui) listPanel(gtx layout.Context) layout.Dimensions {
|
||||||
panel := card
|
panel := card
|
||||||
spacing := u.sectionSpacing()
|
spacing := u.sectionSpacing()
|
||||||
@@ -5928,58 +5996,21 @@ func (u *ui) listPanel(gtx layout.Context) layout.Dimensions {
|
|||||||
return panel(gtx, func(gtx layout.Context) layout.Dimensions {
|
return panel(gtx, func(gtx layout.Context) layout.Dimensions {
|
||||||
visibleEntries, entryClicks := u.visibleEntrySnapshot()
|
visibleEntries, entryClicks := u.visibleEntrySnapshot()
|
||||||
rows := make([]layout.Widget, 0, 16+len(visibleEntries))
|
rows := make([]layout.Widget, 0, 16+len(visibleEntries))
|
||||||
if u.state.Section != appstate.SectionAbout {
|
for _, section := range u.listPanelTopSections() {
|
||||||
rows = append(rows, func(gtx layout.Context) layout.Dimensions {
|
switch section {
|
||||||
gtx.Constraints.Min.X = gtx.Constraints.Max.X
|
case listPanelTopSearch:
|
||||||
return u.outlinedFieldState(gtx, u.isFocused(focusSearch), func(gtx layout.Context) layout.Dimensions {
|
rows = append(rows, u.listPanelSearchRow)
|
||||||
editor := material.Editor(u.theme, &u.search, u.searchPlaceholder())
|
case listPanelTopNavigation:
|
||||||
editor.Color = u.theme.Palette.Fg
|
rows = append(rows, u.navigationHeader)
|
||||||
editor.HintColor = mutedColor
|
case listPanelTopPath:
|
||||||
return layout.UniformInset(unit.Dp(10)).Layout(gtx, editor.Layout)
|
rows = append(rows, u.pathBar)
|
||||||
})
|
case listPanelTopGroup:
|
||||||
})
|
rows = append(rows, u.groupBar)
|
||||||
rows = append(rows, func(gtx layout.Context) layout.Dimensions {
|
case listPanelTopGroupTools:
|
||||||
return layout.Spacer{Height: spacing}.Layout(gtx)
|
rows = append(rows, u.groupControlsSection)
|
||||||
})
|
case listPanelTopPrimary:
|
||||||
}
|
rows = append(rows, u.listPanelPrimaryActionRow)
|
||||||
if !u.isVaultLocked() {
|
|
||||||
rows = append(rows, u.navigationHeader)
|
|
||||||
if u.state.Section == appstate.SectionEntries || u.state.Section == appstate.SectionAbout {
|
|
||||||
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)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
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")
|
|
||||||
case appstate.SectionAbout:
|
|
||||||
return emptyStatePanel(gtx, u.theme, u.listEmptyState())
|
|
||||||
default:
|
|
||||||
return layout.Dimensions{}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
rows = append(rows, func(gtx layout.Context) layout.Dimensions {
|
rows = append(rows, func(gtx layout.Context) layout.Dimensions {
|
||||||
return layout.Spacer{Height: spacing}.Layout(gtx)
|
return layout.Spacer{Height: spacing}.Layout(gtx)
|
||||||
})
|
})
|
||||||
@@ -6008,84 +6039,45 @@ func (u *ui) listPanel(gtx layout.Context) layout.Dimensions {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
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,
|
children := make([]layout.FlexChild, 0, 16)
|
||||||
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
for _, section := range u.listPanelTopSections() {
|
||||||
if u.isVaultLocked() {
|
switch section {
|
||||||
return layout.Dimensions{}
|
case listPanelTopSearch:
|
||||||
}
|
children = append(children, layout.Rigid(u.listPanelSearchRow))
|
||||||
return u.navigationHeader(gtx)
|
case listPanelTopNavigation:
|
||||||
}),
|
children = append(children, layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
||||||
layout.Rigid(layout.Spacer{Height: spacing}.Layout),
|
if u.isVaultLocked() {
|
||||||
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
return layout.Dimensions{}
|
||||||
if u.state.Section == appstate.SectionAbout {
|
|
||||||
return emptyStatePanel(gtx, u.theme, u.listEmptyState())
|
|
||||||
}
|
|
||||||
return layout.Dimensions{}
|
|
||||||
}),
|
|
||||||
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
|
||||||
if u.state.Section == appstate.SectionAbout {
|
|
||||||
return layout.Dimensions{}
|
|
||||||
}
|
|
||||||
return layout.Spacer{Height: spacing}.Layout(gtx)
|
|
||||||
}),
|
|
||||||
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
|
||||||
if u.isVaultLocked() || (u.state.Section != appstate.SectionEntries && u.state.Section != appstate.SectionRecycleBin) {
|
|
||||||
return layout.Dimensions{}
|
|
||||||
}
|
|
||||||
return u.pathBar(gtx)
|
|
||||||
}),
|
|
||||||
layout.Rigid(layout.Spacer{Height: spacing}.Layout),
|
|
||||||
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
|
||||||
if u.isVaultLocked() || u.state.Section != appstate.SectionEntries {
|
|
||||||
return layout.Dimensions{}
|
|
||||||
}
|
|
||||||
return u.groupBar(gtx)
|
|
||||||
}),
|
|
||||||
layout.Rigid(layout.Spacer{Height: spacing}.Layout),
|
|
||||||
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
|
||||||
if u.isVaultLocked() || u.state.Section != appstate.SectionEntries {
|
|
||||||
return layout.Dimensions{}
|
|
||||||
}
|
|
||||||
return u.groupControlsSection(gtx)
|
|
||||||
}),
|
|
||||||
layout.Rigid(layout.Spacer{Height: spacing}.Layout),
|
|
||||||
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
|
||||||
if u.state.Section == appstate.SectionAbout {
|
|
||||||
return layout.Dimensions{}
|
|
||||||
}
|
|
||||||
if u.mode == "phone" {
|
|
||||||
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, u.searchPlaceholder())
|
|
||||||
editor.Color = u.theme.Palette.Fg
|
|
||||||
editor.HintColor = mutedColor
|
|
||||||
return layout.UniformInset(unit.Dp(10)).Layout(gtx, editor.Layout)
|
|
||||||
})
|
|
||||||
}),
|
|
||||||
layout.Rigid(layout.Spacer{Height: spacing}.Layout),
|
|
||||||
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
|
||||||
if u.state.Section == appstate.SectionAbout {
|
|
||||||
return layout.Dimensions{}
|
|
||||||
}
|
|
||||||
if u.isVaultLocked() {
|
|
||||||
return layout.Dimensions{}
|
|
||||||
}
|
|
||||||
switch u.state.Section {
|
|
||||||
case appstate.SectionEntries:
|
|
||||||
label := "Add Entry"
|
|
||||||
if u.mode == "phone" {
|
|
||||||
label = "+ " + label
|
|
||||||
}
|
}
|
||||||
btn := material.Button(u.theme, &u.addEntry, label)
|
return u.navigationHeader(gtx)
|
||||||
return btn.Layout(gtx)
|
}))
|
||||||
case appstate.SectionAPITokens:
|
case listPanelTopPath:
|
||||||
return tonedButton(gtx, u.theme, &u.issueAPIToken, "Issue API Token")
|
children = append(children, layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
||||||
default:
|
if u.isVaultLocked() || (u.state.Section != appstate.SectionEntries && u.state.Section != appstate.SectionRecycleBin) {
|
||||||
return layout.Dimensions{}
|
return layout.Dimensions{}
|
||||||
}
|
}
|
||||||
}),
|
return u.pathBar(gtx)
|
||||||
layout.Rigid(layout.Spacer{Height: spacing}.Layout),
|
}))
|
||||||
|
case listPanelTopGroup:
|
||||||
|
children = append(children, layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
||||||
|
if u.isVaultLocked() || u.state.Section != appstate.SectionEntries {
|
||||||
|
return layout.Dimensions{}
|
||||||
|
}
|
||||||
|
return u.groupBar(gtx)
|
||||||
|
}))
|
||||||
|
case listPanelTopGroupTools:
|
||||||
|
children = append(children, layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
||||||
|
if u.isVaultLocked() || u.state.Section != appstate.SectionEntries {
|
||||||
|
return layout.Dimensions{}
|
||||||
|
}
|
||||||
|
return u.groupControlsSection(gtx)
|
||||||
|
}))
|
||||||
|
case listPanelTopPrimary:
|
||||||
|
children = append(children, layout.Rigid(u.listPanelPrimaryActionRow))
|
||||||
|
}
|
||||||
|
children = append(children, layout.Rigid(layout.Spacer{Height: spacing}.Layout))
|
||||||
|
}
|
||||||
|
children = append(children,
|
||||||
layout.Flexed(1, func(gtx layout.Context) layout.Dimensions {
|
layout.Flexed(1, func(gtx layout.Context) layout.Dimensions {
|
||||||
if u.state.Section == appstate.SectionAPITokens {
|
if u.state.Section == appstate.SectionAPITokens {
|
||||||
return u.apiTokenListPanel(gtx)
|
return u.apiTokenListPanel(gtx)
|
||||||
@@ -6094,7 +6086,7 @@ func (u *ui) listPanel(gtx layout.Context) layout.Dimensions {
|
|||||||
return u.apiAuditListPanel(gtx)
|
return u.apiAuditListPanel(gtx)
|
||||||
}
|
}
|
||||||
if u.state.Section == appstate.SectionAbout {
|
if u.state.Section == appstate.SectionAbout {
|
||||||
return layout.Dimensions{}
|
return emptyStatePanel(gtx, u.theme, u.listEmptyState())
|
||||||
}
|
}
|
||||||
if len(u.visible) == 0 {
|
if len(u.visible) == 0 {
|
||||||
return emptyStatePanel(gtx, u.theme, u.listEmptyState())
|
return emptyStatePanel(gtx, u.theme, u.listEmptyState())
|
||||||
@@ -6106,6 +6098,7 @@ func (u *ui) listPanel(gtx layout.Context) layout.Dimensions {
|
|||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
return layout.Flex{Axis: layout.Vertical}.Layout(gtx, children...)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -251,6 +251,30 @@ func TestUISearchBehaviorIsConsistentAcrossDesktopAndPhoneLayouts(t *testing.T)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestUIListPanelTopSectionsMatchAcrossDesktopAndPhoneForEntries(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
desktop := newUIWithModel("desktop", vault.Model{})
|
||||||
|
desktop.state.Section = appstate.SectionEntries
|
||||||
|
phone := newUIWithModel("phone", vault.Model{})
|
||||||
|
phone.state.Section = appstate.SectionEntries
|
||||||
|
|
||||||
|
want := []listPanelTopSection{
|
||||||
|
listPanelTopSearch,
|
||||||
|
listPanelTopNavigation,
|
||||||
|
listPanelTopPath,
|
||||||
|
listPanelTopGroup,
|
||||||
|
listPanelTopGroupTools,
|
||||||
|
listPanelTopPrimary,
|
||||||
|
}
|
||||||
|
if got := desktop.listPanelTopSections(); !slices.Equal(got, want) {
|
||||||
|
t.Fatalf("desktop.listPanelTopSections() = %v, want %v", got, want)
|
||||||
|
}
|
||||||
|
if got := phone.listPanelTopSections(); !slices.Equal(got, want) {
|
||||||
|
t.Fatalf("phone.listPanelTopSections() = %v, want %v", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestUICurrentVaultSummary(t *testing.T) {
|
func TestUICurrentVaultSummary(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user