# AniTrack → Wails v3 + Android plan Goal: run this same app on my Android phone for personal use. Sideload the APK. No Play Store. No official F-Droid. Non-goals: no rewrite of AniList / MAL / Simkl logic. No iOS. No store releases. ## Big picture (3 steps) 1. **Desktop parity** — get v3 building and acting like v2 on Linux. 2. **Android storage** — swap where tokens are saved on Android only. 3. **Android login** — replace the localhost login callback with a deep link. Each step must run before moving on. If a step fails, stay on the previous one. ## Step 0 — Done on main (already in this branch) Fixed ignored errors in the 3 login files. Same wallet (`ServiceName: AniTrack`), same keys, per-file helpers: - `AniListUserFunctions.go`: `aniRingReady()` + `aniRingSet()`, `keyring.Open` error logged, `Set` errors logged with key name, bad `ExpiresIn` logged instead of silently kept. - `MALUserFunctions.go`: `malRingReady()` + `malRingSet()`, same treatment, including refresh-token saves. - `SimklUserFunctions.go`: `simklRingReady()` + `simklRingSet()`, same treatment. - Logouts still clear in-memory JWT even if storage is missing. No more nil-pointer panic when storage fails. ## Step 1 — Desktop v3 parity (mechanical, no logic changes) What changes and nothing else: - `main.go`: `wails.Run(options.App{Bind: app})` → `application.New(Services: [app])` + `Window.New()`. - `app.go`: move the 4 runtime calls to v3 equivalents — `WindowSetTitle`, `WindowUnminimise/Show`, `EventsEmit`, `MessageDialog`. - Go login files: `BrowserOpenURL` and `MessageDialog` imports change from `wails/v2/pkg/runtime` to v3. Logic stays. - Frontend (11 files import `wailsjs/go/main/App`, 2 import `wailsjs/runtime`): regenerate with `wails3 generate bindings`, script-replace the import paths. No Svelte rewrites. - `wails.json` → v3 `Taskfile + build/config.yml`. `Makefile` `wails build` → `wails3 task build`. Check: `wails3 doctor`, then desktop app logs in/out of all 3 services exactly like v2. ## Step 2 — Android token storage (per-file shims) Why: `99designs/keyring` is desktop-only (macOS Keychain / WinCred / Linux Secret Service). No Android backend. On Android `Open` returns “no backend”. Keep your organization: one file per service, same function names. Only the helper body changes by platform: - Desktop files (`//go:build !android`): keep calling `keyring` via `aniRingSet / malRingSet / simklRingSet`. - Android files (`//go:build android`): same helper names, but call `application.Android.SecureSet / SecureGet / SecureDelete` (backed by EncryptedSharedPreferences). - Keys stay the same strings (`anilistAccessToken`, `MyAnimeListRefreshToken`, `SimklScope`, …). Check: `GOOS=android` compiles; login persists after app restart on emulator. ## Step 3 — Android login callback (the one redesign) Why: today each login opens the browser then listens on `http://localhost:6734/callback` (`AniList:77`, `MAL:127`, `Simkl:71`). Android WebView serves assets in-process — no localhost server, no open ports. New flow per service (same order, different plumbing): 1. App opens system browser to AniList / MAL / Simkl authorize URL. 2. Provider redirects to `anitrack://callback?code=...` instead of `http://localhost:6734/callback`. 3. Android activity receives the deep link, hands `code` to the existing `get*AuthorizationToken()` function. 4. Rest is unchanged: save with `*RingSet()`, same in-memory JWT. Requires: add `anitrack://callback` redirect URI in each provider dashboard (AniList, MAL, Simkl), add intent-filter in `build/android`, keep desktop on localhost. Start with ONE provider (suggest AniList) to prove the pattern, then copy to the other two. ## Step 4 — Run it on my phone Need: JDK 21, Android SDK 35 + NDK 26.3.x, `ANDROID_HOME` set. `wails3 doctor` confirms. ```bash wails3 task android:run # emulator wails3 task android:run:device # my phone via adb, debug APK wails3 task android:package # release APK I sideload manually ``` Updates: drop APKs in GitHub Releases, point Obtainium at it. No stores. ## Rules for AI doing this work - Small diffs, one step at a time. Never rewrite domain logic to “clean it up”. - `AniList*` stays in `AniListUserFunctions.go`, MAL in its file, Simkl in its file. - New platform code goes in new `//go:build` files, not edits to shared logic. - Every step ends with a runnable check (see “Check” lines). Stop if it fails. - Go stays plain Go: services are thin facades over existing funcs. No frameworks, no inheritance. ## Open decisions (mine) - [ ] First Android login: AniList only, or all 3 day one? - [ ] Keep desktop building in parallel on this branch? - [ ] New `anitrack://callback` URIs registered yet in the 3 dashboards?