diff --git a/app-phone/src/main/kotlin/pw/binom/viewmate/phone/ui/DetailsScreen.kt b/app-phone/src/main/kotlin/pw/binom/viewmate/phone/ui/DetailsScreen.kt index c6f5913..214bd01 100644 --- a/app-phone/src/main/kotlin/pw/binom/viewmate/phone/ui/DetailsScreen.kt +++ b/app-phone/src/main/kotlin/pw/binom/viewmate/phone/ui/DetailsScreen.kt @@ -130,13 +130,20 @@ fun DetailsScreen( } fun onWatch() { - // звук уже играет — повторный тап не должен пересоздавать аудио-плеер. - // state.playing в guard НЕ включаем: он остаётся true после рестарта телефона - // (очки продолжают играть), когда аудио-плеер ещё не создан, и блокировал бы запуск звука. if (app.audioSync.isActive) { - log("watch", "пропущено: аудио-плеер уже активен (audioSync.isActive=true)") - scope.launch { snackbar.showSnackbar("уже играет") } - return + // Очки реально играют (позиция растёт) — повторный тап не должен + // пересоздавать звук. Если очки перезапустились/на паузе (позиция 0 + // или не играют) — старый аудио-плеер мёртв: сбрасываем и запускаем + // новый watch (звук пересоздастся с позиции очков). + val playing = app.state.playing + val positionMs = app.server.hub.positionMs.value ?: 0L + if (shouldSkipReWatch(playing, positionMs)) { + log("watch", "пропущено: аудио-плеер уже активен и очки играют (pos=$positionMs)") + scope.launch { snackbar.showSnackbar("уже играет") } + return + } + log("watch", "очки не играют (playing=$playing, pos=$positionMs) — сбрасываю аудио-плеер") + app.audioSync.stop() } if (!glassesFully) { log("watch", "пропущено: контент не скачан на очки (glassesFully=false)") @@ -590,6 +597,14 @@ private fun ConversionStatus( } } +/** + * Guard повторного тапа «Смотреть на очках» при живом аудио-плеере: пропускаем + * перезапуск звука только если очки реально играют (playing=true и позиция >0). + * Очки на паузе или перезапустились (позиция 0) — старый плеер мёртв, нужно сбросить и создать заново. + */ +internal fun shouldSkipReWatch(playing: Boolean, positionMs: Long): Boolean = + playing && positionMs > 0 + private fun detailMeta(item: JellyfinItem): String { val parts = mutableListOf() when (item.Type) { diff --git a/app-phone/src/test/kotlin/pw/binom/viewmate/phone/ui/ComponentsTest.kt b/app-phone/src/test/kotlin/pw/binom/viewmate/phone/ui/ComponentsTest.kt index fd6dbcb..00446e2 100644 --- a/app-phone/src/test/kotlin/pw/binom/viewmate/phone/ui/ComponentsTest.kt +++ b/app-phone/src/test/kotlin/pw/binom/viewmate/phone/ui/ComponentsTest.kt @@ -2,9 +2,26 @@ package pw.binom.viewmate.phone.ui import kotlin.test.Test import kotlin.test.assertEquals +import kotlin.test.assertFalse +import kotlin.test.assertTrue class ComponentsTest { + @Test + fun shouldSkipReWatchWhenPlayingWithPosition() { + assertTrue(shouldSkipReWatch(playing = true, positionMs = 42_000), "очки играют и позиция >0 — повторный тап пропускаем") + } + + @Test + fun shouldNotSkipReWatchWhenNotPlaying() { + assertFalse(shouldSkipReWatch(playing = false, positionMs = 42_000), "очки не играют — сбрасываем плеер и перезапускаем watch") + } + + @Test + fun shouldNotSkipReWatchWhenPositionZero() { + assertFalse(shouldSkipReWatch(playing = true, positionMs = 0), "позиция 0 — очки перезапустились/на паузе, старый плеер мёртв") + } + @Test fun bytesToSizeKilobytes() { assertEquals("512 КБ", bytesToSize(512 * 1024L))