diff --git a/app/src/main/java/chat/revolt/api/internals/ChannelUtils.kt b/app/src/main/java/chat/revolt/api/internals/ChannelUtils.kt index a5d43751..28875661 100644 --- a/app/src/main/java/chat/revolt/api/internals/ChannelUtils.kt +++ b/app/src/main/java/chat/revolt/api/internals/ChannelUtils.kt @@ -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 { + val output = mutableListOf() + + 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 + } } \ No newline at end of file diff --git a/app/src/main/java/chat/revolt/components/screens/chat/drawer/channel/ChannelList.kt b/app/src/main/java/chat/revolt/components/screens/chat/drawer/channel/ChannelList.kt index 59978971..7347db40 100644 --- a/app/src/main/java/chat/revolt/components/screens/chat/drawer/channel/ChannelList.kt +++ b/app/src/main/java/chat/revolt/components/screens/chat/drawer/channel/ChannelList.kt @@ -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 -> {} } } }