Fix time desync if animation scale is not 1

This commit is contained in:
MM20 2024-04-08 18:08:42 +02:00
parent 7d945019b5
commit cdf161f377
No known key found for this signature in database
GPG Key ID: 0B61A8F2DEAFA389

View File

@ -1,13 +1,9 @@
package de.mm20.launcher2.ui.base
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.LinearEasing
import androidx.compose.animation.core.snap
import androidx.compose.animation.core.tween
import android.os.Handler
import android.os.Looper
import android.os.SystemClock
import android.util.Log
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.LaunchedEffect
@ -16,13 +12,15 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableLongStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.awaitCancellation
import java.time.Instant
import java.time.ZoneId
import kotlin.math.max
/**
* Provide the current time (in millis) to the LocalTime composition local.
@ -31,64 +29,38 @@ import java.time.ZoneId
@Composable
fun ProvideCurrentTime(content: @Composable () -> Unit) {
val context = LocalContext.current
val lifecycleOwner = LocalLifecycleOwner.current
var time by remember { mutableLongStateOf(System.currentTimeMillis()) }
val secondsAnimation = remember { Animatable(0f) }
LaunchedEffect(time) {
val currentTime = System.currentTimeMillis()
val seconds = Instant
.ofEpochMilli(currentTime)
.atZone(ZoneId.systemDefault()).second
val millis = (currentTime % 1000).toInt()
secondsAnimation.animateTo(seconds.toFloat() + millis / 1000f, snap())
secondsAnimation.animateTo(
60f,
tween(
(60 - seconds) * 1000 - millis,
delayMillis = millis,
easing = LinearEasing
)
)
}
val lifecycleOwner = LocalLifecycleOwner.current
LaunchedEffect(null) {
lifecycleOwner.lifecycle.repeatOnLifecycle(Lifecycle.State.RESUMED) {
val dateTime = Instant.ofEpochMilli(System.currentTimeMillis())
.atZone(ZoneId.systemDefault())
.withSecond(0)
.withNano(0)
val handler = Handler(Looper.getMainLooper())
val runnable = object : Runnable {
override fun run() {
val dateTime = Instant.now().atZone(ZoneId.systemDefault())
time = dateTime.toEpochSecond() * 1000
time = dateTime.toEpochSecond() * 1000
val receiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
val dt = Instant.ofEpochMilli(System.currentTimeMillis())
.atZone(ZoneId.systemDefault())
.withSecond(0)
.withNano(0)
time = dt.toEpochSecond() * 1000
}
val millis = dateTime.nano / 1000000L
var next = 1000L - millis
if (next <= 200L) next += 1000L
handler.postDelayed(this, 1000 - millis)
}
context.registerReceiver(receiver, IntentFilter().apply {
addAction(Intent.ACTION_TIME_CHANGED)
addAction(Intent.ACTION_TIME_TICK)
})
}
lifecycleOwner.repeatOnLifecycle(Lifecycle.State.RESUMED) {
handler.post(runnable)
try {
awaitCancellation()
} finally {
context.unregisterReceiver(receiver)
} catch (e: CancellationException) {
handler.removeCallbacks(runnable)
}
}
}
CompositionLocalProvider(
LocalTime provides time + secondsAnimation.value.toInt() * 1000,
LocalTime provides time,
content = content
)
}