diff --git a/app/src/main/java/chat/revolt/activities/MainActivity.kt b/app/src/main/java/chat/revolt/activities/MainActivity.kt
index 1c35551d..c22be35d 100644
--- a/app/src/main/java/chat/revolt/activities/MainActivity.kt
+++ b/app/src/main/java/chat/revolt/activities/MainActivity.kt
@@ -23,6 +23,7 @@ import androidx.compose.animation.core.FiniteAnimationSpec
import androidx.compose.animation.core.tween
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
+import androidx.compose.animation.scaleIn
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.MaterialTheme
@@ -36,6 +37,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.TransformOrigin
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.Dp
@@ -66,6 +68,7 @@ import chat.revolt.screens.DefaultDestinationScreen
import chat.revolt.screens.about.AboutScreen
import chat.revolt.screens.about.AttributionScreen
import chat.revolt.screens.chat.ChatRouterScreen
+import chat.revolt.screens.chat.views.channel.ChannelScreen
import chat.revolt.screens.create.CreateGroupScreen
import chat.revolt.screens.labs.LabsRootScreen
import chat.revolt.screens.login.LoginGreetingScreen
@@ -571,11 +574,56 @@ fun AppEntrypoint(
easing = CubicBezierEasing(0.05f, 0.7f, 0.1f, 1f)
),
initialOffset = { it / 3 }
- ) + fadeIn(animationSpec = RevoltTweenFloat)
+ ) + fadeIn(animationSpec = RevoltTweenFloat) + scaleIn(
+ animationSpec = tween(
+ 400,
+ // cf. https://m3.material.io/styles/motion/easing-and-duration/tokens-specs#cbea5c6e-7b0d-47a0-98c3-767080a38d95
+ easing = CubicBezierEasing(0.05f, 0.7f, 0.1f, 1f)
+ ),
+ initialScale = 0.8f,
+ transformOrigin = TransformOrigin.Center
+ )
}
) {
MainScreen(navController)
}
+ composable(
+ "main/conversation/{channelId}",
+ enterTransition = {
+ slideIntoContainer(
+ AnimatedContentTransitionScope.SlideDirection.Left,
+ animationSpec = tween(
+ 600,
+ // cf. https://m3.material.io/styles/motion/easing-and-duration/tokens-specs#cbea5c6e-7b0d-47a0-98c3-767080a38d95
+ easing = CubicBezierEasing(0.05f, 0.7f, 0.1f, 1f)
+ ),
+ initialOffset = { it }
+ ) + fadeIn(animationSpec = RevoltTweenFloat)
+ },
+ exitTransition = {
+ slideOutOfContainer(
+ AnimatedContentTransitionScope.SlideDirection.Right,
+ animationSpec = tween(
+ 600,
+ // cf. https://m3.material.io/styles/motion/easing-and-duration/tokens-specs#cbea5c6e-7b0d-47a0-98c3-767080a38d95
+ easing = CubicBezierEasing(0.05f, 0.7f, 0.1f, 1f)
+ ),
+ targetOffset = { it }
+ ) + fadeOut(animationSpec = RevoltTweenFloat)
+ }
+ ) { backStackEntry ->
+ val channelId = backStackEntry.arguments?.getString("channelId") ?: ""
+ ChannelScreen(
+ channelId = channelId,
+ onToggleDrawer = {},
+ useDrawer = false,
+ useBackButton = true,
+ backButtonAction = {
+ navController.popBackStack()
+ },
+ useChatUI = true
+ )
+ }
composable("create/group") { CreateGroupScreen(navController) }
diff --git a/app/src/main/java/chat/revolt/screens/chat/views/channel/ChannelScreen.kt b/app/src/main/java/chat/revolt/screens/chat/views/channel/ChannelScreen.kt
index e9f3c9cd..5c5c2224 100644
--- a/app/src/main/java/chat/revolt/screens/chat/views/channel/ChannelScreen.kt
+++ b/app/src/main/java/chat/revolt/screens/chat/views/channel/ChannelScreen.kt
@@ -45,11 +45,13 @@ import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.requiredHeight
import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.statusBars
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.text.InlineTextContent
import androidx.compose.foundation.text.appendInlineContent
import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight
import androidx.compose.material.icons.filled.Close
import androidx.compose.material.icons.filled.Edit
@@ -186,6 +188,9 @@ fun ChannelScreen(
channelId: String,
onToggleDrawer: () -> Unit,
useDrawer: Boolean,
+ useBackButton: Boolean = false,
+ backButtonAction: (() -> Unit)? = null,
+ useChatUI: Boolean = true,
viewModel: ChannelScreenViewModel = hiltViewModel()
) {
//
@@ -495,12 +500,7 @@ fun ChannelScreen(
//
//
Scaffold(
- contentWindowInsets = WindowInsets(
- left = 0,
- right = 0,
- top = 0,
- bottom = 0
- ),
+ contentWindowInsets = WindowInsets.zero,
topBar = {
TopAppBar(
modifier = Modifier.clickable {
@@ -602,7 +602,7 @@ fun ChannelScreen(
}
}
},
- windowInsets = WindowInsets.zero,
+ windowInsets = if (useChatUI) WindowInsets.statusBars else WindowInsets.zero,
navigationIcon = {
if (useDrawer) {
IconButton(onClick = onToggleDrawer) {
@@ -612,6 +612,14 @@ fun ChannelScreen(
)
}
}
+ if (useBackButton) {
+ IconButton(onClick = backButtonAction ?: {}) {
+ Icon(
+ imageVector = Icons.AutoMirrored.Default.ArrowBack,
+ contentDescription = stringResource(id = R.string.back)
+ )
+ }
+ }
}
)
}
diff --git a/app/src/main/java/chat/revolt/screens/main/ConversationsScreen.kt b/app/src/main/java/chat/revolt/screens/main/ConversationsScreen.kt
new file mode 100644
index 00000000..9d778767
--- /dev/null
+++ b/app/src/main/java/chat/revolt/screens/main/ConversationsScreen.kt
@@ -0,0 +1,129 @@
+package chat.revolt.screens.main
+
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.WindowInsets
+import androidx.compose.foundation.layout.exclude
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.lazy.LazyColumn
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.Badge
+import androidx.compose.material3.CenterAlignedTopAppBar
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.HorizontalDivider
+import androidx.compose.material3.Icon
+import androidx.compose.material3.ListItem
+import androidx.compose.material3.NavigationBarDefaults
+import androidx.compose.material3.Scaffold
+import androidx.compose.material3.ScaffoldDefaults
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.style.TextOverflow
+import androidx.compose.ui.unit.dp
+import androidx.navigation.NavController
+import chat.revolt.R
+import chat.revolt.api.RevoltAPI
+import chat.revolt.api.schemas.ChannelType
+import chat.revolt.api.schemas.User
+import chat.revolt.api.settings.LoadedSettings
+import chat.revolt.components.generic.UserAvatar
+import chat.revolt.internals.extensions.zero
+
+// Note - this is not a traditional screen per se, as it is a part of the main screen
+@OptIn(ExperimentalMaterial3Api::class)
+@Composable
+fun ConversationsScreen(navController: NavController) {
+ val context = LocalContext.current
+ val dmAbleChannels =
+ RevoltAPI.channelCache.values
+ .filter { it.channelType == ChannelType.DirectMessage || it.channelType == ChannelType.Group }
+ .filter { if (it.channelType == ChannelType.DirectMessage) it.active == true else true }
+ .sortedBy { it.lastMessageID ?: it.id }
+ .reversed()
+
+ Scaffold(
+ contentWindowInsets = ScaffoldDefaults.contentWindowInsets.exclude(NavigationBarDefaults.windowInsets),
+ topBar = {
+ CenterAlignedTopAppBar(
+ title = { Text(stringResource(R.string.main_tab_conversations)) },
+ windowInsets = WindowInsets.zero
+ )
+ },
+ ) { pv ->
+ LazyColumn(
+ modifier = Modifier.padding(pv),
+ ) {
+ item(key = "saved_messages") {
+ val notesChannel =
+ RevoltAPI.channelCache.values.firstOrNull { it.channelType == ChannelType.SavedMessages }
+ val lastMessage = notesChannel?.lastMessageID?.let { RevoltAPI.messageCache[it] }
+ val hasAttachments = remember {
+ context.getString(R.string.reply_message_empty_has_attachments)
+ }
+ val preview = remember(lastMessage) {
+ (RevoltAPI.userCache[RevoltAPI.selfId]?.let {
+ User.resolveDefaultName(
+ it
+ )
+ }
+ .orEmpty() + ": Remember to fdjhlfhdsfdsjfds").trim()// + (lastMessage?.content ?: hasAttachments)).trim()
+ }
+
+ if (notesChannel != null) {
+ ListItem(
+ headlineContent = {
+ Text(stringResource(R.string.channel_notes))
+ },
+ supportingContent = {
+ if (preview.isNotBlank()) {
+ Text(
+ preview,
+ maxLines = 1,
+ overflow = TextOverflow.Ellipsis,
+ )
+ }
+ },
+ leadingContent = {
+ Box(contentAlignment = Alignment.TopEnd) {
+ RevoltAPI.userCache[RevoltAPI.selfId]?.let {
+ UserAvatar(
+ username = it.username.toString(),
+ avatar = it.avatar,
+ userId = it.id.toString(),
+ shape = RoundedCornerShape(LoadedSettings.avatarRadius)
+ )
+ }
+ Badge {
+ Icon(
+ painter = painterResource(R.drawable.ic_pin_24dp),
+ contentDescription = null,
+ modifier = Modifier.size(12.dp)
+ )
+ }
+ }
+ },
+ modifier = Modifier.clickable {
+ navController.navigate("main/conversation/${notesChannel.id}")
+ }
+ )
+ HorizontalDivider()
+ }
+ }
+ items(1000) {
+ Text("Conversation $it", modifier = Modifier
+ .clickable {
+ navController.navigate("main/conversation/${it}")
+ }
+ .fillMaxWidth())
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/chat/revolt/screens/main/MainScreen.kt b/app/src/main/java/chat/revolt/screens/main/MainScreen.kt
index bb4a654e..eb98221b 100644
--- a/app/src/main/java/chat/revolt/screens/main/MainScreen.kt
+++ b/app/src/main/java/chat/revolt/screens/main/MainScreen.kt
@@ -14,6 +14,7 @@ import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.res.stringResource
import androidx.navigation.NavController
import chat.revolt.R
import chat.revolt.screens.chat.views.OverviewScreen
@@ -47,7 +48,7 @@ fun MainScreen(navController: NavController) {
)
},
label = {
- Text("Communities")
+ Text(stringResource(R.string.main_tab_communities))
}
)
NavigationBarItem(
@@ -66,7 +67,7 @@ fun MainScreen(navController: NavController) {
)
},
label = {
- Text("Conversations")
+ Text(stringResource(R.string.main_tab_conversations))
}
)
NavigationBarItem(
@@ -85,7 +86,7 @@ fun MainScreen(navController: NavController) {
)
},
label = {
- Text("Overview")
+ Text(stringResource(R.string.main_tab_overview))
}
)
}
@@ -94,7 +95,12 @@ fun MainScreen(navController: NavController) {
Box(Modifier.padding(pv)) {
when (currentTab) {
MainScreenTab.Communities -> {}
- MainScreenTab.Conversations -> {}
+ MainScreenTab.Conversations -> {
+ ConversationsScreen(
+ navController
+ )
+ }
+
MainScreenTab.Overview -> {
OverviewScreen(
navController,
diff --git a/app/src/main/res/drawable/ic_pin_24dp.xml b/app/src/main/res/drawable/ic_pin_24dp.xml
new file mode 100644
index 00000000..17f89a78
--- /dev/null
+++ b/app/src/main/res/drawable/ic_pin_24dp.xml
@@ -0,0 +1,9 @@
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index bb02387f..53939ba1 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -169,6 +169,13 @@
Clear all incoming requests
New Group
+
+ Communities
+
+ Conversations
+
+ You
+
Create a new group
Round up your crew in a group chat. You can add up to %1$d people.
Group Name