Add sleep-safe activity window

This commit is contained in:
Kris
2026-08-17 21:37:57 -04:00
parent cb39e5482d
commit 0db0feba84
2 changed files with 274 additions and 14 deletions
@@ -52,7 +52,8 @@ import kotlinx.coroutines.delay
@Composable
fun TouchGrassActivityScreen(
lcdDark: Color,
onGrassTap: () -> Unit
onGrassTap: () -> Unit,
statusText: String = "Pet is taking time alone."
) {
var grassFingerColumn by remember { mutableIntStateOf(-1) }
var grassWaveTick by remember { mutableIntStateOf(0) }
@@ -127,7 +128,7 @@ fun TouchGrassActivityScreen(
)
Text(
text = "Pet is taking time alone.",
text = statusText,
color = lcdDark,
textAlign = TextAlign.Center
)
@@ -139,7 +140,8 @@ fun WatchTvActivityScreen(
lcdDark: Color,
selectedChannel: TvChannel,
weatherLabel: String,
onChannelSelected: (TvChannel) -> Unit
onChannelSelected: (TvChannel) -> Unit,
statusText: String = "Pet is outside having alone time."
) {
var tvFrame by remember { mutableIntStateOf(0) }
var tvPowerState by remember { mutableIntStateOf(1) }
@@ -459,7 +461,7 @@ fun WatchTvActivityScreen(
}
Text(
text = "Pet is outside having alone time.",
text = statusText,
color = lcdDark,
textAlign = TextAlign.Center
)
@@ -671,6 +671,7 @@ fun Greeting(name: String, modifier: Modifier = Modifier) {
var testWantMenuOpen by remember { mutableStateOf(false) }
var testBondMenuOpen by remember { mutableStateOf(false) }
var downtimeMode by remember { mutableStateOf(DowntimeMode.None) }
var sleepWakeConfirm by remember { mutableStateOf(false) }
var selectedTvChannel by remember { mutableStateOf(TvChannel.Weather) }
var currentWant by remember { mutableStateOf("") }
@@ -2290,6 +2291,8 @@ fun Greeting(name: String, modifier: Modifier = Modifier) {
}
fun wakeFromAutoSleep() {
if (isSleeping && sleepMode == "Auto") {
sleepWakeConfirm = false
downtimeMode = DowntimeMode.None
val sleptOutside = location == "Outside"
val startedAtMs = if (autoSleepStartedAtMs > 0L) autoSleepStartedAtMs else System.currentTimeMillis()
val sleptMs = (System.currentTimeMillis() - startedAtMs).coerceAtLeast(0L)
@@ -2334,6 +2337,39 @@ fun Greeting(name: String, modifier: Modifier = Modifier) {
}
}
fun wakeFromManualNap() {
if (isSleeping && sleepMode == "Nap") {
sleepWakeConfirm = false
downtimeMode = DowntimeMode.None
roughWakeDarkFlash = true
activityMood = "Asleep"
frameProp = ""
framePropAnimation = ""
framePropStyle = 0
saveScope.launch {
delay(if (testingMode) 1_500L else 1_200L)
if (isSleeping && sleepMode == "Nap") {
isSleeping = false
sleepMode = ""
autoSleepStartedAtMs = 0L
restoredManualNap = false
roughWakeDarkFlash = false
roughWakeNervousHold = false
status = "Nervous"
activityMood = "RoughWake"
roughWakeAlert = true
frameProp = "!?!"
framePropAnimation = ""
framePropStyle = 0
happiness = (happiness - 1).coerceAtLeast(0)
}
}
}
}
val currentNeedsPetName by rememberUpdatedState(needsPetName)
val currentSaveLoaded by rememberUpdatedState(saveLoaded)
val currentLocation by rememberUpdatedState(location)
@@ -3895,6 +3931,8 @@ fun Greeting(name: String, modifier: Modifier = Modifier) {
sickCount = 0
}
sleepWakeConfirm = false
downtimeMode = DowntimeMode.None
isSleeping = false
sleepMode = ""
autoSleepStartedAtMs = 0L
@@ -4833,13 +4871,18 @@ fun Greeting(name: String, modifier: Modifier = Modifier) {
verticalArrangement = Arrangement.Center
) {
val downtimeActive =
testingMode && downtimeMode != DowntimeMode.None
!isSleeping && downtimeMode != DowntimeMode.None
val downtimeTitle = when {
testingMode && downtimeMode == DowntimeMode.TouchGrass -> "TOUCH GRASS"
testingMode && downtimeMode == DowntimeMode.WatchTv -> "WATCH TV"
else -> ""
}
val downtimeTitle =
if (isSleeping) {
""
} else {
when (downtimeMode) {
DowntimeMode.TouchGrass -> "TOUCH GRASS"
DowntimeMode.WatchTv -> "WATCH TV"
DowntimeMode.None -> ""
}
}
if (downtimeTitle.isNotEmpty()) {
Text(
@@ -4864,17 +4907,29 @@ fun Greeting(name: String, modifier: Modifier = Modifier) {
)
)
if (testingMode && downtimeMode == DowntimeMode.TouchGrass) {
if (!isSleeping && downtimeMode == DowntimeMode.TouchGrass) {
TouchGrassActivityScreen(
lcdDark = petFrameForeground,
onGrassTap = {}
onGrassTap = {},
statusText =
if (isSleeping) {
"$displayPetName is sleeping."
} else {
"Pet is taking time alone."
}
)
} else if (testingMode && downtimeMode == DowntimeMode.WatchTv) {
} else if (!isSleeping && downtimeMode == DowntimeMode.WatchTv) {
WatchTvActivityScreen(
lcdDark = petFrameForeground,
selectedChannel = selectedTvChannel,
weatherLabel = weather,
onChannelSelected = { selectedTvChannel = it }
onChannelSelected = { selectedTvChannel = it },
statusText =
if (isSleeping) {
"$displayPetName is sleeping."
} else {
"Pet is outside having alone time."
}
)
} else {
Text(
@@ -5532,6 +5587,209 @@ fun Greeting(name: String, modifier: Modifier = Modifier) {
"RecoverWeak"
)
if (isSleeping) {
androidx.compose.ui.window.Popup(
alignment = Alignment.TopCenter,
properties = androidx.compose.ui.window.PopupProperties(
focusable = true
)
) {
Box(
modifier = Modifier
.width(configuration.screenWidthDp.dp)
.height(configuration.screenHeightDp.dp)
.background(petHomeBackground)
.border(2.dp, petFrameForeground)
.padding(screenPadding)
) {
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
text = "$displayPetName is sleeping.",
fontWeight = FontWeight.Bold,
color = petFrameForeground,
textAlign = TextAlign.Center,
modifier = Modifier.fillMaxWidth()
)
Spacer(modifier = Modifier.height(12.dp))
LCDSubMenuFrame(lcdDark = petFrameForeground) {
LCDSubButton(
text = "TOUCH GRASS",
modifier = Modifier.weight(1f),
fillWidthFraction = 1f,
enabled = !roughWakeDarkFlash,
lcdDark = petFrameForeground,
lcdFaded = lcdFaded,
onClick = {
downtimeMode = DowntimeMode.TouchGrass
}
)
LCDSubButton(
text = "WATCH TV",
modifier = Modifier.weight(1f),
fillWidthFraction = 1f,
enabled = !roughWakeDarkFlash,
lcdDark = petFrameForeground,
lcdFaded = lcdFaded,
onClick = {
downtimeMode = DowntimeMode.WatchTv
}
)
}
Spacer(modifier = Modifier.height(12.dp))
Box(
modifier = Modifier
.weight(1f)
.fillMaxWidth(),
contentAlignment = Alignment.Center
) {
when (downtimeMode) {
DowntimeMode.TouchGrass -> {
TouchGrassActivityScreen(
lcdDark = petFrameForeground,
onGrassTap = {},
statusText = "$displayPetName is sleeping."
)
}
DowntimeMode.WatchTv -> {
WatchTvActivityScreen(
lcdDark = petFrameForeground,
selectedChannel = selectedTvChannel,
weatherLabel = weather,
onChannelSelected = {
selectedTvChannel = it
},
statusText = "$displayPetName is sleeping."
)
}
DowntimeMode.None -> {
Column(
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
text = petArt,
fontSize = 24.sp,
lineHeight = 24.sp,
fontFamily = FontFamily.Monospace,
textAlign = TextAlign.Center,
color = petFrameForeground
)
Spacer(modifier = Modifier.height(12.dp))
Text(
text = "ZzZ",
fontWeight = FontWeight.Bold,
color = petFrameForeground
)
}
}
}
}
Spacer(modifier = Modifier.height(12.dp))
LCDMenuButton(
text = "EXIT QUIETLY",
enabled = !roughWakeDarkFlash,
lcdDark = petFrameForeground,
lcdFaded = lcdFaded,
onClick = {
downtimeMode = DowntimeMode.None
(context as? android.app.Activity)
?.moveTaskToBack(true)
}
)
LCDMenuButton(
text = "WAKE ${displayPetName.uppercase()}",
enabled = !roughWakeDarkFlash,
lcdDark = petFrameForeground,
lcdFaded = lcdFaded,
onClick = {
sleepWakeConfirm = true
}
)
}
if (sleepWakeConfirm) {
Box(
modifier = Modifier
.matchParentSize()
.background(petHomeBackground),
contentAlignment = Alignment.Center
) {
Column(
modifier = Modifier
.fillMaxWidth()
.padding(24.dp),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(12.dp)
) {
Text(
text = "ARE YOU SURE?",
fontWeight = FontWeight.Bold,
color = petFrameForeground,
textAlign = TextAlign.Center
)
Text(
text = "Wake $displayPetName?",
color = petFrameForeground,
textAlign = TextAlign.Center
)
LCDSubMenuFrame(
lcdDark = petFrameForeground
) {
LCDSubButton(
text = "CANCEL",
modifier = Modifier.weight(1f),
fillWidthFraction = 1f,
enabled = true,
lcdDark = petFrameForeground,
lcdFaded = lcdFaded,
onClick = {
sleepWakeConfirm = false
}
)
LCDSubButton(
text = "WAKE",
modifier = Modifier.weight(1f),
fillWidthFraction = 1f,
enabled = true,
lcdDark = petFrameForeground,
lcdFaded = lcdFaded,
onClick = {
when (sleepMode) {
"Auto" ->
wakeFromAutoSleep()
"Nap" ->
wakeFromManualNap()
}
}
)
}
}
}
}
}
}
Spacer(modifier = Modifier.height(0.dp))
}
if (location == "Inside") {
LCDMenuButton(
text = if (careMenuOpen) "CARE ▲" else "CARE ▼",