mirror of
https://github.com/project-dorado/dorado-hd.git
synced 2026-10-12 02:21:19 +00:00
test(playback): pure sleep-timer math + controller uses it
Extracts deadline/remaining/expiry into SleepTimer with unit tests (arm, disarm, countdown clamp, expiry) so the M10 sleep timer is directly covered.
This commit is contained in:
@@ -281,9 +281,9 @@ class PlaybackController(
|
||||
cancelSleepTimer()
|
||||
return
|
||||
}
|
||||
sleepDeadlineElapsedMs = android.os.SystemClock.elapsedRealtime() + minutes * 60_000L
|
||||
sleepDeadlineElapsedMs = SleepTimer.deadlineMs(android.os.SystemClock.elapsedRealtime(), minutes)
|
||||
sleepActive = true
|
||||
_sleepRemainingMs.value = minutes * 60_000L
|
||||
_sleepRemainingMs.value = SleepTimer.remainingMs(sleepDeadlineElapsedMs, android.os.SystemClock.elapsedRealtime())
|
||||
}
|
||||
|
||||
fun cancelSleepTimer() {
|
||||
@@ -294,9 +294,9 @@ class PlaybackController(
|
||||
|
||||
private fun tickSleepTimer(player: MediaController) {
|
||||
if (!sleepActive) return
|
||||
val remaining = (sleepDeadlineElapsedMs - android.os.SystemClock.elapsedRealtime()).coerceAtLeast(0L)
|
||||
val remaining = SleepTimer.remainingMs(sleepDeadlineElapsedMs, android.os.SystemClock.elapsedRealtime())
|
||||
_sleepRemainingMs.value = remaining
|
||||
if (remaining > 0L) return
|
||||
if (!SleepTimer.expired(sleepDeadlineElapsedMs, android.os.SystemClock.elapsedRealtime())) return
|
||||
sleepActive = false
|
||||
// Fade out over a short window, then stop; restore volume for the
|
||||
// next manual play.
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.heretek.dorado_hd.media
|
||||
|
||||
/**
|
||||
* Pure sleep-timer math (post-device extension, canon §10). Kept free of
|
||||
* Android so arming/expiry is unit-testable.
|
||||
*/
|
||||
object SleepTimer {
|
||||
|
||||
/** Deadline for [minutes] from [elapsedNowMs]; 0 or less means disarmed. */
|
||||
fun deadlineMs(elapsedNowMs: Long, minutes: Int): Long =
|
||||
if (minutes <= 0) 0L else elapsedNowMs + minutes * 60_000L
|
||||
|
||||
/** Milliseconds left, never negative. A disarmed deadline yields 0. */
|
||||
fun remainingMs(deadlineMs: Long, elapsedNowMs: Long): Long {
|
||||
if (deadlineMs <= 0L) return 0L
|
||||
return (deadlineMs - elapsedNowMs).coerceAtLeast(0L)
|
||||
}
|
||||
|
||||
/** True once the deadline has passed (disarmed deadlines never expire). */
|
||||
fun expired(deadlineMs: Long, elapsedNowMs: Long): Boolean =
|
||||
deadlineMs > 0L && elapsedNowMs >= deadlineMs
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.heretek.dorado_hd
|
||||
|
||||
import com.heretek.dorado_hd.media.SleepTimer
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Test
|
||||
|
||||
class SleepTimerTest {
|
||||
|
||||
@Test
|
||||
fun `minutes arm a deadline and non-positive values disarm`() {
|
||||
assertEquals(30 * 60_000L, SleepTimer.deadlineMs(0L, 30))
|
||||
assertEquals(1_000L + 15 * 60_000L, SleepTimer.deadlineMs(1_000L, 15))
|
||||
assertEquals(0L, SleepTimer.deadlineMs(1_000L, 0))
|
||||
assertEquals(0L, SleepTimer.deadlineMs(1_000L, -5))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `remaining counts down and never goes negative`() {
|
||||
val deadline = SleepTimer.deadlineMs(0L, 2)
|
||||
assertEquals(120_000L, SleepTimer.remainingMs(deadline, 0L))
|
||||
assertEquals(60_000L, SleepTimer.remainingMs(deadline, 60_000L))
|
||||
assertEquals(0L, SleepTimer.remainingMs(deadline, 200_000L))
|
||||
assertEquals(0L, SleepTimer.remainingMs(0L, 5L))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `expiry fires at the deadline and never when disarmed`() {
|
||||
val deadline = SleepTimer.deadlineMs(10_000L, 1)
|
||||
assertFalse(SleepTimer.expired(deadline, 69_999L))
|
||||
assertTrue(SleepTimer.expired(deadline, 70_000L))
|
||||
assertTrue(SleepTimer.expired(deadline, 99_000L))
|
||||
assertFalse(SleepTimer.expired(0L, Long.MAX_VALUE))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user