mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-03-27 10:11:48 -04:00
feat: Add "now" string and update formatAgo function (#4183)
Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com>
This commit is contained in:
@@ -1088,4 +1088,5 @@
|
||||
<string name="compass_uncertainty">Estimated area: \u00b1%1$s (\u00b1%2$s)</string>
|
||||
<string name="compass_uncertainty_unknown">Estimated area: unknown accuracy</string>
|
||||
<string name="mark_as_read">Mark as read</string>
|
||||
<string name="now">Now</string>
|
||||
</resources>
|
||||
|
||||
@@ -17,16 +17,38 @@
|
||||
package org.meshtastic.core.ui.util
|
||||
|
||||
import android.text.format.DateUtils
|
||||
import com.meshtastic.core.strings.getString
|
||||
import org.meshtastic.core.strings.Res
|
||||
import org.meshtastic.core.strings.now
|
||||
import java.lang.System.currentTimeMillis
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
import kotlin.time.Duration.Companion.minutes
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
|
||||
@Suppress("MagicNumber")
|
||||
fun formatAgo(lastSeenUnix: Int, currentTimeMillis: Long = System.currentTimeMillis()): String {
|
||||
val timeInMillis = lastSeenUnix * 1000L
|
||||
/**
|
||||
* Formats a given Unix timestamp (in seconds) into a relative "time ago" string.
|
||||
*
|
||||
* For durations less than a minute, it returns "now". For longer durations, it uses Android's
|
||||
* `DateUtils.getRelativeTimeSpanString` to generate a concise, localized, and abbreviated representation (e.g., "5m
|
||||
* ago", "2h ago").
|
||||
*
|
||||
* @param lastSeenUnixSeconds The Unix timestamp in seconds to be formatted.
|
||||
* @return A [String] representing the relative time that has passed.
|
||||
*/
|
||||
fun formatAgo(lastSeenUnixSeconds: Int): String {
|
||||
val lastSeenDuration = lastSeenUnixSeconds.seconds
|
||||
val currentDuration = currentTimeMillis().milliseconds
|
||||
val diff = (currentDuration - lastSeenDuration).absoluteValue
|
||||
|
||||
return DateUtils.getRelativeTimeSpanString(
|
||||
timeInMillis,
|
||||
currentTimeMillis,
|
||||
DateUtils.SECOND_IN_MILLIS,
|
||||
DateUtils.FORMAT_ABBREV_RELATIVE,
|
||||
)
|
||||
.toString()
|
||||
return if (diff < 1.minutes) {
|
||||
getString(Res.string.now)
|
||||
} else {
|
||||
DateUtils.getRelativeTimeSpanString(
|
||||
lastSeenDuration.inWholeMilliseconds,
|
||||
currentDuration.inWholeMilliseconds,
|
||||
DateUtils.MINUTE_IN_MILLIS,
|
||||
DateUtils.FORMAT_ABBREV_RELATIVE,
|
||||
)
|
||||
.toString()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,14 +34,13 @@ import org.meshtastic.core.ui.util.formatAgo
|
||||
fun LastHeardInfo(
|
||||
modifier: Modifier = Modifier,
|
||||
lastHeard: Int,
|
||||
currentTimeMillis: Long,
|
||||
contentColor: Color = MaterialTheme.colorScheme.onSurface,
|
||||
) {
|
||||
IconInfo(
|
||||
modifier = modifier,
|
||||
icon = ImageVector.vectorResource(id = R.drawable.ic_antenna_24),
|
||||
contentDescription = stringResource(Res.string.node_sort_last_heard),
|
||||
text = formatAgo(lastHeard, currentTimeMillis),
|
||||
text = formatAgo(lastHeard),
|
||||
contentColor = contentColor,
|
||||
)
|
||||
}
|
||||
@@ -49,10 +48,5 @@ fun LastHeardInfo(
|
||||
@PreviewLightDark
|
||||
@Composable
|
||||
private fun LastHeardInfoPreview() {
|
||||
AppTheme {
|
||||
LastHeardInfo(
|
||||
lastHeard = (System.currentTimeMillis() / 1000).toInt() - 8600,
|
||||
currentTimeMillis = System.currentTimeMillis(),
|
||||
)
|
||||
}
|
||||
AppTheme { LastHeardInfo(lastHeard = (System.currentTimeMillis() / 1000).toInt() - 8600) }
|
||||
}
|
||||
|
||||
@@ -74,7 +74,6 @@ fun NodeItem(
|
||||
modifier: Modifier = Modifier,
|
||||
onClick: () -> Unit = {},
|
||||
onLongClick: (() -> Unit)? = null,
|
||||
currentTimeMillis: Long,
|
||||
connectionState: ConnectionState,
|
||||
isActive: Boolean = false,
|
||||
) {
|
||||
@@ -137,11 +136,7 @@ fun NodeItem(
|
||||
textDecoration = TextDecoration.LineThrough.takeIf { isIgnored },
|
||||
softWrap = true,
|
||||
)
|
||||
LastHeardInfo(
|
||||
lastHeard = thatNode.lastHeard,
|
||||
currentTimeMillis = currentTimeMillis,
|
||||
contentColor = contentColor,
|
||||
)
|
||||
LastHeardInfo(lastHeard = thatNode.lastHeard, contentColor = contentColor)
|
||||
NodeStatusIcons(
|
||||
isThisNode = isThisNode,
|
||||
isFavorite = isFavorite,
|
||||
@@ -228,14 +223,7 @@ fun NodeInfoSimplePreview() {
|
||||
AppTheme {
|
||||
val thisNode = NodePreviewParameterProvider().values.first()
|
||||
val thatNode = NodePreviewParameterProvider().values.last()
|
||||
NodeItem(
|
||||
thisNode = thisNode,
|
||||
thatNode = thatNode,
|
||||
0,
|
||||
true,
|
||||
currentTimeMillis = System.currentTimeMillis(),
|
||||
connectionState = ConnectionState.Connected,
|
||||
)
|
||||
NodeItem(thisNode = thisNode, thatNode = thatNode, 0, true, connectionState = ConnectionState.Connected)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -249,7 +237,6 @@ fun NodeInfoPreview(@PreviewParameter(NodePreviewParameterProvider::class) thatN
|
||||
thatNode = thatNode,
|
||||
distanceUnits = 1,
|
||||
tempInFahrenheit = true,
|
||||
currentTimeMillis = System.currentTimeMillis(),
|
||||
connectionState = ConnectionState.Connected,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -78,7 +78,6 @@ import org.meshtastic.core.strings.unmute
|
||||
import org.meshtastic.core.ui.component.AddContactFAB
|
||||
import org.meshtastic.core.ui.component.MainAppBar
|
||||
import org.meshtastic.core.ui.component.ScrollToTopEvent
|
||||
import org.meshtastic.core.ui.component.rememberTimeTickWithLifecycle
|
||||
import org.meshtastic.core.ui.component.smartScrollToTop
|
||||
import org.meshtastic.core.ui.theme.StatusColors.StatusRed
|
||||
import org.meshtastic.feature.node.component.NodeActionDialogs
|
||||
@@ -115,7 +114,6 @@ fun NodeListScreen(
|
||||
}
|
||||
}
|
||||
|
||||
val currentTimeMillis = rememberTimeTickWithLifecycle()
|
||||
val connectionState by viewModel.connectionState.collectAsStateWithLifecycle()
|
||||
|
||||
val isScrollInProgress by remember {
|
||||
@@ -224,7 +222,6 @@ fun NodeListScreen(
|
||||
tempInFahrenheit = state.tempInFahrenheit,
|
||||
onClick = { navigateToNodeDetails(node.num) },
|
||||
onLongClick = longClick,
|
||||
currentTimeMillis = currentTimeMillis,
|
||||
connectionState = connectionState,
|
||||
isActive = isActive,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user