diff --git a/android/CHANGELOG.md b/android/CHANGELOG.md index 22c38bf..0310067 100644 --- a/android/CHANGELOG.md +++ b/android/CHANGELOG.md @@ -313,3 +313,8 @@ - Added `SessionCleanupRepository` + `DefaultSessionCleanupRepository` to wipe Room tables and clear per-chat notification overrides. - Added logout action in chat list UI and wired it to `AuthViewModel`, with automatic navigation back to login via auth state. - Added unit tests for logout use case orchestration and notification override cleanup. + +### Step 52 - Settings/Profile shell and logout relocation +- Added dedicated `Settings` and `Profile` routes/screens with mobile-safe insets and placeholder content. +- Removed direct logout action from chat list and moved logout action to `Settings`. +- Wired bottom navigation pills in chats to open `Settings` and `Profile`. diff --git a/android/app/src/main/java/ru/daemonlord/messenger/ui/chats/ChatListScreen.kt b/android/app/src/main/java/ru/daemonlord/messenger/ui/chats/ChatListScreen.kt index 1ff3e34..eb417b4 100644 --- a/android/app/src/main/java/ru/daemonlord/messenger/ui/chats/ChatListScreen.kt +++ b/android/app/src/main/java/ru/daemonlord/messenger/ui/chats/ChatListScreen.kt @@ -29,7 +29,6 @@ import androidx.compose.material3.Surface import androidx.compose.material3.Tab import androidx.compose.material3.TabRow import androidx.compose.material3.Text -import androidx.compose.material3.TextButton import androidx.compose.material3.pulltorefresh.PullToRefreshBox import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect @@ -51,7 +50,8 @@ import java.time.format.DateTimeFormatter @Composable fun ChatListRoute( onOpenChat: (Long) -> Unit, - onLogout: () -> Unit, + onOpenSettings: () -> Unit, + onOpenProfile: () -> Unit, inviteToken: String?, onInviteTokenConsumed: () -> Unit, viewModel: ChatListViewModel = hiltViewModel(), @@ -74,7 +74,8 @@ fun ChatListRoute( onFilterSelected = viewModel::onFilterSelected, onSearchChanged = viewModel::onSearchChanged, onRefresh = viewModel::onPullToRefresh, - onLogout = onLogout, + onOpenSettings = onOpenSettings, + onOpenProfile = onOpenProfile, onOpenChat = onOpenChat, ) } @@ -87,7 +88,8 @@ fun ChatListScreen( onFilterSelected: (ChatListFilter) -> Unit, onSearchChanged: (String) -> Unit, onRefresh: () -> Unit, - onLogout: () -> Unit, + onOpenSettings: () -> Unit, + onOpenProfile: () -> Unit, onOpenChat: (Long) -> Unit, ) { Column( @@ -119,16 +121,6 @@ fun ChatListScreen( .fillMaxWidth() .padding(horizontal = 16.dp, vertical = 8.dp), ) - Row( - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 16.dp), - horizontalArrangement = Arrangement.End, - ) { - TextButton(onClick = onLogout) { - Text("Logout") - } - } Row( modifier = Modifier .fillMaxWidth() @@ -224,8 +216,8 @@ fun ChatListScreen( ) { BottomNavPill(label = "Chats", selected = true, onClick = {}) BottomNavPill(label = "Contacts", selected = false, onClick = {}) - BottomNavPill(label = "Settings", selected = false, onClick = {}) - BottomNavPill(label = "Profile", selected = false, onClick = {}) + BottomNavPill(label = "Settings", selected = false, onClick = onOpenSettings) + BottomNavPill(label = "Profile", selected = false, onClick = onOpenProfile) } } } diff --git a/android/app/src/main/java/ru/daemonlord/messenger/ui/navigation/AppNavGraph.kt b/android/app/src/main/java/ru/daemonlord/messenger/ui/navigation/AppNavGraph.kt index 5ce8c2f..adbe2d5 100644 --- a/android/app/src/main/java/ru/daemonlord/messenger/ui/navigation/AppNavGraph.kt +++ b/android/app/src/main/java/ru/daemonlord/messenger/ui/navigation/AppNavGraph.kt @@ -33,11 +33,15 @@ import ru.daemonlord.messenger.ui.auth.AuthViewModel import ru.daemonlord.messenger.ui.auth.LoginScreen import ru.daemonlord.messenger.ui.chat.ChatRoute import ru.daemonlord.messenger.ui.chats.ChatListRoute +import ru.daemonlord.messenger.ui.profile.ProfileRoute +import ru.daemonlord.messenger.ui.settings.SettingsRoute private object Routes { const val AuthGraph = "auth_graph" const val Login = "login" const val Chats = "chats" + const val Settings = "settings" + const val Profile = "profile" const val Chat = "chat" } @@ -125,13 +129,29 @@ fun MessengerNavHost( ChatListRoute( inviteToken = inviteToken, onInviteTokenConsumed = onInviteTokenConsumed, - onLogout = viewModel::logout, + onOpenSettings = { navController.navigate(Routes.Settings) }, + onOpenProfile = { navController.navigate(Routes.Profile) }, onOpenChat = { chatId -> navController.navigate("${Routes.Chat}/$chatId") } ) } + composable(route = Routes.Settings) { + SettingsRoute( + onBackToChats = { navController.popBackStack() }, + onOpenProfile = { navController.navigate(Routes.Profile) }, + onLogout = viewModel::logout, + ) + } + + composable(route = Routes.Profile) { + ProfileRoute( + onBackToChats = { navController.popBackStack() }, + onOpenSettings = { navController.navigate(Routes.Settings) }, + ) + } + composable( route = "${Routes.Chat}/{chatId}", arguments = listOf( diff --git a/android/app/src/main/java/ru/daemonlord/messenger/ui/profile/ProfileScreen.kt b/android/app/src/main/java/ru/daemonlord/messenger/ui/profile/ProfileScreen.kt new file mode 100644 index 0000000..0eebff3 --- /dev/null +++ b/android/app/src/main/java/ru/daemonlord/messenger/ui/profile/ProfileScreen.kt @@ -0,0 +1,64 @@ +package ru.daemonlord.messenger.ui.profile + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.safeDrawing +import androidx.compose.foundation.layout.windowInsetsPadding +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.OutlinedButton +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp + +@Composable +fun ProfileRoute( + onBackToChats: () -> Unit, + onOpenSettings: () -> Unit, +) { + ProfileScreen( + onBackToChats = onBackToChats, + onOpenSettings = onOpenSettings, + ) +} + +@Composable +fun ProfileScreen( + onBackToChats: () -> Unit, + onOpenSettings: () -> Unit, +) { + Column( + modifier = Modifier + .fillMaxSize() + .windowInsetsPadding(WindowInsets.safeDrawing) + .padding(16.dp), + verticalArrangement = Arrangement.spacedBy(12.dp), + ) { + Text( + text = "Profile", + style = MaterialTheme.typography.headlineSmall, + ) + Text( + text = "Profile editing screen placeholder. Telegram-like account editor will be implemented in a dedicated step.", + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onSurfaceVariant, + ) + OutlinedButton( + onClick = onOpenSettings, + modifier = Modifier.fillMaxWidth(), + ) { + Text("Open settings") + } + OutlinedButton( + onClick = onBackToChats, + modifier = Modifier.fillMaxWidth(), + ) { + Text("Back to chats") + } + } +} + diff --git a/android/app/src/main/java/ru/daemonlord/messenger/ui/settings/SettingsScreen.kt b/android/app/src/main/java/ru/daemonlord/messenger/ui/settings/SettingsScreen.kt new file mode 100644 index 0000000..e6a35e8 --- /dev/null +++ b/android/app/src/main/java/ru/daemonlord/messenger/ui/settings/SettingsScreen.kt @@ -0,0 +1,79 @@ +package ru.daemonlord.messenger.ui.settings + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.safeDrawing +import androidx.compose.foundation.layout.windowInsetsPadding +import androidx.compose.material3.Button +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.OutlinedButton +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp + +@Composable +fun SettingsRoute( + onBackToChats: () -> Unit, + onOpenProfile: () -> Unit, + onLogout: () -> Unit, +) { + SettingsScreen( + onBackToChats = onBackToChats, + onOpenProfile = onOpenProfile, + onLogout = onLogout, + ) +} + +@Composable +fun SettingsScreen( + onBackToChats: () -> Unit, + onOpenProfile: () -> Unit, + onLogout: () -> Unit, +) { + Column( + modifier = Modifier + .fillMaxSize() + .windowInsetsPadding(WindowInsets.safeDrawing) + .padding(16.dp), + verticalArrangement = Arrangement.spacedBy(12.dp), + ) { + Text( + text = "Settings", + style = MaterialTheme.typography.headlineSmall, + ) + Text( + text = "Core account actions are here. More Telegram-like settings will be added in next iterations.", + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onSurfaceVariant, + ) + OutlinedButton( + onClick = onOpenProfile, + modifier = Modifier.fillMaxWidth(), + ) { + Text("Open profile") + } + Button( + onClick = onLogout, + modifier = Modifier.fillMaxWidth(), + ) { + Text("Logout") + } + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.End, + verticalAlignment = Alignment.CenterVertically, + ) { + OutlinedButton(onClick = onBackToChats) { + Text("Back to chats") + } + } + } +} +