feat: support for categories

Signed-off-by: Infi <infi@infi.sh>
This commit is contained in:
Infi 2023-10-21 15:40:33 +02:00
parent 5251d3f7aa
commit a2801b29d7
2 changed files with 97 additions and 14 deletions

View File

@ -2,8 +2,14 @@ package chat.revolt.api.internals
import chat.revolt.api.RevoltAPI
import chat.revolt.api.schemas.Channel
import chat.revolt.api.schemas.Server
import chat.revolt.api.schemas.User
sealed class CategorisedChannelList {
data class Channel(val channel: chat.revolt.api.schemas.Channel) : CategorisedChannelList()
data class Category(val category: chat.revolt.api.schemas.Category) : CategorisedChannelList()
}
object ChannelUtils {
fun resolveDMName(channel: Channel): String? {
return channel.name
@ -17,4 +23,31 @@ object ChannelUtils {
fun resolveDMPartner(channel: Channel): String? {
return channel.recipients?.first { u -> u != RevoltAPI.selfId }
}
fun categoriseServerFlat(server: Server): List<CategorisedChannelList> {
val output = mutableListOf<CategorisedChannelList>()
val uncategorised =
server.channels?.filter { c -> server.categories?.none { cat -> cat.channels?.contains(c) == true } == true }
?.mapNotNull {
RevoltAPI.channelCache[it]?.let { it1 ->
CategorisedChannelList.Channel(it1)
}
} ?: emptyList()
output.addAll(uncategorised)
val categories =
server.categories?.map { CategorisedChannelList.Category(it) } ?: emptyList()
categories.forEach {
output.add(it)
val channels = it.category.channels?.mapNotNull { c ->
RevoltAPI.channelCache[c]?.let { it1 ->
CategorisedChannelList.Channel(it1)
}
} ?: emptyList()
output.addAll(channels)
}
return output
}
}

View File

@ -60,6 +60,7 @@ import chat.revolt.activities.RevoltTweenDp
import chat.revolt.activities.RevoltTweenFloat
import chat.revolt.api.REVOLT_FILES
import chat.revolt.api.RevoltAPI
import chat.revolt.api.internals.CategorisedChannelList
import chat.revolt.api.internals.ChannelUtils
import chat.revolt.api.schemas.ChannelType
import chat.revolt.api.schemas.ServerFlags
@ -138,6 +139,13 @@ fun RowScope.ChannelList(
.sortedBy { it.lastMessageID ?: it.id }
.reversed()
val server = remember(serverId, RevoltAPI.serverCache) { RevoltAPI.serverCache[serverId] }
val categorisedChannels = remember(server, RevoltAPI.channelCache) {
server?.let {
ChannelUtils.categoriseServerFlat(it)
}
}
Surface(
tonalElevation = 1.dp,
modifier = Modifier
@ -262,8 +270,6 @@ fun RowScope.ChannelList(
)
}
} else {
val server = RevoltAPI.serverCache[serverId]
stickyHeader {
Box(
contentAlignment = Alignment.BottomStart,
@ -435,7 +441,7 @@ fun RowScope.ChannelList(
}
if (server?.channels?.isEmpty() == true) {
if (categorisedChannels.isNullOrEmpty()) {
item {
Column(
Modifier.weight(1f),
@ -458,30 +464,74 @@ fun RowScope.ChannelList(
}
} else {
items(
server?.channels?.size ?: 0,
key = { server?.channels?.get(it) ?: "" }
categorisedChannels.size ?: 0,
key = { index ->
val channel = categorisedChannels.getOrNull(index)
channel?.let {
when (it) {
is CategorisedChannelList.Channel -> it.channel.id
is CategorisedChannelList.Category -> it.category.id
}
} ?: index
}
) {
server?.channels?.get(it)?.let { channelId ->
RevoltAPI.channelCache[channelId]?.let { ch ->
when (val item = categorisedChannels.getOrNull(it)) {
is CategorisedChannelList.Channel -> {
val channel = item.channel
val partner =
if (channel.channelType == ChannelType.DirectMessage) RevoltAPI.userCache[ChannelUtils.resolveDMPartner(
channel
)] else null
DrawerChannel(
name = ch.name ?: stringResource(R.string.unknown),
channelType = ch.channelType ?: ChannelType.TextChannel,
selected = currentDestination == "channel/{channelId}" && currentChannel == ch.id,
hasUnread = ch.lastMessageID?.let { lastMessageID ->
name = partner?.let { p -> User.resolveDefaultName(p) }
?: channel.name
?: stringResource(R.string.unknown),
channelType = channel.channelType ?: ChannelType.TextChannel,
selected = currentDestination == "channel/{channelId}" && currentChannel == channel.id,
hasUnread = channel.lastMessageID?.let { lastMessageID ->
RevoltAPI.unreads.hasUnread(
ch.id!!,
channel.id!!,
lastMessageID
)
} ?: false,
dmPartnerIcon = partner?.avatar ?: channel.icon,
dmPartnerId = partner?.id,
dmPartnerName = partner?.let { p -> User.resolveDefaultName(p) },
dmPartnerStatus = presenceFromStatus(
status = partner?.status?.presence,
online = partner?.online ?: false
),
onClick = {
onChannelClick(ch.id ?: return@DrawerChannel)
onChannelClick(channel.id ?: return@DrawerChannel)
},
onLongClick = {
channelContextSheetTarget = ch.id ?: return@DrawerChannel
channelContextSheetTarget =
channel.id ?: return@DrawerChannel
channelContextSheetShown = true
}
)
}
is CategorisedChannelList.Category -> {
val category = item.category
Text(
text = category.title ?: stringResource(R.string.unknown),
style = MaterialTheme.typography.labelLarge,
fontSize = 16.sp,
modifier = Modifier
.padding(
start = 16.dp,
end = 16.dp,
top = 24.dp,
bottom = 16.dp
)
)
}
else -> {}
}
}
}