Commit graph

339 commits

Author SHA1 Message Date
1f3c7975eb feat(site,docs): Tane is in F-Droid — link it next to Play
All checks were successful
ci / analyze (push) Successful in 1m3s
ci / test-commons-core (push) Successful in 36s
ci / test-app-seeds (push) Successful in 6m1s
site / deploy (push) Successful in 34s
The inclusion MR was merged on 2026-07-25 and the app page went live on
2026-07-28 (v0.1.16, no antifeatures), so the landing page can finally
offer both stores.

- site: publish the F-Droid link and give each store link a single-colour
  icon, so the two are told apart by shape (play triangle vs. the
  free-software robot) rather than by brand colour. The badge row is a
  flex row now: left-aligned in the hero, centred under "Get Tane".
- README: an Install section with both stores, and a Status that matches
  reality (Block 1 shipped, Block 2 under way) instead of "early design".
- release.md: record that the app is published, that further releases only
  need a versionCode bump in the fdroiddata recipe, and that publication
  lags the green build by a day or two.
- open-decisions.md: log what unblocked inclusion — reproducible
  developer-signed builds, a Google-free APK, and opt-in networking.
2026-07-28 11:55:54 +02:00
30024ca977 chore(docs): keep internal working notes out of the public repo
Some checks failed
ci / analyze (push) Successful in 2m43s
ci / test-commons-core (push) Successful in 1m21s
ci / test-app-seeds (push) Successful in 12m53s
site / deploy (push) Failing after 1m19s
The NGI funding draft and the Ecorred meeting note are internal
working documents; they were committed by accident. They now live in
the private repo alongside the other internal notes, and docs/notes/
is ignored here so it can't happen again.
2026-07-28 07:55:13 +02:00
dd01603ad0 docs(fdroid): sync metadata mirror to v0.1.16 with the tag's full commit hash
All checks were successful
ci / analyze (push) Successful in 1m13s
ci / test-commons-core (push) Successful in 43s
ci / test-app-seeds (push) Successful in 6m22s
site / deploy (push) Successful in 30s
2026-07-25 18:46:37 +02:00
954dc2caae chore(release): prep v0.1.16 — say plainly which servers Tane talks to
All checks were successful
ci / analyze (push) Successful in 1m7s
ci / test-commons-core (push) Successful in 36s
ci / test-app-seeds (push) Successful in 5m48s
site / deploy (push) Successful in 35s
release / analyze (push) Successful in 1m7s
release / test-commons-core (push) Successful in 44s
release / test-app-seeds (push) Successful in 6m26s
release / play (push) Successful in 13m5s
release / fdroid_reference_armeabi_v7a (push) Successful in 23m4s
release / fdroid_reference_arm64_v8a (push) Successful in 23m23s
release / fdroid_reference_x86_64 (push) Successful in 23m13s
The store listing claimed "No account, no server, no trackers" while the
app was dialling four relays at launch. The app side is fixed; this is
the half a reader sees.

- Store description, both locales: the false line is gone, and a new
  "Sharing needs the internet" block names relay.comunes.org (ours),
  nos.lol, relay.damus.io and relay.primal.net, says when Tane talks to
  them, what they can see (a key and an IP — no name, no account), and
  where to switch any or all of them off, or point Tane at your own.
  Deliberately plain: no protocol names, no jargon. The audience is
  gardeners; the technical detail belongs in the F-Droid thread.
- The same correction on the landing page (feature card, FAQ, status).
- 0.1.16+18, so the F-Droid recipe's versionCodes become 181/182/183.
  F-Droid reads fastlane metadata from the checkout of the newest built
  version, so the description only reaches it via a new release.

The recipe mirror's `commit:` still points at v0.1.15 — it needs a hash
that does not exist yet, and is synced here and in the fdroiddata fork
once v0.1.16 is tagged.
2026-07-25 16:50:40 +02:00
fed0e8200e feat(sharing): make going online opt-in, and show what it unlocks
Tane dialled its four default relays at launch, before anyone had asked
for anything — an F-Droid reviewer spotted it, and they were right. The
seed book needs no network at all, so the app should not have one until
the person joins the sharing side.

- SocialSettings gains a three-state `sharingEnabled`. `null` means
  "never asked", which is what lets `migrateSharingEnabled` keep an
  existing install exactly as it was: anyone past the intro was on a
  build that connected at launch, so they keep messaging, device sync
  and offer alerts. A fresh install starts fully offline.
- bootstrap only starts the shared connection when sharing is on. The
  inbox/sync/plantaré/alert listeners are untouched: they react to a
  session, and none arrives.
- SharingSwitch is the single place that moves the stored choice, the
  live connection and the flag the UI listens to, so they cannot drift.
- Agreeing to the community rules is the opt-in — one consent surface,
  reached from the market or from the drawer's invitation.
- SocialConnection.start is now idempotent and gains stop(), so turning
  sharing off goes offline immediately instead of at the next launch.
- The social drawer entries stay visible but padlocked while sharing is
  off; tapping one explains what wakes up and offers to join. Hiding
  them would have kept the tool a secret. "Coming soon" is gone for
  good — everything it labelled is built.

Covered by tests for the migration in both directions, start/stop
lifecycle, the gate turning sharing on, the invitation, and the drawer
in all three states (no social layer / off / on).
2026-07-25 16:47:56 +02:00
62123582f5 docs(fdroid): sync metadata mirror to v0.1.15 with full commit hash 2026-07-25 16:30:53 +02:00
7ae35920f8 ci(release): gate Play + F-Droid deploy on the test suite
Forgejo workflows are independent — ci.yml never triggers on tag pushes
(its branches filter skips refs/tags/*), so releases shipped with zero
test gating. Duplicate analyze + test-commons-core + test-app-seeds into
release.yml and make play needs them; gate the fdroid chain on the same
tests via explicit result checks while keeping !cancelled() so it stays
decoupled from play's result. Red suite now blocks every deploy.
2026-07-25 16:29:41 +02:00
f04dd3da1a fix(fdroid): drop Google Play Core so the scanner accepts the APK; prep v0.1.15
All checks were successful
ci / analyze (push) Successful in 1m5s
ci / test-commons-core (push) Successful in 37s
ci / test-app-seeds (push) Successful in 5m44s
site / deploy (push) Successful in 32s
release / play (push) Successful in 11m49s
release / fdroid_reference_armeabi_v7a (push) Successful in 22m20s
release / fdroid_reference_arm64_v8a (push) Successful in 23m16s
release / fdroid_reference_x86_64 (push) Successful in 22m11s
F-Droid's APK scanner rejected v0.1.14: 6 com.google.android.play.core.*
(SplitInstall/SplitCompat/tasks) references. They came from Flutter's
io.flutter.embedding.engine.deferredcomponents.PlayStoreDeferredComponentManager
being pinned by our over-broad '-keep class io.flutter.** { *; }' ProGuard
rule — Tane uses no deferred components, so R8 should shrink that manager
away (as it does for immich and other Flutter F-Droid apps, which don't
carry such a keep). Narrow the keep to io.flutter.plugins.**; JNI-critical
embedding classes (FlutterJNI, …) stay via the embedding AAR's own consumer
ProGuard rules — verified the built APK still contains FlutterJNI and no
com.google.android.play.core.* at all. Also exclude the com.google.android.play
group at the dependency level (belt-and-suspenders) + -dontwarn.

Bumps to 0.1.15 (+17); fdroid recipe versionCodes 171/172/173.
2026-07-23 10:47:01 +02:00
facd72db16 ci(release): apksigner --alignment-preserved true (reproducibility, final layer)
All checks were successful
ci / analyze (push) Successful in 1m29s
ci / test-commons-core (push) Successful in 55s
ci / test-app-seeds (push) Successful in 9m51s
Even with the /home/vagrant path fix and v2/v3-only signing, the verify
still failed on a v3 CHUNKED_SHA512 mismatch with an EMPTY file diff. Cause
found by byte-level compare: apksigner (build-tools 35+) re-aligns native
libs to 16KB pages by default (--alignment-preserved defaults to false),
rewriting each .so's ZIP local-header extra field from gradle's 0x0 padding
to the 0xd935 alignment marker. F-Droid's reproducibility check compares
against the raw gradle output (0x0), so our re-aligned reference (0xd935)
differed in the signed bytes though every file was identical. Proven: 273
entries differed only in the extra field, 0 in compressed data. Signing
F-Droid's own unsigned build with --alignment-preserved true yields content
byte-identical to it (0 extra-field diffs, 0 data diffs). So preserve the
build's alignment when signing the reference.
2026-07-22 22:57:51 +02:00
6c9de115e9 ci(release): sign fdroid references v2/v3 only (no v1) for reproducibility
All checks were successful
ci / analyze (push) Successful in 1m14s
ci / test-commons-core (push) Successful in 45s
ci / test-app-seeds (push) Successful in 6m28s
The reproducible-build verify failed even after the /home/vagrant path fix
made every file identical: our reference APK carried a v1 (JAR) signature,
which adds META-INF/{MANIFEST.MF,*.SF,*.RSA} as three extra ZIP ENTRIES.
F-Droid's apksigcopier transplants only the v2/v3 signing block onto its
rebuild, so those 3 v1 entries make the reference's signed content differ
from F-Droid's build — apksigner then reports a v3 CHUNKED_SHA512 digest
mismatch though 'diff -r' shows no file differences. Proven by zipinfo: our
ref had 486 entries vs F-Droid's 483, the delta being exactly the v1 files;
the shared 483 are byte-identical. minSdk is 24 so v1 is never needed.
Sign v2/v3 only so the reference byte-matches F-Droid's rebuild.
2026-07-22 20:37:38 +02:00
8818576ee8 fix(android): declare INTERNET permission in the main manifest (release had none)
Some checks failed
ci / analyze (push) Successful in 1m25s
ci / test-commons-core (push) Successful in 50s
site / deploy (push) Successful in 30s
release / play (push) Successful in 36m40s
ci / test-app-seeds (push) Failing after 17m37s
release / fdroid_reference_armeabi_v7a (push) Successful in 24m4s
release / fdroid_reference_arm64_v8a (push) Successful in 25m5s
release / fdroid_reference_x86_64 (push) Successful in 25m14s
Flutter auto-adds android.permission.INTERNET only to the debug/profile
manifests, so every RELEASE build (Play + F-Droid) shipped with no network
permission at all — the whole social layer (market, messaging, trust, sync)
was dead on Android release, while desktop (no permission model) worked. The
market's 'can't reach the servers' was the visible symptom. Adds it to
android/app/src/main/AndroidManifest.xml.

Release prep v0.1.14: pubspec 0.1.13+15 -> 0.1.14+16; fdroid recipe
versionCodes 161/162/163, commit v0.1.14, CurrentVersionCode 163.
2026-07-22 17:11:12 +02:00
3d042c673e chore(release): prep v0.1.13 — point fdroid recipe at v0.1.13 so references build
Some checks failed
ci / analyze (push) Successful in 1m22s
ci / test-commons-core (push) Successful in 45s
ci / test-app-seeds (push) Successful in 16m43s
site / deploy (push) Successful in 31s
release / play (push) Successful in 16m54s
release / fdroid_reference_arm64_v8a (push) Has been cancelled
release / fdroid_reference_x86_64 (push) Has been cancelled
release / fdroid_reference_armeabi_v7a (push) Has been cancelled
v0.1.11 and v0.1.12 bumped pubspec without advancing the fdroid recipe, so the
fdroid_reference job computed versionCodes 131/141 that the recipe (still
121/122/123) didn't define — 'fdroid build' found no such versionCode and the
job failed. The Play deploys were unaffected.

- pubspec: 0.1.12+14 -> 0.1.13+15.
- fdroid recipe: Builds versionName 0.1.13, versionCodes 151/152/153,
  commit v0.1.13; CurrentVersion 0.1.13, CurrentVersionCode 153.

Play accepts versionCode 15 (new); fdroid_reference now builds 151/152/153.
2026-07-22 16:49:55 +02:00
05e4689339 chore(release): v0.1.12 — fresh-install market connectivity + honest server copy
Some checks failed
ci / analyze (push) Successful in 1m13s
ci / test-commons-core (push) Successful in 38s
ci / test-app-seeds (push) Successful in 7m19s
site / deploy (push) Successful in 34s
release / play (push) Successful in 14m52s
release / fdroid_reference_armeabi_v7a (push) Failing after 11s
release / fdroid_reference_arm64_v8a (push) Has been skipped
release / fdroid_reference_x86_64 (push) Has been skipped
Bumps 0.1.11+13 -> 0.1.12+14. Ships the market fixes: auto-recovery when the
shared relay connection comes up (no more stuck 'can't reach the servers' on a
fresh install), per-relay connect timeout, zone prompt before the connection
error, un-clipped Save button, and honest 'community servers' copy in app + site.

fdroid recipe intentionally not bumped here (as with v0.1.11); F-Droid is tracked
in its own reproducible-build MR.
2026-07-22 16:08:34 +02:00
2c04f4bfb6 fix(site): honest decentralization copy — community servers, not 'no server'
The landing claimed seeds spread 'with no server in the middle' and the About
page said people communicate 'directly with each other', while sharing in fact
travels through community relays. Reworded (en/es/pt, docs sources + generated
about pages via build-legal.sh): what you share travels through community
servers run by people and collectives — many of them, anyone can add one, none
a controllable center.
2026-07-22 16:08:34 +02:00
1a946d5c26 fix(i18n): honest sharing intro — community servers exist, no company runs them
The setup intro claimed sharing happened 'with no company in the middle'
while the sheet itself lists community servers. Reworded in all repo-authored
locales (en/es/fr/de/pt/pt_BR/ast): what you offer travels through community
servers run by people and collectives rather than a company.
2026-07-22 16:08:34 +02:00
13b6b4bfce fix(market): zone prompt before connection error; keep Save above the nav bar
- A new user's first step (set your area) works offline, so that empty state
  now wins over 'can't reach the servers'
- The sharing-setup sheet wraps in SafeArea(top: false) so the Save button
  isn't clipped by the system navigation bar on edge-to-edge devices
2026-07-22 16:08:34 +02:00
8a7dc8d3dc fix(market): recover by itself when the shared connection comes up
Fresh installs could sit on 'can't reach the servers' forever: the offers
cubit captured the transport once at build time, the shared connection only
retried on a connectivity CHANGE, and a silently-filtered relay could stall
the pool for minutes.

- SocialConnection: retry with backoff after a failed attempt while started
  and not knowingly offline (injectable schedule for tests)
- OffersCubit: follow connection.sessions, re-attach the transport and re-run
  the last discovery on (re)connect; announce drops via connectionEpoch
- market _init: record the wanted area on the cubit even while offline
- NostrOfferTransport.discoverPage: sort a copy (channel lists may be
  unmodifiable)
2026-07-22 16:08:34 +02:00
981cf10048 fix(social): cap relay connect with a timeout so one hung relay can't stall the pool 2026-07-22 16:08:34 +02:00
3ec6ed2329 v0.1.11 2026-07-22 16:08:34 +02:00
4963282620 fix(site): only wrap header nav on small screens if it overflows
The forced width:100% on .site-nav below 560px was written back when
the language switcher spelled out every language name and needed the
room. Now that it's a compact pill, the header fits on one line down
to ~360px; let flex-wrap handle the actual overflow case instead of
always forcing a second row.
2026-07-22 16:08:34 +02:00
8aa37bde34 ci(release): retry network-fragile steps (fdroidserver download + fdroid build)
All checks were successful
ci / analyze (push) Successful in 1m22s
ci / test-commons-core (push) Successful in 46s
ci / test-app-seeds (push) Successful in 7m7s
Even after the dnsmasq DNS cache, the Hetzner vSwitch still blips
mid-transfer. Two spots kept killing ~25min builds: the fdroidserver
tarball 'curl -sL | tar' (an empty stream -> 'gzip: unexpected end of
file') and maven/pub fetches mid-Gradle ('Network is unreachable').
Download fdroidserver to a file with curl --retry (+ -f + validate the
gzip before extract), and wrap fdroid build in a 3-attempt loop gated on
the APK actually appearing (fdroid build exits 0 even on failure).
2026-07-22 12:17:11 +02:00
92cc2e6232 ci(release): build fdroid references under /home/vagrant to match F-Droid (reproducibility)
All checks were successful
ci / analyze (push) Successful in 1m12s
ci / test-commons-core (push) Successful in 39s
ci / test-app-seeds (push) Successful in 6m30s
F-Droid's reproducible-build verification failed: the native .so
(Flutter libapp/libdartjni + tesseract4android libjpeg/leptonica/pngx/
libtesseract) differed byte-for-byte. Root cause: F-Droid builds under
/home/vagrant/build/<appid> (its buildserver path) while our reference
built under /tmp/fdroiddata/build/<appid> — the differing absolute build
path leaks into the native libs (debug info / embedded paths). Build the
reference under /home/vagrant so app + srclib paths match F-Droid's.

Also: add a workflow_dispatch ref_tag input to rebuild+re-upload an
existing release's reference APKs (idempotent asset replace) without
cutting a new tag or re-deploying to Play — so reproducibility fixes can
be iterated on the same v* release.
2026-07-22 09:56:59 +02:00
841cb9aaec ci(release): serialize play before the fdroid_reference chain
All checks were successful
ci / analyze (push) Successful in 3m17s
ci / test-commons-core (push) Successful in 1m26s
ci / test-app-seeds (push) Successful in 11m1s
A tag push started play (AAB → Play) and fdroid_reference_armeabi_v7a at
the same instant; two heavy Android builds on the shared runner
(capacity:2) OOM-killed play's Gradle daemon ('daemon disappeared') deep
in bundleRelease. Chain the fdroid references after play with needs:play
+ if:always() so only one Android build runs at a time. if:always() keeps
the fdroid chain independent of play's result (still runs when play fails
or, on workflow_dispatch, is skipped).
2026-07-21 23:57:38 +02:00
538b28e5d2 Lang menu and autodetect
All checks were successful
ci / test-commons-core (push) Successful in 56s
ci / analyze (push) Successful in 1m39s
site / deploy (push) Successful in 44s
ci / test-app-seeds (push) Successful in 7m29s
release / fdroid_reference_armeabi_v7a (push) Successful in 42m36s
release / fdroid_reference_arm64_v8a (push) Successful in 33m58s
release / fdroid_reference_x86_64 (push) Successful in 26m15s
release / play (push) Successful in 12m49s
2026-07-21 19:15:42 +02:00
1b439e9499 chore(release): prep v0.1.10 — harden play vs jcenter/OOM, point recipe at v0.1.10
Some checks failed
ci / test-commons-core (push) Successful in 56s
ci / analyze (push) Successful in 1m47s
site / deploy (push) Successful in 34s
ci / test-app-seeds (push) Has been cancelled
- play job: apply the same two fixes the fdroid recipe uses (strip
  flutter_tesseract_ocr's dead-jcenter buildscript; cap Gradle heap to
  -Xmx4g + no daemon) so a cold-cache production AAB build can't hit
  either blocker. play builds the AAB directly, not via the recipe, so
  it was still exposed.
- pubspec: 0.1.9+11 -> 0.1.10+12.
- fdroid recipe: versionName 0.1.10, versionCodes 121/122/123,
  commit v0.1.10, CurrentVersion(Code) 0.1.10/123. binary: uses %v so
  it resolves to the v0.1.10 release assets the tag build will upload.

The v0.1.10 tag is intentionally NOT cut here: cutting it deploys to
Google Play PRODUCTION (100%) and uploads the 3 signed reference APKs.
2026-07-21 19:12:11 +02:00
e4c62f2b56 fix(fdroid): cap Gradle heap + drop daemons so the build survives host RAM pressure
All checks were successful
ci / test-commons-core (push) Successful in 54s
ci / analyze (push) Successful in 1m51s
site / deploy (push) Successful in 40s
ci / test-app-seeds (push) Successful in 9m28s
The reproducible build OOM-killed the Gradle daemon ('daemon disappeared
unexpectedly') mid flutter-build-apk on the shared runner. The app's
gradle.properties reserves -Xmx8G+4G metaspace (~12G), and the fdroid
build also compiles tesseract4android from source first (its daemon
lingers), so combined peak RAM trips the OS OOM-killer under contention
(the same build succeeded on a quieter host earlier). Scope the fix to
the fdroid build (don't touch the committed 8G the play/local builds
rely on): run tesseract's gradle with --no-daemon so it frees memory
before the app build, and append a lower -Xmx4g + org.gradle.daemon=false
override to gradle.properties in prebuild (last-key-wins; F-Droid runs
the same steps and memory settings don't change output bytes, so it stays
reproducible).
2026-07-21 17:43:37 +02:00
08459ad29d fix(fdroid): strip flutter_tesseract_ocr's stale jcenter buildscript
All checks were successful
ci / test-commons-core (push) Successful in 45s
ci / analyze (push) Successful in 1m30s
site / deploy (push) Successful in 34s
ci / test-app-seeds (push) Successful in 8m8s
The plugin's android/build.gradle pins its own AGP 7.1.2 and resolves it
via jcenter() (dead since 2021). On a cold Gradle cache the AGP-7.1.2
transitives (apkzlib -> fastutil/json-simple/javawriter) only resolve
from jcenter and fail hard, breaking the reproducible fdroid build.
Warm-cache runs masked it (the one green armeabi-v7a run never hit
jcenter). Strip that buildscript block in prebuild so the plugin
inherits the app's AGP 8.11.1 (settings.gradle.kts) and never touches
jcenter or old AGP at all.
2026-07-21 16:50:11 +02:00
64b974a7a6 ci(release): chain fdroid_reference ABIs with needs: (matrix max-parallel not honored by this runner)
All checks were successful
ci / analyze (push) Successful in 2m27s
ci / test-commons-core (push) Successful in 1m16s
ci / test-app-seeds (push) Successful in 12m7s
2026-07-21 13:11:08 +02:00
6a65175154 ci(release): serialize fdroid_reference matrix (max-parallel:1) to avoid OOM contention
All checks were successful
ci / test-commons-core (push) Successful in 45s
ci / analyze (push) Successful in 1m33s
ci / test-app-seeds (push) Successful in 9m9s
2026-07-21 12:31:07 +02:00
fa768ef17f feat(site): add Portuguese to the landing site
All checks were successful
ci / analyze (push) Successful in 2m43s
ci / test-commons-core (push) Successful in 1m32s
site / deploy (push) Successful in 1m23s
ci / test-app-seeds (push) Successful in 12m26s
Mirror the es/ pattern: docs/legal/pt/ + docs/o-que-e-tane.md as the
Portuguese source of truth, build-legal.sh extended to generate the
Hugo pt.* pages from them, config.toml gets a [languages.pt] entry,
i18n/pt.json translates the UI chrome. og-pt.png is a placeholder copy
of og-en.png until a proper Portuguese social card is made by hand
(same as the other og-*.png, per DEPLOY.md). Verified locally with the
Docker build: /pt/, /pt/about/, all four /pt/legal/ pages and the
lang-switch link all resolve correctly.
2026-07-20 23:35:26 +02:00
a47bd6badd docs(claude): point git note at git.comunes.org origin; note pre-split backup
Some checks failed
ci / analyze (push) Successful in 2m1s
ci / test-commons-core (push) Successful in 1m35s
ci / test-app-seeds (push) Has been cancelled
The bare ~/repos/tane.git was renamed to ~/repos/tane-pre-split-2026-07-15.git
(archived pre-filter-repo history) and detached as a remote; origin is now the
forge at git.comunes.org.
2026-07-20 23:16:14 +02:00
d80f6d50fa feat(i18n): complete Portuguese, add Brazilian Portuguese (pt_BR)
Some checks are pending
ci / analyze (push) Waiting to run
ci / test-commons-core (push) Waiting to run
ci / test-app-seeds (push) Waiting to run
Fill the ~74 UI strings pt.i18n.json was missing (saved searches, label
scanning, Plantaré, lot history), then add pt_BR as a proper Brazilian
variant rather than a copy of European Portuguese: tu/teu/tua -> você/
seu/sua with matching verb conjugation, partilhar -> compartilhar, and
Guardar -> Salvar for UI actions (seed-saving keeps "guardar", the
correct term in both variants). Wires AppLocale.ptBr into the language
picker and regenerates slang output.
2026-07-20 23:11:01 +02:00
071be44851 perf(android): R8, bitmap downscaling, edge-to-edge; recover device compat; publish to production
Some checks are pending
ci / analyze (push) Waiting to run
ci / test-commons-core (push) Waiting to run
ci / test-app-seeds (push) Waiting to run
site / deploy (push) Successful in 1m8s
Device compatibility (regression fix):
- The CAMERA permission (from zxing_barcode_scanner / image_picker) implicitly
  required android.hardware.camera, excluding camera-less devices — Play showed
  Automotive -96%, Chromebook -86%, TV -25%. Declare camera & location
  uses-feature required="false" to keep those devices supported.
- Detect a real camera at runtime (PackageManager.FEATURE_CAMERA_ANY via the
  existing MethodChannel), cache it at bootstrap, and hide the QR scan button and
  the camera photo-source option when absent, so no broken actions are offered.

Play "app optimization" recommendations:
- Enable R8 (isMinifyEnabled + isShrinkResources) with keep rules for the
  OCR (tesseract4android), SQLCipher and notifications JNI/reflection code.
- Bitmap downscaling: cacheWidth/cacheHeight (and ResizeImage for avatars) on
  list thumbnails and avatars so photos decode to on-screen size, not full res.
- Edge-to-edge: opt in with transparent system bars in main().

Release flow:
- Tagged builds now publish to the production track at 100% (was internal);
  add a manual deploy_internal lane as a QA safety net.
- Document country/region availability as a Play Console setting (not in-repo).
2026-07-20 22:53:48 +02:00
f17ae7751c perf(market): paginate Nostr offer discovery, infinite scroll, memory cap
Bound market memory and let large areas page instead of loading everything:
- DiscoveryQuery gains an until cursor; OfferTransport gains discoverPage()
  (one-shot, EOSE-bounded, newest-first) alongside the existing live discover()
  stream, which now accepts since so it only carries NEW offers going forward.
- NostrOfferTransport.discoverPage sorts by created_at desc and derives the
  next cursor from the oldest event seen (not the oldest type-matched one, so
  filtering never skips a page).
- OffersCubit: discover() fetches the first page + opens a since=now live sub;
  loadNextPage() pages further back; the in-memory list is capped at 400
  offers (each can carry a ~40KB inline photo thumbnail, so unbounded growth in
  a busy area was a real OOM risk).
- market_screen: infinite scroll via a scroll-position trigger + footer
  spinner, instead of a single unbounded ListView.
- Added discoverPage unit tests (commons_core) and cubit pagination tests
  (first page/cursor, accumulation, cap, cross-page dedup).
2026-07-20 22:53:48 +02:00
3de01bd948 perf(inventory): lazy list, photo thumbnails, indexes, debounced reload
Scale the local inventory to 10k+ varieties:
- Render the list with ListView.builder over a flattened header/item model
  instead of building every tile upfront.
- Store a small regenerable JPEG thumbnail per photo (schema v14) and use it
  for the 48px list avatar; full bytes stay for offer image hosting. Existing
  photos are backfilled lazily at startup. Thumbnail is local-only (excluded
  from CRDT sync and backups by the JSON codec).
- Add indexes on varieties(is_deleted,is_draft), attachments(parent_type,
  parent_id,kind), lots(variety_id) via @TableIndex.
- Debounce watchInventoryView (~250ms) so a burst of table writes triggers one
  reload, not seven.
- cacheWidth/cacheHeight on the list avatar decode.
- Scale test raised 3k -> 10k; migration test v13 -> v14.
2026-07-20 22:53:48 +02:00
2884ddd3c7 ci(release): split fdroid_reference into a 3-way ABI matrix to fit the runner's max job time
All checks were successful
ci / test-commons-core (push) Successful in 1m4s
ci / analyze (push) Successful in 2m5s
ci / test-app-seeds (push) Successful in 8m44s
2026-07-20 22:37:42 +02:00
0763047d02 ci(release): pre-clone app into fdroid build dir so SOURCE_DATE_EPOCH resolves; fail fast unless 3 APKs
All checks were successful
ci / test-commons-core (push) Successful in 59s
ci / analyze (push) Successful in 2m1s
ci / test-app-seeds (push) Successful in 10m58s
2026-07-20 21:39:56 +02:00
06e2ad29c9 chore(release): v0.1.9 (+11) — single-run reproducible developer-signed (SOURCE_DATE_EPOCH comes from the app commit, not fdroiddata)
Some checks failed
ci / test-commons-core (push) Successful in 43s
ci / analyze (push) Successful in 1m24s
site / deploy (push) Successful in 28s
ci / test-app-seeds (push) Successful in 9m35s
release / fdroid_reference (push) Failing after 21s
release / play (push) Successful in 18m50s
2026-07-20 17:24:28 +02:00
bec3493e37 Revert "ci(release): revert to F-Droid-signed recipe; drop pre-merge reference build"
This reverts commit 4d99e1a840.
2026-07-20 17:13:46 +02:00
e054e280dc Revert "docs(fdroid): post-merge runbook for reproducible developer-signed builds"
This reverts commit 85a75ac3b7.
2026-07-20 17:13:46 +02:00
85a75ac3b7 docs(fdroid): post-merge runbook for reproducible developer-signed builds
All checks were successful
ci / test-commons-core (push) Successful in 51s
ci / analyze (push) Successful in 1m35s
site / deploy (push) Successful in 34s
ci / test-app-seeds (push) Successful in 6m40s
2026-07-19 11:36:15 +02:00
4d99e1a840 ci(release): revert to F-Droid-signed recipe; drop pre-merge reference build
All checks were successful
ci / test-commons-core (push) Successful in 44s
ci / analyze (push) Successful in 1m26s
site / deploy (push) Successful in 30s
ci / test-app-seeds (push) Successful in 6m8s
2026-07-19 11:19:46 +02:00
831730e308 ci(release): redirect app clone to internal Forgejo; robust apksigner; manual dispatch (play=tags only)
All checks were successful
ci / test-commons-core (push) Successful in 54s
ci / analyze (push) Successful in 1m48s
ci / test-app-seeds (push) Successful in 6m44s
2026-07-19 10:31:36 +02:00
50edb5ff75 ci(release): vendor fdroid config+srclibs in-repo (no gitlab clone); v0.1.8 (+10)
Some checks failed
ci / test-commons-core (push) Successful in 59s
ci / analyze (push) Successful in 1m53s
site / deploy (push) Successful in 33s
ci / test-app-seeds (push) Successful in 9m52s
release / fdroid_reference (push) Failing after 13s
release / play (push) Successful in 19m22s
2026-07-19 09:54:31 +02:00
9b0ef1fc40 chore(release): v0.1.7 (+9) — reference APKs via fdroid buildserver
Some checks failed
ci / test-commons-core (push) Successful in 44s
ci / analyze (push) Successful in 1m27s
site / deploy (push) Successful in 29s
ci / test-app-seeds (push) Successful in 8m51s
release / fdroid_reference (push) Failing after 1m32s
release / play (push) Successful in 17m48s
2026-07-19 09:32:39 +02:00
b906161d70 ci(release): produce F-Droid reference APKs via fdroid build in buildserver image, then sign 2026-07-19 08:56:54 +02:00
654ed1fe68 ci(release): route dead jcenter deps to mavenCentral; v0.1.6 (+8)
Some checks failed
ci / test-commons-core (push) Successful in 1m3s
ci / analyze (push) Successful in 2m2s
ci / test-app-seeds (push) Successful in 10m51s
release / android (push) Failing after 17m23s
2026-07-19 07:09:07 +02:00
bbd8d3580f chore(release): v0.1.5 (+7) — retag with tesseract build fix
Some checks failed
ci / test-commons-core (push) Successful in 50s
ci / analyze (push) Successful in 1m39s
ci / test-app-seeds (push) Successful in 10m14s
release / android (push) Failing after 20m15s
2026-07-19 06:38:21 +02:00
f968f64de8 ci(release): fix tesseract build — use root gradlew with :tesseract4android task 2026-07-19 06:36:25 +02:00
a575f01207 ci(release): build tesseract4android from source for F-Droid reproducibility; v0.1.4 (+6)
Some checks failed
ci / test-commons-core (push) Successful in 1m27s
ci / analyze (push) Successful in 2m17s
release / android (push) Failing after 4m50s
ci / test-app-seeds (push) Successful in 10m40s
2026-07-19 06:18:04 +02:00