feat: bottom navigation when drawer is open, placeholder settings screen

This commit is contained in:
Infi 2023-01-11 01:24:44 +01:00
parent 89d372d65c
commit 2e6e20939f
7 changed files with 135 additions and 21 deletions

View File

@ -12,6 +12,7 @@ import androidx.compose.material3.*
import androidx.compose.runtime.* import androidx.compose.runtime.*
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.IntSize
import chat.revolt.screens.SplashScreen import chat.revolt.screens.SplashScreen
import chat.revolt.screens.about.AboutScreen import chat.revolt.screens.about.AboutScreen
import chat.revolt.screens.about.AttributionScreen import chat.revolt.screens.about.AttributionScreen
@ -20,6 +21,7 @@ import chat.revolt.screens.chat.ChatRouterScreen
import chat.revolt.screens.login.GreeterScreen import chat.revolt.screens.login.GreeterScreen
import chat.revolt.screens.login.LoginScreen import chat.revolt.screens.login.LoginScreen
import chat.revolt.screens.login.MfaScreen import chat.revolt.screens.login.MfaScreen
import chat.revolt.screens.settings.SettingsScreen
import chat.revolt.ui.theme.RevoltTheme import chat.revolt.ui.theme.RevoltTheme
import com.google.accompanist.navigation.animation.AnimatedNavHost import com.google.accompanist.navigation.animation.AnimatedNavHost
import com.google.accompanist.navigation.animation.composable import com.google.accompanist.navigation.animation.composable
@ -44,6 +46,7 @@ class MainActivity : ComponentActivity() {
} }
val RevoltTweenInt: FiniteAnimationSpec<IntOffset> = tween(400, easing = EaseInOutExpo) 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 RevoltTweenFloat: FiniteAnimationSpec<Float> = tween(400, easing = EaseInOutExpo)
@OptIn(ExperimentalAnimationApi::class) @OptIn(ExperimentalAnimationApi::class)
@ -93,6 +96,8 @@ fun AppEntrypoint() {
composable("chat") { ChatRouterScreen(navController) } composable("chat") { ChatRouterScreen(navController) }
composable("settings") { SettingsScreen(navController) }
composable("about") { AboutScreen(navController) } composable("about") { AboutScreen(navController) }
composable("about/oss") { AttributionScreen(navController) } composable("about/oss") { AttributionScreen(navController) }
composable("about/placeholder") { PlaceholderScreen(navController) } composable("about/placeholder") { PlaceholderScreen(navController) }

View File

@ -3,6 +3,7 @@ package chat.revolt.api.realtime
import android.util.Log import android.util.Log
import androidx.compose.runtime.mutableStateMapOf import androidx.compose.runtime.mutableStateMapOf
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.snapshots.SnapshotStateMap
import chat.revolt.api.REVOLT_WEBSOCKET import chat.revolt.api.REVOLT_WEBSOCKET
import chat.revolt.api.RevoltAPI import chat.revolt.api.RevoltAPI
import chat.revolt.api.RevoltHttp import chat.revolt.api.RevoltHttp
@ -118,9 +119,7 @@ object RealtimeSocket {
RevoltAPI.messageCache[messageFrame.id!!] = messageFrame RevoltAPI.messageCache[messageFrame.id!!] = messageFrame
channelCallbacks[messageFrame.channel]?.forEach { callback -> channelCallbacks[messageFrame.channel]?.onMessage(messageFrame)
callback.onMessage(messageFrame)
}
} }
"ChannelStartTyping" -> { "ChannelStartTyping" -> {
val typingFrame = val typingFrame =
@ -130,9 +129,7 @@ object RealtimeSocket {
"Received channel start typing frame for ${typingFrame.id} from ${typingFrame.user}." "Received channel start typing frame for ${typingFrame.id} from ${typingFrame.user}."
) )
channelCallbacks[typingFrame.id]?.forEach { callback -> channelCallbacks[typingFrame.id]?.onStartTyping(typingFrame)
callback.onStartTyping(typingFrame)
}
} }
"ChannelStopTyping" -> { "ChannelStopTyping" -> {
val typingFrame = val typingFrame =
@ -142,9 +139,7 @@ object RealtimeSocket {
"Received channel stop typing frame for ${typingFrame.id} from ${typingFrame.user}." "Received channel stop typing frame for ${typingFrame.id} from ${typingFrame.user}."
) )
channelCallbacks[typingFrame.id]?.forEach { callback -> channelCallbacks[typingFrame.id]?.onStopTyping(typingFrame)
callback.onStopTyping(typingFrame)
}
} }
"UserUpdate" -> { "UserUpdate" -> {
val userUpdateFrame = val userUpdateFrame =
@ -178,18 +173,16 @@ object RealtimeSocket {
fun onMessage(message: MessageFrame) fun onMessage(message: MessageFrame)
} }
private val channelCallbacks: MutableMap<String, List<ChannelCallback>> = mutableStateMapOf() private val channelCallbacks: SnapshotStateMap<String, ChannelCallback> = mutableStateMapOf()
fun registerChannelCallback(channelId: String, callback: ChannelCallback) { fun registerChannelCallback(channelId: String, callback: ChannelCallback) {
val callbacks = channelCallbacks[channelId] ?: emptyList() channelCallbacks[channelId] = callback
channelCallbacks[channelId] = callbacks + callback
Log.d("RealtimeSocket", "Registered channel callback for $channelId.") Log.d("RealtimeSocket", "Registered channel callback for $channelId.")
} }
fun unregisterChannelCallback(channelId: String, callback: ChannelCallback) { fun unregisterChannelCallback(channelId: String, callback: ChannelCallback) {
val callbacks = channelCallbacks[channelId] ?: emptyList() channelCallbacks.remove(channelId, callback)
channelCallbacks[channelId] = callbacks - callback
Log.d("RealtimeSocket", "Unregistered channel callback for $channelId") Log.d("RealtimeSocket", "Unregistered channel callback for $channelId")
} }

View File

@ -0,0 +1,68 @@
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.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 {
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),
)
}
}
}
}

View File

@ -1,7 +1,6 @@
package chat.revolt.screens.chat package chat.revolt.screens.chat
import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.*
import androidx.compose.animation.Crossfade
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
@ -37,6 +36,7 @@ import chat.revolt.api.realtime.RealtimeSocket
import chat.revolt.api.schemas.ChannelType import chat.revolt.api.schemas.ChannelType
import chat.revolt.components.chat.DisconnectedNotice import chat.revolt.components.chat.DisconnectedNotice
import chat.revolt.components.generic.RemoteImage import chat.revolt.components.generic.RemoteImage
import chat.revolt.components.screens.chat.BottomNavigation
import chat.revolt.components.screens.chat.DrawerChannel import chat.revolt.components.screens.chat.DrawerChannel
import chat.revolt.screens.chat.views.ChannelScreen import chat.revolt.screens.chat.views.ChannelScreen
import chat.revolt.screens.chat.views.HomeScreen import chat.revolt.screens.chat.views.HomeScreen
@ -80,7 +80,7 @@ fun ChatRouterScreen(topNav: NavController, viewModel: ChatRouterViewModel = vie
val navController = rememberNavController() val navController = rememberNavController()
val navBackStackEntry by navController.currentBackStackEntryAsState() val navBackStackEntry by navController.currentBackStackEntryAsState()
Column() { Column {
AnimatedVisibility(visible = RealtimeSocket.disconnectionState != DisconnectionState.Connected) { AnimatedVisibility(visible = RealtimeSocket.disconnectionState != DisconnectionState.Connected) {
DisconnectedNotice( DisconnectedNotice(
state = RealtimeSocket.disconnectionState, state = RealtimeSocket.disconnectionState,
@ -174,7 +174,8 @@ fun ChatRouterScreen(topNav: NavController, viewModel: ChatRouterViewModel = vie
RevoltAPI.channelCache.values.filter { it.channelType == ChannelType.Group } RevoltAPI.channelCache.values.filter { it.channelType == ChannelType.Group }
.forEach { channel -> .forEach { channel ->
DrawerChannel( DrawerChannel(
name = channel.name ?: "GDM #${channel.id}", name = channel.name
?: "GDM #${channel.id}",
channelType = ChannelType.Group, channelType = ChannelType.Group,
selected = channel.id == (navBackStackEntry?.arguments?.getString( selected = channel.id == (navBackStackEntry?.arguments?.getString(
"channelId" "channelId"
@ -192,7 +193,8 @@ fun ChatRouterScreen(topNav: NavController, viewModel: ChatRouterViewModel = vie
val server = RevoltAPI.serverCache[it] val server = RevoltAPI.serverCache[it]
Text( Text(
text = server?.name ?: stringResource(R.string.unknown), text = server?.name
?: stringResource(R.string.unknown),
fontWeight = FontWeight.Black, fontWeight = FontWeight.Black,
fontSize = 24.sp, fontSize = 24.sp,
modifier = Modifier.padding(16.dp) modifier = Modifier.padding(16.dp)
@ -245,5 +247,10 @@ fun ChatRouterScreen(topNav: NavController, viewModel: ChatRouterViewModel = vie
} }
} }
} }
BottomNavigation(
navController = topNav,
show = channelDrawerState.currentValue == DrawerValue.Open,
)
} }
} }

View File

@ -78,10 +78,10 @@ fun GreeterScreen(navController: NavController) {
.padding(horizontal = 20.dp, vertical = 30.dp) .padding(horizontal = 20.dp, vertical = 30.dp)
) { ) {
ElevatedButton( ElevatedButton(
onClick = { navController.navigate("about") }, onClick = { navController.navigate("about/placeholder") },
modifier = Modifier.fillMaxWidth() modifier = Modifier.fillMaxWidth()
) { ) {
Text(text = stringResource(R.string.about)) Text(text = stringResource(R.string.signup))
} }
Button( Button(

View File

@ -0,0 +1,40 @@
package chat.revolt.screens.settings
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material3.Button
import androidx.compose.material3.ElevatedButton
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.navigation.NavController
import chat.revolt.R
import chat.revolt.components.generic.PageHeader
@Composable
fun SettingsScreen(
navController: NavController
) {
Column(
modifier = Modifier
.fillMaxSize()
) {
PageHeader(stringResource(id = R.string.settings))
ElevatedButton(
modifier = Modifier.fillMaxWidth(),
onClick = {
navController.popBackStack()
}) {
Text(text = stringResource(id = R.string.back))
}
Button(
modifier = Modifier.fillMaxWidth(),
onClick = {
navController.navigate("about")
}) {
Text(text = stringResource(id = R.string.about))
}
}
}

View File

@ -106,4 +106,5 @@
<string name="tap_to_retry">Tap to retry</string> <string name="tap_to_retry">Tap to retry</string>
<string name="scroll_to_bottom">Scroll to bottom</string> <string name="scroll_to_bottom">Scroll to bottom</string>
<string name="settings">Settings</string>
</resources> </resources>