Refactored BottomSheetTopBar to BitchatSheetTopBar (#601)

* Automated update of relay data - Sun Sep 21 06:21:05 UTC 2025

* Automated update of relay data - Sun Sep 28 06:20:40 UTC 2025

* refactor: new close button like ios(but not liquid glass)

* Automated update of relay data - Sun Oct  5 06:20:09 UTC 2025

* Automated update of relay data - Sun Oct 12 06:20:12 UTC 2025

* Automated update of relay data - Sun Oct 19 06:21:51 UTC 2025

* Automated update of relay data - Sun Oct 26 06:21:31 UTC 2025

* Automated update of relay data - Sun Nov  2 06:22:16 UTC 2025

* Automated update of relay data - Sun Nov  9 06:21:43 UTC 2025

* Automated update of relay data - Sun Nov 16 06:22:37 UTC 2025

* Automated update of relay data - Sun Nov 23 06:22:51 UTC 2025

* Automated update of relay data - Sun Nov 30 06:24:08 UTC 2025

* Automated update of relay data - Sun Dec  7 06:22:59 UTC 2025

* Automated update of relay data - Sun Dec 14 06:24:33 UTC 2025

* Automated update of relay data - Sun Dec 21 06:24:49 UTC 2025

* Automated update of relay data - Sun Dec 28 06:25:38 UTC 2025

* Automated update of relay data - Sun Jan  4 06:26:28 UTC 2026

* Automated update of relay data - Sun Jan 11 06:26:19 UTC 2026

* feat: Add BitchatSheetTopBar component

* Refactor: Use BitchatSheetTopBar in bottom sheets

This commit refactors several bottom sheet components to use the new reusable `BitchatSheetTopBar` composable.

This change provides a consistent look and feel for top bars across the following sheets:
- DebugSettingsSheet
- MeshPeerListSheet
- LocationNotesSheet
- LocationChannelsSheet
- LocationNotesSheetPresenter (for the location unavailable state)

The `BitchatSheetCenterTopBar` has been removed as its functionality is now covered by the more flexible `BitchatSheetTopBar`.

* Refactor: Use BitchatSheetTopBar in MeshPeerListSheet

---------

Co-authored-by: GitHub Action <action@github.com>
This commit is contained in:
yet300
2026-01-16 01:00:04 +07:00
committed by GitHub
co-authored by GitHub Action
parent fddadbe44a
commit 51a06cf0b7
6 changed files with 312 additions and 241 deletions
@@ -0,0 +1,86 @@
package com.bitchat.android.core.ui.component.sheet
import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.CenterAlignedTopAppBar
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import com.bitchat.android.core.ui.component.button.CloseButton
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun BitchatSheetTopBar(
onClose: () -> Unit,
modifier: Modifier = Modifier,
backgroundAlpha: Float = 0.98f,
title: @Composable () -> Unit,
navigationIcon: (@Composable () -> Unit)? = null,
actions: @Composable RowScope.() -> Unit = {}
) {
TopAppBar(
title = title,
navigationIcon = { navigationIcon?.invoke() },
actions = {
actions()
CloseButton(
onClick = onClose,
modifier = Modifier.padding(horizontal = 16.dp)
)
},
colors = TopAppBarDefaults.topAppBarColors(
containerColor = MaterialTheme.colorScheme.background.copy(alpha = backgroundAlpha),
titleContentColor = MaterialTheme.colorScheme.onSurface,
navigationIconContentColor = MaterialTheme.colorScheme.onSurface,
actionIconContentColor = MaterialTheme.colorScheme.onSurface
),
modifier = modifier
)
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun BitchatSheetCenterTopBar(
onClose: () -> Unit,
modifier: Modifier = Modifier,
backgroundAlpha: Float = 0.98f,
title: @Composable () -> Unit,
navigationIcon: (@Composable () -> Unit)? = null,
actions: @Composable RowScope.() -> Unit = {}
) {
CenterAlignedTopAppBar(
title = title,
navigationIcon = { navigationIcon?.invoke() },
actions = {
actions()
CloseButton(
onClick = onClose,
modifier = Modifier.padding(horizontal = 16.dp)
)
},
colors = TopAppBarDefaults.topAppBarColors(
containerColor = MaterialTheme.colorScheme.background.copy(alpha = backgroundAlpha),
titleContentColor = MaterialTheme.colorScheme.onSurface,
navigationIconContentColor = MaterialTheme.colorScheme.onSurface,
actionIconContentColor = MaterialTheme.colorScheme.onSurface
),
modifier = modifier
)
}
@Composable
fun BitchatSheetTitle(text: String) {
Text(
text = text,
style = MaterialTheme.typography.titleMedium.copy(
fontWeight = FontWeight.Bold,
fontFamily = FontFamily.Monospace
)
)
}
@@ -4,7 +4,6 @@ import android.content.Intent
import android.net.Uri
import android.provider.Settings
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
@@ -39,8 +38,9 @@ import com.bitchat.android.ui.theme.BASE_FONT_SIZE
import androidx.compose.ui.res.stringResource
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.bitchat.android.R
import com.bitchat.android.core.ui.component.button.CloseButton
import com.bitchat.android.core.ui.component.sheet.BitchatBottomSheet
import com.bitchat.android.core.ui.component.sheet.BitchatSheetTopBar
import com.bitchat.android.core.ui.component.sheet.BitchatSheetTitle
/**
* Location Channels Sheet for selecting geohash-based location channels
@@ -125,33 +125,19 @@ fun LocationChannelsSheet(
LazyColumn(
state = listState,
modifier = Modifier.fillMaxSize(),
contentPadding = PaddingValues(top = 48.dp, bottom = 16.dp)
contentPadding = PaddingValues(top = 64.dp, bottom = 16.dp)
) {
// Header Section
item(key = "header") {
Column(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 24.dp)
.padding(bottom = 8.dp),
verticalArrangement = Arrangement.spacedBy(4.dp)
) {
Text(
text = stringResource(R.string.location_channels_title),
style = MaterialTheme.typography.headlineSmall,
fontFamily = FontFamily.Monospace,
fontWeight = FontWeight.Bold,
color = MaterialTheme.colorScheme.onBackground
)
Text(
text = stringResource(R.string.location_channels_desc),
fontSize = 12.sp,
fontFamily = FontFamily.Monospace,
color = MaterialTheme.colorScheme.onBackground.copy(alpha = 0.7f)
color = MaterialTheme.colorScheme.onBackground.copy(alpha = 0.7f),
modifier = Modifier
.padding(horizontal = 24.dp)
)
}
}
// Permission controls if services enabled
if (locationServicesEnabled) {
@@ -515,20 +501,15 @@ fun LocationChannelsSheet(
}
// TopBar (animated)
Box(
modifier = Modifier
.align(Alignment.TopCenter)
.fillMaxWidth()
.height(56.dp)
.background(MaterialTheme.colorScheme.background.copy(alpha = topBarAlpha))
) {
CloseButton(
onClick = onDismiss,
modifier = modifier
.align(Alignment.CenterEnd)
.padding(horizontal = 16.dp),
BitchatSheetTopBar(
onClose = onDismiss,
modifier = modifier.align(Alignment.TopCenter),
title = {
BitchatSheetTitle(
text = stringResource(R.string.location_channels_title)
)
}
)
}
}
}
@@ -26,8 +26,9 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.bitchat.android.core.ui.component.button.CloseButton
import com.bitchat.android.core.ui.component.sheet.BitchatBottomSheet
import com.bitchat.android.core.ui.component.sheet.BitchatSheetTopBar
import com.bitchat.android.core.ui.component.sheet.BitchatSheetTitle
import com.bitchat.android.geohash.GeohashChannelLevel
import com.bitchat.android.geohash.LocationChannelManager
import com.bitchat.android.nostr.LocationNotesManager
@@ -112,8 +113,6 @@ fun LocationNotesSheet(
) {
item(key = "notes_header") {
LocationNotesHeader(
geohash = geohash,
count = count,
locationName = displayLocationName,
state = state,
accentGreen = accentGreen,
@@ -164,20 +163,20 @@ fun LocationNotesSheet(
}
// TopBar (animated)
Box(
modifier = Modifier
.align(Alignment.TopCenter)
.fillMaxWidth()
.height(64.dp)
.background(MaterialTheme.colorScheme.background.copy(alpha = topBarAlpha))
) {
CloseButton(
onClick = onDismiss,
modifier = Modifier
.align(Alignment.CenterEnd)
.padding(horizontal = 16.dp)
BitchatSheetTopBar(
onClose = onDismiss,
modifier = Modifier.align(Alignment.TopCenter),
title = {
BitchatSheetTitle(
text = pluralStringResource(
id = R.plurals.location_notes_title,
count = count,
geohash,
count
)
)
}
)
Box(
modifier = Modifier
@@ -214,12 +213,10 @@ fun LocationNotesSheet(
/**
* Header section - matches iOS headerSection exactly
* Shows: "#geohash • X notes", location name, description, and close button
* Shows: "#geohash • X notes", location name, description
*/
@Composable
private fun LocationNotesHeader(
geohash: String,
count: Int,
locationName: String?,
state: LocationNotesManager.State,
accentGreen: Color,
@@ -228,22 +225,8 @@ private fun LocationNotesHeader(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp)
.padding(top = 16.dp, bottom = 12.dp)
.padding(bottom = 12.dp)
) {
// Localized title with ±1 and note count
Text(
text = pluralStringResource(
id = R.plurals.location_notes_title,
count = count,
geohash,
count
),
fontFamily = FontFamily.Monospace,
fontSize = 18.sp,
color = MaterialTheme.colorScheme.onSurface
)
Spacer(modifier = Modifier.height(8.dp))
// Location name in green (building or block)
locationName?.let { name ->
if (name.isNotEmpty()) {
@@ -471,6 +454,7 @@ private fun LocationNotesInputSection(
Row(
modifier = Modifier
.fillMaxWidth()
.background(color = colorScheme.background)
.padding(horizontal = 12.dp, vertical = 8.dp), // Match main chat padding
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(8.dp) // Match main chat spacing
@@ -9,10 +9,14 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import androidx.compose.ui.res.stringResource
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.bitchat.android.core.ui.component.sheet.BitchatBottomSheet
import com.bitchat.android.core.ui.component.sheet.BitchatSheetTopBar
import com.bitchat.android.core.ui.component.sheet.BitchatSheetTitle
import com.bitchat.android.geohash.GeohashChannelLevel
import com.bitchat.android.geohash.LocationChannelManager
import com.bitchat.android.R
/**
* Presenter component for LocationNotesSheet
@@ -107,11 +111,14 @@ private fun LocationNotesErrorSheet(
BitchatBottomSheet(
onDismissRequest = onDismiss,
) {
Box(modifier = Modifier.fillMaxWidth()) {
Column(
modifier = Modifier
.fillMaxWidth()
.padding(24.dp),
horizontalAlignment = Alignment.CenterHorizontally
.padding(horizontal = 24.dp)
.padding(top = 80.dp, bottom = 24.dp),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center,
) {
Text(
text = "Location Unavailable",
@@ -135,5 +142,16 @@ private fun LocationNotesErrorSheet(
Text("Enable Location")
}
}
BitchatSheetTopBar(
onClose = onDismiss,
modifier = Modifier.align(Alignment.TopCenter),
title = {
BitchatSheetTitle(
text = stringResource(R.string.cd_location_notes).uppercase()
)
}
)
}
}
}
@@ -27,6 +27,9 @@ import androidx.compose.ui.text.style.TextOverflow
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.bitchat.android.core.ui.component.button.CloseButton
import com.bitchat.android.core.ui.component.sheet.BitchatBottomSheet
import com.bitchat.android.core.ui.component.sheet.BitchatSheetCenterTopBar
import com.bitchat.android.core.ui.component.sheet.BitchatSheetTitle
import com.bitchat.android.core.ui.component.sheet.BitchatSheetTopBar
import com.bitchat.android.geohash.ChannelID
import com.bitchat.android.ui.theme.BASE_FONT_SIZE
import com.bitchat.android.nostr.GeohashAliasRegistry
@@ -172,32 +175,12 @@ fun MeshPeerListSheet(
}
// TopBar (animated)
Box(
modifier = Modifier
.align(Alignment.TopCenter)
.fillMaxWidth()
.height(64.dp)
.background(colorScheme.background.copy(alpha = topBarAlpha))
) {
Text(
text = stringResource(id = R.string.your_network).uppercase(),
style = MaterialTheme.typography.titleMedium.copy(
fontWeight = FontWeight.Bold,
fontFamily = FontFamily.Monospace
),
color = colorScheme.onSurface,
modifier = Modifier
.align(Alignment.CenterStart)
.padding(horizontal = 24.dp)
)
Row(
modifier = Modifier
.align(Alignment.CenterEnd)
.padding(horizontal = 16.dp),
horizontalArrangement = Arrangement.spacedBy(8.dp),
verticalAlignment = Alignment.CenterVertically
) {
BitchatSheetTopBar(
title = {
BitchatSheetTitle(text = stringResource(id = R.string.your_network))
},
backgroundAlpha = topBarAlpha,
actions = {
if (selectedLocationChannel !is ChannelID.Location) {
IconButton(
onClick = onShowVerification,
@@ -211,14 +194,11 @@ fun MeshPeerListSheet(
)
}
}
CloseButton(
onClick = onDismiss
},
onClose = onDismiss,
)
}
}
}
}
}
}
@@ -909,15 +889,10 @@ fun PrivateChatSheet(
}
// TopBar (fixed at top, iOS-style)
Box(
modifier = Modifier
.align(Alignment.TopCenter)
.fillMaxWidth()
.height(64.dp)
.background(colorScheme.background),
contentAlignment = Alignment.Center
) {
// Back button
BitchatSheetCenterTopBar(
onClose = onDismiss,
modifier = Modifier.align(Alignment.TopCenter),
navigationIcon = {
IconButton(
onClick = onDismiss,
modifier = Modifier
@@ -931,7 +906,8 @@ fun PrivateChatSheet(
tint = colorScheme.onSurface
)
}
},
title = {
// Center content: connection status + name + encryption
Row(
modifier = Modifier.align(Alignment.Center),
@@ -941,7 +917,7 @@ fun PrivateChatSheet(
when {
isDirect -> {
Icon(
imageVector = Icons.Outlined.Bluetooth,
imageVector = Icons.Outlined.SettingsInputAntenna,
contentDescription = stringResource(R.string.cd_connected_peers),
modifier = Modifier.size(14.dp),
tint = colorScheme.onSurface.copy(alpha = 0.6f)
@@ -1008,15 +984,8 @@ fun PrivateChatSheet(
)
}
}
CloseButton(
onClick = onDismiss,
modifier = Modifier
.align(Alignment.CenterEnd)
.padding(horizontal = 16.dp)
)
}
)
}
}
}
@@ -5,8 +5,10 @@ import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.layout.FlowRow
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.layout.ExperimentalLayoutApi
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Bluetooth
import androidx.compose.material.icons.filled.BugReport
@@ -34,6 +36,8 @@ import androidx.compose.ui.res.stringResource
import com.bitchat.android.R
import androidx.compose.ui.platform.LocalContext
import com.bitchat.android.core.ui.component.sheet.BitchatBottomSheet
import com.bitchat.android.core.ui.component.sheet.BitchatSheetTopBar
import com.bitchat.android.core.ui.component.sheet.BitchatSheetTitle
@Composable
fun MeshTopologySection() {
@@ -111,6 +115,16 @@ fun DebugSettingsSheet(
val gcsFpr by manager.gcsFprPercent.collectAsState()
val context = LocalContext.current
// Persistent notification is now controlled solely by MeshServicePreferences.isBackgroundEnabled
val listState = rememberLazyListState()
val isScrolled by remember {
derivedStateOf {
listState.firstVisibleItemIndex > 0 || listState.firstVisibleItemScrollOffset > 0
}
}
val topBarAlpha by animateFloatAsState(
targetValue = if (isScrolled) 0.95f else 0f,
label = "topBarAlpha"
)
// Push live connected devices from mesh service whenever sheet is visible
LaunchedEffect(isPresented) {
@@ -151,18 +165,16 @@ fun DebugSettingsSheet(
DisposableEffect(Unit) {
onDispose { DebugSettingsManager.getInstance().setDebugSheetVisible(false) }
}
Box(modifier = Modifier.fillMaxWidth()) {
LazyColumn(
state = listState,
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp),
contentPadding = PaddingValues(top = 80.dp),
contentPadding = PaddingValues(top = 80.dp, bottom = 24.dp),
verticalArrangement = Arrangement.spacedBy(16.dp)
) {
item {
Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(8.dp)) {
Icon(Icons.Filled.BugReport, contentDescription = null, tint = Color(0xFFFF9500))
Text(stringResource(R.string.debug_tools), fontFamily = FontFamily.Monospace, fontSize = 18.sp, fontWeight = FontWeight.Medium)
}
Text(
text = stringResource(R.string.debug_tools_desc),
fontFamily = FontFamily.Monospace,
@@ -170,7 +182,6 @@ fun DebugSettingsSheet(
color = colorScheme.onSurface.copy(alpha = 0.7f)
)
}
// Verbose logging toggle
item {
Surface(shape = RoundedCornerShape(12.dp), color = colorScheme.surfaceVariant.copy(alpha = 0.2f)) {
@@ -629,6 +640,28 @@ fun DebugSettingsSheet(
item { Spacer(Modifier.height(16.dp)) }
}
BitchatSheetTopBar(
onClose = onDismiss,
modifier = Modifier.align(Alignment.TopCenter),
backgroundAlpha = topBarAlpha,
title = {
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
Icon(
imageVector = Icons.Filled.BugReport,
contentDescription = null,
tint = Color(0xFFFF9500)
)
BitchatSheetTitle(
text = stringResource(R.string.debug_tools)
)
}
}
)
}
}
}