From 1f05886873ca19339c4adf19ae7cb99d7d9d5a7f Mon Sep 17 00:00:00 2001 From: James Rich <2199651+jamesarich@users.noreply.github.com> Date: Sun, 4 Aug 2024 05:47:48 -0500 Subject: [PATCH] Fix: Periodically update last heard time (#1178) --- .../com/geeksville/mesh/ui/LastHeardInfo.kt | 16 ++++++-- .../java/com/geeksville/mesh/ui/NodeInfo.kt | 13 +++++-- .../com/geeksville/mesh/ui/UsersFragment.kt | 38 ++++++++++++++++++- .../com/geeksville/mesh/util/Extensions.kt | 20 +++++----- 4 files changed, 66 insertions(+), 21 deletions(-) diff --git a/app/src/main/java/com/geeksville/mesh/ui/LastHeardInfo.kt b/app/src/main/java/com/geeksville/mesh/ui/LastHeardInfo.kt index 5d559c3d9..cf711b5a0 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/LastHeardInfo.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/LastHeardInfo.kt @@ -7,6 +7,9 @@ import androidx.compose.material.Icon import androidx.compose.material.MaterialTheme import androidx.compose.material.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector @@ -20,8 +23,10 @@ import com.geeksville.mesh.util.formatAgo @Composable fun LastHeardInfo( modifier: Modifier = Modifier, - lastHeard: Int + lastHeard: Int, + currentTimeMillis: Long, ) { + Row( modifier = modifier, verticalAlignment = Alignment.CenterVertically, @@ -34,7 +39,7 @@ fun LastHeardInfo( tint = MaterialTheme.colors.onSurface, ) Text( - text = formatAgo(lastHeard), + text = formatAgo(lastHeard, currentTimeMillis), color = MaterialTheme.colors.onSurface, fontSize = MaterialTheme.typography.button.fontSize ) @@ -45,6 +50,9 @@ fun LastHeardInfo( @Composable fun LastHeardInfoPreview() { AppTheme { - LastHeardInfo(lastHeard = (System.currentTimeMillis() / 1000).toInt() - 8600) + LastHeardInfo( + lastHeard = (System.currentTimeMillis() / 1000).toInt() - 8600, + currentTimeMillis = System.currentTimeMillis() + ) } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/geeksville/mesh/ui/NodeInfo.kt b/app/src/main/java/com/geeksville/mesh/ui/NodeInfo.kt index b336cb67c..1ba57f18b 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/NodeInfo.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/NodeInfo.kt @@ -73,6 +73,7 @@ fun NodeInfo( chipClicked: () -> Unit = {}, blinking: Boolean = false, expanded: Boolean = false, + currentTimeMillis: Long, ) { val unknownShortName = stringResource(id = R.string.unknown_node_short_name) val unknownLongName = stringResource(id = R.string.unknown_username) @@ -157,7 +158,8 @@ fun NodeInfo( ) LastHeardInfo( - lastHeard = thatNodeInfo.lastHeard + lastHeard = thatNodeInfo.lastHeard, + currentTimeMillis = currentTimeMillis ) } Row( @@ -273,7 +275,8 @@ fun NodeInfoSimplePreview() { thatNodeInfo = thatNodeInfo, 1, 0, - true + true, + currentTimeMillis = System.currentTimeMillis() ) } } @@ -300,7 +303,8 @@ fun NodeInfoPreview( gpsFormat = 0, distanceUnits = 1, tempInFahrenheit = true, - expanded = false + expanded = false, + currentTimeMillis = System.currentTimeMillis() ) Text( text = "Details Shown", @@ -312,7 +316,8 @@ fun NodeInfoPreview( gpsFormat = 0, distanceUnits = 1, tempInFahrenheit = true, - expanded = true + expanded = true, + currentTimeMillis = System.currentTimeMillis() ) } } diff --git a/app/src/main/java/com/geeksville/mesh/ui/UsersFragment.kt b/app/src/main/java/com/geeksville/mesh/ui/UsersFragment.kt index c22464801..a1b0c8364 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/UsersFragment.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/UsersFragment.kt @@ -1,6 +1,7 @@ package com.geeksville.mesh.ui import android.os.Bundle +import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -17,12 +18,17 @@ import androidx.compose.material.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableLongStateOf +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.platform.ComposeView import androidx.compose.ui.platform.ViewCompositionStrategy import androidx.compose.ui.unit.dp import androidx.fragment.app.activityViewModels import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.LifecycleResumeEffect import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.geeksville.mesh.NodeInfo import com.geeksville.mesh.R @@ -31,13 +37,15 @@ import com.geeksville.mesh.model.UIViewModel import com.geeksville.mesh.ui.components.NodeFilterTextField import com.geeksville.mesh.ui.theme.AppTheme import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.delay +import kotlin.time.Duration.Companion.minutes @AndroidEntryPoint class UsersFragment : ScreenFragment("Users"), Logging { private val model: UIViewModel by activityViewModels() - private fun popup(node: NodeInfo) { + private fun popup(node: NodeInfo) { if (!model.isConnected()) return val isOurNode = node.num == model.myNodeNum val ignoreIncomingList = model.ignoreIncomingList @@ -136,6 +144,8 @@ fun NodesScreen( } } + val currentTimeMillis = getCurrentTimeMillisWithLifecycle() + LazyColumn( state = listState, modifier = Modifier.fillMaxSize(), @@ -173,8 +183,32 @@ fun NodesScreen( isIgnored = state.ignoreIncomingList.contains(node.num), chipClicked = { chipClicked(node) }, blinking = node == focusedNode, - expanded = state.showDetails + expanded = state.showDetails, + currentTimeMillis = currentTimeMillis ) } } } + +@Composable +private fun getCurrentTimeMillisWithLifecycle(): Long { + var currentTimeMillis by remember { mutableLongStateOf(System.currentTimeMillis()) } + var running by remember { mutableStateOf(false) } + LaunchedEffect(running) { + if (running) { + while (true) { + delay(1.minutes) + currentTimeMillis = System.currentTimeMillis() + Log.d("NodesScreen", "NodesScreen: $currentTimeMillis") + } + } + } + + LifecycleResumeEffect(Unit) { + running = true + onPauseOrDispose { + running = false + } + } + return currentTimeMillis +} diff --git a/app/src/main/java/com/geeksville/mesh/util/Extensions.kt b/app/src/main/java/com/geeksville/mesh/util/Extensions.kt index e39c24e08..373983a25 100644 --- a/app/src/main/java/com/geeksville/mesh/util/Extensions.kt +++ b/app/src/main/java/com/geeksville/mesh/util/Extensions.kt @@ -31,18 +31,16 @@ fun Any.toPIIString() = fun ByteArray.toHexString() = joinToString("") { "%02x".format(it) } -fun formatAgo(lastSeenUnix: Int): String { - val currentTime = (System.currentTimeMillis() / 1000).toInt() +fun formatAgo(lastSeenUnix: Int, currentTimeMillis: Long = System.currentTimeMillis()): String { + val currentTime = (currentTimeMillis / 1000).toInt() val diffMin = (currentTime - lastSeenUnix) / 60 - if (diffMin < 1) - return "now" - if (diffMin < 60) - return diffMin.toString() + " min" - if (diffMin < 2880) - return (diffMin / 60).toString() + " h" - if (diffMin < 1440000) - return (diffMin / (60 * 24)).toString() + " d" - return "?" + return when { + diffMin < 1 -> "now" + diffMin < 60 -> diffMin.toString() + " min" + diffMin < 2880 -> (diffMin / 60).toString() + " h" + diffMin < 1440000 -> (diffMin / (60 * 24)).toString() + " d" + else -> "?" + } } /// Allows usage like email.onEditorAction(EditorInfo.IME_ACTION_NEXT, { confirm() })