mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-10-06 11:48:24 +00:00
fix: stabilize DVM heartbeat freshness state and label the offline dot
This commit is contained in:
+16
@@ -52,6 +52,7 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.semantics.Role
|
||||
import androidx.compose.ui.semantics.contentDescription
|
||||
import androidx.compose.ui.semantics.onClick
|
||||
import androidx.compose.ui.semantics.role
|
||||
import androidx.compose.ui.semantics.semantics
|
||||
@@ -71,6 +72,7 @@ import com.vitorpamplona.amethyst.commons.icons.symbols.Icon
|
||||
import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols
|
||||
import com.vitorpamplona.amethyst.commons.model.topNavFeeds.TopFilter
|
||||
import com.vitorpamplona.amethyst.commons.resources.Res
|
||||
import com.vitorpamplona.amethyst.commons.resources.dvm_offline
|
||||
import com.vitorpamplona.amethyst.commons.resources.feed_filter_select_an_option
|
||||
import com.vitorpamplona.amethyst.commons.resources.feed_filter_selected
|
||||
import com.vitorpamplona.amethyst.commons.resources.lack_location_permissions
|
||||
@@ -181,11 +183,18 @@ fun FeedFilterSpinner(
|
||||
val favoriteAlgoFeedAddress = (selected?.name as? FavoriteAlgoFeedName)?.note?.address
|
||||
if (favoriteAlgoFeedAddress != null) {
|
||||
val heartbeatFresh by rememberDvmHeartbeatFresh(favoriteAlgoFeedAddress, accountViewModel)
|
||||
val offlineLabel = stringRes(Res.string.dvm_offline)
|
||||
Text(
|
||||
text = if (heartbeatFresh) currentText else "$currentText \u2022",
|
||||
color = if (heartbeatFresh) Color.Unspecified else MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
modifier =
|
||||
if (heartbeatFresh) {
|
||||
Modifier
|
||||
} else {
|
||||
Modifier.semantics { contentDescription = "$currentText, $offlineLabel" }
|
||||
},
|
||||
)
|
||||
} else {
|
||||
Text(
|
||||
@@ -390,6 +399,7 @@ fun RenderOption(
|
||||
} else {
|
||||
true
|
||||
}
|
||||
val offlineLabel = stringRes(Res.string.dvm_offline)
|
||||
Text(
|
||||
text = if (heartbeatFresh) name else "$name \u2022",
|
||||
fontSize = Font14SP,
|
||||
@@ -399,6 +409,12 @@ fun RenderOption(
|
||||
} else {
|
||||
MaterialTheme.colorScheme.onSurfaceVariant
|
||||
},
|
||||
modifier =
|
||||
if (heartbeatFresh) {
|
||||
Modifier
|
||||
} else {
|
||||
Modifier.semantics { contentDescription = "$name, $offlineLabel" }
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+5
-6
@@ -78,19 +78,18 @@ fun rememberDvmHeartbeatFresh(
|
||||
}
|
||||
}
|
||||
|
||||
val resolved = heartbeatNote ?: return remember(heartbeatAddressTag) { mutableStateOf(false) }
|
||||
val observed =
|
||||
heartbeatNote?.let { observeNoteAndMap(it, accountViewModel) { it.event as? DvmHeartbeatEvent } }
|
||||
|
||||
val heartbeat by observeNoteAndMap(resolved, accountViewModel) { it.event as? DvmHeartbeatEvent }
|
||||
|
||||
var now by remember(resolved) { mutableLongStateOf(TimeUtils.now()) }
|
||||
LaunchedEffect(resolved) {
|
||||
var now by remember(heartbeatNote) { mutableLongStateOf(TimeUtils.now()) }
|
||||
LaunchedEffect(heartbeatNote) {
|
||||
while (isActive) {
|
||||
delay(HEARTBEAT_RECHECK_MILLIS)
|
||||
now = TimeUtils.now()
|
||||
}
|
||||
}
|
||||
|
||||
val beat = heartbeat
|
||||
val beat = observed?.value
|
||||
return rememberUpdatedState(beat != null && beat.isFreshAt(now))
|
||||
}
|
||||
|
||||
|
||||
+9
@@ -52,6 +52,7 @@ import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Alignment.Companion.BottomStart
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.semantics.contentDescription
|
||||
import androidx.compose.ui.semantics.semantics
|
||||
import androidx.compose.ui.text.Placeholder
|
||||
import androidx.compose.ui.text.PlaceholderVerticalAlign
|
||||
@@ -67,6 +68,7 @@ import com.vitorpamplona.amethyst.commons.icons.symbols.Icon
|
||||
import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols
|
||||
import com.vitorpamplona.amethyst.commons.model.AddressableNote
|
||||
import com.vitorpamplona.amethyst.commons.resources.Res
|
||||
import com.vitorpamplona.amethyst.commons.resources.dvm_offline
|
||||
import com.vitorpamplona.amethyst.commons.resources.favorite_dvms_add_more
|
||||
import com.vitorpamplona.amethyst.commons.resources.favorite_dvms_empty_cta
|
||||
import com.vitorpamplona.amethyst.commons.resources.favorite_dvms_empty_headline
|
||||
@@ -285,12 +287,19 @@ private fun FavoriteAlgoFeedRow(
|
||||
) {
|
||||
val heartbeatFresh by rememberDvmHeartbeatFresh(feedNote.address, accountViewModel)
|
||||
val displayName = card.name.ifBlank { feedNote.dTag() }
|
||||
val offlineLabel = stringRes(Res.string.dvm_offline)
|
||||
Text(
|
||||
text = if (heartbeatFresh) displayName else "$displayName \u2022",
|
||||
fontWeight = FontWeight.Bold,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
modifier =
|
||||
if (heartbeatFresh) {
|
||||
Modifier
|
||||
} else {
|
||||
Modifier.semantics { contentDescription = "$displayName, $offlineLabel" }
|
||||
},
|
||||
)
|
||||
card.description?.takeIf { it.isNotBlank() }?.let {
|
||||
Spacer(modifier = StdVertSpacer)
|
||||
|
||||
+6
-3
@@ -200,10 +200,13 @@ private fun AllFavoriteAlgoFeedsBanner(
|
||||
|
||||
if (addresses.isEmpty()) return
|
||||
|
||||
// Map every address to its freshness first (non-short-circuiting) so per-address
|
||||
// composable call sites stay stable instead of appearing/disappearing with freshness.
|
||||
val anyHeartbeatFresh =
|
||||
addresses.any { address ->
|
||||
rememberDvmHeartbeatFresh(address, accountViewModel).value
|
||||
}
|
||||
addresses
|
||||
.map { address ->
|
||||
rememberDvmHeartbeatFresh(address, accountViewModel).value
|
||||
}.any { it }
|
||||
if (!anyHeartbeatFresh) {
|
||||
BannerCard(modifier) {
|
||||
BannerMessageRow(
|
||||
|
||||
Reference in New Issue
Block a user