mirror of
https://github.com/permissionlesstech/bitchat-android.git
synced 2026-07-24 23:45:19 +00:00
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:
@@ -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)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user