feat(desktop): Messages-style headers across every remaining screen
Rolled the compact header pattern out to the screens the earlier pass missed. Each one now lives on the same padding/typography rhythm as Messages: Row(fillMaxWidth, padding horizontal = 12, vertical = 8), titleMedium for labels, IconButton size = 32dp with 20dp icons tinted with colorScheme.primary. - ThreadScreen: back button + "Thread" title. Was headlineMedium with bottom-only padding; now compact row. - UserProfileScreen: back + "Profile" title on the left, Edit / Follow buttons kept on the right (they stay as text buttons — they represent destructive intent, not icon affordances). - ArticleReaderScreen: back + "Article" title; zoom % label still surfaces next to the title when != 100%. - ArticleEditorScreen: back IconButton + "Article" title (was a text "Back" OutlinedButton with no title). Save / Publish buttons kept on the right — same reasoning as UserProfileScreen. - ChessScreen: back (conditional) + "Chess" / "Live Game" title; refresh + New Game converted from Button → IconButton so the header reads at the same scale as the rest. - RelayDashboardScreen: had no header at all, just a PrimaryTabRow. Converted Monitor / Configure to FilterChip tabs-first (matching Feed / Reads) so the selected tab is the title. FeedHeader relocation: - Moved commons/ui/feed/FeedHeader.kt → desktopApp/ui/FeedHeader.kt. Only NotificationsScreen.kt referenced it, and dropping the import from that file was enough because it's now in the same package. - Removed the empty commons/ui/feed/ directory. https://claude.ai/code/session_01NufduPfZvYQVYwLkbCjCUo
This commit is contained in:
+26
-19
@@ -31,6 +31,7 @@ import androidx.compose.foundation.layout.fillMaxSize
|
|||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.LazyListState
|
import androidx.compose.foundation.lazy.LazyListState
|
||||||
@@ -38,7 +39,6 @@ import androidx.compose.foundation.lazy.items
|
|||||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||||
import androidx.compose.foundation.rememberScrollState
|
import androidx.compose.foundation.rememberScrollState
|
||||||
import androidx.compose.foundation.verticalScroll
|
import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material3.Button
|
|
||||||
import androidx.compose.material3.Card
|
import androidx.compose.material3.Card
|
||||||
import androidx.compose.material3.CardDefaults
|
import androidx.compose.material3.CardDefaults
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
@@ -179,42 +179,49 @@ fun ChessScreen(
|
|||||||
var showNewGameDialog by remember { mutableStateOf(false) }
|
var showNewGameDialog by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
Column(modifier = Modifier.fillMaxSize()) {
|
Column(modifier = Modifier.fillMaxSize()) {
|
||||||
// Header
|
// Header — Messages-style: compact row, titleMedium title, icon-only actions
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier.fillMaxWidth().padding(bottom = 16.dp),
|
modifier = Modifier.fillMaxWidth().padding(horizontal = 12.dp, vertical = 8.dp),
|
||||||
horizontalArrangement = Arrangement.SpaceBetween,
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
) {
|
) {
|
||||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
if (selectedGameId != null) {
|
if (selectedGameId != null) {
|
||||||
IconButton(onClick = { viewModel.selectGame(null) }) {
|
IconButton(onClick = { viewModel.selectGame(null) }, modifier = Modifier.size(32.dp)) {
|
||||||
Icon(MaterialSymbols.AutoMirrored.ArrowBack, "Back to list")
|
Icon(
|
||||||
|
MaterialSymbols.AutoMirrored.ArrowBack,
|
||||||
|
contentDescription = "Back to list",
|
||||||
|
tint = MaterialTheme.colorScheme.primary,
|
||||||
|
modifier = Modifier.size(20.dp),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
Spacer(Modifier.width(8.dp))
|
Spacer(Modifier.width(8.dp))
|
||||||
}
|
}
|
||||||
Text(
|
Text(
|
||||||
if (selectedGameId != null) "Live Game" else "Chess",
|
if (selectedGameId != null) "Live Game" else "Chess",
|
||||||
style = MaterialTheme.typography.headlineMedium,
|
style = MaterialTheme.typography.titleMedium,
|
||||||
color = MaterialTheme.colorScheme.onBackground,
|
color = MaterialTheme.colorScheme.onBackground,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (selectedGameId == null) {
|
if (selectedGameId == null) {
|
||||||
Row(
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
IconButton(onClick = { viewModel.forceRefresh() }, modifier = Modifier.size(32.dp)) {
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
Icon(
|
||||||
) {
|
MaterialSymbols.Refresh,
|
||||||
// Refresh button
|
contentDescription = "Refresh",
|
||||||
IconButton(onClick = { viewModel.forceRefresh() }) {
|
tint = MaterialTheme.colorScheme.primary,
|
||||||
Icon(MaterialSymbols.Refresh, "Refresh")
|
modifier = Modifier.size(20.dp),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// New Game button
|
|
||||||
if (!account.isReadOnly) {
|
if (!account.isReadOnly) {
|
||||||
Button(onClick = { showNewGameDialog = true }) {
|
IconButton(onClick = { showNewGameDialog = true }, modifier = Modifier.size(32.dp)) {
|
||||||
Icon(MaterialSymbols.Add, "New Game")
|
Icon(
|
||||||
Spacer(Modifier.width(8.dp))
|
MaterialSymbols.Add,
|
||||||
Text("New Game")
|
contentDescription = "New Game",
|
||||||
|
tint = MaterialTheme.colorScheme.primary,
|
||||||
|
modifier = Modifier.size(20.dp),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+28
-6
@@ -29,12 +29,15 @@ import androidx.compose.foundation.layout.fillMaxSize
|
|||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.foundation.layout.width
|
||||||
import androidx.compose.foundation.layout.widthIn
|
import androidx.compose.foundation.layout.widthIn
|
||||||
import androidx.compose.foundation.rememberScrollState
|
import androidx.compose.foundation.rememberScrollState
|
||||||
import androidx.compose.foundation.text.selection.SelectionContainer
|
import androidx.compose.foundation.text.selection.SelectionContainer
|
||||||
import androidx.compose.foundation.verticalScroll
|
import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material3.Button
|
import androidx.compose.material3.Button
|
||||||
import androidx.compose.material3.HorizontalDivider
|
import androidx.compose.material3.HorizontalDivider
|
||||||
|
import androidx.compose.material3.IconButton
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.OutlinedButton
|
import androidx.compose.material3.OutlinedButton
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
@@ -63,6 +66,8 @@ import com.vitorpamplona.amethyst.commons.compose.editor.MarkdownEditorState
|
|||||||
import com.vitorpamplona.amethyst.commons.compose.editor.MarkdownToolbar
|
import com.vitorpamplona.amethyst.commons.compose.editor.MarkdownToolbar
|
||||||
import com.vitorpamplona.amethyst.commons.compose.editor.MetadataPanel
|
import com.vitorpamplona.amethyst.commons.compose.editor.MetadataPanel
|
||||||
import com.vitorpamplona.amethyst.commons.compose.markdown.RenderMarkdown
|
import com.vitorpamplona.amethyst.commons.compose.markdown.RenderMarkdown
|
||||||
|
import com.vitorpamplona.amethyst.commons.icons.symbols.Icon
|
||||||
|
import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols
|
||||||
import com.vitorpamplona.amethyst.commons.model.nip23LongContent.LongFormPublishAction
|
import com.vitorpamplona.amethyst.commons.model.nip23LongContent.LongFormPublishAction
|
||||||
import com.vitorpamplona.amethyst.desktop.account.AccountState
|
import com.vitorpamplona.amethyst.desktop.account.AccountState
|
||||||
import com.vitorpamplona.amethyst.desktop.network.DesktopRelayConnectionManager
|
import com.vitorpamplona.amethyst.desktop.network.DesktopRelayConnectionManager
|
||||||
@@ -227,24 +232,41 @@ fun ArticleEditorScreen(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
// Top bar
|
// Header — Messages-style: back + titleMedium on left, actions on right
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier.fillMaxWidth().padding(bottom = 8.dp),
|
modifier = Modifier.fillMaxWidth().padding(horizontal = 12.dp, vertical = 8.dp),
|
||||||
horizontalArrangement = Arrangement.SpaceBetween,
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
) {
|
) {
|
||||||
OutlinedButton(onClick = onBack) {
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
Text("Back")
|
IconButton(onClick = onBack, modifier = Modifier.size(32.dp)) {
|
||||||
|
Icon(
|
||||||
|
MaterialSymbols.AutoMirrored.ArrowBack,
|
||||||
|
contentDescription = "Back",
|
||||||
|
tint = MaterialTheme.colorScheme.primary,
|
||||||
|
modifier = Modifier.size(20.dp),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Spacer(Modifier.width(8.dp))
|
||||||
|
Text(
|
||||||
|
"Article",
|
||||||
|
style = MaterialTheme.typography.titleMedium,
|
||||||
|
color = MaterialTheme.colorScheme.onBackground,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
|
Row(
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
) {
|
||||||
saveMessage?.let {
|
saveMessage?.let {
|
||||||
Text(
|
Text(
|
||||||
it,
|
it,
|
||||||
style = MaterialTheme.typography.bodySmall,
|
style = MaterialTheme.typography.bodySmall,
|
||||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
modifier = Modifier.align(Alignment.CenterVertically),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
// Save/Publish stay as text buttons — they're primary destructive
|
||||||
|
// actions, not affordances you'd reduce to an icon.
|
||||||
OutlinedButton(onClick = { saveDraft() }) {
|
OutlinedButton(onClick = { saveDraft() }) {
|
||||||
Text("Save")
|
Text("Save")
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-5
@@ -404,24 +404,25 @@ fun ArticleReaderScreen(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
// Top bar: back + bookmark placeholder
|
// Header — Messages-style: compact row, titleMedium title
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier.fillMaxWidth().padding(bottom = 8.dp),
|
modifier = Modifier.fillMaxWidth().padding(horizontal = 12.dp, vertical = 8.dp),
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
horizontalArrangement = Arrangement.SpaceBetween,
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
) {
|
) {
|
||||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
IconButton(onClick = onBack) {
|
IconButton(onClick = onBack, modifier = Modifier.size(32.dp)) {
|
||||||
Icon(
|
Icon(
|
||||||
MaterialSymbols.AutoMirrored.ArrowBack,
|
MaterialSymbols.AutoMirrored.ArrowBack,
|
||||||
contentDescription = "Back",
|
contentDescription = "Back",
|
||||||
modifier = Modifier.size(24.dp),
|
tint = MaterialTheme.colorScheme.primary,
|
||||||
|
modifier = Modifier.size(20.dp),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Spacer(Modifier.width(8.dp))
|
Spacer(Modifier.width(8.dp))
|
||||||
Text(
|
Text(
|
||||||
"Article",
|
"Article",
|
||||||
style = MaterialTheme.typography.headlineMedium,
|
style = MaterialTheme.typography.titleMedium,
|
||||||
color = MaterialTheme.colorScheme.onBackground,
|
color = MaterialTheme.colorScheme.onBackground,
|
||||||
)
|
)
|
||||||
if (zoomLevel != 1.0f) {
|
if (zoomLevel != 1.0f) {
|
||||||
|
|||||||
+1
-1
@@ -18,7 +18,7 @@
|
|||||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
package com.vitorpamplona.amethyst.commons.ui.feed
|
package com.vitorpamplona.amethyst.desktop.ui
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
-1
@@ -56,7 +56,6 @@ import com.vitorpamplona.amethyst.commons.icons.symbols.rememberMaterialSymbolPa
|
|||||||
import com.vitorpamplona.amethyst.commons.state.EventCollectionState
|
import com.vitorpamplona.amethyst.commons.state.EventCollectionState
|
||||||
import com.vitorpamplona.amethyst.commons.ui.components.EmptyState
|
import com.vitorpamplona.amethyst.commons.ui.components.EmptyState
|
||||||
import com.vitorpamplona.amethyst.commons.ui.components.LoadingState
|
import com.vitorpamplona.amethyst.commons.ui.components.LoadingState
|
||||||
import com.vitorpamplona.amethyst.commons.ui.feed.FeedHeader
|
|
||||||
import com.vitorpamplona.amethyst.commons.util.toTimeAgo
|
import com.vitorpamplona.amethyst.commons.util.toTimeAgo
|
||||||
import com.vitorpamplona.amethyst.desktop.account.AccountState
|
import com.vitorpamplona.amethyst.desktop.account.AccountState
|
||||||
import com.vitorpamplona.amethyst.desktop.cache.DesktopLocalCache
|
import com.vitorpamplona.amethyst.desktop.cache.DesktopLocalCache
|
||||||
|
|||||||
@@ -198,22 +198,23 @@ fun ThreadScreen(
|
|||||||
|
|
||||||
Box(modifier = Modifier.fillMaxSize()) {
|
Box(modifier = Modifier.fillMaxSize()) {
|
||||||
Column(modifier = Modifier.fillMaxSize()) {
|
Column(modifier = Modifier.fillMaxSize()) {
|
||||||
// Header with back button
|
// Header — Messages-style: compact row with back + titleMedium
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier.fillMaxWidth().padding(bottom = 16.dp),
|
modifier = Modifier.fillMaxWidth().padding(horizontal = 12.dp, vertical = 8.dp),
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
) {
|
) {
|
||||||
IconButton(onClick = onBack) {
|
IconButton(onClick = onBack, modifier = Modifier.size(32.dp)) {
|
||||||
Icon(
|
Icon(
|
||||||
MaterialSymbols.AutoMirrored.ArrowBack,
|
MaterialSymbols.AutoMirrored.ArrowBack,
|
||||||
contentDescription = "Back",
|
contentDescription = "Back",
|
||||||
modifier = Modifier.size(24.dp),
|
tint = MaterialTheme.colorScheme.primary,
|
||||||
|
modifier = Modifier.size(20.dp),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Spacer(Modifier.width(8.dp))
|
Spacer(Modifier.width(8.dp))
|
||||||
Text(
|
Text(
|
||||||
"Thread",
|
"Thread",
|
||||||
style = MaterialTheme.typography.headlineMedium,
|
style = MaterialTheme.typography.titleMedium,
|
||||||
color = MaterialTheme.colorScheme.onBackground,
|
color = MaterialTheme.colorScheme.onBackground,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-5
@@ -458,21 +458,26 @@ fun UserProfileScreen(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Header with back button
|
// Header — Messages-style: compact row, titleMedium title
|
||||||
item(key = "header") {
|
item(key = "header") {
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier.fillMaxWidth().padding(bottom = 8.dp),
|
modifier = Modifier.fillMaxWidth().padding(horizontal = 12.dp, vertical = 8.dp),
|
||||||
horizontalArrangement = Arrangement.SpaceBetween,
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
) {
|
) {
|
||||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
IconButton(onClick = onBack) {
|
IconButton(onClick = onBack, modifier = Modifier.size(32.dp)) {
|
||||||
Icon(MaterialSymbols.AutoMirrored.ArrowBack, "Back")
|
Icon(
|
||||||
|
MaterialSymbols.AutoMirrored.ArrowBack,
|
||||||
|
contentDescription = "Back",
|
||||||
|
tint = MaterialTheme.colorScheme.primary,
|
||||||
|
modifier = Modifier.size(20.dp),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
Spacer(Modifier.width(8.dp))
|
Spacer(Modifier.width(8.dp))
|
||||||
Text(
|
Text(
|
||||||
"Profile",
|
"Profile",
|
||||||
style = MaterialTheme.typography.headlineMedium,
|
style = MaterialTheme.typography.titleMedium,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+15
-7
@@ -20,11 +20,13 @@
|
|||||||
*/
|
*/
|
||||||
package com.vitorpamplona.amethyst.desktop.ui.relay
|
package com.vitorpamplona.amethyst.desktop.ui.relay
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.material3.PrimaryTabRow
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.material3.Tab
|
import androidx.compose.material3.FilterChip
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
@@ -34,7 +36,9 @@ import androidx.compose.runtime.mutableStateListOf
|
|||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
import com.vitorpamplona.amethyst.commons.model.nip65RelayList.Nip65RelayListState
|
import com.vitorpamplona.amethyst.commons.model.nip65RelayList.Nip65RelayListState
|
||||||
import com.vitorpamplona.amethyst.desktop.model.DesktopAccountRelays
|
import com.vitorpamplona.amethyst.desktop.model.DesktopAccountRelays
|
||||||
import com.vitorpamplona.amethyst.desktop.network.DesktopRelayConnectionManager
|
import com.vitorpamplona.amethyst.desktop.network.DesktopRelayConnectionManager
|
||||||
@@ -50,7 +54,6 @@ enum class DashboardTab(
|
|||||||
CONFIGURE("Configure"),
|
CONFIGURE("Configure"),
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
|
||||||
@Composable
|
@Composable
|
||||||
fun RelayDashboardScreen(
|
fun RelayDashboardScreen(
|
||||||
relayManager: DesktopRelayConnectionManager,
|
relayManager: DesktopRelayConnectionManager,
|
||||||
@@ -79,12 +82,17 @@ fun RelayDashboardScreen(
|
|||||||
}
|
}
|
||||||
|
|
||||||
Column(modifier = modifier.fillMaxSize()) {
|
Column(modifier = modifier.fillMaxSize()) {
|
||||||
PrimaryTabRow(selectedTabIndex = DashboardTab.entries.indexOf(selectedTab)) {
|
// Header — Messages-style tabs-first: selected chip acts as the screen title.
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.fillMaxWidth().padding(horizontal = 12.dp, vertical = 8.dp),
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
) {
|
||||||
DashboardTab.entries.forEach { tab ->
|
DashboardTab.entries.forEach { tab ->
|
||||||
Tab(
|
FilterChip(
|
||||||
selected = selectedTab == tab,
|
selected = selectedTab == tab,
|
||||||
onClick = { selectedTab = tab },
|
onClick = { selectedTab = tab },
|
||||||
text = { Text(tab.label) },
|
label = { Text(tab.label) },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user