Commit Graph
374 Commits
Author SHA1 Message Date
zarzet 20b4c73b8d refactor(android): move RustCoreBackend.invokeApplication into its own file
NT-16 Kotlin part. The application method dispatch (about 290 lines) moves
verbatim into RustCoreBackendApplication.kt as an internal extension
`RustCoreBackend.dispatchApplication`. The `invokeApplication` override
stays in SelectedCoreBackend.kt as a one-line delegate. `synchronized(this)`
still locks the RustCoreBackend object.

The object state and helpers the dispatch uses are widened from private to
internal; method names, argument keys, results and error strings are
unchanged.
2026-10-19 00:21:34 +07:00
zarzet b6b609f334 refactor(android): move Impeller helpers, the SAF tree picker and progress streams out of MainActivity.kt
First NT-12 seam group, following the MainActivitySafScan.kt and
MainActivitySafIo.kt receiver-function shape. Bodies are moved verbatim.

- ImpellerCompatibility.kt: the device lists and shouldDisableImpeller /
  getGpuRenderer, now file-level. ImpellerAwareFlutterFragment stays nested
  in MainActivity because proguard-rules.pro keeps it by that name.
- MainActivitySafTreePicker.kt: the pickSafTree launch (the case now calls
  launchSafTreePicker), the activity-result handler, and the storage id and
  display path helpers. The launcher registration stays a MainActivity
  property so it is still registered at construction.
- MainActivityProgressStreams.kt: both progress EventChannels, their
  start/stop/poll helpers and the channel name and polling constants.

Stream state, the picker store, the launcher, the coroutine scope, the
backend channel and the companion's pending picker result are widened from
private to internal so the receiver functions can reach them. Channel
names, payload keys, error codes and dispatch order are unchanged.
2026-10-19 00:21:34 +07:00
zarzet cc9b9f1162 test(android): assert the backend routing set matches the dispatch cases
MainActivity handles a backend call in its own `when` only when the method
name is listed in `nativeBackendMethods`; any other name falls through to the
selected core backend. A name added to only one of the two silently changes
where the call is handled. This JVM test reads MainActivity.kt as source,
extracts the set literal and the top-level string case labels of
`when (call.method)`, and fails with the symmetric difference when they drift.
2026-10-19 00:21:34 +07:00
zarzet b5cf97881f refactor(android): move finalizer history into NativeFinalizerHistory.kt
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.
2026-10-19 00:14:47 +07:00
zarzet 631b9aa5e8 refactor(android): move finalizer post-processing into NativeFinalizerPostProcess.kt
Move the extension post-processing hook stage out of
NativeDownloadFinalizer into a sibling file as an extension function.
The body is verbatim. The shared materializeForFFmpeg and
replaceStatePath helpers stay on the object because every stage uses
them, and no object member needed wider visibility.
2026-10-19 00:14:47 +07:00
zarzet 0b4725c2c0 refactor(android): move finalizer metadata into NativeFinalizerMetadata.kt
Move the metadata embedding stage, ReplayGain tagging and verification,
the album key and duration helpers, and the final audio quality probe
out of NativeDownloadFinalizer into a sibling file of extension
functions. Bodies are verbatim. The moved code reads three JSON helpers
that stay on the object, so parseObject, optPositiveInt and
optPositiveBitrateKbps widen from private to internal.
2026-10-19 00:14:47 +07:00
zarzet ead04c00b4 refactor(android): move finalizer container into NativeFinalizerContainer.kt
Move the lossless container conversion and automatic conversion stages,
with their file-local helpers (output extension, M4A sniffing, unique
output path, preserved container rename), out of NativeDownloadFinalizer
into a sibling file of extension functions. Bodies are verbatim except
one moved comment line whose em dash is rewritten as a colon. No object
member needed wider visibility.
2026-10-19 00:14:47 +07:00
zarzet 92af56eea7 refactor(android): move finalizer decrypt into NativeFinalizerDecrypt.kt
NativeDownloadFinalizer.kt is a 1300-line god file. Move the decryption
stage (finalizeDecryption, ISO-BMFF extension normalization and key
candidate expansion) into a sibling file as NativeDownloadFinalizer
extension functions, matching NativeFinalizerMedia/FFmpeg/SafPublish.
Bodies are verbatim; file-local helpers stay private, and no object
member needed wider visibility.
2026-10-19 00:14:47 +07:00
zarzet 92adce43ef refactor(native): share errorJson and retire Go-era names in native comments
MainActivitySafIo and SafDownloadHandler each defined an identical
errorJson. Keep one internal top-level function in MainActivitySafIo
and drop the private copy. errorJson, isMediaStoreUri, extFromFileName
and extFromMimeType never used their MainActivity receiver, so they
become plain top-level functions; call sites are unchanged.

Rust is the only backend. Rename the iOS invokeGoMethod, which
dispatches the OS-owned channel methods, to invokeOsMethod, and reword
the comments that still described Go calls, the Go progress stream, the
Go metadata reader or a "native migration boundary" so they describe
the current backend. Channel method names and reply keys are unchanged.
2026-10-18 23:01:04 +07:00
zarzet fcec0942b9 refactor(android): drop SDK checks below minSdk 24
Flutter 3.47.7 sets flutter.minSdkVersion to 24, which
android/app/build.gradle.kts uses as minSdk. The N (24) checks around
StorageManager.storageVolumes and the LOLLIPOP (21) check around
finishAndRemoveTask were therefore always true, and their else branches
could never run. Keep the true-branch bodies. Checks for API levels
above 24 are unchanged.
2026-10-18 23:01:04 +07:00
zarzet 8aca5e4ef2 refactor(android): drop unreachable dispatch cases and dead channel handlers
RustCoreBackend.invokeApplication handled readFileMetadata,
editFileMetadata and cancelNativeDataJob, but MainActivity intercepts
all three first: the metadata methods are in nativeBackendMethods and
dispatchBackendApplication answers cancelNativeDataJob before it calls
invokeApplication. No Kotlin code calls invokeApplication with those
names.

Dart never sends these channel methods, so their handlers go on every
platform:

- shareMultipleContentUris (Android) and getAvailableLyricsProviders
  (Android and iOS) have no Dart caller.
- scanLibraryFolderIncrementalFromSnapshot and
  scanSafTreeIncrementalFromSnapshot are called only from the Dart host
  branch of the library scan, which runs only when
  supportsCoreBackend is false, that is never on Android or iOS. The
  unreachable Dart wrappers are removed separately.

The allowlist and the when cases in MainActivity stay in sync (70
names). The UniFFI exports get_available_lyrics_providers_json and
scan_library_folder_incremental_from_snapshot were used only by the
removed handlers; the backend methods behind them stay.
2026-10-18 23:01:04 +07:00
zarzet ca950dc35a refactor(android): remove backend switches that became constants
Rust is the only backend, so several single-backend switches had become
constants and their other branches could never run:

- CoreBackend.supportsOutputDescriptors was always false. The
  descriptor branch in SafDownloadHandler and its pfd/detachFd cleanup
  never ran, and the Rust planner rejects output_fd anyway.
- routesApplication was always true on Android and iOS. Drop the member,
  the "go" value of getBackendImplementations (the reply keys and the
  "rust" value Dart receives are unchanged), the iOS routing guard and
  the interface defaults that threw for unrouted methods.
- cleanupExtensions(), waitForDownloadProgressDelta and
  scanCueForLibrary had no production caller. Dart reaches cleanup
  through the cleanupExtensions channel method, and RustCoreBackend
  overrides openDownloadProgress, so the polling default goes too.

The UniFFI exports DownloadState.wait_progress_delta and
ExtensionManager.scan_cue_file_for_library were used only by those
Kotlin overrides. Bindings are generated at build time by
scripts/build_rust_backend.sh; no generated binding is tracked.
2026-10-18 23:01:04 +07:00
zarzet 66d480dbdc fix(storage): retain legacy Android cipher migration support 2026-10-18 04:09:16 +07:00
zarzet 75cd4c39b2 feat(android): refresh launcher widgets with adaptive expressive layouts 2026-10-18 03:10:40 +07:00
zarzet e0dfa7eb69 refactor(android): scope Rust download state handles consistently 2026-10-18 00:46:53 +07:00
zarzet 504c3cd18b refactor(android): share native album artist resolution 2026-10-18 00:46:10 +07:00
zarzet fdcd291c78 refactor(android): remove unreachable backend dispatch fallbacks 2026-10-18 00:46:09 +07:00
zarzet 3d11169f21 fix(network): request Android 17 local network access before NAS connections 2026-10-17 16:18:41 +07:00
zarzet 11c6cf9915 feat(player): synchronize music haptics with local playback 2026-10-17 16:18:37 +07:00
zarzet 40f65d3a4d feat(player): show audio source processing and output details 2026-10-17 16:18:32 +07:00
zarzet 3dc2d69051 fix(audio): preserve FLAC precision in Android bit-perfect playback 2026-10-15 00:28:17 +07:00
zarzet c0fd506c78 fix(storage): preserve audio MIME when publishing SAF downloads
Honor the requested MIME across publication paths, retain the audio suffix in temporary names, and exclude unfinished documents from full and incremental scans. Verify MIME and byte integrity across four formats and publication modes.
2026-10-13 19:38:11 +07:00
zarzet 186c66aeb8 fix(lyrics): refresh LRC sidecars in their actual SAF folder
Resolve opaque SAF document ancestry before writing adjacent lyrics. Propagate failed requested LRC writes and cover native word-synced refresh in regression tests.
2026-10-13 19:38:00 +07:00
zarzet e3b69a25ef fix(download): probe M4A streams before preserving requested FLAC
Provider and decryption extensions describe the downloaded container, not
its audio codec. A decrypted M4A/MP4 can still carry FLAC, so a requested
FLAC output now reaches the codec probe instead of being preserved early.
Lossy streams keep their native container and still receive metadata.
2026-10-13 18:27:16 +07:00
zarzet ac8523d789 feat(metadata): add per-field download tag separators 2026-10-12 12:11:06 +07:00
zarzet ebaa6c5c1e test(android): accept validated FLAC fallback across FFmpeg versions 2026-10-11 16:14:01 +07:00
zarzet d611590039 chore(android): update Gradle Kotlin NDK and native build dependencies 2026-10-11 14:33:52 +07:00
zarzet 1b9c35f322 fix(downloads): preserve browser verification and queues across restarts 2026-10-09 18:07:49 +07:00
zarzet 37258a6160 fix(setup): recover folder permissions after Android restarts 2026-10-09 18:07:38 +07:00
zarzet c7b1d0b0ec fix(metadata): preserve original artwork resolution for SAF files 2026-10-09 10:34:49 +07:00
zarzet 2ded1cff68 perf(downloads): batch queue cancellation and progress cleanup 2026-10-08 08:47:47 +07:00
zarzet c67d2a2dd2 perf(downloads): batch cancellation resets for retry 2026-10-08 06:55:26 +07:00
zarzet 6325c4769c fix(downloads): preserve actual provider audio format 2026-10-08 01:50:36 +07:00
zarzet d1de833184 perf(library): index scans and snapshots with native SQLite workers
Move full and incremental ingestion, source snapshots, path keys, and download exclusion to native transactions. Preserve schema 17, FTS, WAL coordination, cancellation, and Android SAF timestamp backfill.
2026-10-06 23:29:33 +07:00
zarzet d693e1a479 perf(theme): extract cover palettes with native quantization
Port the pinned Material quantizer and Dart RNG compatibility to Rust while keeping Material Score and final color schemes in Dart. Include exact palette fixtures, licenses, and Kotlin worker ABI coverage.
2026-10-06 23:27:38 +07:00
zarzet 867371cb67 feat(native): add cancellable data workers and streamed file hashing
Introduce Android, iOS, and Dart worker dispatch with queued cancellation, binary inputs, and background JSON codecs. Move APK verification to streamed native SHA256 while retaining the isolated fallback.
2026-10-06 23:25:39 +07:00
zarzet ca747f8ce2 fix(android): release temporary media on failed SAF operations 2026-10-06 22:00:44 +07:00
zarzet f61e815e24 perf(android): trim platform assets and release Dart symbols 2026-10-06 21:58:55 +07:00
zarzet b8c50b1527 perf(android): reduce release APK size
Keep Dart debug data outside libapp.so and archive matching symbols and R8 mappings in CI. Pack native relocations, preserve JNI exports, and recompress PNG assets losslessly.

ARM64 APK shrinks from 80,306,680 to 76,080,247 bytes (5.26%). Verified with 1,877 Flutter tests, 19 native device tests, Discord SDK integration, and release startup on a 16 KiB Android emulator.
2026-10-06 15:22:42 +07:00
zarzet b8787168d1 refactor(downloads): isolate typed results and audio finalization 2026-10-06 13:09:26 +07:00
zarzet 7493c37698 refactor(android): isolate native download history persistence 2026-10-06 13:08:14 +07:00
zarzet d98ab4852d fix(library): distinguish unavailable storage from missing files 2026-10-06 13:08:12 +07:00
zarzet 772bd97f7d fix(downloads): preserve filenames after decryption and conversion 2026-10-06 00:04:14 +07:00
zarzet 5f0577837d perf(widget): publish artwork only for installed consumers 2026-10-04 01:41:55 +07:00
zarzet c69f2cef9f perf(library): scan SAF CUE audio through live descriptors 2026-10-04 01:41:35 +07:00
zarzet 4e20102bdd perf(usb): reuse PCM buffers and respect native ring capacity 2026-10-04 01:40:59 +07:00
zarzet 9c0b22e2c8 feat(build): require Discord in production and keep Lite opt-in 2026-10-04 01:40:54 +07:00
zarzet 541bfc4002 perf(media): shrink FFmpeg while preserving HTTPS motion artwork 2026-10-04 01:35:48 +07:00
zarzet f035538778 fix(library): expose failed scan files and reasons in app logs 2026-10-03 17:57:35 +07:00
zarzet e35a3cbb84 fix(library): scan remote SAF folders when root metadata is unavailable 2026-10-03 13:40:39 +07:00