diff options
| -rw-r--r-- | FyneApp.toml | 2 | ||||
| -rw-r--r-- | README.md | 70 | ||||
| -rw-r--r-- | android/AndroidManifest.xml | 22 | ||||
| -rw-r--r-- | android_shared_android.go | 34 | ||||
| -rw-r--r-- | android_shared_stub.go | 6 | ||||
| -rw-r--r-- | main.go | 55 |
6 files changed, 157 insertions, 32 deletions
diff --git a/FyneApp.toml b/FyneApp.toml index b9c0a16..c0df1e5 100644 --- a/FyneApp.toml +++ b/FyneApp.toml @@ -5,4 +5,4 @@ Website = "https://codeberg.org/snonux/quicklogger" Name = "quicklogger" ID = "org.buetow.quicklogger" Version = "0.0.3" - Build = 42 + Build = 48 @@ -11,23 +11,67 @@ This are screenshots of the App running on Android and Fedora Linux.   -## Installation +## Build and Run (Mage) -1. Download and install the Android NDK. I personally installed it to `~/android/android-ndk-r26b` as of this writing. -2. Clone Quicklogger: `git clone https://codeberg.org/snonux/quicklogger; cd quicklogger` -3. Build it `./build.sh` - Note, you may need to set the `ANDROID_NDK_HOME` environment variable accordingly. -4. Copy `quicklogger.apk` to your Android phone and install it (You may need to allow installing APKs from this source - just follow the instructions Android is prompting you with). +This repo includes Mage tasks to build, run and cross‑compile. -## Not sure +Install Mage: -... not sure that the above is still required, but I now have to do this to complile this on Fedora Linux for Android: +```sh +go install github.com/magefile/mage@latest +``` + +Clone and enter the repo: ```sh -sudo systemctl start podman -DOCKER_HOST=unix:///run/user/1001/podman/podman.sock -go install github.com/fyne-io/fyne-cross@latest -fyne-cross android --pull -fyne-cross android +git clone https://codeberg.org/snonux/quicklogger +cd quicklogger ``` -And then install the `.apk` file. +Common tasks: + +```sh +# Build desktop binary into ./bin +mage build + +# Run the app (shows verbose Go build output) +mage run + +# Clean build artifacts +mage clean +``` + +## Android Builds + +Two options exist: local Fyne packaging or containerized cross‑compile. + +- Local packaging (requires Fyne CLI and Android NDK): + + ```sh + # Install Fyne CLI if needed + go install fyne.io/fyne/v2/cmd/fyne@latest + + # Ensure ANDROID_NDK_HOME points to your NDK (e.g. ~/android-ndk/android-ndk-r26b) + export ANDROID_NDK_HOME=~/android-ndk/android-ndk-r26b + + # Build APK in the project root as quicklogger.apk + mage android + ``` + +- Containerized cross‑compile (recommended, uses fyne-cross with Docker/Podman): + + ```sh + # Start Podman if you prefer Podman over Docker + sudo systemctl start podman + + # The task auto-detects a user Podman socket; otherwise it uses Docker defaults + mage androidcross + ``` + +After cross‑compiling, the APK is located at `fyne-cross/dist/android/quicklogger.apk`. +Copy it to your device and install it (you may need to allow installing from unknown sources): + +```sh +adb install -r fyne-cross/dist/android/quicklogger.apk +# or copy manually and install on device +``` diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml new file mode 100644 index 0000000..51edc1b --- /dev/null +++ b/android/AndroidManifest.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="org.buetow.quicklogger"> + + <application> + <!-- Share receiver activity: writes text to cache and launches main app --> + <activity + android:name=".ShareActivity" + android:exported="true" + android:excludeFromRecents="true" + android:taskAffinity="" + android:theme="@android:style/Theme.Translucent.NoTitleBar"> + <intent-filter> + <action android:name="android.intent.action.SEND" /> + <category android:name="android.intent.category.DEFAULT" /> + <data android:mimeType="text/plain" /> + <data android:mimeType="text/*" /> + </intent-filter> + </activity> + </application> +</manifest> + diff --git a/android_shared_android.go b/android_shared_android.go new file mode 100644 index 0000000..b736fab --- /dev/null +++ b/android_shared_android.go @@ -0,0 +1,34 @@ +//go:build android + +package main + +import ( + "os" + "path/filepath" +) + +// readSharedFromCache tries to read the shared text written by the Android activity. +// The activity writes into getCacheDir()/quicklogger-shared.txt; on Go, os.TempDir() +// maps to the same location in Android (app cache directory). +func readSharedFromCache() (string, error) { + dir, derr := os.UserCacheDir() + if derr != nil || dir == "" { + dir = os.TempDir() + } + path := filepath.Join(dir, "quicklogger-shared.txt") + b, err := os.ReadFile(path) + if err != nil { + return "", err + } + // best-effort cleanup; ignore errors + _ = os.Remove(path) + return string(b), nil +} + +func debugSharedPath() string { + dir, _ := os.UserCacheDir() + if dir == "" { + dir = os.TempDir() + } + return filepath.Join(dir, "quicklogger-shared.txt") +} diff --git a/android_shared_stub.go b/android_shared_stub.go new file mode 100644 index 0000000..4e6f27e --- /dev/null +++ b/android_shared_stub.go @@ -0,0 +1,6 @@ +//go:build !android + +package main + +func readSharedFromCache() (string, error) { return "", nil } + @@ -58,20 +58,20 @@ func createMainWindow(a fyne.App) fyne.Window { input.Wrapping = fyne.TextWrapWord } input.SetPlaceHolder(placeholderText) - // Optimization 2: Reduce visible rows on mobile to limit rendering area - if fyne.CurrentDevice().IsMobile() { - input.SetMinRowsVisible(10) - } else { - input.SetMinRowsVisible(30) - } + // Optimization 2: Reduce visible rows on mobile to limit rendering area + if fyne.CurrentDevice().IsMobile() { + input.SetMinRowsVisible(10) + } else { + input.SetMinRowsVisible(30) + } // Optimization 3: Add text length indicator charCount := widget.NewLabel("0 chars") - // Optimization 4: Throttle text changes with validation - input.OnChanged = func(text string) { - // Update character count - charCount.SetText(fmt.Sprintf("%d chars", len(text))) + // Optimization 4: Throttle text changes with validation + input.OnChanged = func(text string) { + // Update character count + charCount.SetText(fmt.Sprintf("%d chars", len(text))) // Warn if text is getting too long if len(text) > maxTextLength { @@ -96,12 +96,20 @@ func createMainWindow(a fyne.App) fyne.Window { charCount.SetText("0 chars") }) - // Optimization 5: Add clear button for quick text clearing - clearButton := widget.NewButton("Clear", func() { - input.SetText("") - charCount.SetText("0 chars") - window.Canvas().Focus(input) - }) + // Optimization 5: Add clear button for quick text clearing + clearButton := widget.NewButton("Clear", func() { + input.SetText("") + charCount.SetText("0 chars") + window.Canvas().Focus(input) + }) + + // If running on Android and shared text file exists, load it into the input + if fyne.CurrentDevice().IsMobile() { + if txt, err := readSharedFromCache(); err == nil && txt != "" { + input.SetText(txt) + charCount.SetText(fmt.Sprintf("%d chars", len(txt))) + } + } window.SetContent(container.NewVBox( input, @@ -114,8 +122,19 @@ func createMainWindow(a fyne.App) fyne.Window { charCount, // Show character count ), )) - window.Resize(windowSize) - window.Canvas().Focus(input) + window.Resize(windowSize) + window.Canvas().Focus(input) + + // On Android, also check for new shared text whenever app returns to foreground. + if lc := a.Lifecycle(); lc != nil { + lc.SetOnEnteredForeground(func() { + if txt, err := readSharedFromCache(); err == nil && txt != "" { + input.SetText(txt) + charCount.SetText(fmt.Sprintf("%d chars", len(txt))) + window.Canvas().Focus(input) + } + }) + } return window } |
