Move time tracking into a CompositionLocal (#493)

## Description
Creates a `CompositionLocal` which tracks the current time in a single
place and is usable anywhere in the app.

Can be used such as:
```kotlin
val now = LocalClock.current.now
val details = remember(item, now) {
  // Create detail strings based the item and current time
  // This will be recomposed/updated whenever the time changes
}
```

### Related issues
Related to #475
This commit is contained in:
Ray 2025-12-17 13:25:36 -05:00 committed by GitHub
parent 2908f539e2
commit 7581b05b97
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 54 additions and 24 deletions

View file

@ -47,6 +47,7 @@ import com.github.damontecres.wholphin.ui.launchIO
import com.github.damontecres.wholphin.ui.nav.ApplicationContent import com.github.damontecres.wholphin.ui.nav.ApplicationContent
import com.github.damontecres.wholphin.ui.nav.Destination import com.github.damontecres.wholphin.ui.nav.Destination
import com.github.damontecres.wholphin.ui.theme.WholphinTheme import com.github.damontecres.wholphin.ui.theme.WholphinTheme
import com.github.damontecres.wholphin.ui.util.ProvideLocalClock
import com.github.damontecres.wholphin.util.DebugLogTree import com.github.damontecres.wholphin.util.DebugLogTree
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@ -222,6 +223,7 @@ class MainActivity : AppCompatActivity() {
) )
} }
} }
ProvideLocalClock {
ApplicationContent( ApplicationContent(
user = current?.user, user = current?.user,
server = current?.server, server = current?.server,
@ -237,6 +239,7 @@ class MainActivity : AppCompatActivity() {
} }
} }
} }
}
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()

View file

@ -3,33 +3,18 @@ package com.github.damontecres.wholphin.ui.components
import androidx.compose.foundation.layout.BoxScope import androidx.compose.foundation.layout.BoxScope
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.tv.material3.MaterialTheme import androidx.tv.material3.MaterialTheme
import androidx.tv.material3.Text import androidx.tv.material3.Text
import com.github.damontecres.wholphin.ui.TimeFormatter import com.github.damontecres.wholphin.ui.util.LocalClock
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
import java.time.LocalTime
@Composable @Composable
fun BoxScope.TimeDisplay(modifier: Modifier = Modifier) { fun BoxScope.TimeDisplay(modifier: Modifier = Modifier) {
var now by remember { mutableStateOf(LocalTime.now()) }
LaunchedEffect(Unit) {
while (isActive) {
now = LocalTime.now()
delay(1000L)
}
}
Text( Text(
text = TimeFormatter.format(now), text = LocalClock.current.timeString,
fontSize = 18.sp, fontSize = 18.sp,
color = MaterialTheme.colorScheme.onSurface, color = MaterialTheme.colorScheme.onSurface,
modifier = modifier =

View file

@ -0,0 +1,42 @@
package com.github.damontecres.wholphin.ui.util
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.compositionLocalOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import com.github.damontecres.wholphin.ui.TimeFormatter
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
import java.time.LocalDateTime
val LocalClock = compositionLocalOf<Clock> { throw IllegalStateException() }
/**
* Represents the current time
*/
data class Clock(
/**
* The current [LocalDateTime]
*/
val now: LocalDateTime,
/**
* The current time formatted as a string with [TimeFormatter]
*/
val timeString: String,
)
@Composable
fun ProvideLocalClock(content: @Composable () -> Unit) {
var clock by remember { mutableStateOf(LocalDateTime.now().let { Clock(it, TimeFormatter.format(it)) }) }
LaunchedEffect(Unit) {
while (isActive) {
clock = LocalDateTime.now().let { Clock(it, TimeFormatter.format(it)) }
delay(1_000)
}
}
CompositionLocalProvider(LocalClock provides clock, content)
}