feature/ui - zatim ne uplne uhlazena ale celkem pouzitelna appka #1

Merged
luke-20 merged 17 commits from feature/ui into main 2025-09-28 21:05:52 +02:00
2 changed files with 105 additions and 95 deletions
Showing only changes of commit 8c950dd7fc - Show all commits

View File

@ -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)

198
ui.go
View File

@ -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}),