Fix extra string actions
ci / lint-test (pull_request) Successful in 5m26s
ci / build (pull_request) Successful in 6m28s

This commit is contained in:
Joe Julian
2026-04-28 21:31:40 -07:00
parent 11e883279d
commit 51f2a0121a
6 changed files with 297 additions and 1 deletions
+127 -1
View File
@@ -249,6 +249,7 @@ type ui struct {
entryFields widget.Editor
customFieldKeys []widget.Editor
customFieldValues []widget.Editor
copyCustomFields []widget.Clickable
historyIndex widget.Editor
groupName widget.Editor
groupParentPath widget.Editor
@@ -402,6 +403,8 @@ type ui struct {
vaultRemoteCredentialClicks []widget.Clickable
syncRemoteCredentialClicks []widget.Clickable
removeCustomFields []widget.Clickable
toggleCustomFields []widget.Clickable
revealedCustomFields map[string]bool
state appstate.State
visible []entry
currentPath []string
@@ -662,6 +665,7 @@ func newUIWithState(mode string, sess appstate.CurrentSession, paths statePaths)
pendingSharedLookupPath: paths.PendingSharedLookupPath,
recentVaultGroups: map[string][]string{},
recentVaultUsedAt: map[string]time.Time{},
revealedCustomFields: map[string]bool{},
lifecycleAdvancedHidden: true,
historyHidden: true,
statusBannerTTL: statusBannerDuration,
@@ -940,6 +944,7 @@ func (u *ui) handlePhoneBack() bool {
func (u *ui) resetPasswordPeek() {
u.showPassword = false
u.revealedCustomFields = map[string]bool{}
}
func (u *ui) childGroups() []string {
@@ -2153,6 +2158,12 @@ type detailViewMetrics struct {
cardGap unit.Dp
}
type extraStringView struct {
Key string
Value string
Revealed bool
}
func (u *ui) detailViewContent(gtx layout.Context, item entry) layout.Dimensions {
rows := u.detailViewRows(item)
return layout.Flex{Axis: layout.Vertical}.Layout(gtx,
@@ -2180,6 +2191,8 @@ func (u *ui) detailViewRows(item entry) []layout.Widget {
layout.Spacer{Height: unit.Dp(8)}.Layout,
u.detailNotesCard(item),
layout.Spacer{Height: metrics.cardGap}.Layout,
u.detailExtraStringsCard,
layout.Spacer{Height: metrics.cardGap}.Layout,
u.attachmentSummaryPanel,
layout.Spacer{Height: metrics.cardGap}.Layout,
u.historyPanel,
@@ -2339,6 +2352,115 @@ func (u *ui) detailNotesCard(item entry) layout.Widget {
}
}
func (u *ui) detailExtraStringsCard(gtx layout.Context) layout.Dimensions {
fields := u.detailExtraStrings()
u.ensureExtraStringClickables(len(fields))
if len(fields) == 0 {
return layout.Dimensions{}
}
return compactCard(gtx, func(gtx layout.Context) layout.Dimensions {
children := []layout.FlexChild{
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
lbl := material.Label(u.theme, unit.Sp(12), "EXTRA STRINGS")
lbl.Color = mutedColor
return lbl.Layout(gtx)
}),
layout.Rigid(layout.Spacer{Height: unit.Dp(4)}.Layout),
}
for i, field := range fields {
index := i
item := field
children = append(children, layout.Rigid(func(gtx layout.Context) layout.Dimensions {
return u.detailExtraStringRow(gtx, index, item)
}))
if i < len(fields)-1 {
children = append(children, layout.Rigid(layout.Spacer{Height: unit.Dp(6)}.Layout))
}
}
return layout.Flex{Axis: layout.Vertical}.Layout(gtx, children...)
})
}
func (u *ui) detailExtraStringRow(gtx layout.Context, index int, field extraStringView) layout.Dimensions {
for u.toggleCustomFields[index].Clicked(gtx) {
u.toggleExtraStringReveal(field.Key)
}
for u.copyCustomFields[index].Clicked(gtx) {
key := field.Key
u.runAction("copy extra string", func() error { return u.copySelectedCustomFieldAction(key) })
}
return layout.Flex{Alignment: layout.Middle}.Layout(gtx,
layout.Flexed(1, func(gtx layout.Context) layout.Dimensions {
return layout.Flex{Axis: layout.Vertical}.Layout(gtx,
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
lbl := material.Label(u.theme, unit.Sp(12), strings.ToUpper(field.Key))
lbl.Color = mutedColor
return lbl.Layout(gtx)
}),
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
lbl := material.Label(u.theme, unit.Sp(15), field.Value)
return lbl.Layout(gtx)
}),
)
}),
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
return u.inlinePasswordToggle(gtx, &u.toggleCustomFields[index], field.Revealed)
}),
layout.Rigid(layout.Spacer{Width: unit.Dp(4)}.Layout),
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
btn := material.IconButton(u.theme, &u.copyCustomFields[index], u.copyIcon, "Copy extra string")
btn.Background = color.NRGBA{R: 239, G: 236, B: 229, A: 255}
btn.Color = accentColor
btn.Size = unit.Dp(18)
btn.Inset = layout.UniformInset(unit.Dp(8))
return btn.Layout(gtx)
}),
)
}
func (u *ui) detailExtraStrings() []extraStringView {
item, ok := u.selectedEntry()
if !ok || len(item.Fields) == 0 {
return nil
}
keys := make([]string, 0, len(item.Fields))
for key := range item.Fields {
keys = append(keys, key)
}
slices.Sort(keys)
out := make([]extraStringView, 0, len(keys))
for _, key := range keys {
value := item.Fields[key]
revealed := u.revealedCustomFields[key]
if !revealed {
value = maskedSecretValue(value)
}
out = append(out, extraStringView{Key: key, Value: value, Revealed: revealed})
}
return out
}
func (u *ui) toggleExtraStringReveal(key string) {
if u.revealedCustomFields == nil {
u.revealedCustomFields = map[string]bool{}
}
u.revealedCustomFields[key] = !u.revealedCustomFields[key]
}
func (u *ui) ensureExtraStringClickables(count int) {
if len(u.copyCustomFields) < count {
clicks := make([]widget.Clickable, count)
copy(clicks, u.copyCustomFields)
u.copyCustomFields = clicks
}
if len(u.toggleCustomFields) < count {
clicks := make([]widget.Clickable, count)
copy(clicks, u.toggleCustomFields)
u.toggleCustomFields = clicks
}
}
func (u *ui) detailActionRow(gtx layout.Context) layout.Dimensions {
switch u.state.Section {
case appstate.SectionTemplates:
@@ -2996,7 +3118,11 @@ func (u *ui) detailPasswordValue() string {
if u.showPassword {
return item.Password
}
return strings.Repeat("•", max(8, len(item.Password)))
return maskedSecretValue(item.Password)
}
func maskedSecretValue(value string) string {
return strings.Repeat("•", max(8, len(value)))
}
func card(gtx layout.Context, w layout.Widget) layout.Dimensions {