The 2,100-line file mixed four unrelated groups with the AutoMix tests.
The native-channel fake, analyzer and renderer fakes, the shared setUp
and tearDown, and fakeTimeTest move to
test/support/music_player_automix_harness.dart with public names. Each
top-level group gets its own file (haptics transport, playback failures,
system volume, USB transport); the ungrouped AutoMix, Autoplay, queue
and notification tests stay in music_player_automix_test.dart.
Test bodies are moved verbatim; each file aliases the shared tracks and
wait helper to their previous private names. The test count is
unchanged at 81 (50 + 4 + 5 + 6 + 16).
The startup flush test slept 1.24 s, mostly three 400 ms windows that
must outlast the 350 ms persistence debounce. The body now runs in
VirtualTime, so those waits and the debounce timer advance on virtual
time while platform-channel replies stay real. No production change;
the test body and assertions are unchanged.
The AutoMix tests slept about 17 s of wall time waiting for fades, tempo
recovery and "nothing happens" windows, and the haptics tests 1.15 s.
fake_async is not a direct dependency, so the analyzer rejects importing
it. Haptics tests run as testWidgets on the binding's FakeAsync clock,
which also drives the PlaybackState position extrapolation.
The AutoMix player shares process-wide runtime state (the listening
recorder and personalization write chains), so a FakeAsync zone that
stops after one test would strand later tests. test/support/virtual_time
adds a zone with virtual timers and real microtasks instead: setUp builds
the player in that zone, and fakeTimeTest runs a body with its timers
fired in due order, skipping idle time. Pending timers continue on real
time afterwards.
AutoMix reads its fade and readiness clocks through autoMixStopwatch,
which defaults to Stopwatch.new; tests point it, and the native fake's
deck clocks, at the virtual clock. Test bodies and assertions are
unchanged.
The lookup cache test waited out the 500 ms production debounce four
times (2.7 s). A @visibleForTesting setter lets the test use a 10 ms
debounce while keeping the same 50 to 250 ms margin after the timer
fires for the background encode. The production default stays 500 ms
and the assertions are unchanged.
The Dart incremental ingestion branch runs only when
PlatformBridge.supportsCoreBackend (Platform.isAndroid || Platform.isIOS)
is false. Its useSnapshotBridge flag required Platform.isAndroid, so it
could never be true there, and the native handlers for
scanSafTreeIncrementalFromSnapshot and
scanLibraryFolderIncrementalFromSnapshot are already gone.
Remove the flag, both PlatformBridge methods, and
LibraryDatabase.writeFileModTimesSnapshot(Map), whose only other user was
test/library_scan_snapshot_test.dart (deleted with it). The live native
snapshot path (writeNativeFileModTimesSnapshot) and the host-test branch
with _backfillLegacyFileModTimes are unchanged.
Search bucketing, refresh policy, folder data, history snapshot and the
selection and collapsing-header mixins hold no widgets, so they move to
controllers; the settings search catalog is pure presentation metadata and
moves to utils. Files with many importers keep a re-export in screens.
library_database_models and ffmpeg_models are plain data types, so they live in
models (re-exports stay at the old paths). deleted_library_files uses providers
and download_progress uses provider state, so both move to providers, and
ffmpeg_reenrich is a service. models no longer import from services for these.
Batch actions, clickable metadata, playback, auth launcher, action forms and
the glass warmup drive UI flows, so they belong with the controllers. Files
with more than three importers (or an importer that must stay untouched) keep
a one-line re-export at the old path.
Add fnv1a32 in hash_utils.dart for the scan output name (UTF-8 bytes) and
qualityVariantStagingLabel (UTF-16 code units). Unit tests pin outputs
computed from the original inline code.
Move worker request contract validation and the download history row
and JSON mapping out of NativeDownloadFinalizer into a sibling file of
extension functions. Bodies are verbatim. NATIVE_WORKER_CONTRACT_VERSION
stays on the object with its value, so its contract test is unchanged.
The history column contract test now reads buildHistoryRow from the new
file. normalizeOptional moves with the row builder, so
cleanMetadataString widens from private to internal.
Mirror the library_schema and library_row_mapper split: HistorySchema owns
create, upgrade, index creation and backfills, HistoryRowMapper owns the
JSON/row mapping and the derived normalized and queue-sort columns. SQL text
is unchanged. Tests that read the history CREATE TABLE and index text now
read history_schema.dart.
The log buffer polls the native backend, so isFromGo, the Go log polling
methods and their private state now use native names. Comments that still
described the backend as Go are reworded. No string literals changed.
Replace 16 private SettingsNotifier fakes that only returned a fixed AppSettings with test/support/fixed_settings.dart. Mornye owner WIP tests and bespoke fakes are untouched.
The grab-bag file mixed model tests with tests that pin literal source
text across Dart, Kotlin and Swift. The contracts now live in
source_contracts_test.dart with a header explaining that they must be
updated, never deleted, when code moves. The remaining groups moved
verbatim into domain files.
Applying a preset replaced every setting, so built-in presets silently
turned automatic headroom, the limiter and the compressor back on and
reset balance. Presets now carry only the curve, preamp, bass and treble.
The active preset is matched on the same fields, so it no longer shows as
Custom once headroom is off.
The empty lyrics page offers Search online, which asks the enabled lyrics
providers in their configured order. The result is shown in the player
only and never written to the file; a late result is dropped after the
track changes, and a miss says so.
Add two keyless providers that serve Apple Music TTML: lrc.red, matched by
recording, and BetterLyrics, which answers songs it has already cached.
TTML is read into the first-party Apple line structure, so vocal sides,
backing groups, word timing, translations and romanization share one eLRC
formatter. The XML depth guard moves to core so both readers use it.
SpotiFLAC-Mobile Lyrics becomes its own provider instead of a fallback
inside Apple Music. New defaults are Apple Music, lrc.red, SpotiFLAC-Mobile
Lyrics, LyricsPlus and LRCLIB. Migration 13 moves untouched defaults to the
new list and keeps the former fallback right after Apple Music in custom
orders. Replace the dead LyricsPlus Workers mirror.
Offer default and full-screen artwork in Material and Mornye, retaining landscape layouts and full-screen Mornye motion artwork. Keep the Material header readable over bright covers and normalize invalid saved styles without resetting other settings.
Validation: 144 related Flutter tests, flutter analyze, generated settings, formatter and diff checks.