From 8c950dd7fc294987401b5a7facff1a4772d15c85 Mon Sep 17 00:00:00 2001 From: Lukas Batelka Date: Wed, 24 Sep 2025 22:26:12 +0200 Subject: [PATCH] feature/ui o dost lepsi ui ux --- fyne_ui.go | 2 +- ui.go | 198 ++++++++++++++++++++++++++++------------------------- 2 files changed, 105 insertions(+), 95 deletions(-) diff --git a/fyne_ui.go b/fyne_ui.go index 783b771..b94013c 100644 --- a/fyne_ui.go +++ b/fyne_ui.go @@ -16,7 +16,7 @@ import ( func NewUI() (stprageDir string, window fyne.Window) { // App + storage dir - a := app.New() + a := app.NewWithID("fckeuspy") w := a.NewWindow("Encryptor (Fyne)") prefs := a.Preferences() width := prefs.IntWithFallback("winW", 1100) diff --git a/ui.go b/ui.go index a6f7f3c..ff25449 100644 --- a/ui.go +++ b/ui.go @@ -12,6 +12,7 @@ import ( "fyne.io/fyne/v2/canvas" "fyne.io/fyne/v2/container" "fyne.io/fyne/v2/dialog" + "fyne.io/fyne/v2/layout" "fyne.io/fyne/v2/storage" "fyne.io/fyne/v2/theme" "fyne.io/fyne/v2/widget" @@ -113,12 +114,15 @@ var forceDark = true // Build key section func buildIdentityTab(parts *uiParts, svc ServiceFacade, vaultPath string) fyne.CanvasObject { - btnCopyPub := widget.NewButton("Copy public.pem", func() { copyClip(svc.PublicPEM(), parts) }) - btnCopyCrt := widget.NewButton("Copy identity.crt", func() { copyClip(svc.PublicCert(), parts) }) - btnShowPub := widget.NewButton("Show pub", func() { parts.outKey.SetText(svc.PublicPEM()) }) - btnShowCrt := widget.NewButton("Show crt", func() { parts.outKey.SetText(svc.PublicCert()) }) - btnClear := widget.NewButton("Clear", func() { parts.outKey.SetText("") }) - btnPaste := widget.NewButton("Paste", func() { parts.outKey.SetText(fyne.CurrentApp().Clipboard().Content()) }) + // Toolbar actions + identityToggle := widget.NewToolbarAction(theme.VisibilityOffIcon(), nil) + identityToolbar := widget.NewToolbar( + widget.NewToolbarAction(theme.ContentCopyIcon(), func() { copyClip(svc.PublicPEM()+"\n"+svc.PublicCert(), parts) }), + widget.NewToolbarAction(theme.ContentPasteIcon(), func() { parts.outKey.SetText(fyne.CurrentApp().Clipboard().Content()) }), + widget.NewToolbarAction(theme.ContentClearIcon(), func() { parts.outKey.SetText("") }), + widget.NewToolbarSeparator(), + identityToggle, + ) deleteBtn := widget.NewButton("Smazat identitu", func() { pwEntry := widget.NewPasswordEntry() @@ -175,10 +179,7 @@ func buildIdentityTab(parts *uiParts, svc ServiceFacade, vaultPath string) fyne. } identityContainer := container.NewVBox() - - toggleBtn := widget.NewButton("", nil) - var rebuild func() - rebuild = func() { + rebuild := func() { identityContainer.Objects = nil if parts.showQR { updateQRImages() @@ -193,26 +194,18 @@ func buildIdentityTab(parts *uiParts, svc ServiceFacade, vaultPath string) fyne. } identityContainer.Refresh() if parts.showQR { - toggleBtn.SetText("Zobrazit plaintext") + identityToggle.SetIcon(theme.VisibilityOffIcon()) } else { - toggleBtn.SetText("Zobrazit QR") + identityToggle.SetIcon(theme.VisibilityIcon()) } } - toggleBtn.OnTapped = func() { parts.showQR = !parts.showQR; rebuild() } + identityToggle.OnActivated = func() { parts.showQR = !parts.showQR; rebuild() } rebuild() - // Group buttons by function: data viewing vs clipboard vs destructive - clipboardRow := buttonTile(btnCopyPub, btnCopyCrt, btnPaste, btnClear) - viewRow := buttonTile(btnShowPub, btnShowCrt, toggleBtn) - destroyRow := buttonTile(deleteBtn) - group := container.NewVBox( - widget.NewLabelWithStyle("Moje identita", fyne.TextAlignLeading, fyne.TextStyle{Bold: true}), - viewRow, - identityContainer, - clipboardRow, - destroyRow, - ) - return container.NewVScroll(group) + // Header with toolbar and content + destructive action + header := container.NewHBox(widget.NewLabelWithStyle("Moje identita", fyne.TextAlignLeading, fyne.TextStyle{Bold: true}), layout.NewSpacer(), identityToolbar) + content := container.NewVBox(header, identityContainer, buttonTile(deleteBtn)) + return container.NewVScroll(content) } // Helper functions separated to avoid circular dependency with encrypt.Service @@ -240,14 +233,10 @@ func copyClip(s string, parts *uiParts) { // Tab: Encrypt func buildEncryptTab(parts *uiParts, svc ServiceFacade) fyne.CanvasObject { parts.cipherOut.Disable() - peerBtns := buttonTile( - widget.NewButton("Paste", func() { parts.peer.SetText(fyne.CurrentApp().Clipboard().Content()) }), - widget.NewButton("Clear", func() { parts.peer.SetText("") }), - widget.NewButton("Copy", func() { copyClip(parts.peer.Text, parts) }), - ) + // Peer section with QR/Text toggle peerContainer := container.NewVBox() - peerToggle := widget.NewButton("", nil) + peerToggleAction := widget.NewToolbarAction(theme.VisibilityOffIcon(), nil) var updatePeer func() updatePeerQR := func(text string) { if text == "" { @@ -271,20 +260,24 @@ func buildEncryptTab(parts *uiParts, svc ServiceFacade) fyne.CanvasObject { if parts.showPeerQR { updatePeerQR(parts.peer.Text) peerContainer.Add(container.NewVBox(parts.peerQR, widget.NewButton("Copy", func() { copyClip(parts.peer.Text, parts) }))) - peerToggle.SetText("Zobrazit plaintext") + peerToggleAction.SetIcon(theme.VisibilityOffIcon()) } else { peerContainer.Add(parts.peer) - peerToggle.SetText("Zobrazit QR") + peerToggleAction.SetIcon(theme.VisibilityIcon()) } peerContainer.Refresh() } - peerToggle.OnTapped = func() { parts.showPeerQR = !parts.showPeerQR; updatePeer() } + peerToggleAction.OnActivated = func() { parts.showPeerQR = !parts.showPeerQR; updatePeer() } parts.peer.OnChanged = func(string) { if parts.showPeerQR { updatePeerQR(parts.peer.Text) } } updatePeer() + + // Output section with QR/Text toggle + outputContainer := container.NewVBox() + outputToggleAction := widget.NewToolbarAction(theme.VisibilityOffIcon(), nil) updateQR := func(text string) { if text == "" { parts.cipherQR.Image = nil @@ -304,6 +297,21 @@ func buildEncryptTab(parts *uiParts, svc ServiceFacade) fyne.CanvasObject { parts.cipherQR.Image = img parts.cipherQR.Refresh() } + updateMode := func() { + outputContainer.Objects = nil + if parts.showQR { + updateQR(parts.cipherOut.Text) + outputContainer.Add(container.NewVBox(parts.cipherQR, widget.NewButton("Copy", func() { copyClip(parts.cipherOut.Text, parts) }))) + outputToggleAction.SetIcon(theme.VisibilityOffIcon()) + } else { + outputContainer.Add(parts.cipherOut) + outputToggleAction.SetIcon(theme.VisibilityIcon()) + } + outputContainer.Refresh() + } + outputToggleAction.OnActivated = func() { parts.showQR = !parts.showQR; updateMode() } + updateMode() + encAction := func() { m := parts.msg.Text p := parts.peer.Text @@ -326,6 +334,7 @@ func buildEncryptTab(parts *uiParts, svc ServiceFacade) fyne.CanvasObject { }) }(m, p) } + importPeerQR := func() { fd := dialog.NewFileOpen(func(r fyne.URIReadCloser, err error) { if err != nil || r == nil { @@ -348,46 +357,37 @@ func buildEncryptTab(parts *uiParts, svc ServiceFacade) fyne.CanvasObject { fd.SetFilter(storage.NewExtensionFileFilter([]string{".png"})) fd.Show() } - outputContainer := container.NewVBox() - toggleBtn := widget.NewButton("", nil) - var updateMode func() - updateMode = func() { - outputContainer.Objects = nil - if parts.showQR { - updateQR(parts.cipherOut.Text) - outputContainer.Add(container.NewVBox(parts.cipherQR, widget.NewButton("Copy", func() { copyClip(parts.cipherOut.Text, parts) }))) - } else { - outputContainer.Add(parts.cipherOut) - } - if parts.showQR { - toggleBtn.SetText("Zobrazit plaintext") - } else { - toggleBtn.SetText("Zobrazit QR") - } - outputContainer.Refresh() - } - toggleBtn.OnTapped = func() { parts.showQR = !parts.showQR; updateMode() } - updateMode() - msgBtns := buttonTile( - widget.NewButton("Clear+Paste", func() { parts.msg.SetText(""); parts.msg.SetText(fyne.CurrentApp().Clipboard().Content()) }), - widget.NewButton("Encrypt", func() { encAction(); updateMode() }), - widget.NewButton("Copy", func() { copyClip(parts.cipherOut.Text, parts) }), - widget.NewButton("Import Key QR", importPeerQR), + // Toolbars + peerToolbar := widget.NewToolbar( + widget.NewToolbarAction(theme.ContentPasteIcon(), func() { parts.peer.SetText(fyne.CurrentApp().Clipboard().Content()) }), + widget.NewToolbarAction(theme.ContentClearIcon(), func() { parts.peer.SetText("") }), + widget.NewToolbarAction(theme.ContentCopyIcon(), func() { copyClip(parts.peer.Text, parts) }), + widget.NewToolbarAction(theme.FolderOpenIcon(), importPeerQR), + widget.NewToolbarSeparator(), + peerToggleAction, + ) + outputToolbar := widget.NewToolbar( + widget.NewToolbarAction(theme.ContentCopyIcon(), func() { copyClip(parts.cipherOut.Text, parts) }), + widget.NewToolbarSeparator(), + outputToggleAction, ) + // Primary CTA + encryptBtn := widget.NewButtonWithIcon("Zašifrovat", theme.ConfirmIcon(), func() { encAction(); updateMode() }) + + // Sections peerSection := container.NewVBox( - container.NewHBox(widget.NewLabel("Veřejný klíč příjemce"), peerToggle), + container.NewHBox(widget.NewLabel("Veřejný klíč příjemce"), layout.NewSpacer(), peerToolbar), peerContainer, - peerBtns, ) msgSection := container.NewVBox( widget.NewLabel("Zpráva"), parts.msg, - msgBtns, + container.NewHBox(layout.NewSpacer(), encryptBtn), ) outputSection := container.NewVBox( - container.NewHBox(widget.NewLabel("Výstup"), toggleBtn), + container.NewHBox(widget.NewLabel("Výstup"), layout.NewSpacer(), outputToolbar), outputContainer, ) group := container.NewVBox( @@ -460,8 +460,33 @@ func buildDecryptTab(parts *uiParts, svc ServiceFacade) fyne.CanvasObject { fd.SetFilter(storage.NewExtensionFileFilter([]string{".png"})) fd.Show() } - payloadBtns := buttonTile( - widget.NewButton("Paste+Decrypt", func() { + // Toolbar toggle action for payload section + payloadToggleAction := widget.NewToolbarAction(theme.VisibilityOffIcon(), nil) + + payloadContainer := container.NewVBox() + updateMode := func() { + payloadContainer.Objects = nil + if parts.showPayloadQR { + updatePayloadQR(parts.payload.Text) + payloadContainer.Add(container.NewVBox(parts.payloadQR, widget.NewButton("Copy", func() { copyClip(parts.payload.Text, parts) }))) + payloadToggleAction.SetIcon(theme.VisibilityOffIcon()) + } else { + payloadContainer.Add(parts.payload) + payloadToggleAction.SetIcon(theme.VisibilityIcon()) + } + payloadContainer.Refresh() + } + payloadToggleAction.OnActivated = func() { parts.showPayloadQR = !parts.showPayloadQR; updateMode() } + parts.payload.OnChanged = func(string) { + if parts.showPayloadQR { + updatePayloadQR(parts.payload.Text) + } + } + updateMode() + + // Build payload toolbar + payloadToolbar := widget.NewToolbar( + widget.NewToolbarAction(theme.ContentPasteIcon(), func() { clip := fyne.CurrentApp().Clipboard().Content() parts.payload.SetText(clip) if parts.showPayloadQR { @@ -469,48 +494,33 @@ func buildDecryptTab(parts *uiParts, svc ServiceFacade) fyne.CanvasObject { } decryptAction() }), - widget.NewButton("Clear", func() { + widget.NewToolbarAction(theme.ContentClearIcon(), func() { parts.payload.SetText("") parts.plainOut.SetText("") if parts.showPayloadQR { updatePayloadQR("") } }), - widget.NewButton("QR Import", importPayloadQR), + widget.NewToolbarAction(theme.FolderOpenIcon(), importPayloadQR), + widget.NewToolbarSeparator(), + payloadToggleAction, ) - payloadContainer := container.NewVBox() - payloadToggle := widget.NewButton("", nil) - var updateMode func() - updateMode = func() { - payloadContainer.Objects = nil - if parts.showPayloadQR { - updatePayloadQR(parts.payload.Text) - payloadContainer.Add(container.NewVBox(parts.payloadQR, widget.NewButton("Copy", func() { copyClip(parts.payload.Text, parts) }))) - payloadToggle.SetText("Zobrazit plaintext") - } else { - payloadContainer.Add(parts.payload) - payloadToggle.SetText("Zobrazit QR") - } - payloadContainer.Refresh() - } - payloadToggle.OnTapped = func() { parts.showPayloadQR = !parts.showPayloadQR; updateMode() } - parts.payload.OnChanged = func(string) { - if parts.showPayloadQR { - updatePayloadQR(parts.payload.Text) - } - } - updateMode() - plainBtns := buttonTile(widget.NewButton("Copy", func() { copyClip(parts.plainOut.Text, parts) })) + // Build result toolbar + resultToolbar := widget.NewToolbar( + widget.NewToolbarAction(theme.ContentCopyIcon(), func() { copyClip(parts.plainOut.Text, parts) }), + ) + + // Primary CTA for decryption + decryptBtn := widget.NewButtonWithIcon("Dešifrovat", theme.ConfirmIcon(), func() { decryptAction() }) payloadSection := container.NewVBox( - container.NewHBox(widget.NewLabel("Payload"), payloadToggle), + container.NewHBox(widget.NewLabel("Payload"), layout.NewSpacer(), payloadToolbar), payloadContainer, - payloadBtns, + container.NewHBox(layout.NewSpacer(), decryptBtn), ) resultSection := container.NewVBox( - widget.NewLabel("Výsledek"), + container.NewHBox(widget.NewLabel("Výsledek"), layout.NewSpacer(), resultToolbar), parts.plainOut, - plainBtns, ) group := container.NewVBox( widget.NewLabelWithStyle("Dešifrování", fyne.TextAlignLeading, fyne.TextStyle{Bold: true}),