diff --git a/main.go b/main.go index 415d06f..3e3072c 100644 --- a/main.go +++ b/main.go @@ -4801,46 +4801,6 @@ func (u *ui) syncHostedAPI() { } } -func (u *ui) lifecycleScreen(gtx layout.Context) layout.Dimensions { - panel := card - if u.mode == "phone" { - panel = compactCard - } - return panel(gtx, func(gtx layout.Context) layout.Dimensions { - rows := []layout.Widget{ - u.lifecycleBranding, - layout.Spacer{Height: unit.Dp(8)}.Layout, - u.lifecycleControls, - } - return material.List(u.theme, &u.lifecycleList).Layout(gtx, len(rows), func(gtx layout.Context, i int) layout.Dimensions { - return rows[i](gtx) - }) - }) -} - -func (u *ui) syncDialog(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(620)) - 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.syncDialogContent) - }) - }), - ) -} - func (u *ui) securityDialog(gtx layout.Context) layout.Dimensions { return layout.Stack{}.Layout(gtx, layout.Expanded(func(gtx layout.Context) layout.Dimensions { @@ -5263,160 +5223,6 @@ func (u *ui) approvalDialogContent(gtx layout.Context) layout.Dimensions { ) } -func (u *ui) syncDialogContent(gtx layout.Context) layout.Dimensions { - matchingCredentials := u.matchingAdvancedSyncRemoteCredentialEntries() - if len(u.syncRemoteCredentialClicks) < len(matchingCredentials) { - u.syncRemoteCredentialClicks = make([]widget.Clickable, len(matchingCredentials)) - } - return material.List(u.theme, &u.syncDialogList).Layout(gtx, 1, func(gtx layout.Context, _ int) 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), u.syncDialogTitle()) - 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), u.syncDialogDescription()) - lbl.Color = mutedColor - return lbl.Layout(gtx) - }), - layout.Rigid(layout.Spacer{Height: unit.Dp(12)}.Layout), - layout.Rigid(func(gtx layout.Context) layout.Dimensions { - if !u.shouldShowSyncDirectionChoices() { - return layout.Dimensions{} - } - return layout.Flex{Axis: layout.Vertical}.Layout(gtx, - layout.Rigid(syncDialogSectionLabel(u.theme, "Direction")), - layout.Rigid(layout.Spacer{Height: unit.Dp(6)}.Layout), - layout.Rigid(func(gtx layout.Context) layout.Dimensions { - return layout.Flex{Spacing: layout.SpaceStart}.Layout(gtx, - layout.Rigid(func(gtx layout.Context) layout.Dimensions { - return syncChoiceButton(gtx, u.theme, &u.showSyncPull, "Pull Into Current Vault", u.syncDirection == syncDirectionPull) - }), - layout.Rigid(layout.Spacer{Width: unit.Dp(6)}.Layout), - layout.Rigid(func(gtx layout.Context) layout.Dimensions { - return syncChoiceButton(gtx, u.theme, &u.showSyncPush, "Push Current Vault Out", u.syncDirection == syncDirectionPush) - }), - ) - }), - ) - }), - layout.Rigid(func(gtx layout.Context) layout.Dimensions { - if !u.shouldShowSyncDirectionChoices() { - return layout.Dimensions{} - } - return layout.Spacer{Height: unit.Dp(12)}.Layout(gtx) - }), - layout.Rigid(func(gtx layout.Context) layout.Dimensions { - if !u.shouldShowSyncSourceChoices() { - return layout.Dimensions{} - } - return layout.Flex{Axis: layout.Vertical}.Layout(gtx, - layout.Rigid(syncDialogSectionLabel(u.theme, "Other Source")), - layout.Rigid(layout.Spacer{Height: unit.Dp(6)}.Layout), - layout.Rigid(func(gtx layout.Context) layout.Dimensions { - return layout.Flex{Spacing: layout.SpaceStart}.Layout(gtx, - layout.Rigid(func(gtx layout.Context) layout.Dimensions { - return syncChoiceButton(gtx, u.theme, &u.showSyncLocal, "Local File", u.syncSourceMode == syncSourceLocal) - }), - layout.Rigid(layout.Spacer{Width: unit.Dp(6)}.Layout), - layout.Rigid(func(gtx layout.Context) layout.Dimensions { - return syncChoiceButton(gtx, u.theme, &u.showSyncRemote, "Remote WebDAV", u.syncSourceMode == syncSourceRemote) - }), - ) - }), - ) - }), - layout.Rigid(func(gtx layout.Context) layout.Dimensions { - if !u.shouldShowSyncSourceChoices() { - return layout.Dimensions{} - } - return layout.Spacer{Height: unit.Dp(12)}.Layout(gtx) - }), - layout.Rigid(func(gtx layout.Context) layout.Dimensions { - return syncDialogSummaryCard(gtx, u.theme, u.syncDialogPurpose, u.syncSourceMode, u.syncDirection) - }), - layout.Rigid(layout.Spacer{Height: unit.Dp(12)}.Layout), - layout.Rigid(func(gtx layout.Context) layout.Dimensions { - if u.syncSourceMode == syncSourceRemote { - children := []layout.FlexChild{ - layout.Rigid(labeledEditorHelp(u.theme, "Remote Base URL", "WebDAV base URL for the other source.", &u.syncRemoteBaseURL, false)), - layout.Rigid(layout.Spacer{Height: unit.Dp(6)}.Layout), - layout.Rigid(labeledEditorHelp(u.theme, "Remote Path", "Path to the other remote .kdbx file.", &u.syncRemotePath, false)), - layout.Rigid(layout.Spacer{Height: unit.Dp(6)}.Layout), - layout.Rigid(labeledEditorHelp(u.theme, "Remote Username", "Username for the other WebDAV source.", &u.syncRemoteUsername, false)), - layout.Rigid(layout.Spacer{Height: unit.Dp(6)}.Layout), - layout.Rigid(func(gtx layout.Context) layout.Dimensions { - return u.syncPasswordField(gtx) - }), - } - if u.syncDialogPurpose == syncDialogPurposeRemoteSetup { - children = append(children, - layout.Rigid(layout.Spacer{Height: unit.Dp(8)}.Layout), - layout.Rigid(func(gtx layout.Context) layout.Dimensions { - check := material.CheckBox(u.theme, &u.syncSetupAutomatic, "Sync automatically on open and save") - check.Color = accentColor - return check.Layout(gtx) - }), - ) - } - if len(matchingCredentials) > 0 { - children = append(children, - layout.Rigid(layout.Spacer{Height: unit.Dp(8)}.Layout), - layout.Rigid(func(gtx layout.Context) layout.Dimensions { - lbl := material.Label(u.theme, unit.Sp(11), "Matching vault credentials") - lbl.Color = mutedColor - return lbl.Layout(gtx) - }), - ) - for i, entry := range matchingCredentials { - i := i - entry := entry - children = append(children, - layout.Rigid(layout.Spacer{Height: unit.Dp(4)}.Layout), - layout.Rigid(func(gtx layout.Context) layout.Dimensions { - label := entry.Title - if strings.TrimSpace(entry.Username) != "" { - label += " · " + strings.TrimSpace(entry.Username) - } - selected := strings.TrimSpace(u.selectedSyncRemoteCredentialEntryID) == entry.ID - return recentSelectionCard(gtx, selected, func(gtx layout.Context) layout.Dimensions { - return u.syncRemoteCredentialClicks[i].Layout(gtx, func(gtx layout.Context) layout.Dimensions { - lbl := material.Label(u.theme, unit.Sp(13), label) - lbl.Color = accentColor - return lbl.Layout(gtx) - }) - }) - }), - ) - } - } - return layout.Flex{Axis: layout.Vertical}.Layout(gtx, - children..., - ) - } - if supportsDesktopFilePicker(runtime.GOOS) { - return selectorEditorHelp(u.theme, "Local Vault Path", "Choose the other local .kdbx file to synchronize with.", &u.syncLocalPath, &u.pickSyncLocalPath, "Choose File", false)(gtx) - } - return labeledEditorHelp(u.theme, "Local Vault Path", "Enter the shared-storage path to the other local .kdbx file to synchronize with.", &u.syncLocalPath, false)(gtx) - }), - layout.Rigid(layout.Spacer{Height: unit.Dp(14)}.Layout), - layout.Rigid(func(gtx layout.Context) layout.Dimensions { - return layout.Flex{Spacing: layout.SpaceStart}.Layout(gtx, - layout.Rigid(func(gtx layout.Context) layout.Dimensions { - return tonedButton(gtx, u.theme, &u.runAdvancedSync, u.syncDialogConfirmButtonLabel()) - }), - layout.Rigid(layout.Spacer{Width: unit.Dp(6)}.Layout), - layout.Rigid(func(gtx layout.Context) layout.Dimensions { - return tonedButton(gtx, u.theme, &u.closeAdvancedSync, "Cancel") - }), - ) - }), - ) - }) -} - func (u *ui) pendingApproval() (apiapproval.Request, bool) { pending := u.state.PendingApprovals() if len(pending) == 0 { @@ -5473,40 +5279,6 @@ func approvalFact(theme *material.Theme, title, primary, secondary string) layou } } -func (u *ui) syncPasswordField(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), "REMOTE PASSWORD") - lbl.Color = mutedColor - return lbl.Layout(gtx) - }), - layout.Rigid(layout.Spacer{Height: unit.Dp(4)}.Layout), - layout.Rigid(func(gtx layout.Context) layout.Dimensions { - field := func(gtx layout.Context) layout.Dimensions { - editor := material.Editor(u.theme, &u.syncRemotePassword, "Remote Password") - editor.Color = u.theme.Palette.Fg - editor.HintColor = mutedColor - return layout.UniformInset(unit.Dp(10)).Layout(gtx, editor.Layout) - } - return layout.Flex{Alignment: layout.Middle}.Layout(gtx, - layout.Flexed(1, func(gtx layout.Context) layout.Dimensions { - return u.outlinedFieldState(gtx, false, field) - }), - layout.Rigid(layout.Spacer{Width: unit.Dp(8)}.Layout), - layout.Rigid(func(gtx layout.Context) layout.Dimensions { - return u.inlinePasswordToggle(gtx, &u.toggleSyncPassword, u.showSyncPassword) - }), - ) - }), - 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), "Password or app token for the other WebDAV source.") - lbl.Color = mutedColor - return lbl.Layout(gtx) - }), - ) -} - func (u *ui) header(gtx layout.Context) layout.Dimensions { if u.mode == "phone" { if u.shouldShowLifecycleSetup() || u.isVaultLocked() { @@ -5614,12 +5386,22 @@ func (u *ui) headerActions(gtx layout.Context) layout.Dimensions { func (u *ui) mainMenu(gtx layout.Context) layout.Dimensions { rows := []layout.Widget{ - func(gtx layout.Context) layout.Dimensions { return tonedButton(gtx, u.theme, &u.showEntries, "Entries") }, - func(gtx layout.Context) layout.Dimensions { return tonedButton(gtx, u.theme, &u.showRecycle, "Recycle Bin") }, - func(gtx layout.Context) layout.Dimensions { return tonedButton(gtx, u.theme, &u.showAPITokens, "API Tokens") }, - func(gtx layout.Context) layout.Dimensions { return tonedButton(gtx, u.theme, &u.showAPIAudit, "API Audit") }, + func(gtx layout.Context) layout.Dimensions { + return tonedButton(gtx, u.theme, &u.showEntries, "Entries") + }, + func(gtx layout.Context) layout.Dimensions { + return tonedButton(gtx, u.theme, &u.showRecycle, "Recycle Bin") + }, + func(gtx layout.Context) layout.Dimensions { + return tonedButton(gtx, u.theme, &u.showAPITokens, "API Tokens") + }, + func(gtx layout.Context) layout.Dimensions { + return tonedButton(gtx, u.theme, &u.showAPIAudit, "API Audit") + }, func(gtx layout.Context) layout.Dimensions { return tonedButton(gtx, u.theme, &u.showAbout, "About") }, - func(gtx layout.Context) layout.Dimensions { return tonedButton(gtx, u.theme, &u.openSecuritySettings, "Settings") }, + func(gtx layout.Context) layout.Dimensions { + return tonedButton(gtx, u.theme, &u.openSecuritySettings, "Settings") + }, } rowWidth := menuActionWidth(gtx, rows) return intrinsicCompactCard(gtx, func(gtx layout.Context) layout.Dimensions { @@ -5763,7 +5545,9 @@ func (u *ui) syncMenu(gtx layout.Context) layout.Dimensions { u.vaultRemoteCredentialClicks = make([]widget.Clickable, len(credentials)) } actionRows := []layout.Widget{ - func(gtx layout.Context) layout.Dimensions { return tonedButton(gtx, u.theme, &u.openAdvancedSync, "Open Advanced Sync") }, + func(gtx layout.Context) layout.Dimensions { + return tonedButton(gtx, u.theme, &u.openAdvancedSync, "Open Advanced Sync") + }, } if supportsVaultShare(runtime.GOOS) && u.vaultSharer != nil && strings.TrimSpace(u.currentShareableVaultPath()) != "" { actionRows = append(actionRows, func(gtx layout.Context) layout.Dimensions { diff --git a/ui_layout_lifecycle.go b/ui_layout_lifecycle.go new file mode 100644 index 0000000..25b67ac --- /dev/null +++ b/ui_layout_lifecycle.go @@ -0,0 +1,24 @@ +package main + +import ( + "gioui.org/layout" + "gioui.org/unit" + "gioui.org/widget/material" +) + +func (u *ui) lifecycleScreen(gtx layout.Context) layout.Dimensions { + panel := card + if u.mode == "phone" { + panel = compactCard + } + return panel(gtx, func(gtx layout.Context) layout.Dimensions { + rows := []layout.Widget{ + u.lifecycleBranding, + layout.Spacer{Height: unit.Dp(8)}.Layout, + u.lifecycleControls, + } + return material.List(u.theme, &u.lifecycleList).Layout(gtx, len(rows), func(gtx layout.Context, i int) layout.Dimensions { + return rows[i](gtx) + }) + }) +} diff --git a/ui_sync_dialog.go b/ui_sync_dialog.go new file mode 100644 index 0000000..bb794fd --- /dev/null +++ b/ui_sync_dialog.go @@ -0,0 +1,223 @@ +package main + +import ( + "image/color" + "runtime" + "strings" + + "gioui.org/layout" + "gioui.org/op/clip" + "gioui.org/op/paint" + "gioui.org/unit" + "gioui.org/widget" + "gioui.org/widget/material" +) + +func (u *ui) syncDialog(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(620)) + 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.syncDialogContent) + }) + }), + ) +} + +func (u *ui) syncDialogContent(gtx layout.Context) layout.Dimensions { + matchingCredentials := u.matchingAdvancedSyncRemoteCredentialEntries() + if len(u.syncRemoteCredentialClicks) < len(matchingCredentials) { + u.syncRemoteCredentialClicks = make([]widget.Clickable, len(matchingCredentials)) + } + return material.List(u.theme, &u.syncDialogList).Layout(gtx, 1, func(gtx layout.Context, _ int) 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), u.syncDialogTitle()) + 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), u.syncDialogDescription()) + lbl.Color = mutedColor + return lbl.Layout(gtx) + }), + layout.Rigid(layout.Spacer{Height: unit.Dp(12)}.Layout), + layout.Rigid(func(gtx layout.Context) layout.Dimensions { + if !u.shouldShowSyncDirectionChoices() { + return layout.Dimensions{} + } + return layout.Flex{Axis: layout.Vertical}.Layout(gtx, + layout.Rigid(syncDialogSectionLabel(u.theme, "Direction")), + layout.Rigid(layout.Spacer{Height: unit.Dp(6)}.Layout), + layout.Rigid(func(gtx layout.Context) layout.Dimensions { + return layout.Flex{Spacing: layout.SpaceStart}.Layout(gtx, + layout.Rigid(func(gtx layout.Context) layout.Dimensions { + return syncChoiceButton(gtx, u.theme, &u.showSyncPull, "Pull Into Current Vault", u.syncDirection == syncDirectionPull) + }), + layout.Rigid(layout.Spacer{Width: unit.Dp(6)}.Layout), + layout.Rigid(func(gtx layout.Context) layout.Dimensions { + return syncChoiceButton(gtx, u.theme, &u.showSyncPush, "Push Current Vault Out", u.syncDirection == syncDirectionPush) + }), + ) + }), + ) + }), + layout.Rigid(func(gtx layout.Context) layout.Dimensions { + if !u.shouldShowSyncDirectionChoices() { + return layout.Dimensions{} + } + return layout.Spacer{Height: unit.Dp(12)}.Layout(gtx) + }), + layout.Rigid(func(gtx layout.Context) layout.Dimensions { + if !u.shouldShowSyncSourceChoices() { + return layout.Dimensions{} + } + return layout.Flex{Axis: layout.Vertical}.Layout(gtx, + layout.Rigid(syncDialogSectionLabel(u.theme, "Other Source")), + layout.Rigid(layout.Spacer{Height: unit.Dp(6)}.Layout), + layout.Rigid(func(gtx layout.Context) layout.Dimensions { + return layout.Flex{Spacing: layout.SpaceStart}.Layout(gtx, + layout.Rigid(func(gtx layout.Context) layout.Dimensions { + return syncChoiceButton(gtx, u.theme, &u.showSyncLocal, "Local File", u.syncSourceMode == syncSourceLocal) + }), + layout.Rigid(layout.Spacer{Width: unit.Dp(6)}.Layout), + layout.Rigid(func(gtx layout.Context) layout.Dimensions { + return syncChoiceButton(gtx, u.theme, &u.showSyncRemote, "Remote WebDAV", u.syncSourceMode == syncSourceRemote) + }), + ) + }), + ) + }), + layout.Rigid(func(gtx layout.Context) layout.Dimensions { + if !u.shouldShowSyncSourceChoices() { + return layout.Dimensions{} + } + return layout.Spacer{Height: unit.Dp(12)}.Layout(gtx) + }), + layout.Rigid(func(gtx layout.Context) layout.Dimensions { + return syncDialogSummaryCard(gtx, u.theme, u.syncDialogPurpose, u.syncSourceMode, u.syncDirection) + }), + layout.Rigid(layout.Spacer{Height: unit.Dp(12)}.Layout), + layout.Rigid(func(gtx layout.Context) layout.Dimensions { + if u.syncSourceMode == syncSourceRemote { + children := []layout.FlexChild{ + layout.Rigid(labeledEditorHelp(u.theme, "Remote Base URL", "WebDAV base URL for the other source.", &u.syncRemoteBaseURL, false)), + layout.Rigid(layout.Spacer{Height: unit.Dp(6)}.Layout), + layout.Rigid(labeledEditorHelp(u.theme, "Remote Path", "Path to the other remote .kdbx file.", &u.syncRemotePath, false)), + layout.Rigid(layout.Spacer{Height: unit.Dp(6)}.Layout), + layout.Rigid(labeledEditorHelp(u.theme, "Remote Username", "Username for the other WebDAV source.", &u.syncRemoteUsername, false)), + layout.Rigid(layout.Spacer{Height: unit.Dp(6)}.Layout), + layout.Rigid(func(gtx layout.Context) layout.Dimensions { + return u.syncPasswordField(gtx) + }), + } + if u.syncDialogPurpose == syncDialogPurposeRemoteSetup { + children = append(children, + layout.Rigid(layout.Spacer{Height: unit.Dp(8)}.Layout), + layout.Rigid(func(gtx layout.Context) layout.Dimensions { + check := material.CheckBox(u.theme, &u.syncSetupAutomatic, "Sync automatically on open and save") + check.Color = accentColor + return check.Layout(gtx) + }), + ) + } + if len(matchingCredentials) > 0 { + children = append(children, + layout.Rigid(layout.Spacer{Height: unit.Dp(8)}.Layout), + layout.Rigid(func(gtx layout.Context) layout.Dimensions { + lbl := material.Label(u.theme, unit.Sp(11), "Matching vault credentials") + lbl.Color = mutedColor + return lbl.Layout(gtx) + }), + ) + for i, entry := range matchingCredentials { + i := i + entry := entry + children = append(children, + layout.Rigid(layout.Spacer{Height: unit.Dp(4)}.Layout), + layout.Rigid(func(gtx layout.Context) layout.Dimensions { + label := entry.Title + if strings.TrimSpace(entry.Username) != "" { + label += " · " + strings.TrimSpace(entry.Username) + } + selected := strings.TrimSpace(u.selectedSyncRemoteCredentialEntryID) == entry.ID + return recentSelectionCard(gtx, selected, func(gtx layout.Context) layout.Dimensions { + return u.syncRemoteCredentialClicks[i].Layout(gtx, func(gtx layout.Context) layout.Dimensions { + lbl := material.Label(u.theme, unit.Sp(13), label) + lbl.Color = accentColor + return lbl.Layout(gtx) + }) + }) + }), + ) + } + } + return layout.Flex{Axis: layout.Vertical}.Layout(gtx, children...) + } + if supportsDesktopFilePicker(runtime.GOOS) { + return selectorEditorHelp(u.theme, "Local Vault Path", "Choose the other local .kdbx file to synchronize with.", &u.syncLocalPath, &u.pickSyncLocalPath, "Choose File", false)(gtx) + } + return labeledEditorHelp(u.theme, "Local Vault Path", "Enter the shared-storage path to the other local .kdbx file to synchronize with.", &u.syncLocalPath, false)(gtx) + }), + layout.Rigid(layout.Spacer{Height: unit.Dp(14)}.Layout), + layout.Rigid(func(gtx layout.Context) layout.Dimensions { + return layout.Flex{Spacing: layout.SpaceStart}.Layout(gtx, + layout.Rigid(func(gtx layout.Context) layout.Dimensions { + return tonedButton(gtx, u.theme, &u.runAdvancedSync, u.syncDialogConfirmButtonLabel()) + }), + layout.Rigid(layout.Spacer{Width: unit.Dp(6)}.Layout), + layout.Rigid(func(gtx layout.Context) layout.Dimensions { + return tonedButton(gtx, u.theme, &u.closeAdvancedSync, "Cancel") + }), + ) + }), + ) + }) +} + +func (u *ui) syncPasswordField(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), "REMOTE PASSWORD") + lbl.Color = mutedColor + return lbl.Layout(gtx) + }), + layout.Rigid(layout.Spacer{Height: unit.Dp(4)}.Layout), + layout.Rigid(func(gtx layout.Context) layout.Dimensions { + field := func(gtx layout.Context) layout.Dimensions { + editor := material.Editor(u.theme, &u.syncRemotePassword, "Remote Password") + editor.Color = u.theme.Palette.Fg + editor.HintColor = mutedColor + return layout.UniformInset(unit.Dp(10)).Layout(gtx, editor.Layout) + } + return layout.Flex{Alignment: layout.Middle}.Layout(gtx, + layout.Flexed(1, func(gtx layout.Context) layout.Dimensions { + return u.outlinedFieldState(gtx, false, field) + }), + layout.Rigid(layout.Spacer{Width: unit.Dp(8)}.Layout), + layout.Rigid(func(gtx layout.Context) layout.Dimensions { + return u.inlinePasswordToggle(gtx, &u.toggleSyncPassword, u.showSyncPassword) + }), + ) + }), + 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), "Password or app token for the other WebDAV source.") + lbl.Color = mutedColor + return lbl.Layout(gtx) + }), + ) +}