Move remote preference help out of open flow
This commit is contained in:
@@ -224,8 +224,10 @@ type ui struct {
|
|||||||
toggleSyncMenu widget.Clickable
|
toggleSyncMenu widget.Clickable
|
||||||
openAdvancedSync widget.Clickable
|
openAdvancedSync widget.Clickable
|
||||||
openSecuritySettings widget.Clickable
|
openSecuritySettings widget.Clickable
|
||||||
|
openRemotePrefsHelp widget.Clickable
|
||||||
closeAdvancedSync widget.Clickable
|
closeAdvancedSync widget.Clickable
|
||||||
closeSecuritySettings widget.Clickable
|
closeSecuritySettings widget.Clickable
|
||||||
|
closeRemotePrefsHelp widget.Clickable
|
||||||
runAdvancedSync widget.Clickable
|
runAdvancedSync widget.Clickable
|
||||||
saveSecuritySettings widget.Clickable
|
saveSecuritySettings widget.Clickable
|
||||||
editEntry widget.Clickable
|
editEntry widget.Clickable
|
||||||
@@ -342,6 +344,7 @@ type ui struct {
|
|||||||
syncDialogOpen bool
|
syncDialogOpen bool
|
||||||
syncMenuOpen bool
|
syncMenuOpen bool
|
||||||
securityDialogOpen bool
|
securityDialogOpen bool
|
||||||
|
remotePrefsDialogOpen bool
|
||||||
showSyncPassword bool
|
showSyncPassword bool
|
||||||
keyboardFocus focusID
|
keyboardFocus focusID
|
||||||
defaultSaveAsPath string
|
defaultSaveAsPath string
|
||||||
@@ -1425,20 +1428,28 @@ func (u *ui) applyRecentRemoteRecord(record recentRemoteRecord) {
|
|||||||
u.rememberRemoteAuth.Value = strings.TrimSpace(record.Username) != "" || record.Password != ""
|
u.rememberRemoteAuth.Value = strings.TrimSpace(record.Username) != "" || record.Password != ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *ui) remoteAuthStatusMessage() string {
|
func (u *ui) remotePreferencesCurrentSummary() string {
|
||||||
selected, hasSelected := u.selectedRecentRemoteRecord()
|
selected, hasSelected := u.selectedRecentRemoteRecord()
|
||||||
switch {
|
switch {
|
||||||
case !u.rememberRemoteAuth.Value:
|
case !u.rememberRemoteAuth.Value:
|
||||||
return "Only the location will be saved in Recent Connections."
|
return "Current choice: KeePassGO will remember only the WebDAV location for this connection."
|
||||||
case hasSelected && (strings.TrimSpace(selected.Username) != "" || selected.Password != ""):
|
case hasSelected && (strings.TrimSpace(selected.Username) != "" || selected.Password != ""):
|
||||||
return "Saved sign-in will be updated for this connection."
|
return "Current choice: a successful open will update the saved sign-in for this connection on this device."
|
||||||
case strings.TrimSpace(u.remoteUsername.Text()) != "" || u.remotePassword.Text() != "":
|
case strings.TrimSpace(u.remoteUsername.Text()) != "" || u.remotePassword.Text() != "":
|
||||||
return "This sign-in will be saved in Recent Connections after a successful open."
|
return "Current choice: a successful open will save the entered sign-in for this connection on this device."
|
||||||
default:
|
default:
|
||||||
return "Enter a username or password to save sign-in details for this connection."
|
return "Current choice: sign-in retention is enabled, but no username or password is entered yet."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *ui) remotePreferencesAlwaysSavedSummary() string {
|
||||||
|
return "Recent Connections always stores the WebDAV base URL, remote path, and the last group you opened for that connection."
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *ui) remotePreferencesRetentionSummary() string {
|
||||||
|
return "KeePassGO keeps up to six recent connections. Turning off Remember sign-in and reopening rewrites that connection without the saved username or password."
|
||||||
|
}
|
||||||
|
|
||||||
func (u *ui) noteCurrentRemotePath() {
|
func (u *ui) noteCurrentRemotePath() {
|
||||||
status, ok := u.state.Session.(sessionStatus)
|
status, ok := u.state.Session.(sessionStatus)
|
||||||
if !ok || !status.IsRemote() || status.IsLocked() {
|
if !ok || !status.IsRemote() || status.IsLocked() {
|
||||||
@@ -2441,6 +2452,9 @@ func (u *ui) layout(gtx layout.Context) layout.Dimensions {
|
|||||||
u.loadSecuritySettingsFromSession()
|
u.loadSecuritySettingsFromSession()
|
||||||
u.securityDialogOpen = true
|
u.securityDialogOpen = true
|
||||||
}
|
}
|
||||||
|
for u.openRemotePrefsHelp.Clicked(gtx) {
|
||||||
|
u.remotePrefsDialogOpen = true
|
||||||
|
}
|
||||||
for u.closeAdvancedSync.Clicked(gtx) {
|
for u.closeAdvancedSync.Clicked(gtx) {
|
||||||
u.syncDialogOpen = false
|
u.syncDialogOpen = false
|
||||||
u.showSyncPassword = false
|
u.showSyncPassword = false
|
||||||
@@ -2448,6 +2462,9 @@ func (u *ui) layout(gtx layout.Context) layout.Dimensions {
|
|||||||
for u.closeSecuritySettings.Clicked(gtx) {
|
for u.closeSecuritySettings.Clicked(gtx) {
|
||||||
u.securityDialogOpen = false
|
u.securityDialogOpen = false
|
||||||
}
|
}
|
||||||
|
for u.closeRemotePrefsHelp.Clicked(gtx) {
|
||||||
|
u.remotePrefsDialogOpen = false
|
||||||
|
}
|
||||||
for u.runAdvancedSync.Clicked(gtx) {
|
for u.runAdvancedSync.Clicked(gtx) {
|
||||||
u.runAction("advanced synchronize vault", u.advancedSyncAction)
|
u.runAction("advanced synchronize vault", u.advancedSyncAction)
|
||||||
}
|
}
|
||||||
@@ -2853,6 +2870,12 @@ func (u *ui) layout(gtx layout.Context) layout.Dimensions {
|
|||||||
}
|
}
|
||||||
return u.securityDialog(gtx)
|
return u.securityDialog(gtx)
|
||||||
}),
|
}),
|
||||||
|
layout.Stacked(func(gtx layout.Context) layout.Dimensions {
|
||||||
|
if !u.remotePrefsDialogOpen {
|
||||||
|
return layout.Dimensions{}
|
||||||
|
}
|
||||||
|
return u.remotePrefsDialog(gtx)
|
||||||
|
}),
|
||||||
layout.Stacked(func(gtx layout.Context) layout.Dimensions {
|
layout.Stacked(func(gtx layout.Context) layout.Dimensions {
|
||||||
if _, ok := u.pendingApproval(); !ok {
|
if _, ok := u.pendingApproval(); !ok {
|
||||||
return layout.Dimensions{}
|
return layout.Dimensions{}
|
||||||
@@ -2935,6 +2958,29 @@ func (u *ui) securityDialog(gtx layout.Context) layout.Dimensions {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *ui) remotePrefsDialog(gtx layout.Context) layout.Dimensions {
|
||||||
|
return layout.Stack{}.Layout(gtx,
|
||||||
|
layout.Expanded(func(gtx layout.Context) layout.Dimensions {
|
||||||
|
paint.FillShape(gtx.Ops, color.NRGBA{A: 90}, clip.Rect{Max: gtx.Constraints.Max}.Op())
|
||||||
|
return layout.Dimensions{Size: gtx.Constraints.Max}
|
||||||
|
}),
|
||||||
|
layout.Stacked(func(gtx layout.Context) layout.Dimensions {
|
||||||
|
return layout.Center.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
|
||||||
|
width := gtx.Dp(unit.Dp(660))
|
||||||
|
if width > gtx.Constraints.Max.X {
|
||||||
|
width = gtx.Constraints.Max.X - gtx.Dp(unit.Dp(24))
|
||||||
|
}
|
||||||
|
if width < 1 {
|
||||||
|
width = gtx.Constraints.Max.X
|
||||||
|
}
|
||||||
|
gtx.Constraints.Min.X = width
|
||||||
|
gtx.Constraints.Max.X = width
|
||||||
|
return card(gtx, u.remotePrefsDialogContent)
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
func (u *ui) securityDialogContent(gtx layout.Context) layout.Dimensions {
|
func (u *ui) securityDialogContent(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 {
|
||||||
@@ -2967,6 +3013,42 @@ func (u *ui) securityDialogContent(gtx layout.Context) layout.Dimensions {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *ui) remotePrefsDialogContent(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(20), "Remote Connection Settings & Help")
|
||||||
|
lbl.Color = accentColor
|
||||||
|
return lbl.Layout(gtx)
|
||||||
|
}),
|
||||||
|
layout.Rigid(layout.Spacer{Height: unit.Dp(8)}.Layout),
|
||||||
|
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
||||||
|
lbl := material.Label(u.theme, unit.Sp(14), "Use Recent Connections to reopen WebDAV-backed vaults quickly without cluttering the main open flow.")
|
||||||
|
lbl.Color = mutedColor
|
||||||
|
return lbl.Layout(gtx)
|
||||||
|
}),
|
||||||
|
layout.Rigid(layout.Spacer{Height: unit.Dp(12)}.Layout),
|
||||||
|
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
||||||
|
return approvalFact(u.theme, "Current", u.remotePreferencesCurrentSummary(), "")(gtx)
|
||||||
|
}),
|
||||||
|
layout.Rigid(layout.Spacer{Height: unit.Dp(8)}.Layout),
|
||||||
|
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
||||||
|
return approvalFact(u.theme, "Always Saved", u.remotePreferencesAlwaysSavedSummary(), "")(gtx)
|
||||||
|
}),
|
||||||
|
layout.Rigid(layout.Spacer{Height: unit.Dp(8)}.Layout),
|
||||||
|
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
||||||
|
return approvalFact(u.theme, "Retention", u.remotePreferencesRetentionSummary(), "")(gtx)
|
||||||
|
}),
|
||||||
|
layout.Rigid(layout.Spacer{Height: unit.Dp(8)}.Layout),
|
||||||
|
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
||||||
|
return approvalFact(u.theme, "When Sign-in Saves", "Username and password or app token are only stored after a successful remote open when Remember sign-in is enabled.", "")(gtx)
|
||||||
|
}),
|
||||||
|
layout.Rigid(layout.Spacer{Height: unit.Dp(14)}.Layout),
|
||||||
|
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
||||||
|
return tonedButton(gtx, u.theme, &u.closeRemotePrefsHelp, "Done")
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
func (u *ui) approvalDialog(gtx layout.Context) layout.Dimensions {
|
func (u *ui) approvalDialog(gtx layout.Context) layout.Dimensions {
|
||||||
return layout.Stack{}.Layout(gtx,
|
return layout.Stack{}.Layout(gtx,
|
||||||
layout.Expanded(func(gtx layout.Context) layout.Dimensions {
|
layout.Expanded(func(gtx layout.Context) layout.Dimensions {
|
||||||
|
|||||||
+45
-9
@@ -3600,25 +3600,25 @@ func TestRecentRemoteStoredAuthSummaryDescribesSavedCredentialState(t *testing.T
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUIRemoteAuthStatusMessageExplainsWhatWillBeRemembered(t *testing.T) {
|
func TestUIRemotePreferencesCurrentSummaryExplainsWhatWillBeRemembered(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
u := newUIWithSession("desktop", &session.Manager{})
|
u := newUIWithSession("desktop", &session.Manager{})
|
||||||
u.remoteBaseURL.SetText("https://dav.example.com")
|
u.remoteBaseURL.SetText("https://dav.example.com")
|
||||||
u.remotePath.SetText("vaults/home.kdbx")
|
u.remotePath.SetText("vaults/home.kdbx")
|
||||||
|
|
||||||
if got := u.remoteAuthStatusMessage(); got != "Only the location will be saved in Recent Connections." {
|
if got := u.remotePreferencesCurrentSummary(); got != "Current choice: KeePassGO will remember only the WebDAV location for this connection." {
|
||||||
t.Fatalf("remoteAuthStatusMessage() = %q, want location-only guidance", got)
|
t.Fatalf("remotePreferencesCurrentSummary() = %q, want location-only guidance", got)
|
||||||
}
|
}
|
||||||
|
|
||||||
u.rememberRemoteAuth.Value = true
|
u.rememberRemoteAuth.Value = true
|
||||||
if got := u.remoteAuthStatusMessage(); got != "Enter a username or password to save sign-in details for this connection." {
|
if got := u.remotePreferencesCurrentSummary(); got != "Current choice: sign-in retention is enabled, but no username or password is entered yet." {
|
||||||
t.Fatalf("remoteAuthStatusMessage() = %q, want empty-sign-in guidance", got)
|
t.Fatalf("remotePreferencesCurrentSummary() = %q, want empty-sign-in guidance", got)
|
||||||
}
|
}
|
||||||
|
|
||||||
u.remoteUsername.SetText("alice")
|
u.remoteUsername.SetText("alice")
|
||||||
if got := u.remoteAuthStatusMessage(); got != "This sign-in will be saved in Recent Connections after a successful open." {
|
if got := u.remotePreferencesCurrentSummary(); got != "Current choice: a successful open will save the entered sign-in for this connection on this device." {
|
||||||
t.Fatalf("remoteAuthStatusMessage() = %q, want pending-save guidance", got)
|
t.Fatalf("remotePreferencesCurrentSummary() = %q, want pending-save guidance", got)
|
||||||
}
|
}
|
||||||
|
|
||||||
u.recentRemotes = []recentRemoteRecord{{
|
u.recentRemotes = []recentRemoteRecord{{
|
||||||
@@ -3627,8 +3627,44 @@ func TestUIRemoteAuthStatusMessageExplainsWhatWillBeRemembered(t *testing.T) {
|
|||||||
Username: "alice",
|
Username: "alice",
|
||||||
Password: "secret-1",
|
Password: "secret-1",
|
||||||
}}
|
}}
|
||||||
if got := u.remoteAuthStatusMessage(); got != "Saved sign-in will be updated for this connection." {
|
if got := u.remotePreferencesCurrentSummary(); got != "Current choice: a successful open will update the saved sign-in for this connection on this device." {
|
||||||
t.Fatalf("remoteAuthStatusMessage() = %q, want saved-sign-in guidance", got)
|
t.Fatalf("remotePreferencesCurrentSummary() = %q, want saved-sign-in guidance", got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUIRemotePreferencesHelpExplainsSavedFieldsAndRetention(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
u := newUIWithSession("desktop", &session.Manager{})
|
||||||
|
|
||||||
|
if got := u.remotePreferencesAlwaysSavedSummary(); got != "Recent Connections always stores the WebDAV base URL, remote path, and the last group you opened for that connection." {
|
||||||
|
t.Fatalf("remotePreferencesAlwaysSavedSummary() = %q, want saved-fields guidance", got)
|
||||||
|
}
|
||||||
|
if got := u.remotePreferencesRetentionSummary(); got != "KeePassGO keeps up to six recent connections. Turning off Remember sign-in and reopening rewrites that connection without the saved username or password." {
|
||||||
|
t.Fatalf("remotePreferencesRetentionSummary() = %q, want retention guidance", got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUIRemotePreferencesHelpDialogToggle(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
u := newUIWithSession("desktop", &session.Manager{})
|
||||||
|
gtx := layout.Context{}
|
||||||
|
|
||||||
|
u.openRemotePrefsHelp.Click()
|
||||||
|
for u.openRemotePrefsHelp.Clicked(gtx) {
|
||||||
|
u.remotePrefsDialogOpen = true
|
||||||
|
}
|
||||||
|
if !u.remotePrefsDialogOpen {
|
||||||
|
t.Fatal("remotePrefsDialogOpen = false after open click, want true")
|
||||||
|
}
|
||||||
|
|
||||||
|
u.closeRemotePrefsHelp.Click()
|
||||||
|
for u.closeRemotePrefsHelp.Clicked(gtx) {
|
||||||
|
u.remotePrefsDialogOpen = false
|
||||||
|
}
|
||||||
|
if u.remotePrefsDialogOpen {
|
||||||
|
t.Fatal("remotePrefsDialogOpen = true after close click, want false")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-4
@@ -150,11 +150,10 @@ func (u *ui) lifecycleControls(gtx layout.Context) layout.Dimensions {
|
|||||||
box.Color = accentColor
|
box.Color = accentColor
|
||||||
return box.Layout(gtx)
|
return box.Layout(gtx)
|
||||||
}),
|
}),
|
||||||
layout.Rigid(layout.Spacer{Height: unit.Dp(2)}.Layout),
|
|
||||||
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
||||||
lbl := material.Label(u.theme, unit.Sp(11), u.remoteAuthStatusMessage())
|
return layout.Inset{Top: unit.Dp(4)}.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
|
||||||
lbl.Color = mutedColor
|
return tonedButton(gtx, u.theme, &u.openRemotePrefsHelp, "Settings & Help")
|
||||||
return lbl.Layout(gtx)
|
})
|
||||||
}),
|
}),
|
||||||
layout.Rigid(layout.Spacer{Height: unit.Dp(8)}.Layout),
|
layout.Rigid(layout.Spacer{Height: unit.Dp(8)}.Layout),
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user