Merge commit 'cffe05a' into merge-main-13-seg13-copy-reveal
# Conflicts: # main.go
This commit is contained in:
@@ -118,12 +118,14 @@ type ui struct {
|
||||
masterKeyKeyFileOnly widget.Clickable
|
||||
masterKeyComposite widget.Clickable
|
||||
entryClicks []widget.Clickable
|
||||
historyClicks []widget.Clickable
|
||||
breadcrumbs []widget.Clickable
|
||||
groupClicks []widget.Clickable
|
||||
state appstate.State
|
||||
masterKeyMode vault.MasterKeyMode
|
||||
visible []entry
|
||||
currentPath []string
|
||||
selectedHistoryIndex int
|
||||
showPassword bool
|
||||
togglePassword widget.Clickable
|
||||
phoneSplit widget.Float
|
||||
@@ -138,7 +140,7 @@ type ui struct {
|
||||
loadingMessage string
|
||||
statusMessage string
|
||||
errorMessage string
|
||||
keyboardFocus focusID
|
||||
keyboardFocus focusID
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -205,8 +207,9 @@ func newUIWithState(mode string, sess appstate.CurrentSession) *ui {
|
||||
detailList: widget.List{
|
||||
List: layout.List{Axis: layout.Vertical},
|
||||
},
|
||||
state: appstate.State{},
|
||||
masterKeyMode: vault.MasterKeyModePasswordOnly,
|
||||
state: appstate.State{},
|
||||
masterKeyMode: vault.MasterKeyModePasswordOnly,
|
||||
selectedHistoryIndex: -1,
|
||||
}
|
||||
u.state.Session = sess
|
||||
u.phoneSplit.Value = 0.46
|
||||
@@ -305,6 +308,13 @@ func (u *ui) selectedEntry() (entry, bool) {
|
||||
return entry{}, false
|
||||
}
|
||||
|
||||
func (u *ui) ensureHistoryClickables() {
|
||||
history := u.visibleHistory()
|
||||
if len(u.historyClicks) < len(history) {
|
||||
u.historyClicks = make([]widget.Clickable, len(history))
|
||||
}
|
||||
}
|
||||
|
||||
func (u *ui) currentMasterKey() (vault.MasterKey, error) {
|
||||
password := u.masterPassword.Text()
|
||||
path := strings.TrimSpace(u.keyFilePath.Text())
|
||||
@@ -1057,6 +1067,8 @@ func (u *ui) detailPanel(gtx layout.Context) layout.Dimensions {
|
||||
return lbl.Layout(gtx)
|
||||
},
|
||||
layout.Spacer{Height: unit.Dp(12)}.Layout,
|
||||
u.historyPanel,
|
||||
layout.Spacer{Height: unit.Dp(12)}.Layout,
|
||||
u.entryEditorPanel,
|
||||
}
|
||||
return material.List(u.theme, &u.detailList).Layout(gtx, len(rows), func(gtx layout.Context, i int) layout.Dimensions {
|
||||
@@ -1091,6 +1103,118 @@ func (u *ui) banner(gtx layout.Context) layout.Dimensions {
|
||||
})
|
||||
}
|
||||
|
||||
func (u *ui) historyPanel(gtx layout.Context) layout.Dimensions {
|
||||
history := u.visibleHistory()
|
||||
u.ensureHistoryClickables()
|
||||
|
||||
children := []layout.FlexChild{
|
||||
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
||||
lbl := material.Label(u.theme, unit.Sp(14), "History")
|
||||
lbl.Color = accentColor
|
||||
return lbl.Layout(gtx)
|
||||
}),
|
||||
layout.Rigid(layout.Spacer{Height: unit.Dp(8)}.Layout),
|
||||
}
|
||||
|
||||
if len(history) == 0 {
|
||||
children = append(children, layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
||||
lbl := material.Label(u.theme, unit.Sp(12), "No history for this entry yet.")
|
||||
lbl.Color = mutedColor
|
||||
return lbl.Layout(gtx)
|
||||
}))
|
||||
return layout.Flex{Axis: layout.Vertical}.Layout(gtx, children...)
|
||||
}
|
||||
|
||||
for i := range history {
|
||||
index := i
|
||||
children = append(children, layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
||||
return u.historyRow(gtx, &u.historyClicks[index], index, history[index])
|
||||
}))
|
||||
children = append(children, layout.Rigid(layout.Spacer{Height: unit.Dp(6)}.Layout))
|
||||
}
|
||||
|
||||
if selected, ok := u.selectedHistoryEntry(); ok {
|
||||
children = append(children,
|
||||
layout.Rigid(layout.Spacer{Height: unit.Dp(4)}.Layout),
|
||||
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
||||
lbl := material.Label(u.theme, unit.Sp(12), "Selected Version")
|
||||
lbl.Color = mutedColor
|
||||
return lbl.Layout(gtx)
|
||||
}),
|
||||
layout.Rigid(layout.Spacer{Height: unit.Dp(6)}.Layout),
|
||||
layout.Rigid(detailLine(u.theme, "Path", strings.Join(selected.Path, " / "))),
|
||||
layout.Rigid(layout.Spacer{Height: unit.Dp(6)}.Layout),
|
||||
layout.Rigid(detailLine(u.theme, "Username", selected.Username)),
|
||||
layout.Rigid(layout.Spacer{Height: unit.Dp(6)}.Layout),
|
||||
layout.Rigid(detailLine(u.theme, "URL", selected.URL)),
|
||||
layout.Rigid(layout.Spacer{Height: unit.Dp(6)}.Layout),
|
||||
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
||||
lbl := material.Body2(u.theme, selected.Notes)
|
||||
lbl.Color = mutedColor
|
||||
return lbl.Layout(gtx)
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
return layout.Flex{Axis: layout.Vertical}.Layout(gtx, children...)
|
||||
}
|
||||
|
||||
func (u *ui) historyRow(gtx layout.Context, click *widget.Clickable, index int, item entry) layout.Dimensions {
|
||||
for click.Clicked(gtx) {
|
||||
_ = u.selectHistoryVersion(index)
|
||||
}
|
||||
|
||||
return click.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
|
||||
row := func(gtx layout.Context) layout.Dimensions {
|
||||
return layout.UniformInset(unit.Dp(10)).Layout(gtx, 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(13), fmt.Sprintf("Version %d", index))
|
||||
lbl.Color = accentColor
|
||||
return lbl.Layout(gtx)
|
||||
}),
|
||||
layout.Rigid(layout.Spacer{Height: unit.Dp(2)}.Layout),
|
||||
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
||||
lbl := material.Label(u.theme, unit.Sp(12), item.Username)
|
||||
lbl.Color = mutedColor
|
||||
return lbl.Layout(gtx)
|
||||
}),
|
||||
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
||||
lbl := material.Label(u.theme, unit.Sp(12), item.URL)
|
||||
lbl.Color = mutedColor
|
||||
return lbl.Layout(gtx)
|
||||
}),
|
||||
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
||||
lbl := material.Body2(u.theme, item.Notes)
|
||||
lbl.Color = mutedColor
|
||||
return lbl.Layout(gtx)
|
||||
}),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
if index == u.selectedHistoryIndex {
|
||||
return layout.Stack{}.Layout(gtx,
|
||||
layout.Expanded(func(gtx layout.Context) layout.Dimensions {
|
||||
size := gtx.Constraints.Min
|
||||
if size.X == 0 {
|
||||
size.X = gtx.Constraints.Max.X
|
||||
}
|
||||
if size.Y == 0 {
|
||||
size.Y = gtx.Constraints.Max.Y
|
||||
}
|
||||
paint.FillShape(gtx.Ops, selectedColor, clip.Rect{Max: size}.Op())
|
||||
paint.FillShape(gtx.Ops, selectedEdge, clip.Rect{Max: image.Pt(4, size.Y)}.Op())
|
||||
return layout.Dimensions{Size: size}
|
||||
}),
|
||||
layout.Stacked(row),
|
||||
)
|
||||
}
|
||||
|
||||
return layout.Background{}.Layout(gtx, fill(panelColor), row)
|
||||
})
|
||||
}
|
||||
|
||||
func (u *ui) pathBar(gtx layout.Context) layout.Dimensions {
|
||||
if u.state.Section == appstate.SectionRecycleBin {
|
||||
lbl := material.Label(u.theme, unit.Sp(13), "Recycle Bin")
|
||||
|
||||
Reference in New Issue
Block a user