mirror of
https://github.com/block/buzz.git
synced 2026-08-18 06:50:31 +02:00
Mobile channel-section edits were silently lost: sections publish on a 5s
debounce, but the provider tears the sync manager down on every relay-session
status flip without flushing. The rebuilt manager then fetched the stale
remote blob and unconditionally adopted it over newer local state, erasing
the just-made edit ("groups do not persist").
Fix, mirroring the read-state manager pattern:
- Persisted dirty flag (dirty-since) in ChannelSectionsStorage so
unpublished edits survive manager teardown and app restarts.
- Dirty-state protection in _mergeEvent: a remote blob never overwrites
unpublished local edits; the pending publish reconciles the relay.
- Publish-on-reconnect: initialize() re-schedules a publish when the dirty
flag is set, and seed-publishes local state when the relay confirms it has
no blob (never on a failed fetch).
- Edit-generation guard so a publish only clears the dirty flag when no new
edit landed while it was in flight.
Also adds mobile channel-sort sync parity (desktop-only until now):
- New channel_sort feature (storage/manager/provider) using the same
encrypted NIP-78 blob desktop publishes (kind 30078, d-tag channel-sort,
NIP-44 to self, whole-blob LWW) including the dirty-flag protection above.
- Per-group Sort: Recent / A-Z controls on Starred, custom sections,
Channels, and DMs, matching desktop group keys (starred/channels/dms,
section:<id>) and sort semantics; orphaned section:<id> keys are pruned
on write.
Co-authored-by: npub1223z34hd7vtwc6qj4s7flsxkj644nlre2nthu7lrrmkumhu3xddsrx9r6w <52a228d6edf316ec6812ac3c9fc0d696ab59fc7954d77e7be31eedcddf91335b@buzz.block.builderlab.xyz>
Signed-off-by: npub1223z34hd7vtwc6qj4s7flsxkj644nlre2nthu7lrrmkumhu3xddsrx9r6w <52a228d6edf316ec6812ac3c9fc0d696ab59fc7954d77e7be31eedcddf91335b@buzz.block.builderlab.xyz>
Buzz Mobile
Flutter mobile client for Buzz.
Setup
cd mobile
flutter pub get
Run
# From repo root (recommended — starts Docker, relay, and simulator):
just mobile-dev
# Direct (requires services and relay already running):
cd mobile && flutter run
Checks
dart format --output=none --set-exit-if-changed .
flutter analyze
flutter test
Or from the repo root: just mobile-check and just mobile-test.
Android release signing
Android release builds fail unless all upload-key inputs are supplied through the environment:
BUZZ_ANDROID_UPLOAD_KEYSTORE_PATH: path to a CI-vended keystore fileBUZZ_ANDROID_UPLOAD_KEYSTORE_PASSWORDBUZZ_ANDROID_UPLOAD_KEY_ALIASBUZZ_ANDROID_UPLOAD_KEY_PASSWORD
The keystore path must be absolute, and the keystore must remain outside the repository. Development and debug builds do not require these variables.
Release pipelines that sign through the central APK Signer service instead of
a local upload keystore must set BUZZ_ANDROID_RELEASE_SIGNING=external. That
mode produces an unsigned release bundle and refuses to run if any
BUZZ_ANDROID_UPLOAD_* value is also set.
Architecture
lib/
├── main.dart # Entry point, Riverpod bootstrap
├── app.dart # MaterialApp with theme
├── shared/
│ └── theme/ # Catppuccin light/dark, spacing tokens, extensions
└── features/
└── home/ # Placeholder home surface
- State management: Riverpod + Hooks (
HookConsumerWidget) - Theme: Catppuccin Latte (light) / Macchiato (dark) — matches desktop
- Spacing:
Gridtokens for consistent spacing - Linting:
flutter_lints+riverpod_lintviacustom_lint - Feature isolation: No cross-feature imports except
shared/