# Linthra v0.1.0-alpha.1 — release notes (draft)

> **Draft, not published.** This is the GitHub Release body to use when the
> `v0.1.0-alpha.1` tag is cut. Nothing here publishes automatically; see
> [docs/release-process.md](../release-process.md) for the manual steps.

**Linthra is a modern, local-first, privacy-focused music player for people who
own their music.** This is the **first manually testable alpha** — an Android
APK you can sideload and try end to end. It is early software: the sections
below separate what works today from the known limitations, honestly.

- **Version:** `0.1.0-alpha.1` (`versionName`), `versionCode` 1
- **Platform:** Android (Linux desktop planned later, same codebase)
- **Application ID:** `io.github.thezupzup.linthra`
- **License:** [MPL-2.0](../../LICENSE)

## What works in this alpha

- **Local scanning.** Pick a folder with the native Android folder chooser; the
  Storage Access Framework (SAF) tree is walked through the content resolver
  (no broad storage permission), and the discovered tracks are listed. The
  chosen folder and the scanned catalog persist across restarts. Desktop/Linux
  selections scan a real filesystem path.
- **Local playback.** Tap a track to play it; the rest of the visible list
  becomes the up-next queue, with play / pause / next / stop on the Now Playing
  screen.
- **Background playback & media notification.** Playback survives backgrounding
  via a foreground media session: a media notification mirrors the track with
  transport controls, plus lock-screen, Bluetooth, and wired-headset buttons.
  On Android 13+ the app asks once for the notification permission.
- **Android Auto foundation.** The same media session exposes a browsable
  **Library** and **Queue** to Android Auto, so you can pick what to play from
  the car screen. The tree is intentionally shallow (flat track list + current
  queue).
- **Jellyfin connection / sync / streaming.** Connect to your own Jellyfin
  server (including HTTPS via a Cloudflare domain or tunnel), test the
  connection, sign in, sync your artists/albums/tracks into the local catalog,
  and stream them. The session token is stored encrypted (Android
  Keystore-backed); passwords are never persisted, and the token never appears
  in URIs, logs, errors, or cache file names.
- **Explicit offline cache / downloads.** Mark individual Jellyfin tracks for
  offline use; the bytes are fetched to an app-private directory and playback
  then prefers the local copy. Downloads are **always user-initiated** — there
  is no automatic full-library sync — and a **"Wi-Fi only"** toggle can queue
  remote downloads off Wi-Fi.

## Known limitations (honest)

**Android SAF / device-specific**

- Cross-restart re-scanning depends on the picker granting a *persistable* URI
  permission; if it didn't, re-pick the folder.
- No runtime `READ_MEDIA_AUDIO` flow yet, and `MANAGE_EXTERNAL_STORAGE` is
  intentionally **not** requested. On Android 11+ the filesystem-path fallback
  can be unreadable under scoped storage — prefer a folder picked through the
  SAF chooser.
- The native SAF traversal is verifiable only on a real device/emulator; the
  Dart seams are fully unit-tested but the manual smoke test on hardware is the
  real check (see the README checklist).
- **No tag/metadata parsing yet.** Tracks show a title derived from the file
  name and fall back to the path when artist/album tags are absent; no album
  artwork.

**Jellyfin**

- **Single server only** — one session is stored; no multi-server support.
- **Cloudflare Access / Zero Trust is not supported** — Linthra speaks only to
  Jellyfin's own auth, so use a hostname that reaches Jellyfin directly.
- No lyrics, no sync-conflict handling, and no richer transcoding/streaming
  parameters yet.

**Offline cache**

- **Track-level downloads only** — no album/playlist "download all".
- **No background download manager** — downloads run inline; there is no worker,
  no resume of a partial transfer, and no auto-flush of the queue when Wi-Fi
  returns (re-tap a queued track to retry).
- **Connectivity is optimistic** — until `connectivity_plus` is wired in, the
  app assumes Wi-Fi, so the "Wi-Fi only" gate only blocks when a detector
  reports mobile/offline.
- Only `downloaded` is durable; `queued` / `downloading` / `failed` reset on
  restart.

**Playlists & queue**

- No saved playlists yet (model + repository interface exist, no persisted
  store). The queue is play-from-here + jump only — no reorder, shuffle, or
  repeat.

**Distribution**

- **Not on F-Droid yet** — no submission has been made. This alpha is a
  sideloadable APK only. A GitHub-Release APK is signed with **our** key while a
  future F-Droid build would be signed with **F-Droid's** key, so the two can't
  cross-update; don't mix sources.

## Install (sideload)

1. Download the `app-release.apk` attached to this release (or build it
   yourself — see the README).
2. On your Android device, allow installing from unknown sources if prompted,
   then open the APK. Or, with the device connected over ADB:
   ```bash
   adb install -r app-release.apk
   ```
3. On first launch (Android 13+), tap **Allow** on the notification prompt so
   the media notification and its controls can appear.

See the **Manual smoke test on a real Android phone** checklist in the README
for a full walkthrough of every path worth exercising in this alpha.

## Manual release steps (operator)

These are **not** automated — nothing publishes on its own.

1. Confirm CI is green and generated Drift files are current on the commit.
2. Verify `pubspec.yaml` is `0.1.0-alpha.1+1` and `versionCode` is monotonic.
3. Tag the release commit:
   ```bash
   git tag -a v0.1.0-alpha.1 -m "Linthra 0.1.0-alpha.1"
   git push origin v0.1.0-alpha.1
   ```
4. Run the **Android Release Build** workflow with `signed = true` (requires the
   `LINTHRA_*` keystore secrets — see
   [docs/release-signing.md](../release-signing.md)) and download the
   `linthra-release-signed-apk` / `-aab` artifacts. A `signed = false` run
   produces debug-signed previews that must **not** be attached to a release.
5. Create the GitHub Release against the `v0.1.0-alpha.1` tag, mark it a
   **pre-release**, paste this document as the body, and attach the signed
   APK/AAB.

Full reference: [docs/release-process.md](../release-process.md).
