fix(android): scrobble respects 1/3 & 2/3 again; no settings flicker on open
Scrobble timing: at onMediaItemTransition ctrl.duration is still TIME_UNSET (→0), so getScrobbleDelayMs's third/two_thirds modes hit the 15s floor and scrobbled way too early (both Navidrome + our play-log). Use the song's KNOWN duration (song.duration), falling back to the player only if absent. Web was unaffected (it already used the song's duration). Settings flicker: the ViewModel started with default state (theme = Dark Ocean) and rendered a frame before DataStore emitted the real values, so the theme picker visibly jumped. Gate the form on a 'loaded' flag set after the first emit; show a spinner until then. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1 parent
0c7132a7f2
commit
711a084686
3 files changed
+16
-1
No files matched your search
@@ -315,7 +315,11 @@ class PlayerController(private val context: Context, private val repo: MusicRepo
|
||||
val mediaId = ctrl.currentMediaItem?.mediaId ?: return
|
||||
if (mediaId.startsWith("abs:")) return
|
||||
val song = queue.getOrNull(ctrl.currentMediaItemIndex) ?: return
|
||||
val dur = ctrl.duration.coerceAtLeast(0)
|
||||
// Use the song's KNOWN duration — at a media transition ctrl.duration is still
|
||||
// TIME_UNSET (→0), which collapsed the 1/3 / 2/3 modes to the 15s floor and scrobbled
|
||||
// far too early. Fall back to the player only if the song has no duration.
|
||||
val songDurMs = (song.duration?.toLong() ?: 0L) * 1000L
|
||||
val dur = if (songDurMs > 0) songDurMs else ctrl.duration.coerceAtLeast(0)
|
||||
scheduleScrobble(song, dur)
|
||||
scope.launch { runCatching { repo.saveLastSong(song) } }
|
||||
prefetchLyrics(song)
|
||||
|
||||
@@ -67,6 +67,15 @@ fun SettingsScreen(onOpenStats: () -> Unit = {}) {
|
||||
)
|
||||
}
|
||||
|
||||
// Wait for the persisted settings before drawing the form — otherwise the default state
|
||||
// (e.g. theme = Dark Ocean) flashes for a frame and then jumps to the real values.
|
||||
if (!state.loaded) {
|
||||
Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
|
||||
CircularProgressIndicator(color = NsAccent)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(12.dp),
|
||||
modifier = Modifier
|
||||
|
||||
@@ -35,6 +35,7 @@ data class SettingsUiState(
|
||||
val absUrl: String = "",
|
||||
val absApiKey: String = "",
|
||||
val absChapterTrackMode: Boolean = false,
|
||||
val loaded: Boolean = false,
|
||||
val isSaving: Boolean = false,
|
||||
val savedOk: Boolean = false,
|
||||
val error: String? = null,
|
||||
@@ -66,6 +67,7 @@ class SettingsViewModel(app: Application) : AndroidViewModel(app) {
|
||||
absUrl = s.absUrl,
|
||||
absApiKey = s.absApiKey,
|
||||
absChapterTrackMode = s.absChapterTrackMode,
|
||||
loaded = true,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user