mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2025-04-08 20:08:06 +02:00
Moves lastread routes to mutableStateFlow
This commit is contained in:
parent
6c81fbbcf9
commit
239f973e89
@ -349,9 +349,15 @@ object LocalPreferences {
|
||||
putInt(PrefKeys.PROXY_PORT, account.proxyPort)
|
||||
putBoolean(PrefKeys.WARN_ABOUT_REPORTS, account.warnAboutPostsWithReports)
|
||||
putBoolean(PrefKeys.FILTER_SPAM_FROM_STRANGERS, account.filterSpamFromStrangers)
|
||||
|
||||
val regularMap =
|
||||
account.lastReadPerRoute.value.mapValues {
|
||||
it.value.value
|
||||
}
|
||||
|
||||
putString(
|
||||
PrefKeys.LAST_READ_PER_ROUTE,
|
||||
Event.mapper.writeValueAsString(account.lastReadPerRoute),
|
||||
Event.mapper.writeValueAsString(regularMap),
|
||||
)
|
||||
putStringSet(PrefKeys.HAS_DONATED_IN_VERSION, account.hasDonatedInVersion)
|
||||
|
||||
@ -611,9 +617,10 @@ object LocalPreferences {
|
||||
val lastReadPerRoute =
|
||||
try {
|
||||
getString(PrefKeys.LAST_READ_PER_ROUTE, null)?.let {
|
||||
Event.mapper.readValue<Map<String, Long>?>(it)
|
||||
}
|
||||
?: mapOf()
|
||||
Event.mapper.readValue<Map<String, Long>?>(it)?.mapValues {
|
||||
MutableStateFlow(it.value)
|
||||
}
|
||||
} ?: mapOf()
|
||||
} catch (e: Throwable) {
|
||||
if (e is CancellationException) throw e
|
||||
Log.w(
|
||||
@ -669,7 +676,7 @@ object LocalPreferences {
|
||||
showSensitiveContent = MutableStateFlow(showSensitiveContent),
|
||||
warnAboutPostsWithReports = warnAboutReports,
|
||||
filterSpamFromStrangers = filterSpam,
|
||||
lastReadPerRoute = lastReadPerRoute,
|
||||
lastReadPerRoute = MutableStateFlow(lastReadPerRoute),
|
||||
hasDonatedInVersion = hasDonatedInVersion,
|
||||
pendingAttestations = MutableStateFlow(pendingAttestations ?: emptyMap()),
|
||||
)
|
||||
|
@ -202,7 +202,7 @@ class Account(
|
||||
var showSensitiveContent: MutableStateFlow<Boolean?> = MutableStateFlow(null),
|
||||
var warnAboutPostsWithReports: Boolean = true,
|
||||
var filterSpamFromStrangers: Boolean = true,
|
||||
var lastReadPerRoute: Map<String, Long> = mapOf<String, Long>(),
|
||||
var lastReadPerRoute: MutableStateFlow<Map<String, MutableStateFlow<Long>>> = MutableStateFlow(mapOf()),
|
||||
var hasDonatedInVersion: Set<String> = setOf<String>(),
|
||||
var pendingAttestations: MutableStateFlow<Map<HexKey, String>> = MutableStateFlow<Map<HexKey, String>>(mapOf()),
|
||||
val scope: CoroutineScope = Amethyst.instance.applicationIOScope,
|
||||
@ -3213,9 +3213,15 @@ class Account(
|
||||
route: String,
|
||||
timestampInSecs: Long,
|
||||
): Boolean {
|
||||
val lastTime = lastReadPerRoute[route]
|
||||
return if (lastTime == null || timestampInSecs > lastTime) {
|
||||
lastReadPerRoute = lastReadPerRoute + Pair(route, timestampInSecs)
|
||||
val lastTime = lastReadPerRoute.value[route]
|
||||
return if (lastTime == null) {
|
||||
lastReadPerRoute.update {
|
||||
it + Pair(route, MutableStateFlow(timestampInSecs))
|
||||
}
|
||||
saveable.invalidateData()
|
||||
true
|
||||
} else if (timestampInSecs > lastTime.value) {
|
||||
lastTime.tryEmit(timestampInSecs)
|
||||
saveable.invalidateData()
|
||||
true
|
||||
} else {
|
||||
@ -3223,7 +3229,16 @@ class Account(
|
||||
}
|
||||
}
|
||||
|
||||
fun loadLastRead(route: String): Long = lastReadPerRoute[route] ?: 0
|
||||
fun loadLastRead(route: String): Long = lastReadPerRoute.value[route]?.value ?: 0
|
||||
|
||||
fun loadLastReadFlow(route: String): StateFlow<Long> =
|
||||
lastReadPerRoute.value[route] ?: run {
|
||||
val newFlow = MutableStateFlow<Long>(0)
|
||||
lastReadPerRoute.update {
|
||||
it + Pair(route, newFlow)
|
||||
}
|
||||
newFlow
|
||||
}
|
||||
|
||||
fun hasDonatedInThisVersion(): Boolean = hasDonatedInVersion.contains(BuildConfig.VERSION_NAME)
|
||||
|
||||
|
@ -50,7 +50,6 @@ import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.Alignment
|
||||
@ -387,8 +386,6 @@ private fun RenderChannel(
|
||||
loadRobohash: Boolean,
|
||||
onClick: () -> Unit,
|
||||
) {
|
||||
val hasNewMessages = remember { mutableStateOf(false) }
|
||||
|
||||
ChannelName(
|
||||
channelIdHex = item.idHex,
|
||||
channelPicture = item.profilePicture(),
|
||||
@ -400,7 +397,7 @@ private fun RenderChannel(
|
||||
},
|
||||
channelLastTime = null,
|
||||
channelLastContent = item.summary(),
|
||||
hasNewMessages,
|
||||
hasNewMessages = false,
|
||||
onClick = onClick,
|
||||
loadProfilePicture = loadProfilePicture,
|
||||
loadRobohash = loadRobohash,
|
||||
|
@ -33,7 +33,6 @@ import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
@ -54,6 +53,7 @@ import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.text.withStyle
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import androidx.lifecycle.distinctUntilChanged
|
||||
import androidx.lifecycle.map
|
||||
import com.patrykandpatrick.vico.core.extension.forEachIndexedExtended
|
||||
@ -171,15 +171,14 @@ private fun ChannelRoomCompose(
|
||||
.observeAsState()
|
||||
val authorName = remember(note, authorState) { authorState?.user?.toBestDisplayName() }
|
||||
|
||||
val chanHex = remember { channel.idHex }
|
||||
|
||||
val channelState by channel.live.observeAsState()
|
||||
val channelPicture by remember(note, channelState) { derivedStateOf { channel.profilePicture() } }
|
||||
val channelName by remember(note, channelState) { derivedStateOf { channel.toBestDisplayName() } }
|
||||
|
||||
val channelPicture = channelState?.channel?.profilePicture() ?: channel.profilePicture()
|
||||
val channelName = channelState?.channel?.toBestDisplayName() ?: channel.toBestDisplayName()
|
||||
|
||||
val noteEvent = note.event
|
||||
|
||||
val route = remember(note) { "Channel/$chanHex" }
|
||||
val route = "Channel/${channel.idHex}"
|
||||
|
||||
val description =
|
||||
if (noteEvent is ChannelCreateEvent) {
|
||||
@ -190,21 +189,15 @@ private fun ChannelRoomCompose(
|
||||
noteEvent?.content()?.take(200)
|
||||
}
|
||||
|
||||
val hasNewMessages = remember { mutableStateOf<Boolean>(false) }
|
||||
|
||||
WatchNotificationChanges(note, route, accountViewModel) { newHasNewMessages ->
|
||||
if (hasNewMessages.value != newHasNewMessages) {
|
||||
hasNewMessages.value = newHasNewMessages
|
||||
}
|
||||
}
|
||||
val lastReadTime by accountViewModel.account.loadLastReadFlow(route).collectAsStateWithLifecycle()
|
||||
|
||||
ChannelName(
|
||||
channelIdHex = chanHex,
|
||||
channelIdHex = channel.idHex,
|
||||
channelPicture = channelPicture,
|
||||
channelTitle = { modifier -> ChannelTitleWithLabelInfo(channelName, modifier) },
|
||||
channelLastTime = remember(note) { note.createdAt() },
|
||||
channelLastContent = remember(note, authorState) { "$authorName: $description" },
|
||||
hasNewMessages = hasNewMessages,
|
||||
channelLastTime = note.createdAt(),
|
||||
channelLastContent = "$authorName: $description",
|
||||
hasNewMessages = (noteEvent?.createdAt() ?: Long.MIN_VALUE) > lastReadTime,
|
||||
loadProfilePicture = accountViewModel.settings.showProfilePictures.value,
|
||||
loadRobohash = accountViewModel.settings.featureSet != FeatureSetType.PERFORMANCE,
|
||||
onClick = { nav(route) },
|
||||
@ -257,17 +250,9 @@ private fun UserRoomCompose(
|
||||
accountViewModel: AccountViewModel,
|
||||
nav: (String) -> Unit,
|
||||
) {
|
||||
val hasNewMessages = remember { mutableStateOf<Boolean>(false) }
|
||||
val route = "Room/${room.hashCode()}"
|
||||
|
||||
val route = remember(room) { "Room/${room.hashCode()}" }
|
||||
|
||||
val createAt by remember(note) { derivedStateOf { note.createdAt() } }
|
||||
|
||||
WatchNotificationChanges(note, route, accountViewModel) { newHasNewMessages ->
|
||||
if (hasNewMessages.value != newHasNewMessages) {
|
||||
hasNewMessages.value = newHasNewMessages
|
||||
}
|
||||
}
|
||||
val lastReadTime by accountViewModel.account.loadLastReadFlow(route).collectAsStateWithLifecycle()
|
||||
|
||||
LoadDecryptedContentOrNull(note, accountViewModel) { content ->
|
||||
ChannelName(
|
||||
@ -279,9 +264,9 @@ private fun UserRoomCompose(
|
||||
)
|
||||
},
|
||||
channelTitle = { RoomNameDisplay(room, it, accountViewModel) },
|
||||
channelLastTime = createAt,
|
||||
channelLastTime = note.createdAt(),
|
||||
channelLastContent = content,
|
||||
hasNewMessages = hasNewMessages,
|
||||
hasNewMessages = (note.createdAt() ?: Long.MIN_VALUE) > lastReadTime,
|
||||
onClick = { nav(route) },
|
||||
)
|
||||
}
|
||||
@ -412,20 +397,6 @@ fun ShortUsernameDisplay(
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun WatchNotificationChanges(
|
||||
note: Note,
|
||||
route: String,
|
||||
accountViewModel: AccountViewModel,
|
||||
onNewStatus: (Boolean) -> Unit,
|
||||
) {
|
||||
LaunchedEffect(key1 = note, accountViewModel.accountMarkAsReadUpdates.intValue) {
|
||||
note.event?.createdAt()?.let {
|
||||
onNewStatus(it > accountViewModel.account.loadLastRead(route))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun LoadUser(
|
||||
baseUserHex: String,
|
||||
@ -455,7 +426,7 @@ fun ChannelName(
|
||||
channelTitle: @Composable (Modifier) -> Unit,
|
||||
channelLastTime: Long?,
|
||||
channelLastContent: String?,
|
||||
hasNewMessages: MutableState<Boolean>,
|
||||
hasNewMessages: Boolean,
|
||||
loadProfilePicture: Boolean,
|
||||
loadRobohash: Boolean,
|
||||
onClick: () -> Unit,
|
||||
@ -485,7 +456,7 @@ fun ChannelName(
|
||||
channelTitle: @Composable (Modifier) -> Unit,
|
||||
channelLastTime: Long?,
|
||||
channelLastContent: String?,
|
||||
hasNewMessages: MutableState<Boolean>,
|
||||
hasNewMessages: Boolean,
|
||||
onClick: () -> Unit,
|
||||
) {
|
||||
ChatHeaderLayout(
|
||||
@ -514,7 +485,7 @@ fun ChannelName(
|
||||
)
|
||||
}
|
||||
|
||||
if (hasNewMessages.value) {
|
||||
if (hasNewMessages) {
|
||||
NewItemsBubble()
|
||||
}
|
||||
},
|
||||
|
@ -27,7 +27,6 @@ import android.util.LruCache
|
||||
import androidx.compose.runtime.Immutable
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
@ -150,7 +149,6 @@ class AccountViewModel(
|
||||
Dao {
|
||||
val accountLiveData: LiveData<AccountState> = account.live.map { it }
|
||||
val accountLanguagesLiveData: LiveData<AccountState> = account.liveLanguages.map { it }
|
||||
val accountMarkAsReadUpdates = mutableIntStateOf(0)
|
||||
|
||||
// TODO: contact lists are not notes yet
|
||||
// val kind3Relays: StateFlow<ContactListEvent?> = observeByAuthor(ContactListEvent.KIND, account.signer.pubKey)
|
||||
@ -1121,7 +1119,6 @@ class AccountViewModel(
|
||||
|
||||
suspend fun refreshMarkAsReadObservers() {
|
||||
updateNotificationDots()
|
||||
accountMarkAsReadUpdates.value++
|
||||
}
|
||||
|
||||
fun loadAndMarkAsRead(
|
||||
|
@ -380,8 +380,6 @@ private fun DisplaySearchResults(
|
||||
val channels by searchBarViewModel.searchResultsChannels.collectAsStateWithLifecycle()
|
||||
val notes by searchBarViewModel.searchResultsNotes.collectAsStateWithLifecycle()
|
||||
|
||||
val hasNewMessages = remember { mutableStateOf(false) }
|
||||
|
||||
LazyColumn(
|
||||
modifier = Modifier.fillMaxHeight(),
|
||||
contentPadding = FeedPadding,
|
||||
@ -425,7 +423,7 @@ private fun DisplaySearchResults(
|
||||
},
|
||||
channelLastTime = null,
|
||||
channelLastContent = item.summary(),
|
||||
hasNewMessages = hasNewMessages,
|
||||
hasNewMessages = false,
|
||||
loadProfilePicture = accountViewModel.settings.showProfilePictures.value,
|
||||
loadRobohash = accountViewModel.settings.featureSet != FeatureSetType.PERFORMANCE,
|
||||
onClick = { nav("Channel/${item.idHex}") },
|
||||
|
Loading…
x
Reference in New Issue
Block a user