Use viewport width for adaptive layout

This commit is contained in:
Joe Julian
2026-04-08 23:49:07 -07:00
parent b256a77d0c
commit 07a071503a
6 changed files with 115 additions and 39 deletions
+37 -22
View File
@@ -453,6 +453,8 @@ type ui struct {
splitBase float32
splitStartY float32
phoneSpan int
compactViewport bool
viewportMeasured bool
phoneGroupBrowserExpanded bool
eyeIcon *widget.Icon
eyeOffIcon *widget.Icon
@@ -3896,16 +3898,28 @@ func (u *ui) lifecycleBusy() bool {
return u.shouldShowLifecycleSetup() && strings.TrimSpace(u.loadingMessage) != ""
}
func (u *ui) updateViewportLayoutMode(gtx layout.Context) {
u.viewportMeasured = true
u.compactViewport = gtx.Constraints.Max.X < gtx.Dp(unit.Dp(720))
}
func (u *ui) usesCompactViewport() bool {
if u.viewportMeasured {
return u.compactViewport
}
return u.mode == "phone"
}
func (u *ui) shouldUseLockedSinglePane() bool {
return u.isVaultLocked() && !u.shouldShowLifecycleSetup()
}
func (u *ui) shouldShowDesktopWorkingHeader() bool {
return u.mode == "desktop" && !u.shouldShowLifecycleSetup() && !u.isVaultLocked()
return !u.usesCompactViewport() && !u.shouldShowLifecycleSetup() && !u.isVaultLocked()
}
func (u *ui) shouldUseCompactPhoneDetailPane() bool {
if u.mode != "phone" {
if !u.usesCompactViewport() {
return false
}
if u.isVaultLocked() || u.editingEntry {
@@ -4044,7 +4058,7 @@ func (u *ui) ensureNavClickables() {
}
func (u *ui) syncPhoneGroupBrowser(path []string) {
if u.mode != "phone" {
if !u.usesCompactViewport() {
return
}
u.phoneGroupBrowserExpanded = len(u.displayEntryPath(path)) == 0
@@ -4651,6 +4665,7 @@ func (u *ui) layout(gtx layout.Context) layout.Dimensions {
if _, changed := u.search.Update(gtx); changed {
u.filter()
}
u.updateViewportLayoutMode(gtx)
inset := layout.UniformInset(unit.Dp(16))
return layout.Stack{}.Layout(gtx,
layout.Expanded(func(gtx layout.Context) layout.Dimensions {
@@ -4688,7 +4703,7 @@ func (u *ui) layout(gtx layout.Context) layout.Dimensions {
if u.shouldUseLockedSinglePane() {
return u.detailPanel(gtx)
}
if u.mode == "phone" || gtx.Constraints.Max.X < gtx.Dp(unit.Dp(720)) {
if u.usesCompactViewport() {
u.phoneSpan = gtx.Constraints.Max.Y
listHeight := int(float32(gtx.Constraints.Max.Y) * u.phoneSplit.Value)
if listHeight < gtx.Dp(unit.Dp(180)) {
@@ -5053,7 +5068,7 @@ func (u *ui) securityDialogContent(gtx layout.Context) layout.Dimensions {
layout.Spacer{Height: unit.Dp(8)}.Layout,
labeledEditorHelp(u.theme, "Package rules", "One rule per line, for example `com.android.chrome=hostname` or `org.keepassgo.browser=view-id`.", &u.autofillPackageRules, false),
func(gtx layout.Context) layout.Dimensions {
if u.mode == "phone" {
if u.usesCompactViewport() {
return layout.Dimensions{}
}
return layout.Flex{Spacing: layout.SpaceStart}.Layout(gtx,
@@ -5307,7 +5322,7 @@ func aboutFact(theme *material.Theme, title, primary, secondary string) layout.W
}
func (u *ui) sectionSpacing() unit.Dp {
if u.mode == "phone" {
if u.usesCompactViewport() {
if u.denseLayout {
return unit.Dp(4)
}
@@ -5334,7 +5349,7 @@ func (u *ui) entryRowMetrics() (unit.Dp, unit.Sp, unit.Sp, unit.Sp, unit.Sp, uni
pathSize = unit.Sp(10)
dividerGap = unit.Dp(5)
}
if u.mode == "phone" {
if u.usesCompactViewport() {
inset = unit.Dp(9)
titleSize = unit.Sp(15)
metaSize = unit.Sp(12)
@@ -5377,7 +5392,7 @@ func (u *ui) listPanelSearchRow(gtx layout.Context) layout.Dimensions {
if u.state.Section == appstate.SectionAbout {
return layout.Dimensions{}
}
if u.mode == "phone" {
if u.usesCompactViewport() {
gtx.Constraints.Min.X = gtx.Constraints.Max.X
}
return u.outlinedFieldState(gtx, u.isFocused(focusSearch), func(gtx layout.Context) layout.Dimensions {
@@ -5398,7 +5413,7 @@ func (u *ui) listPanelPrimaryActionRow(gtx layout.Context) layout.Dimensions {
switch u.state.Section {
case appstate.SectionEntries:
label := "Add Entry"
if u.mode == "phone" {
if u.usesCompactViewport() {
label = "+ " + label
}
btn := material.Button(u.theme, &u.addEntry, label)
@@ -5413,11 +5428,11 @@ func (u *ui) listPanelPrimaryActionRow(gtx layout.Context) layout.Dimensions {
func (u *ui) listPanel(gtx layout.Context) layout.Dimensions {
panel := card
spacing := u.sectionSpacing()
if u.mode == "phone" {
if u.usesCompactViewport() {
panel = compactCard
}
u.ensureNavClickables()
if u.mode == "phone" {
if u.usesCompactViewport() {
return panel(gtx, func(gtx layout.Context) layout.Dimensions {
visibleEntries, entryClicks := u.visibleEntrySnapshot()
rows := make([]layout.Widget, 0, 16+len(visibleEntries))
@@ -5561,7 +5576,7 @@ func (u *ui) sectionBar(gtx layout.Context) layout.Dimensions {
{click: &u.showAPITokens, label: "API Tokens", compact: "Tokens", active: u.state.Section == appstate.SectionAPITokens},
{click: &u.showAPIAudit, label: "API Audit", compact: "Audit", active: u.state.Section == appstate.SectionAPIAudit},
}
if u.mode == "phone" {
if u.usesCompactViewport() {
return layout.Flex{Axis: layout.Vertical}.Layout(gtx,
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
return layout.Flex{Spacing: layout.SpaceBetween}.Layout(gtx,
@@ -5713,7 +5728,7 @@ func (u *ui) entryRow(gtx layout.Context, click *widget.Clickable, idx int, item
}
func (u *ui) phoneSlider(gtx layout.Context) layout.Dimensions {
if u.mode != "phone" {
if !u.usesCompactViewport() {
return layout.Dimensions{}
}
for {
@@ -5759,7 +5774,7 @@ func (u *ui) phoneSlider(gtx layout.Context) layout.Dimensions {
func (u *ui) detailPanel(gtx layout.Context) layout.Dimensions {
panel := card
if u.mode == "phone" {
if u.usesCompactViewport() {
panel = compactCard
}
return panel(gtx, func(gtx layout.Context) layout.Dimensions {
@@ -5874,7 +5889,7 @@ func (u *ui) detailPanelContent(gtx layout.Context) layout.Dimensions {
sectionGap = unit.Dp(4)
cardGap = unit.Dp(6)
}
if u.mode == "phone" {
if u.usesCompactViewport() {
titleSize = unit.Sp(18)
titlePad = unit.Dp(4)
sectionGap = unit.Dp(4)
@@ -5898,7 +5913,7 @@ func (u *ui) detailPanelContent(gtx layout.Context) layout.Dimensions {
layout.Spacer{Height: titlePad}.Layout,
func(gtx layout.Context) layout.Dimensions {
if u.state.Section != appstate.SectionRecycleBin {
if u.mode == "phone" {
if u.usesCompactViewport() {
return layout.Flex{Spacing: layout.SpaceStart}.Layout(gtx,
layout.Flexed(0.5, func(gtx layout.Context) layout.Dimensions {
return compactTonedButton(gtx, u.theme, &u.copyUser, "Copy Username")
@@ -5955,7 +5970,7 @@ func (u *ui) detailPanelContent(gtx layout.Context) layout.Dimensions {
layout.Rigid(u.passwordLine("Password", password)),
layout.Rigid(layout.Spacer{Height: unit.Dp(8)}.Layout),
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
if u.mode == "phone" {
if u.usesCompactViewport() {
return compactTonedButton(gtx, u.theme, &u.copyURL, "Copy URL")
}
return layout.Flex{Spacing: layout.SpaceStart}.Layout(gtx,
@@ -6478,7 +6493,7 @@ func (u *ui) pathBar(gtx layout.Context) layout.Dimensions {
btn := material.Button(u.theme, &u.breadcrumbs[index], label)
btn.Background, btn.Color = buttonFocusColors(u.accessibilityPrefs, u.isFocused(breadcrumbFocusID(index)))
btn.TextSize = unit.Sp(11)
if u.mode == "phone" {
if u.usesCompactViewport() {
btn.TextSize = unit.Sp(9)
btn.Inset = layout.Inset{Top: 3, Bottom: 3, Left: 6, Right: 6}
} else {
@@ -6491,7 +6506,7 @@ func (u *ui) pathBar(gtx layout.Context) layout.Dimensions {
lbl := material.Label(u.theme, unit.Sp(12), "/")
lbl.Color = mutedColor
inset := unit.Dp(6)
if u.mode == "phone" {
if u.usesCompactViewport() {
inset = unit.Dp(4)
}
return layout.UniformInset(inset).Layout(gtx, lbl.Layout)
@@ -6515,7 +6530,7 @@ func (u *ui) visibleBreadcrumbs(displayPath []string) ([]string, []int) {
return indices
}()
}
if u.mode != "phone" || len(displayPath) <= 2 {
if !u.usesCompactViewport() || len(displayPath) <= 2 {
crumbs := append([]string{"/"}, append([]string{}, displayPath...)...)
indices := make([]int, 0, len(crumbs))
indices = append(indices, 0)
@@ -6535,7 +6550,7 @@ func (u *ui) groupBar(gtx layout.Context) layout.Dimensions {
u.groupClicks = make([]widget.Clickable, len(groups))
}
return compactCard(gtx, func(gtx layout.Context) layout.Dimensions {
if u.mode == "phone" {
if u.usesCompactViewport() {
if len(u.displayPath()) == 0 {
u.phoneGroupBrowserExpanded = true
}
@@ -6562,7 +6577,7 @@ func (u *ui) groupBar(gtx layout.Context) layout.Dimensions {
return layout.Dimensions{}
}
maxGroupListHeight := 200
if u.mode == "phone" {
if u.usesCompactViewport() {
maxGroupListHeight = 96
}
maxY := gtx.Dp(unit.Dp(maxGroupListHeight))