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.net.Uri
import android.provider.Settings import android.provider.Settings
import androidx.compose.animation.core.animateFloatAsState import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items 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.compose.ui.res.stringResource
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.bitchat.android.R 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.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 * Location Channels Sheet for selecting geohash-based location channels
@@ -125,32 +125,18 @@ fun LocationChannelsSheet(
LazyColumn( LazyColumn(
state = listState, state = listState,
modifier = Modifier.fillMaxSize(), modifier = Modifier.fillMaxSize(),
contentPadding = PaddingValues(top = 48.dp, bottom = 16.dp) contentPadding = PaddingValues(top = 64.dp, bottom = 16.dp)
) { ) {
// Header Section // Header Section
item(key = "header") { item(key = "header") {
Column( Text(
text = stringResource(R.string.location_channels_desc),
fontSize = 12.sp,
fontFamily = FontFamily.Monospace,
color = MaterialTheme.colorScheme.onBackground.copy(alpha = 0.7f),
modifier = Modifier modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 24.dp) .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)
)
}
} }
// Permission controls if services enabled // Permission controls if services enabled
@@ -515,20 +501,15 @@ fun LocationChannelsSheet(
} }
// TopBar (animated) // TopBar (animated)
Box( BitchatSheetTopBar(
modifier = Modifier onClose = onDismiss,
.align(Alignment.TopCenter) modifier = modifier.align(Alignment.TopCenter),
.fillMaxWidth() title = {
.height(56.dp) BitchatSheetTitle(
.background(MaterialTheme.colorScheme.background.copy(alpha = topBarAlpha)) text = stringResource(R.string.location_channels_title)
) { )
CloseButton( }
onClick = onDismiss, )
modifier = modifier
.align(Alignment.CenterEnd)
.padding(horizontal = 16.dp),
)
}
} }
} }
} }
@@ -26,8 +26,9 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.lifecycle.compose.collectAsStateWithLifecycle 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.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.GeohashChannelLevel
import com.bitchat.android.geohash.LocationChannelManager import com.bitchat.android.geohash.LocationChannelManager
import com.bitchat.android.nostr.LocationNotesManager import com.bitchat.android.nostr.LocationNotesManager
@@ -112,8 +113,6 @@ fun LocationNotesSheet(
) { ) {
item(key = "notes_header") { item(key = "notes_header") {
LocationNotesHeader( LocationNotesHeader(
geohash = geohash,
count = count,
locationName = displayLocationName, locationName = displayLocationName,
state = state, state = state,
accentGreen = accentGreen, accentGreen = accentGreen,
@@ -164,20 +163,20 @@ fun LocationNotesSheet(
} }
// TopBar (animated) // TopBar (animated)
Box( BitchatSheetTopBar(
modifier = Modifier onClose = onDismiss,
.align(Alignment.TopCenter) modifier = Modifier.align(Alignment.TopCenter),
.fillMaxWidth() title = {
.height(64.dp) BitchatSheetTitle(
.background(MaterialTheme.colorScheme.background.copy(alpha = topBarAlpha)) text = pluralStringResource(
) { id = R.plurals.location_notes_title,
CloseButton( count = count,
onClick = onDismiss, geohash,
modifier = Modifier count
.align(Alignment.CenterEnd) )
.padding(horizontal = 16.dp) )
) }
} )
Box( Box(
modifier = Modifier modifier = Modifier
@@ -214,12 +213,10 @@ fun LocationNotesSheet(
/** /**
* Header section - matches iOS headerSection exactly * Header section - matches iOS headerSection exactly
* Shows: "#geohash • X notes", location name, description, and close button * Shows: "#geohash • X notes", location name, description
*/ */
@Composable @Composable
private fun LocationNotesHeader( private fun LocationNotesHeader(
geohash: String,
count: Int,
locationName: String?, locationName: String?,
state: LocationNotesManager.State, state: LocationNotesManager.State,
accentGreen: Color, accentGreen: Color,
@@ -228,22 +225,8 @@ private fun LocationNotesHeader(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(horizontal = 16.dp) .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) // Location name in green (building or block)
locationName?.let { name -> locationName?.let { name ->
if (name.isNotEmpty()) { if (name.isNotEmpty()) {
@@ -471,6 +454,7 @@ private fun LocationNotesInputSection(
Row( Row(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.background(color = colorScheme.background)
.padding(horizontal = 12.dp, vertical = 8.dp), // Match main chat padding .padding(horizontal = 12.dp, vertical = 8.dp), // Match main chat padding
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(8.dp) // Match main chat spacing 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.Modifier
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.res.stringResource
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.bitchat.android.core.ui.component.sheet.BitchatBottomSheet 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.GeohashChannelLevel
import com.bitchat.android.geohash.LocationChannelManager import com.bitchat.android.geohash.LocationChannelManager
import com.bitchat.android.R
/** /**
* Presenter component for LocationNotesSheet * Presenter component for LocationNotesSheet
@@ -107,33 +111,47 @@ private fun LocationNotesErrorSheet(
BitchatBottomSheet( BitchatBottomSheet(
onDismissRequest = onDismiss, onDismissRequest = onDismiss,
) { ) {
Column( Box(modifier = Modifier.fillMaxWidth()) {
modifier = Modifier Column(
.fillMaxWidth() modifier = Modifier
.padding(24.dp), .fillMaxWidth()
horizontalAlignment = Alignment.CenterHorizontally .padding(horizontal = 24.dp)
) { .padding(top = 80.dp, bottom = 24.dp),
Text( horizontalAlignment = Alignment.CenterHorizontally,
text = "Location Unavailable", verticalArrangement = Arrangement.Center,
style = MaterialTheme.typography.titleMedium, ) {
color = MaterialTheme.colorScheme.onSurface Text(
) text = "Location Unavailable",
Spacer(modifier = Modifier.height(16.dp)) style = MaterialTheme.typography.titleMedium,
Text( color = MaterialTheme.colorScheme.onSurface
text = "Location permission is required for notes", )
style = MaterialTheme.typography.bodyMedium, Spacer(modifier = Modifier.height(16.dp))
color = MaterialTheme.colorScheme.onSurfaceVariant Text(
) text = "Location permission is required for notes",
Spacer(modifier = Modifier.height(24.dp)) style = MaterialTheme.typography.bodyMedium,
Button(onClick = { color = MaterialTheme.colorScheme.onSurfaceVariant
// UNIFIED FIX: Enable location services first (user toggle) )
locationManager.enableLocationServices() Spacer(modifier = Modifier.height(24.dp))
// Then request location channels (which will also request permission if needed) Button(onClick = {
locationManager.enableLocationChannels() // UNIFIED FIX: Enable location services first (user toggle)
locationManager.refreshChannels() locationManager.enableLocationServices()
}) { // Then request location channels (which will also request permission if needed)
Text("Enable Location") locationManager.enableLocationChannels()
locationManager.refreshChannels()
}) {
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 androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.bitchat.android.core.ui.component.button.CloseButton 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.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.geohash.ChannelID
import com.bitchat.android.ui.theme.BASE_FONT_SIZE import com.bitchat.android.ui.theme.BASE_FONT_SIZE
import com.bitchat.android.nostr.GeohashAliasRegistry import com.bitchat.android.nostr.GeohashAliasRegistry
@@ -172,32 +175,12 @@ fun MeshPeerListSheet(
} }
// TopBar (animated) // TopBar (animated)
Box( BitchatSheetTopBar(
modifier = Modifier title = {
.align(Alignment.TopCenter) BitchatSheetTitle(text = stringResource(id = R.string.your_network))
.fillMaxWidth() },
.height(64.dp) backgroundAlpha = topBarAlpha,
.background(colorScheme.background.copy(alpha = topBarAlpha)) actions = {
) {
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
) {
if (selectedLocationChannel !is ChannelID.Location) { if (selectedLocationChannel !is ChannelID.Location) {
IconButton( IconButton(
onClick = onShowVerification, onClick = onShowVerification,
@@ -211,12 +194,9 @@ fun MeshPeerListSheet(
) )
} }
} }
},
CloseButton( onClose = onDismiss,
onClick = onDismiss )
)
}
}
} }
} }
@@ -790,7 +770,7 @@ fun PrivateChatSheet(
} }
val isNostrPeer = peerID.startsWith("nostr_") || peerID.startsWith("nostr:") val isNostrPeer = peerID.startsWith("nostr_") || peerID.startsWith("nostr:")
// Compute display name and title text reactively // Compute display name and title text reactively
val displayName = peerNicknames[peerID] ?: peerID.take(12) val displayName = peerNicknames[peerID] ?: peerID.take(12)
val titleText = remember(peerID, peerNicknames) { val titleText = remember(peerID, peerNicknames) {
@@ -909,61 +889,57 @@ fun PrivateChatSheet(
} }
// TopBar (fixed at top, iOS-style) // TopBar (fixed at top, iOS-style)
Box( BitchatSheetCenterTopBar(
modifier = Modifier onClose = onDismiss,
.align(Alignment.TopCenter) modifier = Modifier.align(Alignment.TopCenter),
.fillMaxWidth() navigationIcon = {
.height(64.dp) IconButton(
.background(colorScheme.background), onClick = onDismiss,
contentAlignment = Alignment.Center modifier = Modifier
) { .align(Alignment.CenterStart)
// Back button .padding(start = 16.dp)
IconButton( .size(32.dp)
onClick = onDismiss, ) {
modifier = Modifier Icon(
.align(Alignment.CenterStart) imageVector = Icons.AutoMirrored.Filled.ArrowBack,
.padding(start = 16.dp) contentDescription = stringResource(R.string.chat_back),
.size(32.dp) tint = colorScheme.onSurface
) { )
Icon(
imageVector = Icons.AutoMirrored.Filled.ArrowBack,
contentDescription = stringResource(R.string.chat_back),
tint = colorScheme.onSurface
)
}
// Center content: connection status + name + encryption
Row(
modifier = Modifier.align(Alignment.Center),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(6.dp)
) {
when {
isDirect -> {
Icon(
imageVector = Icons.Outlined.Bluetooth,
contentDescription = stringResource(R.string.cd_connected_peers),
modifier = Modifier.size(14.dp),
tint = colorScheme.onSurface.copy(alpha = 0.6f)
)
}
isConnected -> {
Icon(
imageVector = Icons.Filled.Route,
contentDescription = stringResource(R.string.cd_ready_for_handshake),
modifier = Modifier.size(14.dp),
tint = colorScheme.onSurface.copy(alpha = 0.6f)
)
}
isNostrPeer -> {
Icon(
imageVector = Icons.Filled.Public,
contentDescription = stringResource(R.string.cd_nostr_reachable),
modifier = Modifier.size(14.dp),
tint = Color(0xFF9C27B0)
)
}
} }
},
title = {
// Center content: connection status + name + encryption
Row(
modifier = Modifier.align(Alignment.Center),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(6.dp)
) {
when {
isDirect -> {
Icon(
imageVector = Icons.Outlined.SettingsInputAntenna,
contentDescription = stringResource(R.string.cd_connected_peers),
modifier = Modifier.size(14.dp),
tint = colorScheme.onSurface.copy(alpha = 0.6f)
)
}
isConnected -> {
Icon(
imageVector = Icons.Filled.Route,
contentDescription = stringResource(R.string.cd_ready_for_handshake),
modifier = Modifier.size(14.dp),
tint = colorScheme.onSurface.copy(alpha = 0.6f)
)
}
isNostrPeer -> {
Icon(
imageVector = Icons.Filled.Public,
contentDescription = stringResource(R.string.cd_nostr_reachable),
modifier = Modifier.size(14.dp),
tint = Color(0xFF9C27B0)
)
}
}
Text( Text(
text = titleText, text = titleText,
@@ -974,49 +950,42 @@ fun PrivateChatSheet(
color = if (isNostrPeer) Color(0xFFFF9500) else colorScheme.onSurface color = if (isNostrPeer) Color(0xFFFF9500) else colorScheme.onSurface
) )
Row( Row(
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.then(securityModifier) modifier = Modifier.then(securityModifier)
) { ) {
if (!isNostrPeer) { if (!isNostrPeer) {
NoiseSessionIcon( NoiseSessionIcon(
sessionState = sessionState, sessionState = sessionState,
modifier = Modifier.size(14.dp) modifier = Modifier.size(14.dp)
) )
}
if (isVerified) {
Spacer(modifier = Modifier.width(4.dp))
Icon(
imageVector = Icons.Filled.Verified,
contentDescription = stringResource(R.string.verify_title),
modifier = Modifier.size(14.dp),
tint = Color(0xFF32D74B) // iOS Green
)
}
} }
if (isVerified) { IconButton(
Spacer(modifier = Modifier.width(4.dp)) onClick = { viewModel.toggleFavorite(peerID) },
modifier = Modifier.size(28.dp)
) {
Icon( Icon(
imageVector = Icons.Filled.Verified, imageVector = if (isFavorite) Icons.Filled.Star else Icons.Outlined.Star,
contentDescription = stringResource(R.string.verify_title), contentDescription = if (isFavorite) stringResource(R.string.cd_remove_favorite) else stringResource(R.string.cd_add_favorite),
modifier = Modifier.size(14.dp), modifier = Modifier.size(16.dp),
tint = Color(0xFF32D74B) // iOS Green tint = if (isFavorite) Color(0xFFFFD700) else colorScheme.onSurface.copy(alpha = 0.6f)
) )
} }
} }
IconButton(
onClick = { viewModel.toggleFavorite(peerID) },
modifier = Modifier.size(28.dp)
) {
Icon(
imageVector = if (isFavorite) Icons.Filled.Star else Icons.Outlined.Star,
contentDescription = if (isFavorite) stringResource(R.string.cd_remove_favorite) else stringResource(R.string.cd_add_favorite),
modifier = Modifier.size(16.dp),
tint = if (isFavorite) Color(0xFFFFD700) else colorScheme.onSurface.copy(alpha = 0.6f)
)
}
} }
)
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.*
import androidx.compose.foundation.layout.FlowRow import androidx.compose.foundation.layout.FlowRow
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.layout.ExperimentalLayoutApi import androidx.compose.foundation.layout.ExperimentalLayoutApi
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Bluetooth import androidx.compose.material.icons.filled.Bluetooth
import androidx.compose.material.icons.filled.BugReport import androidx.compose.material.icons.filled.BugReport
@@ -34,6 +36,8 @@ import androidx.compose.ui.res.stringResource
import com.bitchat.android.R import com.bitchat.android.R
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import com.bitchat.android.core.ui.component.sheet.BitchatBottomSheet 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 @Composable
fun MeshTopologySection() { fun MeshTopologySection() {
@@ -111,6 +115,16 @@ fun DebugSettingsSheet(
val gcsFpr by manager.gcsFprPercent.collectAsState() val gcsFpr by manager.gcsFprPercent.collectAsState()
val context = LocalContext.current val context = LocalContext.current
// Persistent notification is now controlled solely by MeshServicePreferences.isBackgroundEnabled // 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 // Push live connected devices from mesh service whenever sheet is visible
LaunchedEffect(isPresented) { LaunchedEffect(isPresented) {
@@ -151,26 +165,23 @@ fun DebugSettingsSheet(
DisposableEffect(Unit) { DisposableEffect(Unit) {
onDispose { DebugSettingsManager.getInstance().setDebugSheetVisible(false) } onDispose { DebugSettingsManager.getInstance().setDebugSheetVisible(false) }
} }
LazyColumn( Box(modifier = Modifier.fillMaxWidth()) {
modifier = Modifier LazyColumn(
.fillMaxWidth() state = listState,
.padding(horizontal = 16.dp), modifier = Modifier
contentPadding = PaddingValues(top = 80.dp), .fillMaxWidth()
verticalArrangement = Arrangement.spacedBy(16.dp) .padding(horizontal = 16.dp),
) { contentPadding = PaddingValues(top = 80.dp, bottom = 24.dp),
item { verticalArrangement = Arrangement.spacedBy(16.dp)
Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(8.dp)) { ) {
Icon(Icons.Filled.BugReport, contentDescription = null, tint = Color(0xFFFF9500)) item {
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,
fontSize = 12.sp,
color = colorScheme.onSurface.copy(alpha = 0.7f)
)
} }
Text(
text = stringResource(R.string.debug_tools_desc),
fontFamily = FontFamily.Monospace,
fontSize = 12.sp,
color = colorScheme.onSurface.copy(alpha = 0.7f)
)
}
// Verbose logging toggle // Verbose logging toggle
item { item {
Surface(shape = RoundedCornerShape(12.dp), color = colorScheme.surfaceVariant.copy(alpha = 0.2f)) { Surface(shape = RoundedCornerShape(12.dp), color = colorScheme.surfaceVariant.copy(alpha = 0.2f)) {
@@ -627,7 +638,29 @@ fun DebugSettingsSheet(
} }
} }
item { Spacer(Modifier.height(16.dp)) } 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)
)
}
}
)
} }
} }
} }