disallow to disable guard during focus
docker / image (push) Failing after 24s
lint / ruff (push) Failing after 28s
tests / backend (push) Successful in 37s
tests / desktop (push) Successful in 22s
tests / android-core (push) Successful in 49s
tests / web (push) Successful in 1m20s
android / apk (push) Successful in 8m49s
docker / image (push) Failing after 24s
lint / ruff (push) Failing after 28s
tests / backend (push) Successful in 37s
tests / desktop (push) Successful in 22s
tests / android-core (push) Successful in 49s
tests / web (push) Successful in 1m20s
android / apk (push) Successful in 8m49s
This commit is contained in:
21 files changed
+481
-43
No files matched your search
@@ -39,7 +39,6 @@ data class BlockerRules(
|
||||
val blockedApps: List<String> = emptyList(),
|
||||
val killBlockedApps: Boolean = true,
|
||||
val schedule: List<BlockWindow> = emptyList(),
|
||||
val strict: Boolean = false,
|
||||
val notifyOnBlock: Boolean = true,
|
||||
) {
|
||||
companion object {
|
||||
@@ -246,6 +245,20 @@ fun evaluatePolicy(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The port of `guard_locked()`: whether the guard may be switched off right now.
|
||||
*
|
||||
* A free function rather than a field on [PolicyVerdict], because this is a verdict
|
||||
* about *editing* the rules and not about whether to block — and the two answers do
|
||||
* disagree: scheduled mode outside its window is `active = false`, `locked = true`.
|
||||
*
|
||||
* Any kind of interval counts, running or paused. Switching the guard *on* is never
|
||||
* locked, which is why "and the guard is on" is folded in here rather than left to
|
||||
* the screen.
|
||||
*/
|
||||
fun guardLocked(rules: BlockerRules, current: IntervalFacts?): Boolean =
|
||||
rules.enabled && current != null && current.isActiveStatus
|
||||
|
||||
/** Convenience for callers that only have an IANA zone id string. */
|
||||
fun zoneOrDefault(timezone: String?): ZoneId =
|
||||
runCatching { ZoneId.of(timezone?.trim().orEmpty()) }.getOrElse { ZoneId.systemDefault() }
|
||||
@@ -303,4 +303,42 @@ class BlockerTest {
|
||||
|
||||
assertEquals(listOf("reddit.com", "www.reddit.com", "m.reddit.com"), expandDomains(rules))
|
||||
}
|
||||
|
||||
// ---- the lock -----------------------------------------------------------
|
||||
// Parity with `blocker_service.guard_locked()`.
|
||||
|
||||
@Test
|
||||
fun `a live interval of any kind locks the guard on`() {
|
||||
val on = BlockerRules(enabled = true)
|
||||
assertTrue(guardLocked(on, working))
|
||||
assertTrue(guardLocked(on, IntervalFacts("work", "paused")))
|
||||
assertTrue(guardLocked(on, breaking))
|
||||
assertTrue(guardLocked(on, IntervalFacts("long_break", "paused")))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `nothing live leaves the guard switchable`() {
|
||||
val on = BlockerRules(enabled = true)
|
||||
assertFalse(guardLocked(on, null))
|
||||
assertFalse(guardLocked(on, IntervalFacts("work", "completed")))
|
||||
assertFalse(guardLocked(on, IntervalFacts("work", "abandoned")))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `a guard that is off is never locked, so it can always be switched on`() {
|
||||
assertFalse(guardLocked(BlockerRules(enabled = false), working))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `scheduled mode outside its window is inactive and still locked`() {
|
||||
// The distinction `active` cannot express: nothing is being blocked right now,
|
||||
// and the guard still must not be switched off before the window opens.
|
||||
val rules = BlockerRules(
|
||||
enabled = true,
|
||||
mode = "scheduled",
|
||||
schedule = listOf(BlockWindow("Work hours", "09:00", "18:00", listOf(0))),
|
||||
)
|
||||
assertFalse(evaluatePolicy(rules, working, at("2026-10-19", "20:00")).active)
|
||||
assertTrue(guardLocked(rules, working))
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user