Scroll the guide a row early and show which channels are in view (0.53.0)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -9,8 +9,8 @@ android {
|
||||
applicationId = "tv.orbit.classic"
|
||||
minSdk = 26
|
||||
targetSdk = 36
|
||||
versionCode = 53
|
||||
versionName = "0.52.0-grid-rework"
|
||||
versionCode = 54
|
||||
versionName = "0.53.0-guide-scroll-hint"
|
||||
}
|
||||
buildFeatures { compose = true }
|
||||
compileOptions { sourceCompatibility = JavaVersion.VERSION_17; targetCompatibility = JavaVersion.VERSION_17 }
|
||||
|
||||
@@ -41,7 +41,7 @@ internal class HttpsEmbyTransport(internal val deviceId: String = UUID.randomUUI
|
||||
connection.connectTimeout = 10_000
|
||||
connection.readTimeout = request.readTimeoutMs ?: if (request.path == "/Sessions/Logout") 5_000 else 15_000
|
||||
connection.setRequestProperty("Accept", "application/json")
|
||||
connection.setRequestProperty("X-Emby-Authorization", "Emby Client=\"Orbit TV\", Device=\"Orbit TV\", DeviceId=\"$deviceId\", Version=\"0.52.0\"")
|
||||
connection.setRequestProperty("X-Emby-Authorization", "Emby Client=\"Orbit TV\", Device=\"Orbit TV\", DeviceId=\"$deviceId\", Version=\"0.53.0\"")
|
||||
request.token?.let { connection.setRequestProperty("X-Emby-Token", it) }
|
||||
if (request.method == "POST") {
|
||||
val bytes = request.body.orEmpty().toByteArray(Charsets.UTF_8)
|
||||
|
||||
@@ -73,12 +73,13 @@ internal fun guideCellTime(startMs: Long, endMs: Long, nowMs: Long) = when {
|
||||
private val GuideChannelColumn = Color(0xFF0A1B3C)
|
||||
private val GuidePast = Color(0xFF0D2247)
|
||||
|
||||
/** The first row to draw, moving only as far as it takes to keep the chosen row on screen. */
|
||||
/** The first row to draw. It moves a row before the edge, so there's always a sign of the next channel. */
|
||||
internal fun guideFirstRow(row: Int, first: Int, visible: Int, count: Int): Int {
|
||||
val last = (count - visible).coerceAtLeast(0)
|
||||
val margin = if (visible >= 3) 1 else 0
|
||||
return when {
|
||||
row < first -> row
|
||||
row >= first + visible -> row - visible + 1
|
||||
row < first + margin -> row - margin
|
||||
row > first + visible - 1 - margin -> row - visible + 1 + margin
|
||||
else -> first
|
||||
}.coerceIn(0, last)
|
||||
}
|
||||
@@ -101,6 +102,7 @@ internal fun GuideGrid(channels: List<SampleChannel>, selectedNumber: Int, modif
|
||||
var cursor by remember { mutableLongStateOf(now) }
|
||||
var slotsAhead by remember { mutableIntStateOf(0) }
|
||||
var firstRow by remember { mutableIntStateOf(0) }
|
||||
var rowsShown by remember { mutableIntStateOf(0) }
|
||||
val gridFocus = remember { FocusRequester() }
|
||||
var gridFocused by remember { mutableStateOf(true) }
|
||||
LaunchedEffect(Unit) { gridFocus.requestFocus() }
|
||||
@@ -142,6 +144,7 @@ internal fun GuideGrid(channels: List<SampleChannel>, selectedNumber: Int, modif
|
||||
BoxWithConstraints(Modifier.fillMaxWidth().weight(1f)) {
|
||||
val visibleRows = ((maxHeight + 3.dp) / 41.dp).toInt().coerceAtLeast(1)
|
||||
firstRow = guideFirstRow(row, firstRow, visibleRows, channels.size)
|
||||
rowsShown = minOf(visibleRows, channels.size)
|
||||
Column(Modifier.fillMaxWidth().focusRequester(gridFocus).onFocusChanged { gridFocused = it.isFocused }.focusable().onPreviewKeyEvent { event ->
|
||||
val native = event.nativeKeyEvent
|
||||
if (native.action != KeyEvent.ACTION_DOWN) return@onPreviewKeyEvent false
|
||||
@@ -193,6 +196,6 @@ internal fun GuideGrid(channels: List<SampleChannel>, selectedNumber: Int, modif
|
||||
}
|
||||
}
|
||||
}
|
||||
Text("▲▼ Channel ◄► Time Hold ◄► Day OK Watch Back Home", color = Muted, fontSize = 11.sp)
|
||||
Text("▲▼ Channel ◄► Time Hold ◄► Day OK Watch Back Home${if (rowsShown < channels.size) " • Channels ${firstRow + 1} to ${firstRow + rowsShown} of ${channels.size}" else ""}", color = Muted, fontSize = 11.sp)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ internal class SecureMediaDataSource(private val session: EmbySampleSession) : B
|
||||
next.instanceFollowRedirects = false
|
||||
next.connectTimeout = 10_000
|
||||
next.readTimeout = 20_000
|
||||
next.setRequestProperty("User-Agent", "OrbitTV/0.52.0")
|
||||
next.setRequestProperty("User-Agent", "OrbitTV/0.53.0")
|
||||
next.setRequestProperty("Accept-Encoding", "identity")
|
||||
session.mediaHeaders(address).forEach { (key, value) -> next.setRequestProperty(key, value) }
|
||||
if (dataSpec.position != 0L || dataSpec.length != C.LENGTH_UNSET.toLong()) {
|
||||
|
||||
@@ -86,9 +86,9 @@ class GuideGridTest {
|
||||
@Test
|
||||
fun theGridScrollsOnlyWhenTheChosenRowLeavesTheScreen() {
|
||||
assertEquals(0, guideFirstRow(3, 0, 8, 25))
|
||||
assertEquals(1, guideFirstRow(8, 0, 8, 25))
|
||||
assertEquals(2, guideFirstRow(8, 0, 8, 25))
|
||||
assertEquals(5, guideFirstRow(9, 5, 8, 25))
|
||||
assertEquals(4, guideFirstRow(4, 5, 8, 25))
|
||||
assertEquals(3, guideFirstRow(4, 5, 8, 25))
|
||||
assertEquals(17, guideFirstRow(24, 10, 8, 25))
|
||||
}
|
||||
|
||||
@@ -97,4 +97,12 @@ class GuideGridTest {
|
||||
assertEquals(0, guideFirstRow(2, 0, 8, 3))
|
||||
assertEquals(0, guideFirstRow(0, 4, 8, 3))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun theNextChannelIsAlwaysInSight() {
|
||||
assertEquals(1, guideFirstRow(1, 2, 6, 11))
|
||||
assertEquals(0, guideFirstRow(0, 1, 6, 11))
|
||||
assertEquals(1, guideFirstRow(5, 0, 6, 11))
|
||||
assertEquals(5, guideFirstRow(10, 0, 6, 11))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user