summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2025-09-13 10:31:07 +0300
committerPaul Buetow <paul@buetow.org>2025-09-13 10:31:07 +0300
commit4f4d430db11f4d7be9cb7c6562d611f088cc01cc (patch)
tree071f180b0433efa60f9cbeaba6bc8e039ab545fc
parente32cd22fea7e575f0d007226c34f711387aba923 (diff)
Simplify UI: remove Days/Tag/What menus; reorder bottom controls to 'Log text', 'Clear', 'Preferences', char count. Simplify Preferences to directory only. Add Magefile with build, run, clean, android, androidcross targets; make run verbose for debugging.
-rw-r--r--Magefile.go201
-rw-r--r--go.mod1
-rw-r--r--go.sum2
-rw-r--r--main.go171
-rw-r--r--ql-250516-000347.md1
5 files changed, 256 insertions, 120 deletions
diff --git a/Magefile.go b/Magefile.go
new file mode 100644
index 0000000..49a5fb4
--- /dev/null
+++ b/Magefile.go
@@ -0,0 +1,201 @@
+//go:build mage
+// +build mage
+
+package main
+
+import (
+ "io"
+ "fmt"
+ "os"
+ "path/filepath"
+ "runtime"
+ "strconv"
+ "time"
+
+ "github.com/magefile/mage/sh"
+)
+
+// Build compiles the quicklogger app into ./bin.
+func Build() error {
+ outDir := "bin"
+ if err := os.MkdirAll(outDir, 0o755); err != nil {
+ return err
+ }
+
+ binName := "quicklogger"
+ if runtime.GOOS == "windows" {
+ binName += ".exe"
+ }
+
+ out := filepath.Join(outDir, binName)
+ fmt.Printf("Building %s\n", out)
+ return sh.RunV("go", "build", "-o", out, ".")
+}
+
+// Run launches the app with `go run .`.
+func Run() error {
+ fmt.Println("Running quicklogger (verbose build)")
+ // Show Go version and key env for diagnostics
+ _ = sh.RunV("go", "version")
+ _ = sh.RunV("go", "env", "GOVERSION", "GOOS", "GOARCH", "GOMOD", "GOMODCACHE", "GOCACHE")
+ // Compile+run with verbose and trace flags to show build steps
+ return sh.RunV("go", "run", "-v", "-x", ".")
+}
+
+// Clean removes build artifacts (bin/ and local APK).
+func Clean() error {
+ fmt.Println("Cleaning build artifacts")
+ // Remove bin directory
+ if err := os.RemoveAll("bin"); err != nil {
+ return err
+ }
+ // Remove generated APK if present
+ _ = os.Remove("quicklogger.apk")
+ return nil
+}
+
+// Android packages an Android APK via Fyne and copies it to ~/Documents/APKs if present.
+func Android() error {
+ env := map[string]string{}
+
+ // Respect existing ANDROID_NDK_HOME. If not set, try legacy var or a common default path.
+ ndk := os.Getenv("ANDROID_NDK_HOME")
+ if ndk == "" {
+ // Some setups export a misspelled var; honor it if present.
+ ndk = os.Getenv("ANDORID_NDK_HOME")
+ }
+ if ndk == "" {
+ if home, err := os.UserHomeDir(); err == nil {
+ guess := filepath.Join(home, "android-ndk", "android-ndk-r26b")
+ env["ANDROID_NDK_HOME"] = guess
+ fmt.Printf("ANDROID_NDK_HOME not set, guessing %s\n", guess)
+ }
+ }
+
+ fmt.Println("Packaging Android APK via Fyne")
+ if err := sh.RunWithV(env, "fyne", "package", "-os", "android"); err != nil {
+ return err
+ }
+
+ // If ~/Documents/APKs exists, copy the APK there.
+ home, err := os.UserHomeDir()
+ if err != nil {
+ return nil // packaging succeeded; copying is best-effort
+ }
+ destDir := filepath.Join(home, "Documents", "APKs")
+ if st, err := os.Stat(destDir); err == nil && st.IsDir() {
+ src := "quicklogger.apk"
+ if _, err := os.Stat(src); err == nil {
+ dst := filepath.Join(destDir, filepath.Base(src))
+ if err := copyFile(src, dst); err != nil {
+ return err
+ }
+ fmt.Printf("Copied %s to %s\n", src, dst)
+ }
+ }
+ return nil
+}
+
+// AndroidCross builds an Android APK using fyne-cross with Docker/Podman.
+// Mirrors steps from README using a Podman socket if available.
+func AndroidCross() error {
+ env := map[string]string{}
+
+ // If DOCKER_HOST is not set, try a sensible Podman socket default.
+ if os.Getenv("DOCKER_HOST") == "" {
+ uid := os.Geteuid()
+ sock := filepath.Join("/run/user", strconv.Itoa(uid), "podman", "podman.sock")
+ if _, err := os.Stat(sock); err == nil {
+ env["DOCKER_HOST"] = "unix://" + sock
+ fmt.Printf("Using Podman socket: %s\n", env["DOCKER_HOST"])
+ } else {
+ fmt.Println("DOCKER_HOST is not set and no Podman socket found; relying on default Docker daemon.")
+ }
+ }
+
+ // Ensure fyne-cross is available; attempt install if not.
+ if _, err := sh.Output("which", "fyne-cross"); err != nil {
+ fmt.Println("Installing fyne-cross (requires network access)...")
+ if err := sh.RunV("go", "install", "github.com/fyne-io/fyne-cross@latest"); err != nil {
+ return fmt.Errorf("fyne-cross not found and installation failed: %w", err)
+ }
+ }
+
+ // Pull/update builder image then build.
+ if err := sh.RunWithV(env, "fyne-cross", "android", "--pull"); err != nil {
+ return err
+ }
+ if err := sh.RunWithV(env, "fyne-cross", "android"); err != nil {
+ return err
+ }
+
+ // Copy newest APK to ~/Documents/APKs if available.
+ apk, err := newestAPK("fyne-cross/dist/android")
+ if err != nil {
+ // Not fatal; print a note and finish
+ fmt.Printf("Note: could not locate built APK: %v\n", err)
+ return nil
+ }
+ home, herr := os.UserHomeDir()
+ if herr != nil {
+ return nil
+ }
+ destDir := filepath.Join(home, "Documents", "APKs")
+ if st, err := os.Stat(destDir); err == nil && st.IsDir() {
+ dst := filepath.Join(destDir, filepath.Base(apk))
+ if err := copyFile(apk, dst); err != nil {
+ return err
+ }
+ fmt.Printf("Copied %s to %s\n", apk, dst)
+ }
+ return nil
+}
+
+func newestAPK(dir string) (string, error) {
+ entries, err := os.ReadDir(dir)
+ if err != nil {
+ return "", err
+ }
+ var newest string
+ var newestMod time.Time
+ for _, e := range entries {
+ if e.IsDir() {
+ continue
+ }
+ name := e.Name()
+ if filepath.Ext(name) != ".apk" {
+ continue
+ }
+ info, err := e.Info()
+ if err != nil {
+ continue
+ }
+ if info.ModTime().After(newestMod) {
+ newestMod = info.ModTime()
+ newest = filepath.Join(dir, name)
+ }
+ }
+ if newest == "" {
+ return "", fmt.Errorf("no .apk found in %s", dir)
+ }
+ return newest, nil
+}
+
+func copyFile(src, dst string) error {
+ in, err := os.Open(src)
+ if err != nil {
+ return err
+ }
+ defer in.Close()
+
+ out, err := os.Create(dst)
+ if err != nil {
+ return err
+ }
+ defer func() { _ = out.Close() }()
+
+ if _, err = io.Copy(out, in); err != nil {
+ return err
+ }
+ return out.Sync()
+}
diff --git a/go.mod b/go.mod
index 278297d..033fb60 100644
--- a/go.mod
+++ b/go.mod
@@ -19,6 +19,7 @@ require (
github.com/godbus/dbus/v5 v5.1.0 // indirect
github.com/gopherjs/gopherjs v1.17.2 // indirect
github.com/jsummers/gobmp v0.0.0-20151104160322-e2ba15ffa76e // indirect
+ github.com/magefile/mage v1.15.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/srwiley/oksvg v0.0.0-20221011165216-be6e8873101c // indirect
github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef // indirect
diff --git a/go.sum b/go.sum
index d8295d1..f7804c4 100644
--- a/go.sum
+++ b/go.sum
@@ -207,6 +207,8 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/magefile/mage v1.15.0 h1:BvGheCMAsG3bWUDbZ8AyXXpCNwU9u5CB6sM+HNb9HYg=
+github.com/magefile/mage v1.15.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A=
github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
diff --git a/main.go b/main.go
index 5a7d35a..863a40d 100644
--- a/main.go
+++ b/main.go
@@ -1,16 +1,15 @@
package main
import (
- "fmt"
- "os"
- "strings"
- "time"
-
- "fyne.io/fyne/v2"
- "fyne.io/fyne/v2/app"
- "fyne.io/fyne/v2/container"
- "fyne.io/fyne/v2/dialog"
- "fyne.io/fyne/v2/widget"
+ "fmt"
+ "os"
+ "time"
+
+ "fyne.io/fyne/v2"
+ "fyne.io/fyne/v2/app"
+ "fyne.io/fyne/v2/container"
+ "fyne.io/fyne/v2/dialog"
+ "fyne.io/fyne/v2/widget"
)
const (
@@ -20,74 +19,28 @@ const (
)
var (
- defaultDirectory = "."
- defaultTagItems = []string{
- "infra",
- "log",
- "share",
- "share:li",
- "share:ma",
- "share:no",
- "track",
- "track 10",
- "track 15",
- "track 20",
- "track 25",
- "track 30",
- "track 5",
- "work",
- }
- defaultWhatItems = []string{
- "Breathing",
- "Bulgarian",
- "Ema",
- "Exercise",
- "Meditation",
- "Music",
- "Reading Articles",
- "Reading Books",
- "Stretching",
- "Tech",
- }
+ defaultDirectory = "."
)
var windowSize = fyne.NewSize(400, 100)
func createPreferenceWindow(a fyne.App) fyne.Window {
- window := a.NewWindow("Preferences")
- directoryPreference := widget.NewEntry()
- directoryPreference.SetText(a.Preferences().StringWithFallback("Directory", defaultDirectory))
-
- tagDropdownPreference := widget.NewEntry()
- tagDropdownPreference.SetText(a.Preferences().StringWithFallback("Tags", strings.Join(defaultTagItems, ",")))
-
- whatDropdownPreference := widget.NewEntry()
- whatDropdownPreference.SetText(a.Preferences().StringWithFallback("Whats", strings.Join(defaultWhatItems, ",")))
-
- window.SetContent(container.NewVBox(
- container.NewVBox(
- widget.NewLabel("Directory:"),
- directoryPreference,
- widget.NewLabel("Tags:"),
- tagDropdownPreference,
- widget.NewLabel("Whats:"),
- whatDropdownPreference,
- ),
- container.NewHBox(
- widget.NewButton("Save", func() {
- a.Preferences().SetString("Directory", directoryPreference.Text)
- a.Preferences().SetString("Tags", tagDropdownPreference.Text)
- a.Preferences().SetString("Whats", whatDropdownPreference.Text)
- window.Hide()
- }),
- widget.NewButton("Reset dropdowns", func() {
- // directoryPreference.SetText(defaultDirectory)
- tagDropdownPreference.SetText(strings.Join(defaultTagItems, ","))
- whatDropdownPreference.SetText(strings.Join(defaultWhatItems, ","))
- },
- ),
- )))
- window.Resize(windowSize)
+ window := a.NewWindow("Preferences")
+ directoryPreference := widget.NewEntry()
+ directoryPreference.SetText(a.Preferences().StringWithFallback("Directory", defaultDirectory))
+
+ window.SetContent(container.NewVBox(
+ container.NewVBox(
+ widget.NewLabel("Directory:"),
+ directoryPreference,
+ ),
+ container.NewHBox(
+ widget.NewButton("Save", func() {
+ a.Preferences().SetString("Directory", directoryPreference.Text)
+ window.Hide()
+ }),
+ )))
+ window.Resize(windowSize)
return window
}
@@ -128,42 +81,20 @@ func createMainWindow(a fyne.App) fyne.Window {
}
}
- // Dropdown with pre-selectable items
- daysDropdown := widget.NewSelect([]string{"0", "1", "3", "7", "14", "30", "60", "99"}, func(selected string) {
- input.SetText(selected + " ")
- window.Canvas().Focus(input)
- })
- daysDropdown.PlaceHolder = "Days"
-
- tagDropdownItems := strings.Split(a.Preferences().StringWithFallback("Tags", strings.Join(defaultTagItems, ",")), ",")
- tagDropdown := widget.NewSelect(tagDropdownItems, func(selected string) {
- input.Append(selected + " ")
- window.Canvas().Focus(input)
- })
- tagDropdown.PlaceHolder = "Tag"
-
- whatDropdownItems := strings.Split(a.Preferences().StringWithFallback("Whats", strings.Join(defaultWhatItems, ",")), ",")
- whatDropdown := widget.NewSelect(whatDropdownItems, func(selected string) {
- input.Append(selected + " ")
- window.Canvas().Focus(input)
- input.Cursor()
- })
- whatDropdown.PlaceHolder = "What"
-
- logTextButton := widget.NewButton("Log text", func() {
- filename := fmt.Sprintf("%s/ql-%s.md",
- a.Preferences().StringWithFallback("Directory", defaultDirectory),
- time.Now().Format("060102-150405"),
- )
- if err := os.WriteFile(filename, []byte(input.Text), 0644); err != nil {
- dialog.ShowError(err, window)
- return
- }
- input.SetText("")
- input.SetPlaceHolder(placeholderText)
- // Reset character count
- charCount.SetText("0 chars")
- })
+ logTextButton := widget.NewButton("Log text", func() {
+ filename := fmt.Sprintf("%s/ql-%s.md",
+ a.Preferences().StringWithFallback("Directory", defaultDirectory),
+ time.Now().Format("060102-150405"),
+ )
+ if err := os.WriteFile(filename, []byte(input.Text), 0644); err != nil {
+ dialog.ShowError(err, window)
+ return
+ }
+ input.SetText("")
+ input.SetPlaceHolder(placeholderText)
+ // Reset character count
+ charCount.SetText("0 chars")
+ })
// Optimization 5: Add clear button for quick text clearing
clearButton := widget.NewButton("Clear", func() {
@@ -172,17 +103,17 @@ func createMainWindow(a fyne.App) fyne.Window {
window.Canvas().Focus(input)
})
- window.SetContent(container.NewVBox(
- container.NewHBox(daysDropdown, tagDropdown, whatDropdown, logTextButton),
- input,
- container.NewHBox(
- widget.NewButton("Preferences", func() {
- createPreferenceWindow(a).Show()
- }),
- clearButton,
- charCount, // Show character count
- ),
- ))
+ window.SetContent(container.NewVBox(
+ input,
+ container.NewHBox(
+ logTextButton,
+ clearButton,
+ widget.NewButton("Preferences", func() {
+ createPreferenceWindow(a).Show()
+ }),
+ charCount, // Show character count
+ ),
+ ))
window.Resize(windowSize)
window.Canvas().Focus(input)
diff --git a/ql-250516-000347.md b/ql-250516-000347.md
new file mode 100644
index 0000000..09c37cb
--- /dev/null
+++ b/ql-250516-000347.md
@@ -0,0 +1 @@
+7 share:ma Reading Articles \ No newline at end of file