Commit Graph
2481 Commits
Author SHA1 Message Date
zarzet 5b3a2b9575 refactor(queue): move the completion bridge into CompletionBridgeTracker
The completion bridge maps, the precache set, the History row matcher and the
bodies of the queue lookup and History index listeners lived on the Library
tab State. CompletionBridgeTracker in lib/controllers now owns them. The two
ref.listen registrations stay in build at the same positions and call into
the tracker; the State forwards the old field names as getters so the part
files read the same collections.

Guards, the setState that drops removed items, the file check refresh order
(file cache, then playable probe), the offset reset and the mounted rebuild
after a History index change are unchanged.
2026-10-19 01:12:21 +07:00
zarzet 830dee31ed refactor(queue): move library paging state into QueueLibraryPager
The Library tab State held the page offsets, the load-more guard, the count
and page snapshot caches, the blank-library repair throttle and their trim
and scope rules inline. QueueLibraryPager in lib/controllers now owns that
state and logic; the State keeps one _pager field and forwards, passing
setState, mounted and the provider reloads as callbacks.

The page request and page data types implement two small interfaces so the
pager can compare scopes and test emptiness without seeing the private
types. Provider reads, page size, trim limits, the repair throttle and the
order of cache writes and setState calls are unchanged.
2026-10-19 01:12:21 +07:00
zarzet db4643c26e refactor(bridge): share one generic cache entry and put/prune helper
The map and list lookup caches had twin entry classes and twin put and
prune helpers that differed only in the value type. Replace them with
_BridgeCacheEntry<T>, _putMemoryCached<T> and _pruneExpiredBridgeCache<T>.
Each cache keeps its own map, TTL and budget accounting; the byte estimate,
shared budget constants and oldest-first eviction are unchanged.
2026-10-19 01:06:12 +07:00
zarzet 857c2954d8 refactor(collections): move playlist cover file I/O into PlaylistCoverStore
LibraryCollectionsNotifier carried about 130 lines of File and Directory
work for playlist covers. PlaylistCoverStore now owns the playlist_covers
directory, the <playlistId>.jpg normalization with its temp file, the
backup restore copy or base64 write, and the delete helpers. The
directory is still resolved through getApplicationSupportDirectory on
each call, at the same points as before.

The notifier keeps setPlaylistCover, removePlaylistCover,
exportPlaylistCoverFiles and restoreFromBackup with unchanged signatures,
mutation ordering and error handling: a failed restore of one cover still
drops that cover path, removePlaylistCover still propagates delete
errors, and replacing a cover still deletes the old file quietly.
2026-10-19 01:01:25 +07:00
zarzet 8fffb9230a refactor(cache): move directory scanning and clearing into CacheMaintenanceService
The cache management page walked and deleted directories itself. Move
_scanDirectory and _clearDirectoryContents verbatim into
CacheMaintenanceService.scanDirectory and clearDirectoryContents in
lib/services/cache_maintenance_service.dart, with _DirectoryStats
becoming the public DirectoryStats it returns.

The page calls the service at the same points with the same arguments,
so scan concurrency, the 24-entity delete chunks, the directory
re-creation after clearing and every action key are unchanged.
2026-10-19 00:59:24 +07:00
zarzet 755c907982 refactor(analysis): move the FFmpeg runner out of the widget
The card ran ffprobe, both FFmpeg sessions, SAF temp copies, the
native spectral-cutoff job and its cancellation inside State. Move that
pipeline verbatim into AudioAnalysisRunner in
lib/services/audio_analysis_runner.dart together with the private
per-run records from the widget's models part, which is now empty and
removed.

The card keeps request ids and every setState. The runner takes a
`bool Function() isCancelled` that the card builds from the same
`!mounted || requestId != _spectrogramRequestId` test, polled at the
same points that used to call _checkAnalysisRequest. cancel() and
dispose() run the jobs invalidate/dispose, network cancel and native
job cancel in the original order.

Subprocess order, temp file names and cleanup, SAF copy and the native
data job payload are unchanged.
2026-10-19 00:59:24 +07:00
zarzet b575a4ea38 refactor(analysis): move the analysis disk cache into audio_analysis_cache.dart
The card owned the bundle storage (key derivation, {key}.json,
{key}.png and {key}_ch{n}.png, the shared trim budget) as static
members, and the cache page spelled the audio_analysis_cache directory
literal twice more.

Move the storage verbatim into AudioAnalysisDiskCache next to the
existing lease/trim policy. AudioAnalysisDiskCache.directoryIn is now
the only place that names the directory; the card's cacheDir and both
cache page call sites use it, with the page keeping its non-creating
behavior and await order. loadFromCache takes the card's network input
as a parameter instead of reading the field.

The 63-bit FNV-1a cache key stays local: lib/utils/hash_utils.dart
fnv1a32 uses a different basis, prime and width, so reusing it would
rename every cached bundle on devices.
2026-10-19 00:59:24 +07:00
zarzet 34a004f96f refactor(analysis): move the pure FFmpeg builders and parsers to a service
The audio analysis card mixed FFmpeg argument builders, astats and
metadata parsers and the spectral cutoff estimator with widget state.
Move them verbatim into lib/services/audio_analysis_ffmpeg.dart so the
runner and cache can depend on them without importing a widget.

The parsers return ChannelAnalysisStats, so the two public result
models (AudioAnalysisData, ChannelAnalysisStats) move verbatim from the
widget's models part into lib/services/audio_analysis_models.dart. The
per-run private records stay in the part for now.

Only two names change: the unsupported-codec exception loses its
leading underscore because the widget and the future runner live in
different libraries, and the in-class _parseChannelStats becomes the
top-level parseChannelStats. The widget re-exports both service files,
so tests and importers are unchanged.
2026-10-19 00:59:24 +07:00
zarzet 7628800604 refactor(setup): move SharedPreferences access behind SetupProgressStore and SafMigrationPromptStore
The setup draft and the SAF migration prompt flag were read and written
directly from screens. Keys, JSON shape and defaults are unchanged.
2026-10-19 00:56:52 +07:00
zarzet 8af7efb6ce refactor(providers): move UI-declared providers to lib/providers
The listening summary and system volume providers lived in UI files.
They move verbatim to lib/providers with the same names; the old files
re-export them so tests and other importers are unchanged.
2026-10-19 00:56:52 +07:00
zarzet bff5123c0e refactor(concerts): move the calendar channel into a service
The screen built the method channel inline. ConcertCalendarService owns it
with the same channel name, method and payload keys.
2026-10-19 00:48:31 +07:00
zarzet ba376d69fc refactor(repo): prepare install paths in the repo notifier
The store list and the detail screen both built the temp and extension
directories before calling the notifier. The notifier now offers
installExtensionToDefaultPaths and updateExtensionToDefaultPaths; the
existing methods keep their signatures.
2026-10-19 00:48:31 +07:00
zarzet b10370e4fc refactor(share): share the widget capture helper
The lyrics card and the rewind slide both rendered a RepaintBoundary to a
temp PNG. captureBoundaryToPngFile does that; pixel ratio, file name, frame
waiting and share parameters stay with each caller.
2026-10-19 00:48:31 +07:00
zarzet da2fc2c9c9 refactor(extensions): share the extension health color and icon helpers
The detail page and the list page carried identical color mappings. Only
color and icon move; each screen keeps its own label mapping.
2026-10-19 00:48:31 +07:00
zarzet fe29f304aa refactor(playlists): share the playlist name prompt and dispose its controller
The create, picker and rename dialogs were three copies of one form. They
now call promptPlaylistName, whose controller lives in a dialog state and is
disposed with it.
2026-10-19 00:48:31 +07:00
zarzet 485be2f468 refactor(artist): move the discography download into a part
artist_screen.dart mixed the artist page with the whole discography
download flow (option sheet, album fetching, queueing and its progress
dialog). Moving that flow into its own part keeps one responsibility per
file and shrinks the screen file. Bodies are moved verbatim.
2026-10-19 00:48:05 +07:00
zarzet 263a10171d refactor(home): use downloadSingleTrack for search results
The search result download re-implemented the shared flow with the same
provider calls and snackbars; the helper only adds a mounted check.
2026-10-19 00:47:55 +07:00
zarzet 4598773cd3 refactor(storage): share the SAF download tree pick
Three screens repeated the pick, parse and store sequence. The helper keeps
each site's call order; the SAF migration prompt skips the storage mode
switch as before.
2026-10-19 00:47:55 +07:00
zarzet 78799e1bbc refactor(layout): share responsiveScale and effectiveTextScale
The same clamp helpers were copied into four screens. They now live in
adaptive_layout.dart with identical bodies and clamp values.
2026-10-19 00:47:54 +07:00
zarzet 1521c49508 docs(selection): correct the SelectionModeMixin doc
The doc named queue_tab as a user, but queue_tab has its own selection state.
List the screens that actually mix it in.
2026-10-19 00:37:42 +07:00
zarzet 99ccc8826f refactor(layering): move logic files out of screens
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.
2026-10-19 00:37:42 +07:00
zarzet ce21896ff5 refactor(layering): move model files to models and fix inverted imports
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.
2026-10-19 00:37:42 +07:00
zarzet ab8a329d2d refactor(layering): move UI action helpers from services and utils to controllers
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.
2026-10-19 00:37:42 +07:00
zarzet ff3f752014 refactor(metadata): share the sidecar publish path between save-cover and save-lyrics
_saveCoverArt and _saveLyrics repeated the same SAF/local publish
skeleton: render into a temp dir and publish it to the download tree
with createSafFileFromPath (or write next to the audio file), clean the
temp dir, then report the outcome. Move that skeleton into
_publishSidecarFile with parameters for the temp prefix, extension, mime
type, success message and whether a snackbar hides the current one.

Each caller keeps its own try/catch, base name, lyrics progress
snackbar and the render step. The cover render returns null after its
no-source snackbar so the helper stops at the same point as before
(without deleting the temp dir, as before). Await order, mounted checks,
messages and cleanup placement are unchanged.
2026-10-19 00:23:50 +07:00
zarzet adf2047df6 refactor(utils): share the FNV-1a 32-bit hash
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.
2026-10-19 00:15:48 +07:00
zarzet 036589a4b1 refactor(notifications): reuse formatMegabytes
The progress notification formatted megabytes inline with the same
expression as formatMegabytes (one decimal, power-of-two scaling, so the
double result is identical). It now calls the helper. No output change.
2026-10-19 00:15:48 +07:00
zarzet d6fd05c3a7 refactor(io): use isContentUri instead of inline content:// checks
The same startsWith check was inlined in 21 places across services and
providers. They now call the existing helper, which has identical
semantics (no trim, no case folding). No behavior change.
2026-10-19 00:15:48 +07:00
zarzet 0797085385 refactor(io): use deleteFileQuietly for exists-then-delete
Add deleteFileQuietly to file_access.dart (exists check, delete, swallow
errors) and use it for the try/exists/delete/catch (_) {} copies.
2026-10-19 00:15:48 +07:00
zarzet 92d655fd1c refactor(player): move restorePlaybackSession to playback_session_restore.dart
The function only needed the file-level logger, which the new file declares
with the same tag. It is re-exported from music_player_service.dart.
2026-10-18 23:53:44 +07:00
zarzet 548567eff3 refactor(player): move PlayableMedia to playable_media.dart
The class moves verbatim and is re-exported from music_player_service.dart.
The toJson/fromJson artwork round trips stay: toJson drops non-positive
numbers, blank formats and empty artwork, so a copyWith would not be an
exact replacement for them.
2026-10-18 23:53:44 +07:00
zarzet 992e21e297 refactor(player): port tests to musicPlayerRuntime and delete the test-only wrappers
The wrappers only forwarded to musicPlayerRuntime and were referenced by one
test file. The forwarding helpers now live in that test.
2026-10-18 23:53:38 +07:00
zarzet 95666c1043 refactor(settings): move log_screen widgets into a part
The page file mixed the log_screen State with standalone private
widgets and helpers. They move verbatim into log_screen_widgets.dart so the
page file holds only the page and its State. Private visibility is
unchanged because parts share the library. No behavior change.

_domainPattern moves with its only user, _LogSummaryCard.
2026-10-18 23:49:17 +07:00
zarzet 0d2fef4c33 refactor(settings): move extensions_page widgets into a part
The page file mixed the extensions_page State with standalone private
widgets and helpers. They move verbatim into extensions_page_widgets.dart so the
page file holds only the page and its State. Private visibility is
unchanged because parts share the library. No behavior change.
2026-10-18 23:49:17 +07:00
zarzet 6e43c03691 refactor(settings): move appearance_settings_page widgets into a part
The page file mixed the appearance_settings_page State with standalone private
widgets and helpers. They move verbatim into appearance_settings_page_widgets.dart so the
page file holds only the page and its State. Private visibility is
unchanged because parts share the library. No behavior change.
2026-10-18 23:49:17 +07:00
zarzet a3961eeff5 refactor(settings): move files_settings_page widgets into a part
The page file mixed the files_settings_page State with standalone private
widgets and helpers. They move verbatim into files_settings_page_widgets.dart so the
page file holds only the page and its State. Private visibility is
unchanged because parts share the library. No behavior change.
2026-10-18 23:49:16 +07:00
zarzet 486fd3b6e7 refactor(settings): move download_settings_page widgets into a part
The page file mixed the download_settings_page State with standalone private
widgets and helpers. They move verbatim into download_settings_page_widgets.dart so the
page file holds only the page and its State. Private visibility is
unchanged because parts share the library. No behavior change.
2026-10-18 23:49:16 +07:00
zarzet f3e44f3ee6 refactor(settings): move library_settings_page widgets into a part
The page file mixed the library_settings_page State with standalone private
widgets and helpers. They move verbatim into library_settings_page_widgets.dart so the
page file holds only the page and its State. Private visibility is
unchanged because parts share the library. No behavior change.
2026-10-18 23:49:16 +07:00
zarzet d0cdaafcfa refactor(settings): move extension_detail_page widgets into a part
The page file mixed the extension_detail_page State with standalone private
widgets and helpers. They move verbatim into extension_detail_page_widgets.dart so the
page file holds only the page and its State. Private visibility is
unchanged because parts share the library. No behavior change.
2026-10-18 23:49:16 +07:00
zarzet eeb010cd52 refactor(library): extract the ingestion store from library_database.dart
LibraryIngestionStore holds scan and incremental ingestion writes with
bodies unchanged. LibraryDatabase keeps thin delegating methods with the
same public signatures and passes in its connection and the lazy History
attachment. SQL text is unchanged.
2026-10-18 23:28:33 +07:00
zarzet fbed496014 refactor(history): move the history schema and row mapper into their own files
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.
2026-10-18 23:28:33 +07:00
zarzet c2b7a0b782 refactor(downloads): move pure queue policy helpers into download_queue_policy.dart
The queue provider library mixed pure, notifier-free helpers (processing
gate, storage-write recovery, native worker status/progress mapping,
batch album-artist normalization) with the notifier. They now live in a
standalone file that the library imports and re-exports, so existing
importers are unchanged.
2026-10-18 23:28:33 +07:00
zarzet b64b08c4d0 refactor(shell): move nav icons to a widget file and startup prompts into a part
BouncingIcon, SlidingIcon and SpinIcon are standalone widgets, so they now
live in lib/widgets/nav_destination_icons.dart. The SAF repair, upgrade intro,
update, announcement and SAF migration prompts move into a part as an
extension on the shell State; the call sites in initState are unchanged.
2026-10-18 22:42:38 +07:00
zarzet 12ff09907e refactor(setup): move the setup step builders into a part
The setup screen State mixed permission and folder logic with the step
builders. Move the builders and the step widgets into a part as an extension
on the State; the two setState calls in moved code go through a _setState
forwarder.
2026-10-18 22:42:37 +07:00
zarzet e9834f060c refactor(equalizer): split the equalizer screen into widgets and curve parts
The screen file mixed state, a dozen private widgets and the curve painter.
Move the widgets and the painter with its helpers into part files; code is
unchanged.
2026-10-18 22:42:37 +07:00
zarzet 8fd574f010 refactor(rewind): split the listening rewind screen and move its providers
The two Rewind providers move to lib/providers and are re-exported from the
screen so existing imports keep working. Story, slides and widgets become
part files of the screen library. No behavior change.
2026-10-18 22:40:10 +07:00
zarzet 77c8639df2 refactor(lyrics): split player_lyrics.dart into line-style and word-sweep parts
The word-sweep painter and the line style helpers are self-contained, so
they move into part files of the same library. No behavior change.
2026-10-18 22:40:10 +07:00
zarzet 237690cd89 refactor(metadata): move editor form primitives into a widgets file
Options group, quick-select button, switch field, selection field and
section card become public StatelessWidgets in metadata_editor_fields.dart
with unchanged build bodies; State fields they read (color scheme, fetching
flag) are now constructor parameters.
2026-10-18 22:39:31 +07:00
zarzet 714bec6aaf refactor(metadata): split the edit sheet into cover and auto-fill parts
Cover editor members and auto-fill members move to extensions in part
files; bodies are unchanged except setState goes through a _setState
forwarder, as in the other State part files.
2026-10-18 22:39:31 +07:00
zarzet 77377f6b67 refactor(metadata): one option picker for provider and cover size
The provider and cover-size pickers shared the sheet shell and row layout.
Both now go through _showEditorOptionPicker<T>; per-picker differences
(label ellipsis, which context supplies the check icon theme) stay as
parameters.
2026-10-18 22:39:31 +07:00
zarzet 1c7146f906 refactor(home): split the home tab build into sliver-group builders
The 440 line build method now computes shared state once and composes one
private builder per sliver group (header, intro, search bar, filters, recent
access, home sections, explore, explore skeleton, search results). Conditions,
order, keys and provider watches are unchanged.
2026-10-18 22:32:15 +07:00