fix(app-glasses): scale на паузе — принудительная перерисовка кадра
На паузе ExoPlayer не шлёт кадры — поверхность меняла размер/позицию, но кадр оставался старым (часть видео не видно). requestRedraw(): updateTexImage + drawFrame для всех outputs — вызывается при смене scale (LaunchedEffect) и в surfaceChanged. Подтверждено на железе.
This commit is contained in:
@@ -16,6 +16,7 @@ import pw.binom.viewmate.core.protocol.DownloadFiles
|
||||
import pw.binom.viewmate.core.protocol.MediaCommandMsg
|
||||
import pw.binom.viewmate.core.protocol.PlayVideo
|
||||
import pw.binom.viewmate.core.protocol.SetMode
|
||||
import pw.binom.viewmate.core.protocol.SetScale
|
||||
import pw.binom.viewmate.core.protocol.ShowText
|
||||
|
||||
/**
|
||||
@@ -102,6 +103,8 @@ class PhoneActions(
|
||||
|
||||
val title = item.Name ?: itemId
|
||||
sender.send(PlayVideo(itemId = itemId, title = title, videoUrl = localVideoPath, audioIndex = audioIndex))
|
||||
// очки не помнят scale между запусками — при старте просмотра шлём текущий
|
||||
if (state.scale != 1f) sender.send(SetScale(state.scale))
|
||||
state.mode = GlassesMode.MOVIE
|
||||
state.currentItem = item
|
||||
state.currentAudioIndex = audioIndex
|
||||
@@ -253,5 +256,12 @@ class PhoneActions(
|
||||
return "команда медиа: $cmd${if (seekMs != 0L) " ($seekMs мс)" else ""}"
|
||||
}
|
||||
|
||||
/** Масштаб экрана очков: SetScale (0.5..1.0). */
|
||||
suspend fun applyScale(scale: Float): String {
|
||||
val clamped = scale.coerceIn(0.5f, 1f)
|
||||
sender.send(SetScale(clamped))
|
||||
return "масштаб → $clamped"
|
||||
}
|
||||
|
||||
private fun ticksToMinutes(ticks: Long): Long = ticks / 10_000_000 / 60
|
||||
}
|
||||
|
||||
@@ -29,6 +29,16 @@ class PhoneState {
|
||||
log("state", "режим → $value")
|
||||
}
|
||||
|
||||
private val _scale = MutableStateFlow(1f)
|
||||
val scaleFlow: StateFlow<Float> = _scale.asStateFlow()
|
||||
/** Масштаб экрана очков (0.5..1.0); слайдер пульта пишет сюда же. */
|
||||
var scale: Float
|
||||
get() = _scale.value
|
||||
set(value) {
|
||||
_scale.value = value.coerceIn(0.5f, 1f)
|
||||
log("state", "масштаб → $value")
|
||||
}
|
||||
|
||||
private val _currentItem = MutableStateFlow<JellyfinItem?>(null)
|
||||
val currentItemFlow: StateFlow<JellyfinItem?> = _currentItem.asStateFlow()
|
||||
var currentItem: JellyfinItem?
|
||||
|
||||
@@ -75,3 +75,8 @@ data class ShowText(val text: String, val sessionId: String? = null) : HostToGla
|
||||
@Serializable
|
||||
@SerialName("chat_session")
|
||||
data class ChatSessionMsg(val sessionId: String, val title: String) : HostToGlasses
|
||||
|
||||
/** Масштаб экрана очков (0.5..1.0); 1.0 — на весь экран. */
|
||||
@Serializable
|
||||
@SerialName("set_scale")
|
||||
data class SetScale(val scale: Float) : HostToGlasses
|
||||
|
||||
@@ -45,6 +45,16 @@ class HostToGlassesTest {
|
||||
assertEquals(GlassesMode.MOVIE, decoded.mode)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun setScaleRoundTrip() {
|
||||
val msg: HostToGlasses = SetScale(scale = 0.7f)
|
||||
val text = json.encodeToString(HostToGlasses.serializer(), msg)
|
||||
assertEquals("""{"type":"set_scale","scale":0.7}""", text)
|
||||
val decoded = json.decodeFromString(HostToGlasses.serializer(), text)
|
||||
assertIs<SetScale>(decoded)
|
||||
assertEquals(0.7f, decoded.scale)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun mediaCommandRoundTrip() {
|
||||
val msg: HostToGlasses = MediaCommandMsg(command = MediaCommand.SEEK_FORWARD, seekMs = 30_000)
|
||||
|
||||
Reference in New Issue
Block a user