diff --git a/app/build.gradle b/app/build.gradle index 203ddd3a..cdf75e39 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -70,6 +70,7 @@ dependencies { // Jetpack Compose implementation "androidx.compose.ui:ui" implementation "androidx.compose.ui:ui-util" + implementation 'androidx.compose.material:material' implementation 'androidx.compose.material3:material3' implementation "androidx.compose.ui:ui-tooling-preview" implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.5.1' diff --git a/app/src/main/java/chat/revolt/components/generic/UserAvatar.kt b/app/src/main/java/chat/revolt/components/generic/UserAvatar.kt index 2cd24ad8..65db6445 100644 --- a/app/src/main/java/chat/revolt/components/generic/UserAvatar.kt +++ b/app/src/main/java/chat/revolt/components/generic/UserAvatar.kt @@ -1,7 +1,9 @@ package chat.revolt.components.generic +import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.background import androidx.compose.foundation.border +import androidx.compose.foundation.combinedClickable import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width @@ -26,7 +28,17 @@ enum class Presence { Idle, Dnd, Focus, - Offline, + Offline +} + +fun presenceFromStatus(status: String): Presence { + return when (status) { + "online" -> Presence.Online + "idle" -> Presence.Idle + "dnd" -> Presence.Dnd + "focus" -> Presence.Focus + else -> Presence.Offline + } } fun presenceColour(presence: Presence): Color { @@ -50,6 +62,7 @@ fun PresenceBadge(presence: Presence, size: Dp = 16.dp) { ) } +@OptIn(ExperimentalFoundationApi::class) @Composable fun UserAvatar( username: String, @@ -60,6 +73,8 @@ fun UserAvatar( rawUrl: String? = null, size: Dp = 40.dp, presenceSize: Dp = 16.dp, + onLongClick: (() -> Unit)? = null, + onClick: (() -> Unit)? = null, ) { Box( modifier = modifier @@ -69,19 +84,35 @@ fun UserAvatar( if (avatar != null) { RemoteImage( url = rawUrl ?: "$REVOLT_FILES/avatars/${avatar.id!!}/user.png", - description = stringResource(id = R.string.avatar_alt, username), contentScale = ContentScale.Crop, + description = stringResource(id = R.string.avatar_alt, username), modifier = Modifier .clip(CircleShape) .size(size) + .then( + if (onLongClick != null || onClick != null) Modifier + .combinedClickable( + onClick = { onClick?.invoke() }, + onLongClick = { onLongClick?.invoke() } + ) + else Modifier + ) ) } else { RemoteImage( url = "$REVOLT_BASE/users/${userId}/default_avatar", + description = stringResource(id = R.string.avatar_alt, username), modifier = Modifier .size(size) + .then( + if (onLongClick != null || onClick != null) Modifier + .combinedClickable( + onClick = { onClick?.invoke() }, + onLongClick = { onLongClick?.invoke() } + ) + else Modifier + ) .clip(CircleShape), - description = stringResource(id = R.string.avatar_alt, username), ) } diff --git a/app/src/main/java/chat/revolt/components/screens/chat/BottomNavigation.kt b/app/src/main/java/chat/revolt/components/screens/chat/BottomNavigation.kt deleted file mode 100644 index b1606021..00000000 --- a/app/src/main/java/chat/revolt/components/screens/chat/BottomNavigation.kt +++ /dev/null @@ -1,71 +0,0 @@ -package chat.revolt.components.screens.chat - -import androidx.compose.animation.AnimatedVisibility -import androidx.compose.animation.expandVertically -import androidx.compose.animation.shrinkVertically -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.Home -import androidx.compose.material.icons.filled.Settings -import androidx.compose.material3.BottomAppBar -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton -import androidx.compose.material3.MaterialTheme -import androidx.compose.runtime.Composable -import androidx.compose.runtime.rememberCoroutineScope -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource -import androidx.navigation.NavController -import chat.revolt.R -import chat.revolt.RevoltTweenIntSize -import kotlinx.coroutines.launch - -@Composable -fun BottomNavigation( - navController: NavController, - show: Boolean, -) { - val scope = rememberCoroutineScope() - - AnimatedVisibility( - visible = show, - enter = expandVertically( - animationSpec = RevoltTweenIntSize - ), - exit = shrinkVertically( - animationSpec = RevoltTweenIntSize - ), - ) { - BottomAppBar( - containerColor = MaterialTheme.colorScheme.background, - ) { - IconButton( - modifier = Modifier.weight(1f), - onClick = { - scope.launch { - if (navController.currentDestination?.route != "chat") { - navController.navigate("chat") - } - } - }) { - Icon( - imageVector = Icons.Default.Home, - contentDescription = stringResource(id = R.string.home), - ) - } - IconButton( - modifier = Modifier.weight(1f), - onClick = { - scope.launch { - if (navController.currentDestination?.route != "settings") { - navController.navigate("settings") - } - } - }) { - Icon( - imageVector = Icons.Default.Settings, - contentDescription = stringResource(id = R.string.settings), - ) - } - } - } -} diff --git a/app/src/main/java/chat/revolt/components/screens/chat/DoubleDrawer.kt b/app/src/main/java/chat/revolt/components/screens/chat/DoubleDrawer.kt new file mode 100644 index 00000000..22fd261a --- /dev/null +++ b/app/src/main/java/chat/revolt/components/screens/chat/DoubleDrawer.kt @@ -0,0 +1,185 @@ +package chat.revolt.components.screens.chat + +import android.content.res.Configuration +import androidx.compose.animation.core.animateDpAsState +import androidx.compose.animation.core.spring +import androidx.compose.foundation.gestures.Orientation +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.* +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.saveable.Saver +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.platform.LocalLayoutDirection +import androidx.compose.ui.unit.IntOffset +import androidx.compose.ui.unit.LayoutDirection +import androidx.compose.ui.unit.dp +import kotlin.math.abs +import kotlin.math.roundToInt + +enum class DoubleDrawerOpenState { + Start, + Center, + End +} + +@OptIn(ExperimentalMaterialApi::class) +class DoubleDrawerState( + var initialValue: DoubleDrawerOpenState = DoubleDrawerOpenState.Center, + val confirmStateChange: (DoubleDrawerOpenState) -> Boolean = { true } +) { + val swipeableState = SwipeableState( + initialValue = initialValue, + animationSpec = spring(), + confirmStateChange = confirmStateChange + ) + + suspend fun focusStart() { + swipeableState.animateTo(DoubleDrawerOpenState.Start) + } + + suspend fun focusCenter() { + swipeableState.animateTo(DoubleDrawerOpenState.Center) + } + + suspend fun focusEnd() { + swipeableState.animateTo(DoubleDrawerOpenState.End) + } + + val isStart: Boolean + get() = swipeableState.currentValue == DoubleDrawerOpenState.Start + val isCenter: Boolean + get() = swipeableState.currentValue == DoubleDrawerOpenState.Center + val isEnd: Boolean + get() = swipeableState.currentValue == DoubleDrawerOpenState.End + + val currentValue: DoubleDrawerOpenState + get() = swipeableState.currentValue + + companion object { + fun Saver( + confirmStateChange: (DoubleDrawerOpenState) -> Boolean + ): Saver = Saver( + save = { it.currentValue }, + restore = { DoubleDrawerState(it, confirmStateChange) } + ) + } +} + +@Composable +fun rememberDoubleDrawerState( + initialValue: DoubleDrawerOpenState = DoubleDrawerOpenState.Center, + confirmStateChange: (DoubleDrawerOpenState) -> Boolean = { true } +): DoubleDrawerState = rememberSaveable( + saver = DoubleDrawerState.Saver(confirmStateChange) +) { + DoubleDrawerState(initialValue, confirmStateChange) +} + +@OptIn(ExperimentalMaterialApi::class) +@Composable +fun DoubleDrawer( + state: DoubleDrawerState = rememberDoubleDrawerState(), + startPanel: @Composable () -> Unit, + endPanel: @Composable () -> Unit, + content: @Composable () -> Unit, +) { + val layoutDirection = LocalLayoutDirection.current + + BoxWithConstraints(Modifier.fillMaxSize()) { + val isPortrait = + LocalContext.current.resources.configuration.orientation == Configuration.ORIENTATION_PORTRAIT + val drawerWeight = + if (isPortrait) 0.9f else 0.8f + + val offsetValue = + (constraints.maxWidth * drawerWeight) + (LocalDensity.current.run { 16.dp.toPx() }) + val isAtOffset = abs(state.swipeableState.offset.value) == abs(offsetValue) + + val contentCornerRadius by animateDpAsState( + targetValue = if (isAtOffset) 16.dp else 0.dp, + ) + + Box( + modifier = Modifier + .fillMaxSize() + .swipeable( + state = state.swipeableState, + orientation = Orientation.Horizontal, + velocityThreshold = 500.dp, + anchors = mapOf( + offsetValue to DoubleDrawerOpenState.Start, + 0f to DoubleDrawerOpenState.Center, + -offsetValue to DoubleDrawerOpenState.End + ), + reverseDirection = layoutDirection == LayoutDirection.Rtl, + resistance = ResistanceConfig(0.5f, 0.5f) + ) + ) { + Box( + modifier = Modifier + .fillMaxHeight() + .fillMaxWidth(drawerWeight) + .clip( + RoundedCornerShape( + topEnd = 16.dp, + bottomEnd = 16.dp + ) + ) + .align(Alignment.CenterStart) + .offset { + IntOffset( + x = state.swipeableState.offset.value.roundToInt() - offsetValue.roundToInt(), + y = 0 + ) + }, + ) { + startPanel() + } + + Box( + modifier = Modifier + .fillMaxSize() + .clip( + RoundedCornerShape(contentCornerRadius) + ) + .align(Alignment.Center) + .offset { + IntOffset( + x = state.swipeableState.offset.value.roundToInt(), + y = 0 + ) + }, + ) { + content() + } + + Box( + modifier = Modifier + .fillMaxHeight() + .fillMaxWidth(drawerWeight) + .clip( + RoundedCornerShape( + topStart = 16.dp, + bottomStart = 16.dp + ) + ) + .align(Alignment.CenterEnd) + .offset { + IntOffset( + x = state.swipeableState.offset.value.roundToInt() + offsetValue.roundToInt(), + y = 0 + ) + }, + ) { + endPanel() + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/chat/revolt/components/screens/chat/DrawerChannel.kt b/app/src/main/java/chat/revolt/components/screens/chat/drawer/server/DrawerChannel.kt similarity index 92% rename from app/src/main/java/chat/revolt/components/screens/chat/DrawerChannel.kt rename to app/src/main/java/chat/revolt/components/screens/chat/drawer/server/DrawerChannel.kt index 8e3a6ba1..07a83ba2 100644 --- a/app/src/main/java/chat/revolt/components/screens/chat/DrawerChannel.kt +++ b/app/src/main/java/chat/revolt/components/screens/chat/drawer/server/DrawerChannel.kt @@ -1,4 +1,4 @@ -package chat.revolt.components.screens.chat +package chat.revolt.components.screens.chat.drawer.server import androidx.compose.foundation.background import androidx.compose.foundation.clickable @@ -14,6 +14,7 @@ import androidx.compose.ui.draw.clip import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import chat.revolt.api.schemas.ChannelType +import chat.revolt.components.screens.chat.ChannelIcon @Composable fun DrawerChannel( diff --git a/app/src/main/java/chat/revolt/components/screens/chat/DrawerServer.kt b/app/src/main/java/chat/revolt/components/screens/chat/drawer/server/DrawerServer.kt similarity index 96% rename from app/src/main/java/chat/revolt/components/screens/chat/DrawerServer.kt rename to app/src/main/java/chat/revolt/components/screens/chat/drawer/server/DrawerServer.kt index 52176fdc..1d157f3a 100644 --- a/app/src/main/java/chat/revolt/components/screens/chat/DrawerServer.kt +++ b/app/src/main/java/chat/revolt/components/screens/chat/drawer/server/DrawerServer.kt @@ -1,4 +1,4 @@ -package chat.revolt.components.screens.chat +package chat.revolt.components.screens.chat.drawer.server import androidx.compose.foundation.background import androidx.compose.foundation.clickable diff --git a/app/src/main/java/chat/revolt/components/screens/chat/DrawerServerlikeIcon.kt b/app/src/main/java/chat/revolt/components/screens/chat/drawer/server/DrawerServerlikeIcon.kt similarity index 93% rename from app/src/main/java/chat/revolt/components/screens/chat/DrawerServerlikeIcon.kt rename to app/src/main/java/chat/revolt/components/screens/chat/drawer/server/DrawerServerlikeIcon.kt index 6b48e882..e41c1958 100644 --- a/app/src/main/java/chat/revolt/components/screens/chat/DrawerServerlikeIcon.kt +++ b/app/src/main/java/chat/revolt/components/screens/chat/drawer/server/DrawerServerlikeIcon.kt @@ -1,4 +1,4 @@ -package chat.revolt.components.screens.chat +package chat.revolt.components.screens.chat.drawer.server import androidx.compose.foundation.background import androidx.compose.foundation.layout.padding diff --git a/app/src/main/java/chat/revolt/components/screens/chat/ServerDrawerSeparator.kt b/app/src/main/java/chat/revolt/components/screens/chat/drawer/server/ServerDrawerSeparator.kt similarity index 92% rename from app/src/main/java/chat/revolt/components/screens/chat/ServerDrawerSeparator.kt rename to app/src/main/java/chat/revolt/components/screens/chat/drawer/server/ServerDrawerSeparator.kt index 58cca645..bab31efc 100644 --- a/app/src/main/java/chat/revolt/components/screens/chat/ServerDrawerSeparator.kt +++ b/app/src/main/java/chat/revolt/components/screens/chat/drawer/server/ServerDrawerSeparator.kt @@ -1,4 +1,4 @@ -package chat.revolt.components.screens.chat +package chat.revolt.components.screens.chat.drawer.server import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box diff --git a/app/src/main/java/chat/revolt/screens/chat/ChatRouterScreen.kt b/app/src/main/java/chat/revolt/screens/chat/ChatRouterScreen.kt index 3334fb8e..021bbe75 100644 --- a/app/src/main/java/chat/revolt/screens/chat/ChatRouterScreen.kt +++ b/app/src/main/java/chat/revolt/screens/chat/ChatRouterScreen.kt @@ -1,19 +1,24 @@ package chat.revolt.screens.chat +import android.widget.Toast import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.Crossfade import androidx.compose.foundation.background import androidx.compose.foundation.layout.* 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.Home +import androidx.compose.material.icons.filled.Add import androidx.compose.material3.* import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf 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.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp @@ -31,9 +36,17 @@ import chat.revolt.api.realtime.DisconnectionState import chat.revolt.api.realtime.RealtimeSocket import chat.revolt.api.schemas.ChannelType import chat.revolt.components.chat.DisconnectedNotice -import chat.revolt.components.screens.chat.* +import chat.revolt.components.generic.UserAvatar +import chat.revolt.components.generic.presenceFromStatus +import chat.revolt.components.screens.chat.DoubleDrawer +import chat.revolt.components.screens.chat.drawer.server.DrawerChannel +import chat.revolt.components.screens.chat.drawer.server.DrawerServer +import chat.revolt.components.screens.chat.drawer.server.DrawerServerlikeIcon +import chat.revolt.components.screens.chat.drawer.server.ServerDrawerSeparator +import chat.revolt.components.screens.chat.rememberDoubleDrawerState 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.ChannelScreen import chat.revolt.screens.chat.views.HomeScreen import com.google.accompanist.navigation.material.ExperimentalMaterialNavigationApi @@ -72,11 +85,12 @@ class ChatRouterViewModel : ViewModel() { } } -@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterialNavigationApi::class) +@OptIn(ExperimentalMaterialNavigationApi::class) @Composable fun ChatRouterScreen(topNav: NavController, viewModel: ChatRouterViewModel = viewModel()) { - val channelDrawerState = rememberDrawerState(DrawerValue.Closed) + val drawerState = rememberDoubleDrawerState() val scope = rememberCoroutineScope() + val context = LocalContext.current val bottomSheetNavigator = rememberBottomSheetNavigator() val navController = rememberNavController(bottomSheetNavigator) @@ -93,56 +107,80 @@ fun ChatRouterScreen(topNav: NavController, viewModel: ChatRouterViewModel = vie }) } - DismissibleNavigationDrawer( - drawerState = channelDrawerState, - drawerContent = { - ModalDrawerSheet( - drawerContainerColor = MaterialTheme.colorScheme.surfaceColorAtElevation(1.dp) - ) { - Column(Modifier.fillMaxWidth()) { - Row { - Column( + DoubleDrawer( + state = drawerState, + startPanel = { + Column(Modifier.fillMaxWidth()) { + Row { + Column( + modifier = Modifier + .fillMaxHeight() + .verticalScroll(rememberScrollState()) + ) { + 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 - .fillMaxHeight() - .verticalScroll(rememberScrollState()) - .background( - MaterialTheme.colorScheme.surfaceColorAtElevation( - 2.dp + .padding(8.dp) + .size(48.dp) + ) + + ServerDrawerSeparator() + + RevoltAPI.serverCache.values + .sortedBy { it.id } + .forEach { server -> + if (server.name == null) return@forEach + + DrawerServer( + iconId = server.icon?.id, + serverName = server.name + ) { + viewModel.navigateToServer( + server.id!!, + navController ) - ) - ) { - DrawerServerlikeIcon( - onClick = { - viewModel.navigateToServer("home", navController) } - ) { - Icon( - Icons.Default.Home, - contentDescription = stringResource(id = R.string.home), - modifier = Modifier.padding(4.dp) - ) } - ServerDrawerSeparator() - - RevoltAPI.serverCache.values - .sortedBy { it.id } - .forEach { server -> - if (server.name == null) return@forEach - - DrawerServer( - iconId = server.icon?.id, - serverName = server.name - ) { - viewModel.navigateToServer( - server.id!!, - navController - ) - } - } + DrawerServerlikeIcon( + onClick = { + Toast.makeText( + context, + context.getString(R.string.comingsoon_toast), + Toast.LENGTH_SHORT + ).show() + } + ) { + Icon( + Icons.Default.Add, + contentDescription = stringResource(id = R.string.server_plus_alt), + modifier = Modifier.padding(4.dp) + ) } + } - Crossfade(targetState = viewModel.currentServer) { + Crossfade(targetState = viewModel.currentServer) { + Surface( + tonalElevation = 1.dp, + modifier = Modifier + .padding(vertical = 4.dp) + .clip(RoundedCornerShape(16.dp)) + ) { Column( Modifier .weight(1f) @@ -165,7 +203,7 @@ fun ChatRouterScreen(topNav: NavController, viewModel: ChatRouterViewModel = vie onClick = { navController.navigate("channel/${channel.id}") scope.launch { - channelDrawerState.close() + drawerState.focusCenter() } } ) @@ -196,13 +234,14 @@ fun ChatRouterScreen(topNav: NavController, viewModel: ChatRouterViewModel = vie "channelId" ) == ch.id, onClick = { - scope.launch { channelDrawerState.close() } + scope.launch { drawerState.focusCenter() } navController.navigate("channel/${ch.id}") { popUpTo("home") { inclusive = true } } - }) + } + ) } } } @@ -213,7 +252,16 @@ fun ChatRouterScreen(topNav: NavController, viewModel: ChatRouterViewModel = vie } } }, - modifier = Modifier.weight(1f), + endPanel = { + Box( + modifier = Modifier + .background(MaterialTheme.colorScheme.surfaceColorAtElevation(2.dp)) + .fillMaxSize(), + contentAlignment = Alignment.Center + ) { + Text(text = "👋", fontSize = 64.sp) + } + }, ) { Column(Modifier.fillMaxSize()) { NavHost(navController = navController, startDestination = "home") { @@ -248,14 +296,12 @@ fun ChatRouterScreen(topNav: NavController, viewModel: ChatRouterViewModel = vie ) } } + bottomSheet("status") { + StatusSheet(navController = navController, topNav = topNav) + } } } } - - BottomNavigation( - navController = topNav, - show = channelDrawerState.currentValue == DrawerValue.Open, - ) } } } \ No newline at end of file diff --git a/app/src/main/java/chat/revolt/screens/chat/sheets/StatusSheet.kt b/app/src/main/java/chat/revolt/screens/chat/sheets/StatusSheet.kt new file mode 100644 index 00000000..ada4201d --- /dev/null +++ b/app/src/main/java/chat/revolt/screens/chat/sheets/StatusSheet.kt @@ -0,0 +1,64 @@ +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") + } + } + } +} \ 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 72b25e97..9672c9e1 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -86,6 +86,8 @@ Home Log out + Add server + %1$s\'s avatar Direct Message