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