chore: update m3 and migrate bottom sheets to m3

Signed-off-by: Infi <wingit@geist.ga>
This commit is contained in:
Infi 2023-05-29 19:53:57 +02:00
parent 7fcc93219e
commit f845c72b23
13 changed files with 458 additions and 342 deletions

View File

@ -12,7 +12,6 @@ import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.IntSize
import androidx.fragment.app.FragmentActivity
import androidx.navigation.compose.dialog
import chat.revolt.BuildConfig
@ -57,7 +56,6 @@ class MainActivity : FragmentActivity() {
}
val RevoltTweenInt: FiniteAnimationSpec<IntOffset> = tween(400, easing = EaseInOutExpo)
val RevoltTweenIntSize: FiniteAnimationSpec<IntSize> = tween(400, easing = EaseInOutExpo)
val RevoltTweenFloat: FiniteAnimationSpec<Float> = tween(400, easing = EaseInOutExpo)
val RevoltTweenDp: FiniteAnimationSpec<Dp> = tween(400, easing = EaseInOutExpo)
@ -78,25 +76,25 @@ fun AppEntrypoint() {
startDestination = "splash",
enterTransition = {
slideIntoContainer(
AnimatedContentScope.SlideDirection.Left,
AnimatedContentTransitionScope.SlideDirection.Left,
animationSpec = RevoltTweenInt
)
},
exitTransition = {
slideOutOfContainer(
AnimatedContentScope.SlideDirection.Left,
AnimatedContentTransitionScope.SlideDirection.Left,
animationSpec = RevoltTweenInt
) + fadeOut(animationSpec = RevoltTweenFloat)
},
popEnterTransition = {
slideIntoContainer(
AnimatedContentScope.SlideDirection.Right,
AnimatedContentTransitionScope.SlideDirection.Right,
animationSpec = RevoltTweenInt
)
},
popExitTransition = {
slideOutOfContainer(
AnimatedContentScope.SlideDirection.Right,
AnimatedContentTransitionScope.SlideDirection.Right,
animationSpec = RevoltTweenInt
)
}

View File

@ -127,24 +127,20 @@ object RealtimeSocket {
)
Log.d("RealtimeSocket", "Adding users to cache.")
readyFrame.users.forEach { user ->
RevoltAPI.userCache[user.id!!] = user
}
val userMap = readyFrame.users.associateBy { it.id!! }
RevoltAPI.userCache.putAll(userMap)
Log.d("RealtimeSocket", "Adding servers to cache.")
readyFrame.servers.forEach { server ->
RevoltAPI.serverCache[server.id!!] = server
}
val serverMap = readyFrame.servers.associateBy { it.id!! }
RevoltAPI.serverCache.putAll(serverMap)
Log.d("RealtimeSocket", "Adding channels to cache.")
readyFrame.channels.forEach { channel ->
RevoltAPI.channelCache[channel.id!!] = channel
}
val channelMap = readyFrame.channels.associateBy { it.id!! }
RevoltAPI.channelCache.putAll(channelMap)
Log.d("RealtimeSocket", "Adding emojis to cache.")
readyFrame.emojis.forEach { emoji ->
RevoltAPI.emojiCache[emoji.id!!] = emoji
}
val emojiMap = readyFrame.emojis.associateBy { it.id!! }
RevoltAPI.emojiCache.putAll(emojiMap)
}
"Message" -> {

View File

@ -73,7 +73,7 @@ fun MessageField(
keyboardOptions = KeyboardOptions.Default,
keyboardActions = KeyboardActions.Default,
decorationBox = @Composable { innerTextField ->
TextFieldDefaults.TextFieldDecorationBox(
TextFieldDefaults.DecorationBox(
value = messageContent,
innerTextField = innerTextField,
enabled = !disabled,
@ -90,13 +90,17 @@ fun MessageField(
overflow = TextOverflow.Ellipsis,
)
},
colors = TextFieldDefaults.textFieldColors(
colors = TextFieldDefaults.colors(
focusedIndicatorColor = Color.Transparent,
unfocusedIndicatorColor = Color.Transparent,
disabledIndicatorColor = Color.Transparent,
errorIndicatorColor = Color.Transparent,
placeholderColor = Color.Gray,
containerColor = MaterialTheme.colorScheme.surfaceColorAtElevation(1.dp)
unfocusedPlaceholderColor = Color.Gray,
focusedPlaceholderColor = Color.Gray,
unfocusedContainerColor = MaterialTheme.colorScheme.surfaceColorAtElevation(
1.dp
),
focusedContainerColor = Color.Transparent,
),
contentPadding = PaddingValues(16.dp),
leadingIcon = {

View File

@ -11,10 +11,16 @@ import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.DrawerState
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.rememberModalBottomSheetState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
@ -26,6 +32,7 @@ import chat.revolt.R
import chat.revolt.api.RevoltAPI
import chat.revolt.api.schemas.ChannelType
import chat.revolt.components.screens.chat.drawer.server.DrawerChannel
import chat.revolt.sheets.ChannelContextSheet
import kotlinx.coroutines.launch
@OptIn(ExperimentalMaterial3Api::class)
@ -35,10 +42,31 @@ fun RowScope.ChannelList(
drawerState: DrawerState,
currentChannel: String?,
onChannelClick: (String) -> Unit,
onChannelLongClick: (String) -> Unit,
) {
val coroutineScope = rememberCoroutineScope()
var channelContextSheetShown by remember { mutableStateOf(false) }
var channelContextSheetTarget by remember { mutableStateOf("") }
if (channelContextSheetShown) {
val channelContextSheetState = rememberModalBottomSheetState()
ModalBottomSheet(
sheetState = channelContextSheetState,
onDismissRequest = {
channelContextSheetShown = false
},
) {
ChannelContextSheet(
channelId = channelContextSheetTarget,
onHideSheet = {
channelContextSheetState.hide()
channelContextSheetShown = false
}
)
}
}
Surface(
tonalElevation = 1.dp,
modifier = Modifier
@ -74,7 +102,8 @@ fun RowScope.ChannelList(
coroutineScope.launch { drawerState.close() }
},
onLongClick = {
onChannelLongClick(channel.id ?: return@DrawerChannel)
channelContextSheetTarget = channel.id ?: return@DrawerChannel
channelContextSheetShown = true
}
)
}
@ -132,7 +161,8 @@ fun RowScope.ChannelList(
coroutineScope.launch { drawerState.close() }
},
onLongClick = {
onChannelLongClick(ch.id ?: return@DrawerChannel)
channelContextSheetTarget = ch.id ?: return@DrawerChannel
channelContextSheetShown = true
}
)
}

View File

@ -12,7 +12,6 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Add
@ -22,10 +21,11 @@ import androidx.compose.material3.DismissibleNavigationDrawer
import androidx.compose.material3.DrawerValue
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.rememberDrawerState
import androidx.compose.material3.rememberModalBottomSheetState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
@ -62,23 +62,16 @@ import chat.revolt.components.screens.chat.drawer.server.DrawerServerlikeIcon
import chat.revolt.components.screens.chat.drawer.server.ServerDrawerSeparator
import chat.revolt.persistence.KVStorage
import chat.revolt.screens.chat.dialogs.safety.ReportMessageDialog
import chat.revolt.screens.chat.sheets.AddServerSheet
import chat.revolt.screens.chat.sheets.ChannelContextSheet
import chat.revolt.screens.chat.sheets.ChannelInfoSheet
import chat.revolt.screens.chat.sheets.MessageContextSheet
import chat.revolt.screens.chat.sheets.StatusSheet
import chat.revolt.screens.chat.views.HomeScreen
import chat.revolt.screens.chat.views.NoCurrentChannelScreen
import chat.revolt.screens.chat.views.channel.ChannelScreen
import chat.revolt.sheets.AddServerSheet
import chat.revolt.sheets.StatusSheet
import com.airbnb.lottie.RenderMode
import com.airbnb.lottie.compose.LottieAnimation
import com.airbnb.lottie.compose.LottieCompositionSpec
import com.airbnb.lottie.compose.animateLottieCompositionAsState
import com.airbnb.lottie.compose.rememberLottieComposition
import com.google.accompanist.navigation.material.ExperimentalMaterialNavigationApi
import com.google.accompanist.navigation.material.ModalBottomSheetLayout
import com.google.accompanist.navigation.material.bottomSheet
import com.google.accompanist.navigation.material.rememberBottomSheetNavigator
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.launch
@ -163,7 +156,6 @@ class ChatRouterViewModel @Inject constructor(
}
@OptIn(
ExperimentalMaterialNavigationApi::class,
ExperimentalComposeUiApi::class,
ExperimentalMaterial3Api::class
)
@ -173,8 +165,7 @@ fun ChatRouterScreen(topNav: NavController, viewModel: ChatRouterViewModel = hil
val scope = rememberCoroutineScope()
val keyboardController = LocalSoftwareKeyboardController.current
val bottomSheetNavigator = rememberBottomSheetNavigator()
val navController = rememberNavController(bottomSheetNavigator)
val navController = rememberNavController()
val showSidebarSpark = remember { mutableStateOf(false) }
val sidebarSparkComposition by rememberLottieComposition(LottieCompositionSpec.RawRes(R.raw.open_settings_tutorial))
@ -182,6 +173,9 @@ fun ChatRouterScreen(topNav: NavController, viewModel: ChatRouterViewModel = hil
composition = sidebarSparkComposition,
)
var showStatusSheet by remember { mutableStateOf(false) }
var showAddServerSheet by remember { mutableStateOf(false) }
BackHandler(enabled = drawerState.isClosed) {
scope.launch {
drawerState.open()
@ -230,215 +224,210 @@ fun ChatRouterScreen(topNav: NavController, viewModel: ChatRouterViewModel = hil
}
}
ModalBottomSheetLayout(
sheetShape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp),
sheetBackgroundColor = MaterialTheme.colorScheme.surface,
bottomSheetNavigator = bottomSheetNavigator,
) {
if (showSidebarSpark.value) {
AlertDialog(
onDismissRequest = {},
title = {
Text(stringResource(id = R.string.spark_sidebar_settings_tutorial))
},
text = {
Column {
LottieAnimation(
composition = sidebarSparkComposition,
progress = { sidebarSparkProgress },
modifier = Modifier
.fillMaxWidth()
.aspectRatio(1f),
renderMode = RenderMode.HARDWARE
)
Text(stringResource(id = R.string.spark_sidebar_settings_tutorial_description_1))
Text(stringResource(id = R.string.spark_sidebar_settings_tutorial_description_2))
if (showSidebarSpark.value) {
AlertDialog(
onDismissRequest = {},
title = {
Text(stringResource(id = R.string.spark_sidebar_settings_tutorial))
},
text = {
Column {
LottieAnimation(
composition = sidebarSparkComposition,
progress = { sidebarSparkProgress },
modifier = Modifier
.fillMaxWidth()
.aspectRatio(1f),
renderMode = RenderMode.HARDWARE
)
Text(stringResource(id = R.string.spark_sidebar_settings_tutorial_description_1))
Text(stringResource(id = R.string.spark_sidebar_settings_tutorial_description_2))
}
},
confirmButton = {
TextButton(onClick = {
scope.launch {
viewModel.setSettingsHintDisplayed()
}
showSidebarSpark.value = false
}) {
Text(stringResource(id = R.string.spark_sidebar_settings_tutorial_acknowledge))
}
}
)
}
if (showStatusSheet) {
val statusSheetState = rememberModalBottomSheetState()
ModalBottomSheet(
sheetState = statusSheetState,
onDismissRequest = {
showStatusSheet = false
},
) {
StatusSheet(
onBeforeNavigation = {
scope.launch {
statusSheetState.hide()
showStatusSheet = false
}
},
confirmButton = {
TextButton(onClick = {
scope.launch {
viewModel.setSettingsHintDisplayed()
}
showSidebarSpark.value = false
}) {
Text(stringResource(id = R.string.spark_sidebar_settings_tutorial_acknowledge))
}
onGoSettings = {
topNav.navigate("settings")
}
)
}
}
Column {
AnimatedVisibility(visible = RealtimeSocket.disconnectionState != DisconnectionState.Connected) {
DisconnectedNotice(
state = RealtimeSocket.disconnectionState,
onReconnect = {
RealtimeSocket.updateDisconnectionState(DisconnectionState.Reconnecting)
scope.launch { RevoltAPI.connectWS() }
})
}
if (showAddServerSheet) {
val addServerSheetState = rememberModalBottomSheetState()
DismissibleNavigationDrawer(
drawerState = drawerState,
drawerContent = {
DismissibleDrawerSheet(
drawerContainerColor = Color.Transparent,
) {
Column(Modifier.fillMaxWidth()) {
Row {
Column(
modifier = Modifier
.fillMaxHeight()
.verticalScroll(rememberScrollState()),
horizontalAlignment = Alignment.CenterHorizontally
) {
UserAvatar(
username = RevoltAPI.userCache[RevoltAPI.selfId]?.username
?: "",
presence = presenceFromStatus(
RevoltAPI.userCache[RevoltAPI.selfId]?.status?.presence
?: ""
),
userId = RevoltAPI.selfId ?: "",
avatar = RevoltAPI.userCache[RevoltAPI.selfId]?.avatar,
size = 48.dp,
presenceSize = 16.dp,
onClick = {
viewModel.navigateToServer("home", navController)
},
onLongClick = {
navController.navigate("status")
},
modifier = Modifier
.padding(8.dp)
.size(48.dp)
)
ServerDrawerSeparator()
RevoltAPI.serverCache.values
.sortedBy { it.id }
.forEach { server ->
if (server.id == null || server.name == null) return@forEach
DrawerServer(
iconId = server.icon?.id,
serverName = server.name,
hasUnreads = RevoltAPI.unreads.serverHasUnread(
server.id
),
) {
viewModel.navigateToServer(
server.id,
navController
)
}
}
DrawerServerlikeIcon(
onClick = {
navController.navigate("add_server")
}
) {
Icon(
Icons.Default.Add,
contentDescription = stringResource(id = R.string.server_plus_alt),
modifier = Modifier.padding(4.dp)
)
}
}
Crossfade(
targetState = viewModel.currentServer,
label = "Channel List"
) {
ChannelList(
serverId = it,
drawerState = drawerState,
currentChannel = viewModel.currentChannel,
onChannelClick = { channelId ->
viewModel.navigateToChannel(channelId, navController)
},
onChannelLongClick = { channelId ->
navController.navigate("channel/$channelId/info")
},
)
}
}
}
}
},
content = {
Column(Modifier.fillMaxSize()) {
NavHost(navController = navController, startDestination = "home") {
composable("home") {
HomeScreen(navController = topNav)
}
composable("channel/{channelId}") { backStackEntry ->
val channelId = backStackEntry.arguments?.getString("channelId")
if (channelId != null) {
ChannelScreen(
navController = navController,
channelId = channelId,
onToggleDrawer = {
scope.launch {
if (drawerState.isOpen) drawerState.close()
else drawerState.open()
}
}
)
}
}
composable("no_current_channel") {
NoCurrentChannelScreen()
}
bottomSheet("channel/{channelId}/info") { backStackEntry ->
val channelId = backStackEntry.arguments?.getString("channelId")
if (channelId != null) {
ChannelInfoSheet(
navController = navController,
channelId = channelId
)
}
}
bottomSheet("channel/{channelId}/menu") { backStackEntry ->
val channelId = backStackEntry.arguments?.getString("channelId")
if (channelId != null) {
ChannelContextSheet(
navController = navController,
channelId = channelId
)
}
}
bottomSheet("message/{messageId}/menu") { backStackEntry ->
val messageId = backStackEntry.arguments?.getString("messageId")
if (messageId != null) {
MessageContextSheet(
navController = navController,
messageId = messageId
)
}
}
bottomSheet("status") {
StatusSheet(navController = navController, topNav = topNav)
}
bottomSheet("add_server") {
AddServerSheet()
}
dialog("report/message/{messageId}") { backStackEntry ->
val messageId = backStackEntry.arguments?.getString("messageId")
if (messageId != null) {
ReportMessageDialog(
navController = navController,
messageId = messageId
)
}
}
}
}
})
ModalBottomSheet(
sheetState = addServerSheetState,
onDismissRequest = {
showAddServerSheet = false
},
) {
AddServerSheet()
}
}
Column {
AnimatedVisibility(visible = RealtimeSocket.disconnectionState != DisconnectionState.Connected) {
DisconnectedNotice(
state = RealtimeSocket.disconnectionState,
onReconnect = {
RealtimeSocket.updateDisconnectionState(DisconnectionState.Reconnecting)
scope.launch { RevoltAPI.connectWS() }
})
}
DismissibleNavigationDrawer(
drawerState = drawerState,
drawerContent = {
DismissibleDrawerSheet(
drawerContainerColor = Color.Transparent,
) {
Column(Modifier.fillMaxWidth()) {
Row {
Column(
modifier = Modifier
.fillMaxHeight()
.verticalScroll(rememberScrollState()),
horizontalAlignment = Alignment.CenterHorizontally
) {
UserAvatar(
username = RevoltAPI.userCache[RevoltAPI.selfId]?.username
?: "",
presence = presenceFromStatus(
RevoltAPI.userCache[RevoltAPI.selfId]?.status?.presence
?: ""
),
userId = RevoltAPI.selfId ?: "",
avatar = RevoltAPI.userCache[RevoltAPI.selfId]?.avatar,
size = 48.dp,
presenceSize = 16.dp,
onClick = {
viewModel.navigateToServer("home", navController)
},
onLongClick = {
showStatusSheet = true
},
modifier = Modifier
.padding(8.dp)
.size(48.dp)
)
ServerDrawerSeparator()
RevoltAPI.serverCache.values
.sortedBy { it.id }
.forEach { server ->
if (server.id == null || server.name == null) return@forEach
DrawerServer(
iconId = server.icon?.id,
serverName = server.name,
hasUnreads = RevoltAPI.unreads.serverHasUnread(
server.id
),
) {
viewModel.navigateToServer(
server.id,
navController
)
}
}
DrawerServerlikeIcon(
onClick = {
showAddServerSheet = true
}
) {
Icon(
Icons.Default.Add,
contentDescription = stringResource(id = R.string.server_plus_alt),
modifier = Modifier.padding(4.dp)
)
}
}
Crossfade(
targetState = viewModel.currentServer,
label = "Channel List"
) {
ChannelList(
serverId = it,
drawerState = drawerState,
currentChannel = viewModel.currentChannel,
onChannelClick = { channelId ->
viewModel.navigateToChannel(channelId, navController)
}
)
}
}
}
}
},
content = {
Column(Modifier.fillMaxSize()) {
NavHost(navController = navController, startDestination = "home") {
composable("home") {
HomeScreen(navController = topNav)
}
composable("channel/{channelId}") { backStackEntry ->
val channelId = backStackEntry.arguments?.getString("channelId")
if (channelId != null) {
ChannelScreen(
navController = navController,
channelId = channelId,
onToggleDrawer = {
scope.launch {
if (drawerState.isOpen) drawerState.close()
else drawerState.open()
}
}
)
}
}
composable("no_current_channel") {
NoCurrentChannelScreen()
}
dialog("report/message/{messageId}") { backStackEntry ->
val messageId = backStackEntry.arguments?.getString("messageId")
if (messageId != null) {
ReportMessageDialog(
navController = navController,
messageId = messageId
)
}
}
}
}
})
}
}

View File

@ -1,64 +0,0 @@
package chat.revolt.screens.chat.sheets
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Settings
import androidx.compose.material3.Icon
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
import chat.revolt.R
import chat.revolt.api.RevoltAPI
import chat.revolt.components.generic.SheetClickable
@Composable
fun StatusSheet(
navController: NavController,
topNav: NavController,
) {
if (RevoltAPI.selfId == null || RevoltAPI.userCache[RevoltAPI.selfId] == null) {
navController.popBackStack()
return
}
val selfUser = RevoltAPI.userCache[RevoltAPI.selfId]!!
Surface {
Column(
modifier = Modifier
.padding(horizontal = 16.dp, vertical = 8.dp)
.verticalScroll(rememberScrollState())
) {
Text(text = "Logged in as @${selfUser.username} (${selfUser.id})")
Spacer(modifier = Modifier.height(8.dp))
SheetClickable(
icon = { modifier ->
Icon(
imageVector = Icons.Default.Settings,
contentDescription = null,
modifier = modifier
)
},
label = { style ->
Text(
text = stringResource(id = R.string.settings),
style = style
)
}
) {
topNav.navigate("settings")
}
}
}
}

View File

@ -43,6 +43,8 @@ import chat.revolt.internals.markdown.MarkdownState
import chat.revolt.internals.markdown.UserMentionRule
import chat.revolt.internals.markdown.createCodeRule
import chat.revolt.internals.markdown.createInlineCodeRule
import chat.revolt.sheets.ChannelInfoSheet
import chat.revolt.sheets.MessageContextSheet
import com.discord.simpleast.core.simple.SimpleMarkdownRules
import com.discord.simpleast.core.simple.SimpleRenderer
import io.ktor.http.*
@ -50,6 +52,7 @@ import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.launch
import java.io.File
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun ChannelScreen(
navController: NavController,
@ -65,6 +68,11 @@ fun ChannelScreen(
val codeBlockColor = MaterialTheme.colorScheme.surfaceColorAtElevation(2.dp)
var channelInfoSheetShown by remember { mutableStateOf(false) }
var messageContextSheetShown by remember { mutableStateOf(false) }
var messageContextSheetTarget by remember { mutableStateOf("") }
val pickFileLauncher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.OpenMultipleDocuments()
) { uriList ->
@ -108,6 +116,43 @@ fun ChannelScreen(
}
}
if (channelInfoSheetShown) {
val channelInfoSheetState = rememberModalBottomSheetState()
ModalBottomSheet(
sheetState = channelInfoSheetState,
onDismissRequest = {
channelInfoSheetShown = false
},
) {
ChannelInfoSheet(
channelId = channelId,
)
}
}
if (messageContextSheetShown) {
val messageContextSheetState = rememberModalBottomSheetState()
ModalBottomSheet(
sheetState = messageContextSheetState,
onDismissRequest = {
messageContextSheetShown = false
},
) {
MessageContextSheet(
messageId = messageContextSheetTarget,
onHideSheet = {
messageContextSheetState.hide()
messageContextSheetShown = false
},
onReportMessage = {
navController.navigate("report/message/$messageContextSheetTarget")
},
)
}
}
if (channel?.channelType == null) {
CircularProgressIndicator()
return
@ -117,11 +162,11 @@ fun ChannelScreen(
ChannelHeader(
channel = channel,
onChannelClick = {
navController.navigate("channel/${channel.id}/info")
channelInfoSheetShown = true
},
onToggleDrawer = onToggleDrawer
)
val isScrolledToBottom = remember(lazyListState) {
derivedStateOf {
lazyListState.firstVisibleItemIndex <= 6
@ -202,7 +247,8 @@ fun ChannelScreen(
)
},
onMessageContextMenu = {
navController.navigate("message/${message.id}/menu")
messageContextSheetShown = true
messageContextSheetTarget = message.id ?: ""
},
canReply = true,
onReply = {

View File

@ -1,4 +1,4 @@
package chat.revolt.screens.chat.sheets
package chat.revolt.sheets
import android.content.Intent
import android.util.Log

View File

@ -1,17 +1,23 @@
package chat.revolt.screens.chat.sheets
package chat.revolt.sheets
import android.widget.Toast
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalClipboardManager
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.AnnotatedString
import androidx.navigation.NavController
import androidx.compose.ui.unit.dp
import chat.revolt.R
import chat.revolt.api.RevoltAPI
import chat.revolt.components.generic.SheetClickable
@ -19,12 +25,18 @@ import kotlinx.coroutines.launch
@Composable
fun ChannelContextSheet(
navController: NavController,
channelId: String,
onHideSheet: suspend () -> Unit,
) {
val channel = RevoltAPI.channelCache[channelId]
if (channel == null) {
navController.popBackStack()
Box(
modifier = Modifier
.fillMaxWidth()
.height(200.dp)
) {
CircularProgressIndicator(modifier = Modifier.align(Alignment.Center))
}
return
}
@ -57,7 +69,10 @@ fun ChannelContextSheet(
context.getString(R.string.channel_context_sheet_actions_copy_id_copied),
Toast.LENGTH_SHORT
).show()
navController.popBackStack()
coroutineScope.launch {
onHideSheet()
}
}
SheetClickable(
@ -79,8 +94,8 @@ fun ChannelContextSheet(
channel.lastMessageID?.let {
RevoltAPI.unreads.markAsRead(channelId, it, sync = true)
}
onHideSheet()
}
navController.popBackStack()
}
}
}

View File

@ -1,7 +1,9 @@
package chat.revolt.screens.chat.sheets
package chat.revolt.sheets
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
@ -10,26 +12,32 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Add
import androidx.compose.material.icons.filled.List
import androidx.compose.material.icons.filled.Notifications
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
import chat.revolt.R
import chat.revolt.api.RevoltAPI
import chat.revolt.components.generic.SheetClickable
@Composable
fun ChannelInfoSheet(
navController: NavController,
channelId: String,
) {
val channel = RevoltAPI.channelCache[channelId]
if (channel == null) {
navController.popBackStack()
Box(
modifier = Modifier
.fillMaxWidth()
.height(200.dp)
) {
CircularProgressIndicator(modifier = Modifier.align(Alignment.Center))
}
return
}

View File

@ -1,10 +1,11 @@
package chat.revolt.screens.chat.sheets
package chat.revolt.sheets
import android.widget.Toast
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
@ -12,12 +13,14 @@ import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Delete
import androidx.compose.material.icons.filled.Edit
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.surfaceColorAtElevation
import androidx.compose.runtime.Composable
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.LocalClipboardManager
@ -26,7 +29,6 @@ import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
import chat.revolt.R
import chat.revolt.api.REVOLT_APP
import chat.revolt.api.RevoltAPI
@ -37,12 +39,19 @@ import kotlinx.coroutines.launch
@Composable
fun MessageContextSheet(
navController: NavController,
messageId: String,
onHideSheet: suspend () -> Unit,
onReportMessage: () -> Unit,
) {
val message = RevoltAPI.messageCache[messageId]
if (message == null) {
navController.popBackStack()
Box(
modifier = Modifier
.fillMaxWidth()
.height(200.dp)
) {
CircularProgressIndicator(modifier = Modifier.align(Alignment.Center))
}
return
}
@ -89,8 +98,8 @@ fun MessageContextSheet(
) {
coroutineScope.launch {
UiCallbacks.replyToMessage(messageId)
onHideSheet()
}
navController.popBackStack()
}
SheetClickable(
@ -113,7 +122,10 @@ fun MessageContextSheet(
context.getString(R.string.comingsoon_toast),
Toast.LENGTH_SHORT
).show()
navController.popBackStack()
coroutineScope.launch {
onHideSheet()
}
}
SheetClickable(
@ -132,22 +144,27 @@ fun MessageContextSheet(
},
) {
if (message.content.isNullOrEmpty()) {
Toast.makeText(
context,
context.getString(R.string.message_context_sheet_actions_copy_failed_empty),
Toast.LENGTH_SHORT
).show()
navController.popBackStack()
coroutineScope.launch {
onHideSheet()
Toast.makeText(
context,
context.getString(R.string.message_context_sheet_actions_copy_failed_empty),
Toast.LENGTH_SHORT
).show()
}
return@SheetClickable
}
clipboardManager.setText(AnnotatedString(message.content))
Toast.makeText(
context,
context.getString(R.string.copied),
Toast.LENGTH_SHORT
).show()
navController.popBackStack()
coroutineScope.launch {
clipboardManager.setText(AnnotatedString(message.content))
onHideSheet()
}
}
SheetClickable(
@ -171,7 +188,11 @@ fun MessageContextSheet(
context.getString(R.string.message_context_sheet_actions_copy_failed_empty),
Toast.LENGTH_SHORT
).show()
navController.popBackStack()
coroutineScope.launch {
onHideSheet()
}
return@SheetClickable
}
@ -187,7 +208,10 @@ fun MessageContextSheet(
context.getString(R.string.message_context_sheet_actions_copy_link_copied),
Toast.LENGTH_SHORT
).show()
navController.popBackStack()
coroutineScope.launch {
onHideSheet()
}
}
SheetClickable(
@ -213,7 +237,10 @@ fun MessageContextSheet(
context.getString(R.string.message_context_sheet_actions_copy_id_copied),
Toast.LENGTH_SHORT
).show()
navController.popBackStack()
coroutineScope.launch {
onHideSheet()
}
}
@ -237,7 +264,10 @@ fun MessageContextSheet(
context.getString(R.string.comingsoon_toast),
Toast.LENGTH_SHORT
).show()
navController.popBackStack()
coroutineScope.launch {
onHideSheet()
}
}
SheetClickable(
@ -260,7 +290,10 @@ fun MessageContextSheet(
context.getString(R.string.comingsoon_toast),
Toast.LENGTH_SHORT
).show()
navController.popBackStack()
coroutineScope.launch {
onHideSheet()
}
}
SheetClickable(
@ -283,7 +316,10 @@ fun MessageContextSheet(
context.getString(R.string.comingsoon_toast),
Toast.LENGTH_SHORT
).show()
navController.popBackStack()
coroutineScope.launch {
onHideSheet()
}
}
SheetClickable(
@ -301,7 +337,9 @@ fun MessageContextSheet(
)
},
) {
navController.navigate("report/message/${message.id}")
coroutineScope.launch {
onReportMessage()
}
}
}
}

View File

@ -0,0 +1,56 @@
package chat.revolt.sheets
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Settings
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import chat.revolt.R
import chat.revolt.api.RevoltAPI
import chat.revolt.components.generic.SheetClickable
@Composable
fun StatusSheet(
onBeforeNavigation: () -> Unit,
onGoSettings: () -> Unit
) {
val selfUser = RevoltAPI.userCache[RevoltAPI.selfId]!!
Column(
modifier = Modifier
.padding(horizontal = 16.dp, vertical = 8.dp)
.verticalScroll(rememberScrollState())
) {
Text(text = "Logged in as @${selfUser.username} (${selfUser.id})")
Spacer(modifier = Modifier.height(8.dp))
SheetClickable(
icon = { modifier ->
Icon(
imageVector = Icons.Default.Settings,
contentDescription = null,
modifier = modifier
)
},
label = { style ->
Text(
text = stringResource(id = R.string.settings),
style = style
)
}
) {
onBeforeNavigation()
onGoSettings()
}
}
}

View File

@ -1,8 +1,8 @@
buildscript {
ext {
compose_version = '1.4.0'
compose_bom_version = '2023.01.00'
accompanist_version = '0.28.0'
compose_bom_version = '2023.05.01'
accompanist_version = '0.31.2-alpha'
okhttp_version = '4.10.0'
nav_version = '2.5.3'
hilt_version = '2.44'