feat: prototype server unreads

This commit is contained in:
Infi 2023-02-28 00:50:26 +01:00
parent dd78679901
commit 74a1454f73
4 changed files with 70 additions and 30 deletions

View File

@ -7,6 +7,7 @@ import chat.revolt.api.internals.ULID
import chat.revolt.api.routes.channel.ackChannel
import chat.revolt.api.routes.server.ackServer
import chat.revolt.api.routes.sync.syncUnreads
import chat.revolt.api.schemas.ChannelType
import chat.revolt.api.schemas.ChannelUnread
class Unreads {
@ -35,6 +36,17 @@ class Unreads {
return (channels[channelId]?.last_id?.compareTo(lastMessageId) ?: 0) < 0
}
fun serverHasUnread(serverId: String): Boolean {
if (!hasLoaded.value) return false
return RevoltAPI.serverCache[serverId]?.channels?.any {
val channel = RevoltAPI.channelCache[it] ?: return@any false
if (channel.channelType == ChannelType.VoiceChannel) return@any false // TODO remove this when text in voice channels is implemented
hasUnread(it, channel.lastMessageID ?: "")
}
?: false
}
suspend fun markAsRead(channelId: String, messageId: String, sync: Boolean = true) {
if (!hasLoaded.value) return
channels[channelId]?.let {

View File

@ -44,7 +44,7 @@ fun DrawerChannel(
animationSpec = spring()
)
val channelAlpha = animateFloatAsState(
if (hasUnread) 1f else 0.8f,
if (hasUnread || selected) 1f else 0.8f,
animationSpec = spring()
)

View File

@ -1,17 +1,22 @@
package chat.revolt.components.screens.chat.drawer.server
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.spring
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.surfaceColorAtElevation
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.draw.clip
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
@ -23,34 +28,55 @@ import chat.revolt.components.generic.RemoteImage
fun DrawerServer(
iconId: String?,
serverName: String,
hasUnreads: Boolean,
onClick: () -> Unit
) {
if (iconId != null) {
RemoteImage(
url = "$REVOLT_FILES/icons/${iconId}/server.png?max_side=256",
modifier = Modifier
.padding(8.dp)
.size(48.dp)
.clip(CircleShape)
.clickable(onClick = onClick),
description = serverName
)
} else {
Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.padding(8.dp)
.size(48.dp)
.clip(CircleShape)
.background(MaterialTheme.colorScheme.surfaceColorAtElevation(3.dp))
.clickable(onClick = onClick)
) {
Text(
text = serverName.first().uppercase(),
fontSize = 20.sp,
fontWeight = FontWeight.SemiBold,
color = MaterialTheme.colorScheme.onSurface
val unreadIndicatorAlpha = animateFloatAsState(
if (hasUnreads) 1f else 0f,
animationSpec = spring()
)
Box(
contentAlignment = Alignment.CenterStart
) {
if (iconId != null) {
RemoteImage(
url = "$REVOLT_FILES/icons/${iconId}/server.png?max_side=256",
modifier = Modifier
.padding(8.dp)
.size(48.dp)
.clip(CircleShape)
.clickable(onClick = onClick),
description = serverName
)
} else {
Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.padding(8.dp)
.size(48.dp)
.clip(CircleShape)
.background(MaterialTheme.colorScheme.surfaceColorAtElevation(3.dp))
.clickable(onClick = onClick)
) {
Text(
text = serverName.first().uppercase(),
fontSize = 20.sp,
fontWeight = FontWeight.SemiBold,
color = MaterialTheme.colorScheme.onSurface
)
}
}
// Unread indicator
Box(
modifier = Modifier
.padding(8.dp)
.size(8.dp)
.offset(x = (-12).dp)
.clip(CircleShape)
.alpha(unreadIndicatorAlpha.value)
.background(LocalContentColor.current)
)
}
}

View File

@ -113,7 +113,8 @@ fun ChatRouterScreen(topNav: NavController, viewModel: ChatRouterViewModel = vie
Column(
modifier = Modifier
.fillMaxHeight()
.verticalScroll(rememberScrollState())
.verticalScroll(rememberScrollState()),
horizontalAlignment = Alignment.CenterHorizontally
) {
UserAvatar(
username = RevoltAPI.userCache[RevoltAPI.selfId]?.username
@ -142,14 +143,15 @@ fun ChatRouterScreen(topNav: NavController, viewModel: ChatRouterViewModel = vie
RevoltAPI.serverCache.values
.sortedBy { it.id }
.forEach { server ->
if (server.name == null) return@forEach
if (server.id == null || server.name == null) return@forEach
DrawerServer(
iconId = server.icon?.id,
serverName = server.name
serverName = server.name,
hasUnreads = RevoltAPI.unreads.serverHasUnread(server.id),
) {
viewModel.navigateToServer(
server.id!!,
server.id,
navController
)
}