android: add top app bars and safe-area pass for main pages
This commit is contained in:
@@ -494,3 +494,8 @@
|
|||||||
- unified selected/unselected item colors,
|
- unified selected/unselected item colors,
|
||||||
- stable 4-item navigation with icons + labels.
|
- stable 4-item navigation with icons + labels.
|
||||||
- Kept scroll-hide/show behavior and page-level navigation unchanged.
|
- Kept scroll-hide/show behavior and page-level navigation unchanged.
|
||||||
|
|
||||||
|
### Step 79 - Main pages app bars + safe-area pass
|
||||||
|
- Added top app bars for all 4 main pages (`Chats`, `Contacts`, `Settings`, `Profile`) to make them feel like proper standalone sections.
|
||||||
|
- Moved chats management toggle action into chats app bar.
|
||||||
|
- Kept safe-area handling and bottom insets consistent with shared floating tabs bar to avoid overlap.
|
||||||
|
|||||||
@@ -26,12 +26,14 @@ import androidx.compose.material3.Button
|
|||||||
import androidx.compose.material3.CircularProgressIndicator
|
import androidx.compose.material3.CircularProgressIndicator
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.IconButton
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.OutlinedTextField
|
import androidx.compose.material3.OutlinedTextField
|
||||||
import androidx.compose.material3.Surface
|
import androidx.compose.material3.Surface
|
||||||
import androidx.compose.material3.Tab
|
import androidx.compose.material3.Tab
|
||||||
import androidx.compose.material3.TabRow
|
import androidx.compose.material3.TabRow
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.TopAppBar
|
||||||
import androidx.compose.material3.pulltorefresh.PullToRefreshBox
|
import androidx.compose.material3.pulltorefresh.PullToRefreshBox
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
@@ -172,6 +174,17 @@ fun ChatListScreen(
|
|||||||
.then(if (isTabletLayout) Modifier.widthIn(max = 820.dp) else Modifier)
|
.then(if (isTabletLayout) Modifier.widthIn(max = 820.dp) else Modifier)
|
||||||
.padding(bottom = 92.dp),
|
.padding(bottom = 92.dp),
|
||||||
) {
|
) {
|
||||||
|
TopAppBar(
|
||||||
|
title = { Text("Chats") },
|
||||||
|
actions = {
|
||||||
|
IconButton(onClick = { managementExpanded = !managementExpanded }) {
|
||||||
|
Icon(
|
||||||
|
imageVector = if (managementExpanded) Icons.Filled.Close else Icons.Filled.Add,
|
||||||
|
contentDescription = if (managementExpanded) "Close management" else "Open management",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
TabRow(
|
TabRow(
|
||||||
selectedTabIndex = if (state.selectedTab == ChatTab.ALL) 0 else 1,
|
selectedTabIndex = if (state.selectedTab == ChatTab.ALL) 0 else 1,
|
||||||
) {
|
) {
|
||||||
@@ -315,17 +328,6 @@ fun ChatListScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Button(
|
|
||||||
onClick = { managementExpanded = !managementExpanded },
|
|
||||||
modifier = Modifier
|
|
||||||
.align(Alignment.BottomEnd)
|
|
||||||
.padding(end = 16.dp, bottom = 112.dp),
|
|
||||||
) {
|
|
||||||
Icon(
|
|
||||||
imageVector = if (managementExpanded) Icons.Filled.Close else Icons.Filled.Add,
|
|
||||||
contentDescription = if (managementExpanded) "Close management" else "Open management",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (managementExpanded) {
|
if (managementExpanded) {
|
||||||
Surface(
|
Surface(
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ import androidx.compose.foundation.lazy.rememberLazyListState
|
|||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.OutlinedTextField
|
import androidx.compose.material3.OutlinedTextField
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.TopAppBar
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
@@ -38,6 +40,7 @@ fun ContactsRoute(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
private fun ContactsScreen(
|
private fun ContactsScreen(
|
||||||
onMainBarVisibilityChanged: (Boolean) -> Unit,
|
onMainBarVisibilityChanged: (Boolean) -> Unit,
|
||||||
) {
|
) {
|
||||||
@@ -87,9 +90,8 @@ private fun ContactsScreen(
|
|||||||
.padding(start = 16.dp, top = 16.dp, end = 16.dp, bottom = 96.dp),
|
.padding(start = 16.dp, top = 16.dp, end = 16.dp, bottom = 96.dp),
|
||||||
verticalArrangement = Arrangement.spacedBy(12.dp),
|
verticalArrangement = Arrangement.spacedBy(12.dp),
|
||||||
) {
|
) {
|
||||||
Text(
|
TopAppBar(
|
||||||
text = "Contacts",
|
title = { Text("Contacts") },
|
||||||
style = MaterialTheme.typography.headlineSmall,
|
|
||||||
)
|
)
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
value = query,
|
value = query,
|
||||||
|
|||||||
@@ -28,10 +28,12 @@ import androidx.compose.foundation.shape.CircleShape
|
|||||||
import androidx.compose.foundation.verticalScroll
|
import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material3.Button
|
import androidx.compose.material3.Button
|
||||||
import androidx.compose.material3.CircularProgressIndicator
|
import androidx.compose.material3.CircularProgressIndicator
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.OutlinedTextField
|
import androidx.compose.material3.OutlinedTextField
|
||||||
import androidx.compose.material3.OutlinedButton
|
import androidx.compose.material3.OutlinedButton
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.TopAppBar
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
@@ -67,6 +69,7 @@ fun ProfileRoute(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
fun ProfileScreen(
|
fun ProfileScreen(
|
||||||
onBackToChats: () -> Unit,
|
onBackToChats: () -> Unit,
|
||||||
onOpenSettings: () -> Unit,
|
onOpenSettings: () -> Unit,
|
||||||
@@ -128,9 +131,8 @@ fun ProfileScreen(
|
|||||||
.padding(start = 16.dp, top = 16.dp, end = 16.dp, bottom = 96.dp),
|
.padding(start = 16.dp, top = 16.dp, end = 16.dp, bottom = 96.dp),
|
||||||
verticalArrangement = Arrangement.spacedBy(12.dp),
|
verticalArrangement = Arrangement.spacedBy(12.dp),
|
||||||
) {
|
) {
|
||||||
Text(
|
TopAppBar(
|
||||||
text = "Profile",
|
title = { Text("Profile") },
|
||||||
style = MaterialTheme.typography.headlineSmall,
|
|
||||||
)
|
)
|
||||||
if (!avatarUrl.isBlank()) {
|
if (!avatarUrl.isBlank()) {
|
||||||
Box(
|
Box(
|
||||||
|
|||||||
@@ -16,10 +16,12 @@ import androidx.compose.foundation.rememberScrollState
|
|||||||
import androidx.compose.foundation.verticalScroll
|
import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material3.Button
|
import androidx.compose.material3.Button
|
||||||
import androidx.compose.material3.CircularProgressIndicator
|
import androidx.compose.material3.CircularProgressIndicator
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.OutlinedButton
|
import androidx.compose.material3.OutlinedButton
|
||||||
import androidx.compose.material3.OutlinedTextField
|
import androidx.compose.material3.OutlinedTextField
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.TopAppBar
|
||||||
import androidx.compose.runtime.mutableIntStateOf
|
import androidx.compose.runtime.mutableIntStateOf
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
@@ -56,6 +58,7 @@ fun SettingsRoute(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
fun SettingsScreen(
|
fun SettingsScreen(
|
||||||
onBackToChats: () -> Unit,
|
onBackToChats: () -> Unit,
|
||||||
onOpenProfile: () -> Unit,
|
onOpenProfile: () -> Unit,
|
||||||
@@ -108,9 +111,8 @@ fun SettingsScreen(
|
|||||||
.padding(start = 16.dp, top = 16.dp, end = 16.dp, bottom = 96.dp),
|
.padding(start = 16.dp, top = 16.dp, end = 16.dp, bottom = 96.dp),
|
||||||
verticalArrangement = Arrangement.spacedBy(12.dp),
|
verticalArrangement = Arrangement.spacedBy(12.dp),
|
||||||
) {
|
) {
|
||||||
Text(
|
TopAppBar(
|
||||||
text = "Settings",
|
title = { Text("Settings") },
|
||||||
style = MaterialTheme.typography.headlineSmall,
|
|
||||||
)
|
)
|
||||||
Text("Appearance", style = MaterialTheme.typography.titleMedium)
|
Text("Appearance", style = MaterialTheme.typography.titleMedium)
|
||||||
Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
|
Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
- [x] Активный tab в фиолетовом pill-состоянии, неактивные — белые/серые.
|
- [x] Активный tab в фиолетовом pill-состоянии, неактивные — белые/серые.
|
||||||
- [x] Глобальная панель `Chats / Contacts / Settings / Profile` на уровне app-shell (одна на все 4 страницы).
|
- [x] Глобальная панель `Chats / Contacts / Settings / Profile` на уровне app-shell (одна на все 4 страницы).
|
||||||
- [x] Поведение панели: скрывается только при скролле вниз, возвращается при скролле вверх/в начале списка.
|
- [x] Поведение панели: скрывается только при скролле вниз, возвращается при скролле вверх/в начале списка.
|
||||||
- [ ] Safe area для status/nav bars на всех экранах списка/настроек/профиля.
|
- [x] Safe area для status/nav bars на всех экранах списка/настроек/профиля.
|
||||||
|
|
||||||
## P0 — Settings Visual System
|
## P0 — Settings Visual System
|
||||||
- [ ] Экран настроек из секционных rounded cards (а не плоский список).
|
- [ ] Экран настроек из секционных rounded cards (а не плоский список).
|
||||||
|
|||||||
Reference in New Issue
Block a user