fix(android): refresh uiState.isPlaying from remoteState during UPnP
android / Build + lint + test (push) Successful in 4m1s

This commit is contained in:
2026-06-03 23:08:32 -04:00
parent 87ad7f4dc2
commit 33285b53c6
@@ -63,6 +63,7 @@ class PlayerController @Inject constructor(
private val radio: RadioController, private val radio: RadioController,
private val playerFactory: PlayerFactory, private val playerFactory: PlayerFactory,
private val activeUpnpHolder: com.fabledsword.minstrel.player.output.ActiveUpnpHolder, private val activeUpnpHolder: com.fabledsword.minstrel.player.output.ActiveUpnpHolder,
private val remoteState: RemotePlayerState,
) { ) {
/** /**
@@ -471,10 +472,31 @@ class PlayerController @Inject constructor(
scope.launch(Dispatchers.Main.immediate) { scope.launch(Dispatchers.Main.immediate) {
while (isActive) { while (isActive) {
delay(POSITION_POLL_INTERVAL_MS) delay(POSITION_POLL_INTERVAL_MS)
if (!controller.isPlaying) continue // When UPnP is active, MediaController's cached state is stale --
uiStateInternal.value = uiStateInternal.value.copy( // remoteState.applyTransportPlaying() doesn't fire a Player.Listener
positionMs = controller.currentPosition.coerceAtLeast(0), // event, so onEvents never refreshes isPlaying / positionMs from
bufferedPositionMs = controller.bufferedPosition.coerceAtLeast(0), // the wrapped player. Read directly from remoteState here so the
// play/pause toggle and scrubber reflect Sonos's actual state.
val upnpActive = activeUpnpHolder.active.value != null
val effectiveIsPlaying =
if (upnpActive) remoteState.isPlaying else controller.isPlaying
val effectivePosition =
if (upnpActive) remoteState.positionMs else controller.currentPosition
val effectiveDuration =
if (upnpActive) remoteState.durationMs else controller.duration
val current = uiStateInternal.value
val newPos = effectivePosition.coerceAtLeast(0)
val newDur = effectiveDuration.coerceAtLeast(0)
val newBuf = controller.bufferedPosition.coerceAtLeast(0)
val changed = current.isPlaying != effectiveIsPlaying ||
current.positionMs != newPos ||
current.durationMs != newDur
if (!changed) continue
uiStateInternal.value = current.copy(
isPlaying = effectiveIsPlaying,
positionMs = newPos,
durationMs = newDur,
bufferedPositionMs = newBuf,
) )
} }
} }