mirror of
https://github.com/zapstore/zapstore.git
synced 2026-10-05 12:38:24 +00:00
1. main.dart: Add database migration from Documents to Support directory - Migrates existing zapstore.db to new location on first run - Preserves existing users' data after directory change 2. installed_packages_snapshot.dart: Use atomic file replace - Remove explicit delete before rename (rename atomically replaces) - Add try/catch to preserve temp file on rename failure 3. polls_section.dart: Fix useEffect cleanup for dynamic controllers - Capture controller snapshot in useEffect - Properly dispose controllers added via "Add Option" 4. polls_section.dart: Fix filter to include votes at exact end time - Changed from isBefore to !isAfter for inclusive filtering 5. polls_utils.dart: Extract shared utility functions - canCreatePoll, filterValidResponses, calculateVoteCounts - Marked @visibleForTesting for test access 6. FEAT-001-package-manager.md: Add markdown language specifiers - Fix MD040 lint warnings for code blocks 7. polls_section_test.dart: Use production utils instead of duplicates - Import and test actual canCreatePoll from polls_utils - Add test for votes at exact poll end time Signed-off-by: alltheseas <alltheseas@users.noreply.github.com> Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
5.1 KiB
5.1 KiB
FEAT-001 — Package Manager
Goal
Single source of truth for installed packages and active install operations. Manages the complete lifecycle: download → verify → install, with pause/resume/cancel support.
Non-Goals
- Managing non-APK file types
- Auto-updating without user awareness
- Installing from sources other than Nostr-published releases
User-Visible Behavior
Download Phase
- User taps "Install" → download begins, progress shown
- User can pause/resume/cancel active downloads
- Multiple downloads queue automatically (max 3 concurrent)
- "Update All" queues all updates immediately with visual feedback
Verification Phase
- After download completes, hash verification runs
- Verification state is visible (not hidden)
- Hash mismatch blocks install with clear error
Permission Phase
- If "Install unknown apps" permission not granted, user is prompted
- Permission state is explicit in UI
- Once granted, all waiting installs advance automatically
Install Phase
- Native Android install dialog shown
- One install dialog at a time (serialized)
- If user dismisses dialog, install shows "Tap to retry" state
- Success updates installed list immediately (no stale UI)
Failure States
- Download failed → clear error, can retry
- Hash mismatch → error, cannot proceed
- Certificate mismatch → offer "Uninstall and reinstall" option
- Permission denied → guidance to enable in Settings
State Machine
Operations follow this sealed class hierarchy (install_operation.dart):
DownloadQueued → Downloading ↔ DownloadPaused
↓
Verifying
↓
AwaitingPermission (if needed)
↓
ReadyToInstall
↓
Installing → AwaitingUserAction (if dismissed)
↓
[cleared] or OperationFailed
State transitions are unidirectional except Downloading ↔ DownloadPaused.
Edge Cases
- Network drops mid-download → download pauses or fails gracefully, can retry
- App backgrounded during install → install completes, UI updates on return
- 404 from origin server → automatic CDN fallback before failing
- Stale operations (>7 days) → garbage collected on app restart
- Android package DB race condition → state updated from target metadata, not sync
Invariants
These are non-negotiable. Violations mean the implementation is broken.
- UI never blocks —
install()returns immediately; events drive state via EventChannel - One install dialog at a time — Android PackageInstaller limitation, enforced by serialization
- Hash verification before install — Native side verifies before install session opens
- Permission flow is explicit —
AwaitingPermissionstate exists for UI feedback - Downloaded files are cleaned up — Deleted after success or dismissal
- No polling — All state changes via callbacks/events, never periodic checks
Integration Boundaries
┌─────────────────────────────────────────────────────────────┐
│ PackageManager (Dart) │
│ - State machine owner │
│ - Download management (background_downloader) │
│ - Orchestrates flow │
└─────────────────────────┬───────────────────────────────────┘
│ MethodChannel / EventChannel
┌─────────────────────────▼───────────────────────────────────┐
│ AndroidPackageManagerPlugin (Kotlin) │
│ - Hash verification │
│ - PackageInstaller session │
│ - Permission checks │
│ - Emits: verifying/started/success/failed/cancelled │
└─────────────────────────────────────────────────────────────┘
Acceptance Criteria
- User can download, pause, resume, cancel downloads
- User can install apps with proper verification
- Multiple downloads queue correctly (max 3 concurrent)
- Install failures show actionable error messages
- Certificate mismatch offers force-update option
- UI remains responsive throughout all operations
- No operations block the UI thread
Files
lib/services/package_manager/package_manager.dart— Base class, state machinelib/services/package_manager/install_operation.dart— State definitionslib/services/package_manager/android_package_manager.dart— Android implementationandroid/.../AndroidPackageManagerPlugin.kt— Native side