Started without a command, keeporg now shows a padlock in the system tray with a menu like midi-webhook's: a status line, the mirror folder, each database with its state, Sync Now, browser sign-in and sign-out, the web interface, the configuration, the log, Start at Login, About and Quit. The commands are unchanged. config.json now carries every client setting (device_label, request_timeout_seconds, ca_file, log_file, notifications), is written in full on first start and is reloaded by the tray when saved. A lock in the mirror directory admits one agent at a time, since the tray, `keeporg run` and a service unit could otherwise race each other. The tray uses fyne.io/systray: pure Go on Linux, BSD and Windows, cgo on macOS only. The server keeps no third-party dependencies. Desktop versions go to 0.5.0. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
59 lines
1.6 KiB
Go
59 lines
1.6 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"os/exec"
|
|
"runtime"
|
|
)
|
|
|
|
// homepage is where About points.
|
|
const homepage = "https://garage.rcmd.space/keeporg"
|
|
|
|
// openPath opens a file, directory or URL with whatever the desktop
|
|
// associates with it. It is best effort: a caller that matters also logs or
|
|
// prints the target.
|
|
func openPath(target string) {
|
|
var cmd *exec.Cmd
|
|
switch runtime.GOOS {
|
|
case "darwin":
|
|
cmd = exec.Command("open", target)
|
|
case "windows":
|
|
cmd = exec.Command("rundll32", "url.dll,FileProtocolHandler", target)
|
|
default:
|
|
cmd = exec.Command("xdg-open", target)
|
|
}
|
|
_ = cmd.Start()
|
|
}
|
|
|
|
// openText opens a file in a text editor. JSON is associated with an IDE or
|
|
// a browser often enough that "open" is not good enough for a config file.
|
|
func openText(path string) {
|
|
switch runtime.GOOS {
|
|
case "darwin":
|
|
_ = exec.Command("open", "-t", path).Start()
|
|
case "windows":
|
|
_ = exec.Command("notepad", path).Start()
|
|
default:
|
|
openPath(path)
|
|
}
|
|
}
|
|
|
|
// notify shows a desktop notification, best effort. Windows has none without
|
|
// a third-party library; the menu's first line carries the same news there.
|
|
func notify(title, message string) {
|
|
switch runtime.GOOS {
|
|
case "darwin":
|
|
_ = exec.Command("osascript", "-e",
|
|
fmt.Sprintf("display notification %q with title %q", message, title)).Start()
|
|
case "windows":
|
|
default:
|
|
_ = exec.Command("notify-send", "--app-name=KeepOrg", "--icon=keeporg", title, message).Start()
|
|
}
|
|
}
|
|
|
|
// aboutText is the About dialog's body.
|
|
func aboutText(configPath string) string {
|
|
return fmt.Sprintf("KeepOrg %s\n\nKeePass database synchronization.\n\nConfiguration: %s\n%s",
|
|
Version, configPath, homepage)
|
|
}
|