From 3af90ec257c577b3886106555132f9ec482e563b Mon Sep 17 00:00:00 2001 From: Codex Date: Mon, 9 Mar 2026 20:29:05 +0300 Subject: [PATCH] android: fix main tabs bar layout and content overlap --- android/CHANGELOG.md | 5 ++ .../messenger/ui/chats/ChatListScreen.kt | 5 +- .../messenger/ui/contacts/ContactsScreen.kt | 2 +- .../messenger/ui/navigation/AppNavGraph.kt | 84 +++++++------------ .../messenger/ui/profile/ProfileScreen.kt | 2 +- .../messenger/ui/settings/SettingsScreen.kt | 2 +- 6 files changed, 41 insertions(+), 59 deletions(-) diff --git a/android/CHANGELOG.md b/android/CHANGELOG.md index d7671e2..e544d3b 100644 --- a/android/CHANGELOG.md +++ b/android/CHANGELOG.md @@ -482,3 +482,8 @@ - Implemented scroll-direction behavior for all 4 main pages: - hide panel on downward scroll, - show panel on upward scroll / at top. + +### Step 77 - Main tabs bar UX/layout fix +- Replaced custom pill-row main bar with compact `NavigationBar` inside rounded container for stable 4-tab layout on small screens. +- Added bottom content paddings for `Chats/Contacts/Settings/Profile` pages so content is not obscured by the floating main bar. +- Raised chats management FAB offset to avoid overlap with the global bottom bar. 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 9568143..61f018e 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 @@ -169,7 +169,8 @@ fun ChatListScreen( Column( modifier = Modifier .fillMaxSize() - .then(if (isTabletLayout) Modifier.widthIn(max = 820.dp) else Modifier), + .then(if (isTabletLayout) Modifier.widthIn(max = 820.dp) else Modifier) + .padding(bottom = 92.dp), ) { TabRow( selectedTabIndex = if (state.selectedTab == ChatTab.ALL) 0 else 1, @@ -318,7 +319,7 @@ fun ChatListScreen( onClick = { managementExpanded = !managementExpanded }, modifier = Modifier .align(Alignment.BottomEnd) - .padding(end = 16.dp, bottom = 88.dp), + .padding(end = 16.dp, bottom = 112.dp), ) { Icon( imageVector = if (managementExpanded) Icons.Filled.Close else Icons.Filled.Add, diff --git a/android/app/src/main/java/ru/daemonlord/messenger/ui/contacts/ContactsScreen.kt b/android/app/src/main/java/ru/daemonlord/messenger/ui/contacts/ContactsScreen.kt index ee40c8d..0551436 100644 --- a/android/app/src/main/java/ru/daemonlord/messenger/ui/contacts/ContactsScreen.kt +++ b/android/app/src/main/java/ru/daemonlord/messenger/ui/contacts/ContactsScreen.kt @@ -84,7 +84,7 @@ private fun ContactsScreen( modifier = Modifier .fillMaxWidth() .then(if (isTabletLayout) Modifier.widthIn(max = 820.dp) else Modifier) - .padding(16.dp), + .padding(start = 16.dp, top = 16.dp, end = 16.dp, bottom = 96.dp), verticalArrangement = Arrangement.spacedBy(12.dp), ) { Text( 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 db9fd28..1ef4bff 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 @@ -8,9 +8,9 @@ import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.navigationBarsPadding import androidx.compose.foundation.layout.safeDrawing import androidx.compose.foundation.layout.padding @@ -24,8 +24,9 @@ import androidx.compose.material.icons.filled.Settings import androidx.compose.material3.Icon import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.NavigationBar +import androidx.compose.material3.NavigationBarItem import androidx.compose.material3.Surface -import androidx.compose.material3.Text import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut @@ -42,8 +43,7 @@ import androidx.compose.ui.platform.LocalContext import androidx.core.content.ContextCompat import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.semantics.contentDescription -import androidx.compose.ui.semantics.semantics +import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.NavType @@ -295,71 +295,47 @@ private fun MainBottomBar( onNavigate: (String) -> Unit, ) { Surface( + modifier = Modifier + .padding(horizontal = 12.dp) + .fillMaxWidth(), shape = CircleShape, color = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.92f), ) { - androidx.compose.foundation.layout.Row( - modifier = Modifier.padding(horizontal = 12.dp, vertical = 8.dp), - horizontalArrangement = Arrangement.spacedBy(8.dp), + NavigationBar( + containerColor = androidx.compose.ui.graphics.Color.Transparent, + tonalElevation = 0.dp, + modifier = Modifier.padding(horizontal = 8.dp), ) { - MainTabPill( - label = "Chats", + NavigationBarItem( selected = currentRoute == Routes.Chats, - icon = { Icon(Icons.AutoMirrored.Filled.Chat, contentDescription = null) }, onClick = { onNavigate(Routes.Chats) }, + icon = { Icon(Icons.AutoMirrored.Filled.Chat, contentDescription = "Chats") }, + label = { + androidx.compose.material3.Text("Chats", maxLines = 1, overflow = TextOverflow.Ellipsis) + }, ) - MainTabPill( - label = "Contacts", + NavigationBarItem( selected = currentRoute == Routes.Contacts, - icon = { Icon(Icons.Filled.Contacts, contentDescription = null) }, onClick = { onNavigate(Routes.Contacts) }, + icon = { Icon(Icons.Filled.Contacts, contentDescription = "Contacts") }, + label = { + androidx.compose.material3.Text("Contacts", maxLines = 1, overflow = TextOverflow.Ellipsis) + }, ) - MainTabPill( - label = "Settings", + NavigationBarItem( selected = currentRoute == Routes.Settings, - icon = { Icon(Icons.Filled.Settings, contentDescription = null) }, onClick = { onNavigate(Routes.Settings) }, + icon = { Icon(Icons.Filled.Settings, contentDescription = "Settings") }, + label = { + androidx.compose.material3.Text("Settings", maxLines = 1, overflow = TextOverflow.Ellipsis) + }, ) - MainTabPill( - label = "Profile", + NavigationBarItem( selected = currentRoute == Routes.Profile, - icon = { Icon(Icons.Filled.Person, contentDescription = null) }, onClick = { onNavigate(Routes.Profile) }, - ) - } - } -} - -@Composable -private fun MainTabPill( - label: String, - selected: Boolean, - icon: @Composable () -> Unit, - onClick: () -> Unit, -) { - Surface( - shape = CircleShape, - color = if (selected) { - MaterialTheme.colorScheme.primaryContainer - } else { - MaterialTheme.colorScheme.surface - }, - modifier = Modifier - .clickable(onClick = onClick) - .semantics { contentDescription = "$label tab" }, - ) { - androidx.compose.foundation.layout.Row( - modifier = Modifier.padding(horizontal = 10.dp, vertical = 6.dp), - horizontalArrangement = Arrangement.spacedBy(6.dp), - verticalAlignment = Alignment.CenterVertically, - ) { - icon() - Text( - text = label, - color = if (selected) { - MaterialTheme.colorScheme.onPrimaryContainer - } else { - MaterialTheme.colorScheme.onSurface + icon = { Icon(Icons.Filled.Person, contentDescription = "Profile") }, + label = { + androidx.compose.material3.Text("Profile", maxLines = 1, overflow = TextOverflow.Ellipsis) }, ) } 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 index 0c9b860..aed2e17 100644 --- 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 @@ -125,7 +125,7 @@ fun ProfileScreen( .fillMaxWidth() .then(if (isTabletLayout) Modifier.widthIn(max = 720.dp) else Modifier) .verticalScroll(scrollState) - .padding(16.dp), + .padding(start = 16.dp, top = 16.dp, end = 16.dp, bottom = 96.dp), verticalArrangement = Arrangement.spacedBy(12.dp), ) { Text( 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 index 660c743..c228b6c 100644 --- 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 @@ -105,7 +105,7 @@ fun SettingsScreen( .fillMaxWidth() .then(if (isTabletLayout) Modifier.widthIn(max = 720.dp) else Modifier) .verticalScroll(scrollState) - .padding(16.dp), + .padding(start = 16.dp, top = 16.dp, end = 16.dp, bottom = 96.dp), verticalArrangement = Arrangement.spacedBy(12.dp), ) { Text(