Skip to content

Commit

Permalink
Moves lastread routes to mutableStateFlow
Browse files Browse the repository at this point in the history
  • Loading branch information
vitorpamplona committed Aug 16, 2024
1 parent 6c81fbb commit 239f973
Show file tree
Hide file tree
Showing 6 changed files with 51 additions and 66 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -669,7 +676,7 @@ object LocalPreferences {
showSensitiveContent = MutableStateFlow(showSensitiveContent),
warnAboutPostsWithReports = warnAboutReports,
filterSpamFromStrangers = filterSpam,
lastReadPerRoute = lastReadPerRoute,
lastReadPerRoute = MutableStateFlow(lastReadPerRoute),
hasDonatedInVersion = hasDonatedInVersion,
pendingAttestations = MutableStateFlow(pendingAttestations ?: emptyMap()),
)
Expand Down
25 changes: 20 additions & 5 deletions amethyst/src/main/java/com/vitorpamplona/amethyst/model/Account.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -3213,17 +3213,32 @@ 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 {
false
}
}

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)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -387,8 +386,6 @@ private fun RenderChannel(
loadRobohash: Boolean,
onClick: () -> Unit,
) {
val hasNewMessages = remember { mutableStateOf(false) }

ChannelName(
channelIdHex = item.idHex,
channelPicture = item.profilePicture(),
Expand All @@ -400,7 +397,7 @@ private fun RenderChannel(
},
channelLastTime = null,
channelLastContent = item.summary(),
hasNewMessages,
hasNewMessages = false,
onClick = onClick,
loadProfilePicture = loadProfilePicture,
loadRobohash = loadRobohash,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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) {
Expand All @@ -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) },
Expand Down Expand Up @@ -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(
Expand All @@ -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) },
)
}
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -485,7 +456,7 @@ fun ChannelName(
channelTitle: @Composable (Modifier) -> Unit,
channelLastTime: Long?,
channelLastContent: String?,
hasNewMessages: MutableState<Boolean>,
hasNewMessages: Boolean,
onClick: () -> Unit,
) {
ChatHeaderLayout(
Expand Down Expand Up @@ -514,7 +485,7 @@ fun ChannelName(
)
}

if (hasNewMessages.value) {
if (hasNewMessages) {
NewItemsBubble()
}
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -1121,7 +1119,6 @@ class AccountViewModel(

suspend fun refreshMarkAsReadObservers() {
updateNotificationDots()
accountMarkAsReadUpdates.value++
}

fun loadAndMarkAsRead(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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}") },
Expand Down

0 comments on commit 239f973

Please sign in to comment.