From ce5106684f2a425db8d4e5dac75adeca2e01c227 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Sat, 17 Jun 2023 17:28:14 -0400 Subject: [PATCH] Moves the last seen time saved per route to an account property in order to speed up loading and facilitate multithreading in the app. --- .../amethyst/LocalPreferences.kt | 29 ++++--- .../amethyst/NotificationCache.kt | 53 ------------ .../vitorpamplona/amethyst/model/Account.kt | 17 +++- .../amethyst/ui/navigation/AppBottomBar.kt | 8 +- .../amethyst/ui/navigation/Routes.kt | 81 ++++++++++++++----- .../amethyst/ui/note/BadgeCompose.kt | 5 +- .../amethyst/ui/note/ChatroomCompose.kt | 13 +-- .../ui/note/ChatroomMessageCompose.kt | 5 +- .../amethyst/ui/note/MessageSetCompose.kt | 5 +- .../amethyst/ui/note/MultiSetCompose.kt | 5 +- .../amethyst/ui/note/NoteCompose.kt | 5 +- .../amethyst/ui/note/ZapUserSetCompose.kt | 5 +- .../ui/screen/ChatroomListFeedView.kt | 3 +- .../ui/screen/loggedIn/AccountViewModel.kt | 1 + 14 files changed, 115 insertions(+), 120 deletions(-) delete mode 100644 app/src/main/java/com/vitorpamplona/amethyst/NotificationCache.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt b/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt index 8ee3898e0..df3ec608d 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt @@ -64,6 +64,7 @@ private object PrefKeys { const val SHOW_SENSITIVE_CONTENT = "show_sensitive_content" const val WARN_ABOUT_REPORTS = "warn_about_reports" const val FILTER_SPAM_FROM_STRANGERS = "filter_spam_from_strangers" + const val LAST_READ_PER_ROUTE = "last_read_route_per_route" val LAST_READ: (String) -> String = { route -> "last_read_route_$route" } } @@ -223,6 +224,7 @@ object LocalPreferences { putInt(PrefKeys.PROXY_PORT, account.proxyPort) putBoolean(PrefKeys.WARN_ABOUT_REPORTS, account.warnAboutPostsWithReports) putBoolean(PrefKeys.FILTER_SPAM_FROM_STRANGERS, account.filterSpamFromStrangers) + putString(PrefKeys.LAST_READ_PER_ROUTE, gson.toJson(account.lastReadPerRoute)) if (account.showSensitiveContent == null) { remove(PrefKeys.SHOW_SENSITIVE_CONTENT) @@ -320,6 +322,18 @@ object LocalPreferences { val filterSpam = getBoolean(PrefKeys.FILTER_SPAM_FROM_STRANGERS, true) val warnAboutReports = getBoolean(PrefKeys.WARN_ABOUT_REPORTS, true) + val lastReadPerRoute = try { + getString(PrefKeys.LAST_READ_PER_ROUTE, null)?.let { + gson.fromJson( + it, + object : TypeToken>() {}.type + ) as Map + } ?: mapOf() + } catch (e: Throwable) { + e.printStackTrace() + mapOf() + } + val a = Account( loggedIn = Persona(privKey = privKey?.hexToByteArray(), pubKey = pubKey.hexToByteArray()), followingChannels = followingChannels, @@ -343,25 +357,14 @@ object LocalPreferences { proxyPort = proxyPort, showSensitiveContent = showSensitiveContent, warnAboutPostsWithReports = warnAboutReports, - filterSpamFromStrangers = filterSpam + filterSpamFromStrangers = filterSpam, + lastReadPerRoute = lastReadPerRoute ) return a } } - fun saveLastRead(route: String, timestampInSecs: Long) { - encryptedPreferences(currentAccount()).edit().apply { - putLong(PrefKeys.LAST_READ(route), timestampInSecs) - }.apply() - } - - fun loadLastRead(route: String): Long { - encryptedPreferences(currentAccount()).run { - return getLong(PrefKeys.LAST_READ(route), 0) - } - } - fun migrateSingleUserPrefs() { if (currentAccount() != null) return diff --git a/app/src/main/java/com/vitorpamplona/amethyst/NotificationCache.kt b/app/src/main/java/com/vitorpamplona/amethyst/NotificationCache.kt deleted file mode 100644 index 2d444ac77..000000000 --- a/app/src/main/java/com/vitorpamplona/amethyst/NotificationCache.kt +++ /dev/null @@ -1,53 +0,0 @@ -package com.vitorpamplona.amethyst - -import androidx.lifecycle.LiveData -import com.vitorpamplona.amethyst.ui.components.BundledUpdate -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.Job -import kotlinx.coroutines.launch - -object NotificationCache { - // TODO: This must be account-based - val lastReadByRoute = mutableMapOf() - - fun markAsRead(route: String, timestampInSecs: Long) { - val lastTime = lastReadByRoute[route] - if (lastTime == null || timestampInSecs > lastTime) { - lastReadByRoute.put(route, timestampInSecs) - - val scope = CoroutineScope(Job() + Dispatchers.IO) - scope.launch { - LocalPreferences.saveLastRead(route, timestampInSecs) - live.invalidateData() - } - } - } - - fun load(route: String): Long { - var lastTime = lastReadByRoute[route] - if (lastTime == null) { - lastTime = LocalPreferences.loadLastRead(route) - lastReadByRoute[route] = lastTime - } - return lastTime - } - - // Observers line up here. - val live: NotificationLiveData = NotificationLiveData(this) -} - -class NotificationLiveData(val cache: NotificationCache) : LiveData(NotificationState(cache)) { - // Refreshes observers in batches. - private val bundler = BundledUpdate(300, Dispatchers.IO) - - fun invalidateData() { - bundler.invalidate() { - if (hasActiveObservers()) { - postValue(NotificationState(cache)) - } - } - } -} - -class NotificationState(val cache: NotificationCache) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt b/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt index a446f2c0b..5a96fd013 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt @@ -70,13 +70,15 @@ class Account( var proxyPort: Int, var showSensitiveContent: Boolean? = null, var warnAboutPostsWithReports: Boolean = true, - var filterSpamFromStrangers: Boolean = true + var filterSpamFromStrangers: Boolean = true, + var lastReadPerRoute: Map = mapOf() ) { var transientHiddenUsers: Set = setOf() // Observers line up here. val live: AccountLiveData = AccountLiveData(this) val liveLanguages: AccountLiveData = AccountLiveData(this) + val liveLastRead: AccountLiveData = AccountLiveData(this) val saveable: AccountLiveData = AccountLiveData(this) var userProfileCache: User? = null @@ -1154,6 +1156,19 @@ class Account( live.invalidateData() } + fun markAsRead(route: String, timestampInSecs: Long) { + val lastTime = lastReadPerRoute[route] + if (lastTime == null || timestampInSecs > lastTime) { + lastReadPerRoute = lastReadPerRoute + Pair(route, timestampInSecs) + saveable.invalidateData() + liveLastRead.invalidateData() + } + } + + fun loadLastRead(route: String): Long { + return lastReadPerRoute[route] ?: 0 + } + fun registerObservers() { // Observes relays to restart connections userProfile().live().relays.observeForever { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppBottomBar.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppBottomBar.kt index 9901f6e5c..798336471 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppBottomBar.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppBottomBar.kt @@ -39,7 +39,6 @@ import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.navigation.NavBackStackEntry -import com.vitorpamplona.amethyst.NotificationCache import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import kotlinx.coroutines.Dispatchers @@ -165,12 +164,11 @@ fun WatchPossibleNotificationChanges( val accountState by accountViewModel.accountLiveData.observeAsState() val account = remember(accountState) { accountState?.account } ?: return - val notifState by NotificationCache.live.observeAsState() - val notif = remember(notifState) { notifState?.cache } ?: return + val notifState by accountViewModel.accountLastReadLiveData.observeAsState() LaunchedEffect(key1 = notifState, key2 = accountState) { launch(Dispatchers.IO) { - onChange(route.hasNewItems(account, notif, emptySet())) + onChange(route.hasNewItems(account, emptySet())) } } @@ -178,7 +176,7 @@ fun WatchPossibleNotificationChanges( launch(Dispatchers.IO) { LocalCache.live.newEventBundles.collect { launch(Dispatchers.IO) { - onChange(route.hasNewItems(account, notif, it)) + onChange(route.hasNewItems(account, it)) } } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/Routes.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/Routes.kt index e0544f58c..941590351 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/Routes.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/Routes.kt @@ -10,7 +10,6 @@ import androidx.navigation.NavHostController import androidx.navigation.NavType import androidx.navigation.compose.currentBackStackEntryAsState import androidx.navigation.navArgument -import com.vitorpamplona.amethyst.NotificationCache import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.model.Account import com.vitorpamplona.amethyst.model.Note @@ -27,7 +26,7 @@ import kotlinx.collections.immutable.toImmutableList sealed class Route( val route: String, val icon: Int, - val hasNewItems: (Account, NotificationCache, Set) -> Boolean = { _, _, _ -> false }, + val hasNewItems: (Account, Set) -> Boolean = { _, _ -> false }, val arguments: ImmutableList = persistentListOf() ) { val base: String @@ -40,7 +39,7 @@ sealed class Route( navArgument("scrollToTop") { type = NavType.BoolType; defaultValue = false }, navArgument("nip47") { type = NavType.StringType; nullable = true; defaultValue = null } ).toImmutableList(), - hasNewItems = { accountViewModel, cache, newNotes -> HomeLatestItem.hasNewItems(accountViewModel, cache, newNotes) } + hasNewItems = { accountViewModel, newNotes -> HomeLatestItem.hasNewItems(accountViewModel, newNotes) } ) object Search : Route( @@ -59,13 +58,13 @@ sealed class Route( route = "Notification?scrollToTop={scrollToTop}", icon = R.drawable.ic_notifications, arguments = listOf(navArgument("scrollToTop") { type = NavType.BoolType; defaultValue = false }).toImmutableList(), - hasNewItems = { accountViewModel, cache, newNotes -> NotificationLatestItem.hasNewItems(accountViewModel, cache, newNotes) } + hasNewItems = { accountViewModel, newNotes -> NotificationLatestItem.hasNewItems(accountViewModel, newNotes) } ) object Message : Route( route = "Message", icon = R.drawable.ic_dm, - hasNewItems = { accountViewModel, cache, newNotes -> MessagesLatestItem.hasNewItems(accountViewModel, cache, newNotes) } + hasNewItems = { accountViewModel, newNotes -> MessagesLatestItem.hasNewItems(accountViewModel, newNotes) } ) object BlockedUsers : Route( @@ -127,29 +126,40 @@ fun currentRoute(navController: NavHostController): String? { open class LatestItem { var newestItemPerAccount: Map = mapOf() + fun getNewestItem(account: Account): Note? { + return newestItemPerAccount[account.userProfile().pubkeyHex] + } + + fun clearNewestItem(account: Account) { + val userHex = account.userProfile().pubkeyHex + if (newestItemPerAccount.contains(userHex)) { + newestItemPerAccount = newestItemPerAccount - userHex + } + } + fun updateNewestItem(newNotes: Set, account: Account, filter: AdditiveFeedFilter): Note? { val newestItem = newestItemPerAccount[account.userProfile().pubkeyHex] if (newestItem == null) { newestItemPerAccount = newestItemPerAccount + Pair( account.userProfile().pubkeyHex, - filterMore(filter.feed()).firstOrNull { it.createdAt() != null } + filterMore(filter.feed(), account).firstOrNull { it.createdAt() != null } ) } else { newestItemPerAccount = newestItemPerAccount + Pair( account.userProfile().pubkeyHex, - filter.sort(filterMore(filter.applyFilter(newNotes)) + newestItem).first() + filter.sort(filterMore(filter.applyFilter(newNotes), account) + newestItem).first() ) } return newestItemPerAccount[account.userProfile().pubkeyHex] } - open fun filterMore(newItems: Set): Set { + open fun filterMore(newItems: Set, account: Account): Set { return newItems } - open fun filterMore(newItems: List): List { + open fun filterMore(newItems: List, account: Account): List { return newItems } } @@ -157,10 +167,9 @@ open class LatestItem { object HomeLatestItem : LatestItem() { fun hasNewItems( account: Account, - cache: NotificationCache, newNotes: Set ): Boolean { - val lastTime = cache.load("HomeFollows") + val lastTime = account.loadLastRead("HomeFollows") val newestItem = updateNewestItem(newNotes, account, HomeNewThreadFeedFilter(account)) @@ -171,10 +180,9 @@ object HomeLatestItem : LatestItem() { object NotificationLatestItem : LatestItem() { fun hasNewItems( account: Account, - cache: NotificationCache, newNotes: Set ): Boolean { - val lastTime = cache.load("Notification") + val lastTime = account.loadLastRead("Notification") val newestItem = updateNewestItem(newNotes, account, NotificationFeedFilter(account)) @@ -185,24 +193,53 @@ object NotificationLatestItem : LatestItem() { object MessagesLatestItem : LatestItem() { fun hasNewItems( account: Account, - cache: NotificationCache, newNotes: Set ): Boolean { + println("AAA Hey") + + // Checks if the current newest item is still unread. + // If so, there is no need to check anything else + if (isNew(getNewestItem(account), account)) { + println("AAA Enter ${getNewestItem(account)?.author?.toBestDisplayName()}") + + return true + } + + clearNewestItem(account) + + println("AAA Hey 2") + + // gets the newest of the unread items val newestItem = updateNewestItem(newNotes, account, ChatroomListKnownFeedFilter(account)) - val roomUserHex = (newestItem?.event as? PrivateDmEvent)?.talkingWith(account.userProfile().pubkeyHex) + println("AAA ${newestItem?.author?.toBestDisplayName()} ${isNew(newestItem, account)}") - val lastTime = cache.load("Room/$roomUserHex") - - return (newestItem?.createdAt() ?: 0) > lastTime + return isNew(newestItem, account) } - override fun filterMore(newItems: Set): Set { - return newItems.filter { it.event is PrivateDmEvent }.toSet() + fun isNew(it: Note?, account: Account): Boolean { + if (it == null) return false + + val currentUser = account.userProfile().pubkeyHex + val room = (it.event as? PrivateDmEvent)?.talkingWith(currentUser) + return if (room != null) { + val lastRead = account.loadLastRead("Room/$room") + (it.createdAt() ?: 0) > lastRead + } else { + false + } } - override fun filterMore(newItems: List): List { - return newItems.filter { it.event is PrivateDmEvent } + override fun filterMore(newItems: Set, account: Account): Set { + return newItems.filter { + isNew(it, account) + }.toSet() + } + + override fun filterMore(newItems: List, account: Account): List { + return newItems.filter { + isNew(it, account) + } } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/BadgeCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/BadgeCompose.kt index 3fcc3baed..f1643c7d0 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/BadgeCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/BadgeCompose.kt @@ -33,7 +33,6 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp -import com.vitorpamplona.amethyst.NotificationCache import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.ui.screen.BadgeCard import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel @@ -62,9 +61,9 @@ fun BadgeCompose(likeSetCard: BadgeCard, isInnerNote: Boolean = false, routeForL LaunchedEffect(key1 = likeSetCard) { scope.launch(Dispatchers.IO) { - val isNew = likeSetCard.createdAt() > NotificationCache.load(routeForLastRead) + val isNew = likeSetCard.createdAt() > accountViewModel.account.loadLastRead(routeForLastRead) - NotificationCache.markAsRead(routeForLastRead, likeSetCard.createdAt()) + accountViewModel.account.markAsRead(routeForLastRead, likeSetCard.createdAt()) val newBackgroundColor = if (isNew) { newItemColor.compositeOver(defaultBackgroundColor) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomCompose.kt index b698a0218..d73560f0d 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomCompose.kt @@ -39,7 +39,6 @@ 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 com.vitorpamplona.amethyst.NotificationCache import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.model.Channel import com.vitorpamplona.amethyst.model.LocalCache @@ -74,7 +73,7 @@ fun ChatroomCompose( BlankNote(Modifier) } else if (channelHex != null) { LoadChannel(baseChannelHex = channelHex!!) { channel -> - ChannelRoomCompose(note, channel, nav) + ChannelRoomCompose(note, channel, accountViewModel, nav) } } else { val userRoomHex = remember(noteState, accountViewModel) { @@ -91,6 +90,7 @@ fun ChatroomCompose( private fun ChannelRoomCompose( note: Note, channel: Channel, + accountViewModel: AccountViewModel, nav: (String) -> Unit ) { val authorState by note.author!!.live().metadata.observeAsState() @@ -128,7 +128,7 @@ private fun ChannelRoomCompose( var hasNewMessages by remember { mutableStateOf(false) } - WatchNotificationChanges(note, route) { newHasNewMessages -> + WatchNotificationChanges(note, route, accountViewModel) { newHasNewMessages -> if (hasNewMessages != newHasNewMessages) { hasNewMessages = newHasNewMessages } @@ -182,7 +182,7 @@ private fun UserRoomCompose( "Room/${user.pubkeyHex}" } - WatchNotificationChanges(note, route) { newHasNewMessages -> + WatchNotificationChanges(note, route, accountViewModel) { newHasNewMessages -> if (hasNewMessages != newHasNewMessages) { hasNewMessages = newHasNewMessages } @@ -208,14 +208,15 @@ private fun UserRoomCompose( private fun WatchNotificationChanges( note: Note, route: String, + accountViewModel: AccountViewModel, onNewStatus: (Boolean) -> Unit ) { - val cacheState by NotificationCache.live.observeAsState() + val cacheState by accountViewModel.accountLastReadLiveData.observeAsState() LaunchedEffect(key1 = note, cacheState) { launch(Dispatchers.IO) { note.event?.createdAt()?.let { - val lastTime = NotificationCache.load(route) + val lastTime = accountViewModel.account.loadLastRead(route) onNewStatus(it > lastTime) } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomMessageCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomMessageCompose.kt index 8563e147a..16c1b7b8f 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomMessageCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ChatroomMessageCompose.kt @@ -52,7 +52,6 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.IntSize import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import com.vitorpamplona.amethyst.NotificationCache import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.service.model.ChannelCreateEvent @@ -184,11 +183,11 @@ fun ChatroomMessageCompose( LaunchedEffect(key1 = routeForLastRead) { routeForLastRead?.let { scope.launch(Dispatchers.IO) { - val lastTime = NotificationCache.load(it) + val lastTime = accountViewModel.account.loadLastRead(it) val createdAt = note.createdAt() if (createdAt != null) { - NotificationCache.markAsRead(it, createdAt) + accountViewModel.account.markAsRead(it, createdAt) } } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/MessageSetCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/MessageSetCompose.kt index f840e13df..591aaac25 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/MessageSetCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/MessageSetCompose.kt @@ -27,7 +27,6 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.compositeOver import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.dp -import com.vitorpamplona.amethyst.NotificationCache import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.ui.screen.MessageSetCard import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel @@ -53,9 +52,9 @@ fun MessageSetCompose(messageSetCard: MessageSetCard, routeForLastRead: String, LaunchedEffect(key1 = messageSetCard) { scope.launch(Dispatchers.IO) { - val isNew = messageSetCard.createdAt() > NotificationCache.load(routeForLastRead) + val isNew = messageSetCard.createdAt() > accountViewModel.account.loadLastRead(routeForLastRead) - NotificationCache.markAsRead(routeForLastRead, messageSetCard.createdAt()) + accountViewModel.account.markAsRead(routeForLastRead, messageSetCard.createdAt()) val newBackgroundColor = if (isNew) { newItemColor.compositeOver(defaultBackgroundColor) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/MultiSetCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/MultiSetCompose.kt index 94e89f827..705acd7d6 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/MultiSetCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/MultiSetCompose.kt @@ -43,7 +43,6 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import com.vitorpamplona.amethyst.NotificationCache import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.Note @@ -79,9 +78,9 @@ fun MultiSetCompose(multiSetCard: MultiSetCard, routeForLastRead: String, accoun LaunchedEffect(key1 = multiSetCard) { launch(Dispatchers.IO) { - val isNew = multiSetCard.maxCreatedAt > NotificationCache.load(routeForLastRead) + val isNew = multiSetCard.maxCreatedAt > accountViewModel.account.loadLastRead(routeForLastRead) - NotificationCache.markAsRead(routeForLastRead, multiSetCard.maxCreatedAt) + accountViewModel.account.markAsRead(routeForLastRead, multiSetCard.maxCreatedAt) val newBackgroundColor = if (isNew) { newItemColor.compositeOver(defaultBackgroundColor) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt index 2847aa522..7dcb0bc7f 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/NoteCompose.kt @@ -82,7 +82,6 @@ import androidx.core.graphics.get import coil.compose.AsyncImage import coil.compose.AsyncImagePainter import coil.request.SuccessResult -import com.vitorpamplona.amethyst.NotificationCache import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.model.Channel import com.vitorpamplona.amethyst.model.LocalCache @@ -424,11 +423,11 @@ private fun CheckNewAndRenderNote( LaunchedEffect(key1 = routeForLastRead, key2 = parentBackgroundColor?.value) { launch(Dispatchers.IO) { routeForLastRead?.let { - val lastTime = NotificationCache.load(it) + val lastTime = accountViewModel.account.loadLastRead(it) val createdAt = baseNote.createdAt() if (createdAt != null) { - NotificationCache.markAsRead(it, createdAt) + accountViewModel.account.markAsRead(it, createdAt) val isNew = createdAt > lastTime diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapUserSetCompose.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapUserSetCompose.kt index 3a89be323..f0a3b79e5 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapUserSetCompose.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapUserSetCompose.kt @@ -26,7 +26,6 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.compositeOver import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp -import com.vitorpamplona.amethyst.NotificationCache import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.ui.screen.ZapUserSetCard import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel @@ -43,9 +42,9 @@ fun ZapUserSetCompose(zapSetCard: ZapUserSetCard, isInnerNote: Boolean = false, LaunchedEffect(key1 = zapSetCard.createdAt()) { launch(Dispatchers.IO) { - val isNew = zapSetCard.createdAt > NotificationCache.load(routeForLastRead) + val isNew = zapSetCard.createdAt > accountViewModel.account.loadLastRead(routeForLastRead) - NotificationCache.markAsRead(routeForLastRead, zapSetCard.createdAt) + accountViewModel.account.markAsRead(routeForLastRead, zapSetCard.createdAt) val newBackgroundColor = if (isNew) { newItemColor.compositeOver(defaultBackgroundColor) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/ChatroomListFeedView.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/ChatroomListFeedView.kt index 8d917ea4a..6dabc785a 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/ChatroomListFeedView.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/ChatroomListFeedView.kt @@ -26,7 +26,6 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.vitorpamplona.amethyst.NotificationCache import com.vitorpamplona.amethyst.service.model.PrivateDmEvent import com.vitorpamplona.amethyst.ui.note.ChatroomCompose import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel @@ -103,7 +102,7 @@ private fun FeedLoaded( "Room/$roomUser" } - NotificationCache.markAsRead(route, it.createdAt()) + accountViewModel.account.markAsRead(route, it.createdAt()) } } markAsRead.value = false diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt index b2360325e..8bd528cbd 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt @@ -30,6 +30,7 @@ import java.util.Locale class AccountViewModel(val account: Account) : ViewModel() { val accountLiveData: LiveData = account.live.map { it } val accountLanguagesLiveData: LiveData = account.liveLanguages.map { it } + val accountLastReadLiveData: LiveData = account.liveLastRead.map { it } fun isWriteable(): Boolean { return account.isWriteable()