Fix time desync if animation scale is not 1
This commit is contained in:
parent
7d945019b5
commit
cdf161f377
@ -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
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user