Prevent premature 'downloading' status before actual byte transfer
starts, and cache async provider values to avoid UI flicker during
queue library reloads.
Progress pipeline:
- StartItemProgress now initializes with 'preparing' status instead
of 'downloading'
- SetItemProgress ignores synthetic pre-download progress updates
while status is still 'preparing' (no byte data yet)
- DownloadService reads backend status field and propagates preparing/
downloading/finalizing to native worker item snapshot
- Dart progress stream maps 'preparing' to DownloadStatus.downloading
with progress 0.0 (indeterminate spinner)
Queue tab:
- Add _queueLibraryCountsCache and _queueLibraryPageDataCache to
retain last successful data during FutureProvider refetches
- Prevents empty-state flash when loadedIndexVersion bumps trigger
provider invalidation
- Caches trimmed to max 24 entries via FIFO eviction
- Replace hardcoded provider prefix checks with resolveEffectiveMetadataProvider using replacesBuiltInProviders manifest capability
- Add preparing/downloading/finalizing progress status constants and SetItemPreparing/SetItemDownloading APIs
- Expose setDownloadStatus to extension JS runtime for fine-grained progress control
- Skip lyrics search for instrumental tracks detected by title heuristic
- Pass tidal/qobuz IDs to extension checkAvailability for richer matching
- Add shouldAbortCancelledFallback helper for robust cancellation propagation
- Add resolvePreferredTrackIDForExtension for intelligent track ID selection per extension
- Remove ambiguous Auto/Default search provider option, always resolve to concrete provider
- Add tests for shouldAbortCancelledFallback and progress status transitions
- Reduce polling interval from 800ms to 1200ms across download progress, library scan, and Android native stream
- Add dirty-flag caching to Go GetMultiProgress() to skip redundant JSON marshaling
- Replace eager provider initialization with staggered Timer-based warmup (400/900/1600ms)
- Add snapshot-based incremental library scan to avoid large MethodChannel payloads
- Move history stats and grouped album filtering to Riverpod providers for better cache invalidation
- Cap home tab history preview to 48 items with deep equality wrapper to reduce rebuilds
- Throttle foreground service notification updates to 2% progress buckets
- Migrate PageView to PageView.builder with AutomaticKeepAliveClientMixin
- Add comparison table to README
Changes:
- Fix FFmpeg crash issues during M4A to MP3/Opus conversion
- Add format picker (MP3/Opus) when selecting Tidal Lossy 320kbps
- Fix Deezer album blank screen when opened from home
- LRC file generation now follows lyrics mode setting
- Version bump to 3.3.5 (build 70)
- Add extension manager, manifest, runtime, providers, settings
- Add extension provider and UI pages (extensions, detail, priority)
- Add download service picker widget
- Add metadata provider priority page
- Add source field to Track model for extension tracking
- Add skipBuiltInFallback manifest option to skip built-in providers
- Update download queue to use source extension first
- Add extension upgrade support without data loss
- Fix progress bar jumping from 1% to 100% (threshold-based updates)
- Fix incomplete downloads with temp file + size validation
- Applies to Tidal, Qobuz, and Amazon services
- Quality picker now shows track name, artist, and cover
- Tap to expand long track titles (icon only shows when truncated)
- Ripple effect follows rounded corners including drag handle
- Update dialog redesigned with Material Expressive 3 style
- Fixed update notification stuck at 100% after download complete
- Ask before download now enabled by default
- Finalizing notification for multi-progress polling