diff --git a/app/src/main/java/chat/revolt/MainActivity.kt b/app/src/main/java/chat/revolt/MainActivity.kt index 04cad90e..a339f100 100644 --- a/app/src/main/java/chat/revolt/MainActivity.kt +++ b/app/src/main/java/chat/revolt/MainActivity.kt @@ -16,8 +16,7 @@ import chat.revolt.screens.SplashScreen import chat.revolt.screens.about.AboutScreen import chat.revolt.screens.about.AttributionScreen import chat.revolt.screens.about.PlaceholderScreen -import chat.revolt.screens.chat.ChannelScreen -import chat.revolt.screens.chat.HomeScreen +import chat.revolt.screens.chat.ChatRouterScreen import chat.revolt.screens.login.GreeterScreen import chat.revolt.screens.login.LoginScreen import chat.revolt.screens.login.MfaScreen @@ -92,12 +91,7 @@ fun AppEntrypoint() { MfaScreen(navController, allowedAuthTypes, mfaTicket) } - composable("chat/home") { HomeScreen(navController) } - composable("chat/channel/{channelId}") { backStackEntry -> - val channelId = backStackEntry.arguments?.getString("channelId") ?: "" - - ChannelScreen(navController, channelId) - } + composable("chat") { ChatRouterScreen(navController) } composable("about") { AboutScreen(navController) } composable("about/oss") { AttributionScreen(navController) } diff --git a/app/src/main/java/chat/revolt/screens/SplashScreen.kt b/app/src/main/java/chat/revolt/screens/SplashScreen.kt index b47d223c..5332e8cc 100644 --- a/app/src/main/java/chat/revolt/screens/SplashScreen.kt +++ b/app/src/main/java/chat/revolt/screens/SplashScreen.kt @@ -80,7 +80,7 @@ fun SplashScreen(navController: NavController, viewModel: SplashScreenViewModel } } "home" -> { - navController.navigate("chat/home") { + navController.navigate("chat") { popUpTo("splash") { inclusive = true } diff --git a/app/src/main/java/chat/revolt/screens/chat/ChatRouterScreen.kt b/app/src/main/java/chat/revolt/screens/chat/ChatRouterScreen.kt new file mode 100644 index 00000000..d41a8b00 --- /dev/null +++ b/app/src/main/java/chat/revolt/screens/chat/ChatRouterScreen.kt @@ -0,0 +1,132 @@ +package chat.revolt.screens.chat + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.* +import androidx.compose.runtime.Composable +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewmodel.compose.viewModel +import androidx.navigation.NavController +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import androidx.navigation.compose.rememberNavController +import chat.revolt.api.REVOLT_FILES +import chat.revolt.api.RevoltAPI +import chat.revolt.components.generic.RemoteImage +import chat.revolt.components.generic.drawableResource +import chat.revolt.screens.chat.views.HomeScreen +import chat.revolt.R +import chat.revolt.screens.chat.views.ChannelScreen +import kotlinx.coroutines.launch + +class ChatRouterViewModel : ViewModel() { + private var _currentServer = + mutableStateOf(RevoltAPI.serverCache.values.firstOrNull()?.id ?: "home") + val currentServer: String + get() = _currentServer.value + + fun setCurrentServer(serverId: String) { + _currentServer.value = serverId + } + + fun goToHome() { + _currentServer.value = "home" + } +} + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun ChatRouterScreen(topNav: NavController, viewModel: ChatRouterViewModel = viewModel()) { + val channelDrawerState = rememberDrawerState(DrawerValue.Closed) + val scope = rememberCoroutineScope() + val navController = rememberNavController() + + DismissibleNavigationDrawer(drawerState = channelDrawerState, drawerContent = { + ModalDrawerSheet { + Column(Modifier.fillMaxWidth()) { + Row { + Column(Modifier.verticalScroll(rememberScrollState())) { + RemoteImage( + url = drawableResource(R.drawable.ic_launcher_monochrome), + modifier = Modifier + .size(48.dp) + .clip(CircleShape) + .clickable { viewModel.goToHome() }, + description = "Home", + ) + RevoltAPI.serverCache.values.forEach { server -> + server.icon?.let { icon -> + RemoteImage( + url = "$REVOLT_FILES/icons/${icon.id!!}/server.png?max_side=256", + modifier = Modifier + .size(48.dp) + .clip(CircleShape) + .clickable { viewModel.setCurrentServer(server.id!!) }, + description = "${server.name}" + ) + } + } + } + Column( + Modifier + .weight(1f) + ) { + if (viewModel.currentServer != "home") { + val server = RevoltAPI.serverCache[viewModel.currentServer] + + Text( + text = server?.name ?: "Unknown Server", + fontWeight = FontWeight.Black, + fontSize = 24.sp + ) + + Column( + Modifier + .weight(1f) + .verticalScroll(rememberScrollState()) + ) { + server?.channels?.forEach { channelId -> + RevoltAPI.channelCache[channelId]?.let { + Text( + text = it.name ?: "Unnamed Channel", + modifier = Modifier.clickable { + scope.launch { channelDrawerState.close() } + navController.navigate("channel/${it.id}") + } + ) + } + } + } + } else { + Text(text = "Home not implemented!") + } + } + } + } + } + }) { + Column(Modifier.fillMaxSize()) { + NavHost(navController = navController, startDestination = "home") { + composable("home") { + HomeScreen(navController = navController) + } + composable("channel/{channelId}") { backStackEntry -> + val channelId = backStackEntry.arguments?.getString("channelId") + if (channelId != null) { + ChannelScreen(navController, channelId = channelId) + } + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/chat/revolt/screens/chat/HomeScreen.kt b/app/src/main/java/chat/revolt/screens/chat/HomeScreen.kt deleted file mode 100644 index a9353b4a..00000000 --- a/app/src/main/java/chat/revolt/screens/chat/HomeScreen.kt +++ /dev/null @@ -1,121 +0,0 @@ -package chat.revolt.screens.chat - -import androidx.compose.foundation.layout.* -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.verticalScroll -import androidx.compose.material3.* -import androidx.compose.runtime.* -import androidx.compose.ui.Modifier -import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp -import androidx.hilt.navigation.compose.hiltViewModel -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import androidx.navigation.NavController -import chat.revolt.api.RevoltAPI -import chat.revolt.persistence.KVStorage -import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.launch -import kotlinx.coroutines.runBlocking -import javax.inject.Inject - -@HiltViewModel -class HomeScreenViewModel @Inject constructor( - private val kvStorage: KVStorage -) : ViewModel() { - private var _messageContent by mutableStateOf("") - val messageContent: String - get() = _messageContent - - fun setMessageContent(value: String) { - _messageContent = value - } - - fun logout() { - runBlocking { - kvStorage.remove("sessionToken") - RevoltAPI.logout() - } - } - - fun sendMessage() { - viewModelScope.launch { - chat.revolt.api.routes.channel.sendMessage( - "01F7ZSBSFHCAAJQ92ZGTY67HMN", // revolt lounge #general (temporarily hardcoded) FIXME - messageContent - ) - } - setMessageContent("") - } -} - -@OptIn(ExperimentalMaterial3Api::class) -@Composable -fun HomeScreen(navController: NavController, viewModel: HomeScreenViewModel = hiltViewModel()) { - val channelDrawerState = rememberDrawerState(DrawerValue.Closed) - val scope = rememberCoroutineScope() - - DismissibleNavigationDrawer(drawerState = channelDrawerState, drawerContent = { - ModalDrawerSheet { - Spacer(modifier = Modifier.height(16.dp)) - Text( - text = "Revolt Lounge", - style = MaterialTheme.typography.headlineMedium.copy(fontWeight = FontWeight.Black) - ) - Divider() - Column(Modifier.verticalScroll(rememberScrollState())) { - RevoltAPI.channelCache.values - .filter { channel -> - channel.server == "01F7ZSBSFHQ8TA81725KQCSDDP" - } - .forEach { channel -> - NavigationDrawerItem( - selected = false, - label = { Text(text = "#" + channel.name) }, - onClick = { - scope.launch { - channelDrawerState.close() - navController.navigate("chat/channel/${channel.id}") - } - }, - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 16.dp) - ) - } - } - } - }) { - Column() { - Text( - text = "Home (placeholder)", - style = MaterialTheme.typography.displaySmall.copy( - fontWeight = FontWeight.Bold, - textAlign = TextAlign.Left, - fontSize = 24.sp - ), - modifier = Modifier - .padding(horizontal = 15.dp, vertical = 15.dp) - .fillMaxWidth(), - ) - - Button( - onClick = { - viewModel.logout() - navController.navigate("login/greeting") { - popUpTo("chat/home") { - inclusive = true - } - } - }, - modifier = Modifier - .fillMaxWidth() - .padding(bottom = 30.dp, top = 5.dp, start = 20.dp, end = 20.dp) - ) { - Text("Logout") - } - } - } -} \ No newline at end of file diff --git a/app/src/main/java/chat/revolt/screens/chat/ChannelScreen.kt b/app/src/main/java/chat/revolt/screens/chat/views/ChannelScreen.kt similarity index 99% rename from app/src/main/java/chat/revolt/screens/chat/ChannelScreen.kt rename to app/src/main/java/chat/revolt/screens/chat/views/ChannelScreen.kt index f5455a62..e7bd255d 100644 --- a/app/src/main/java/chat/revolt/screens/chat/ChannelScreen.kt +++ b/app/src/main/java/chat/revolt/screens/chat/views/ChannelScreen.kt @@ -1,4 +1,4 @@ -package chat.revolt.screens.chat +package chat.revolt.screens.chat.views import android.util.Log import androidx.compose.animation.AnimatedVisibility diff --git a/app/src/main/java/chat/revolt/screens/chat/views/HomeScreen.kt b/app/src/main/java/chat/revolt/screens/chat/views/HomeScreen.kt new file mode 100644 index 00000000..b9f1efba --- /dev/null +++ b/app/src/main/java/chat/revolt/screens/chat/views/HomeScreen.kt @@ -0,0 +1,83 @@ +package chat.revolt.screens.chat.views + +import androidx.compose.foundation.layout.* +import androidx.compose.material3.* +import androidx.compose.runtime.* +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import androidx.navigation.NavController +import chat.revolt.api.RevoltAPI +import chat.revolt.persistence.KVStorage +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking +import javax.inject.Inject + +@HiltViewModel +class HomeScreenViewModel @Inject constructor( + private val kvStorage: KVStorage +) : ViewModel() { + private var _messageContent by mutableStateOf("") + val messageContent: String + get() = _messageContent + + fun setMessageContent(value: String) { + _messageContent = value + } + + fun logout() { + runBlocking { + kvStorage.remove("sessionToken") + RevoltAPI.logout() + } + } + + fun sendMessage() { + viewModelScope.launch { + chat.revolt.api.routes.channel.sendMessage( + "01F7ZSBSFHCAAJQ92ZGTY67HMN", // revolt lounge #general (temporarily hardcoded) FIXME + messageContent + ) + } + setMessageContent("") + } +} + +@Composable +fun HomeScreen(navController: NavController, viewModel: HomeScreenViewModel = hiltViewModel()) { + Column() { + Text( + text = "Home (placeholder)", + style = MaterialTheme.typography.displaySmall.copy( + fontWeight = FontWeight.Bold, + textAlign = TextAlign.Left, + fontSize = 24.sp + ), + modifier = Modifier + .padding(horizontal = 15.dp, vertical = 15.dp) + .fillMaxWidth(), + ) + + Button( + onClick = { + viewModel.logout() + navController.navigate("login/greeting") { + popUpTo("chat") { + inclusive = true + } + } + }, + modifier = Modifier + .fillMaxWidth() + .padding(bottom = 30.dp, top = 5.dp, start = 20.dp, end = 20.dp) + ) { + Text("Logout") + } + } +} \ No newline at end of file diff --git a/app/src/main/java/chat/revolt/screens/login/LoginScreen.kt b/app/src/main/java/chat/revolt/screens/login/LoginScreen.kt index f81f4b69..be747f9f 100644 --- a/app/src/main/java/chat/revolt/screens/login/LoginScreen.kt +++ b/app/src/main/java/chat/revolt/screens/login/LoginScreen.kt @@ -116,7 +116,7 @@ fun LoginScreen( ) viewModel.navigationComplete() } else if (viewModel.navigateTo == "home") { - navController.navigate("chat/home") { + navController.navigate("chat") { popUpTo("login/greeting") { inclusive = true } } viewModel.navigationComplete() diff --git a/app/src/main/java/chat/revolt/screens/login/MfaScreen.kt b/app/src/main/java/chat/revolt/screens/login/MfaScreen.kt index 1577d44c..a1bc444f 100644 --- a/app/src/main/java/chat/revolt/screens/login/MfaScreen.kt +++ b/app/src/main/java/chat/revolt/screens/login/MfaScreen.kt @@ -127,7 +127,7 @@ fun MfaScreen( val allowedAuthTypes = allowedAuthTypesCommaSep.split(",") if (viewModel.navigateToHome) { - navController.navigate("chat/home") { + navController.navigate("chat") { popUpTo("login/greeting") { inclusive = true } } viewModel.navigationComplete()