diff --git a/app/src/main/java/com/bitchat/android/core/ui/component/sheet/BitchatBottomSheet.kt b/app/src/main/java/com/bitchat/android/core/ui/component/sheet/BitchatBottomSheet.kt new file mode 100644 index 00000000..948fd6d9 --- /dev/null +++ b/app/src/main/java/com/bitchat/android/core/ui/component/sheet/BitchatBottomSheet.kt @@ -0,0 +1,32 @@ +package com.bitchat.android.core.ui.component.sheet + +import androidx.compose.foundation.layout.ColumnScope +import androidx.compose.foundation.layout.statusBarsPadding +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.ModalBottomSheet +import androidx.compose.material3.SheetState +import androidx.compose.material3.rememberModalBottomSheetState +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun BitchatBottomSheet( + modifier: Modifier = Modifier, + sheetState: SheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true), + onDismissRequest: () -> Unit, + content: @Composable (ColumnScope.() -> Unit), +) { + ModalBottomSheet( + modifier = modifier.statusBarsPadding(), + onDismissRequest = onDismissRequest, + sheetState = sheetState, + dragHandle = null, + shape = RoundedCornerShape(topStart = 28.dp, topEnd = 28.dp), + containerColor = MaterialTheme.colorScheme.background, + content = content, + ) +} \ No newline at end of file diff --git a/app/src/main/java/com/bitchat/android/ui/AboutSheet.kt b/app/src/main/java/com/bitchat/android/ui/AboutSheet.kt index d931c027..f137ac63 100644 --- a/app/src/main/java/com/bitchat/android/ui/AboutSheet.kt +++ b/app/src/main/java/com/bitchat/android/ui/AboutSheet.kt @@ -9,18 +9,14 @@ import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Bluetooth -import androidx.compose.material.icons.filled.Close import androidx.compose.material.icons.filled.Lock import androidx.compose.material.icons.filled.Public import androidx.compose.material.icons.filled.Warning import androidx.compose.material.icons.filled.Security -import androidx.compose.material.icons.filled.NetworkCheck import androidx.compose.material.icons.filled.Speed -import androidx.compose.material.icons.outlined.Info import androidx.compose.material3.* import androidx.compose.runtime.* import androidx.compose.ui.Alignment -import kotlinx.coroutines.launch import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.vector.ImageVector @@ -28,15 +24,14 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.text.style.BaselineShift import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.bitchat.android.nostr.NostrProofOfWork import com.bitchat.android.nostr.PoWPreferenceManager 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.net.TorMode import com.bitchat.android.net.TorPreferenceManager import com.bitchat.android.net.ArtiTorManager @@ -218,10 +213,6 @@ fun AboutSheet( } } - val sheetState = rememberModalBottomSheetState( - skipPartiallyExpanded = true - ) - val lazyListState = rememberLazyListState() val isScrolled by remember { derivedStateOf { @@ -237,12 +228,9 @@ fun AboutSheet( val isDark = colorScheme.background.red + colorScheme.background.green + colorScheme.background.blue < 1.5f if (isPresented) { - ModalBottomSheet( - modifier = modifier.statusBarsPadding(), + BitchatBottomSheet( + modifier = modifier, onDismissRequest = onDismiss, - sheetState = sheetState, - containerColor = colorScheme.background, - dragHandle = null ) { Box(modifier = Modifier.fillMaxWidth()) { LazyColumn( @@ -682,27 +670,6 @@ fun AboutSheet( } } -@Composable -fun CloseButton( - onClick: () -> Unit, - modifier: Modifier = Modifier -) { - IconButton( - onClick = onClick, - modifier = modifier - .size(32.dp), - colors = IconButtonDefaults.iconButtonColors( - contentColor = MaterialTheme.colorScheme.onBackground.copy(alpha = 0.6f), - containerColor = MaterialTheme.colorScheme.onBackground.copy(alpha = 0.1f) - ) - ) { - Icon( - imageVector = Icons.Default.Close, - contentDescription = "Close", - modifier = Modifier.size(18.dp) - ) - } -} /** * Password prompt dialog for password-protected channels * Kept as dialog since it requires user input diff --git a/app/src/main/java/com/bitchat/android/ui/ChatUserSheet.kt b/app/src/main/java/com/bitchat/android/ui/ChatUserSheet.kt index 54e7aea4..36ff15a6 100644 --- a/app/src/main/java/com/bitchat/android/ui/ChatUserSheet.kt +++ b/app/src/main/java/com/bitchat/android/ui/ChatUserSheet.kt @@ -4,7 +4,6 @@ import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.material3.* import androidx.compose.runtime.* -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.font.FontFamily @@ -16,7 +15,7 @@ import androidx.compose.ui.res.stringResource import com.bitchat.android.R import androidx.compose.ui.platform.LocalClipboardManager import androidx.compose.ui.text.AnnotatedString -import kotlinx.coroutines.launch +import com.bitchat.android.core.ui.component.sheet.BitchatBottomSheet import com.bitchat.android.model.BitchatMessage /** @@ -36,11 +35,6 @@ fun ChatUserSheet( val coroutineScope = rememberCoroutineScope() val clipboardManager = LocalClipboardManager.current - // Bottom sheet state - val sheetState = rememberModalBottomSheetState( - skipPartiallyExpanded = true - ) - // iOS system colors (matches LocationChannelsSheet exactly) val colorScheme = MaterialTheme.colorScheme val isDark = colorScheme.background.red + colorScheme.background.green + colorScheme.background.blue < 1.5f @@ -50,9 +44,8 @@ fun ChatUserSheet( val standardGrey = if (isDark) Color(0xFF8E8E93) else Color(0xFF6D6D70) // iOS grey if (isPresented) { - ModalBottomSheet( + BitchatBottomSheet( onDismissRequest = onDismiss, - sheetState = sheetState, modifier = modifier ) { Column( diff --git a/app/src/main/java/com/bitchat/android/ui/LocationChannelsSheet.kt b/app/src/main/java/com/bitchat/android/ui/LocationChannelsSheet.kt index 6f47d68f..495683bd 100644 --- a/app/src/main/java/com/bitchat/android/ui/LocationChannelsSheet.kt +++ b/app/src/main/java/com/bitchat/android/ui/LocationChannelsSheet.kt @@ -40,6 +40,7 @@ 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 /** * Location Channels Sheet for selecting geohash-based location channels @@ -113,12 +114,10 @@ fun LocationChannelsSheet( val standardBlue = Color(0xFF007AFF) // iOS blue if (isPresented) { - ModalBottomSheet( - modifier = modifier.statusBarsPadding(), + BitchatBottomSheet( + modifier = modifier, onDismissRequest = onDismiss, sheetState = sheetState, - containerColor = MaterialTheme.colorScheme.background, - dragHandle = null ) { Box(modifier = Modifier.fillMaxWidth()) { LazyColumn( diff --git a/app/src/main/java/com/bitchat/android/ui/LocationNotesSheet.kt b/app/src/main/java/com/bitchat/android/ui/LocationNotesSheet.kt index 93b6d517..222876f8 100644 --- a/app/src/main/java/com/bitchat/android/ui/LocationNotesSheet.kt +++ b/app/src/main/java/com/bitchat/android/ui/LocationNotesSheet.kt @@ -16,7 +16,6 @@ import androidx.compose.runtime.* import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.text.font.FontFamily @@ -27,6 +26,8 @@ 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.geohash.GeohashChannelLevel import com.bitchat.android.geohash.LocationChannelManager import com.bitchat.android.nostr.LocationNotesManager @@ -51,7 +52,6 @@ fun LocationNotesSheet( val isDark = isSystemInDarkTheme() // iOS color scheme - val backgroundColor = if (isDark) Color.Black else Color.White val accentGreen = if (isDark) Color.Green else Color(0xFF008000) // dark: green, light: dark green (0, 0.5, 0) // Managers @@ -99,14 +99,10 @@ fun LocationNotesSheet( notesManager.cancel() } } - - ModalBottomSheet( + + BitchatBottomSheet( onDismissRequest = onDismiss, - modifier = modifier.statusBarsPadding(), - sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true), - dragHandle = null, - containerColor = backgroundColor, - contentColor = if (isDark) Color.White else Color.Black + modifier = modifier, ) { Box(modifier = Modifier.fillMaxWidth()) { LazyColumn( @@ -121,7 +117,6 @@ fun LocationNotesSheet( locationName = displayLocationName, state = state, accentGreen = accentGreen, - backgroundColor = backgroundColor ) } @@ -203,7 +198,6 @@ fun LocationNotesSheet( onDraftChange = { draft = it }, sendButtonEnabled = sendButtonEnabled, accentGreen = accentGreen, - backgroundColor = backgroundColor, onSend = { val content = draft.trim() if (content.isNotEmpty()) { @@ -229,12 +223,11 @@ private fun LocationNotesHeader( locationName: String?, state: LocationNotesManager.State, accentGreen: Color, - backgroundColor: Color, ) { Column( modifier = Modifier .fillMaxWidth() - .background(backgroundColor) + .padding(horizontal = 16.dp) .padding(top = 16.dp, bottom = 12.dp) ) { // Localized title with ±1 and note count @@ -470,7 +463,6 @@ private fun LocationNotesInputSection( onDraftChange: (String) -> Unit, sendButtonEnabled: Boolean, accentGreen: Color, - backgroundColor: Color, onSend: () -> Unit ) { val isDark = isSystemInDarkTheme() @@ -479,7 +471,6 @@ private fun LocationNotesInputSection( Row( modifier = Modifier .fillMaxWidth() - .background(backgroundColor) .padding(horizontal = 12.dp, vertical = 8.dp), // Match main chat padding verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(8.dp) // Match main chat spacing diff --git a/app/src/main/java/com/bitchat/android/ui/LocationNotesSheetPresenter.kt b/app/src/main/java/com/bitchat/android/ui/LocationNotesSheetPresenter.kt index d17b6d7c..850fdfda 100644 --- a/app/src/main/java/com/bitchat/android/ui/LocationNotesSheetPresenter.kt +++ b/app/src/main/java/com/bitchat/android/ui/LocationNotesSheetPresenter.kt @@ -10,6 +10,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.bitchat.android.core.ui.component.sheet.BitchatBottomSheet import com.bitchat.android.geohash.GeohashChannelLevel import com.bitchat.android.geohash.LocationChannelManager @@ -62,11 +63,8 @@ private fun LocationNotesErrorSheet( onDismiss: () -> Unit, locationManager: LocationChannelManager ) { - val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true) - ModalBottomSheet( + BitchatBottomSheet( onDismissRequest = onDismiss, - sheetState = sheetState, - containerColor = MaterialTheme.colorScheme.surface ) { Column( modifier = Modifier diff --git a/app/src/main/java/com/bitchat/android/ui/MeshPeerListSheet.kt b/app/src/main/java/com/bitchat/android/ui/MeshPeerListSheet.kt index e2f1694d..eb20efcd 100644 --- a/app/src/main/java/com/bitchat/android/ui/MeshPeerListSheet.kt +++ b/app/src/main/java/com/bitchat/android/ui/MeshPeerListSheet.kt @@ -25,6 +25,8 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp 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.geohash.ChannelID import com.bitchat.android.ui.theme.BASE_FONT_SIZE @@ -77,12 +79,10 @@ fun MeshPeerListSheet( ) if (isPresented) { - ModalBottomSheet( - modifier = modifier.statusBarsPadding(), + BitchatBottomSheet( + modifier = modifier, onDismissRequest = onDismiss, sheetState = sheetState, - containerColor = MaterialTheme.colorScheme.background, - dragHandle = null ) { Box(modifier = Modifier.fillMaxWidth()) { LazyColumn( @@ -851,12 +851,9 @@ private fun PrivateChatSheet( ) if (isPresented) { - ModalBottomSheet( - modifier = Modifier.statusBarsPadding(), + BitchatBottomSheet( onDismissRequest = onDismiss, sheetState = sheetState, - containerColor = colorScheme.background, - dragHandle = null ) { Box(modifier = Modifier.fillMaxSize()) { Column( diff --git a/app/src/main/java/com/bitchat/android/ui/SecurityVerificationSheet.kt b/app/src/main/java/com/bitchat/android/ui/SecurityVerificationSheet.kt index 59fe6085..9a4a1592 100644 --- a/app/src/main/java/com/bitchat/android/ui/SecurityVerificationSheet.kt +++ b/app/src/main/java/com/bitchat/android/ui/SecurityVerificationSheet.kt @@ -11,7 +11,6 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.statusBarsPadding import androidx.compose.foundation.layout.width import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Lock @@ -22,14 +21,12 @@ import androidx.compose.material.icons.outlined.Sync import androidx.compose.material.icons.outlined.Warning as OutlinedWarning import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.DropdownMenu +import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.ModalBottomSheet -import androidx.compose.material3.DropdownMenu -import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.Text -import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -49,6 +46,8 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp 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 private data class SecurityStatusInfo( val text: String, @@ -66,7 +65,6 @@ fun SecurityVerificationSheet( ) { if (!isPresented) return - val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true) val peerID by viewModel.selectedPrivateChatPeer.collectAsStateWithLifecycle() val verifiedFingerprints by viewModel.verifiedFingerprints.collectAsStateWithLifecycle() val peerSessionStates by viewModel.peerSessionStates.collectAsStateWithLifecycle() @@ -76,12 +74,9 @@ fun SecurityVerificationSheet( val boxColor = if (isDark) Color.White.copy(alpha = 0.06f) else Color.Black.copy(alpha = 0.06f) val peerHexRegex = remember { Regex("^[0-9a-fA-F]{16}$") } - ModalBottomSheet( - modifier = modifier.statusBarsPadding(), + BitchatBottomSheet( + modifier = modifier, onDismissRequest = onDismiss, - sheetState = sheetState, - containerColor = MaterialTheme.colorScheme.background, - dragHandle = null ) { Column( modifier = Modifier diff --git a/app/src/main/java/com/bitchat/android/ui/VerificationSheet.kt b/app/src/main/java/com/bitchat/android/ui/VerificationSheet.kt index 896a66c1..1bf86b5b 100644 --- a/app/src/main/java/com/bitchat/android/ui/VerificationSheet.kt +++ b/app/src/main/java/com/bitchat/android/ui/VerificationSheet.kt @@ -25,7 +25,6 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size -import androidx.compose.foundation.layout.statusBarsPadding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.selection.SelectionContainer @@ -38,9 +37,7 @@ import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.ModalBottomSheet import androidx.compose.material3.Text -import androidx.compose.material3.rememberModalBottomSheetState import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.collectAsState @@ -68,6 +65,8 @@ import androidx.core.graphics.set import androidx.lifecycle.compose.LocalLifecycleOwner 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.services.VerificationService import com.google.accompanist.permissions.ExperimentalPermissionsApi import com.google.accompanist.permissions.isGranted @@ -93,7 +92,6 @@ fun VerificationSheet( ) { if (!isPresented) return - val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true) val isDark = isSystemInDarkTheme() val accent = if (isDark) Color.Green else Color(0xFF008000) val boxColor = if (isDark) Color.White.copy(alpha = 0.06f) else Color.Black.copy(alpha = 0.06f) @@ -109,12 +107,9 @@ fun VerificationSheet( viewModel.buildMyQRString(nickname, npub) } - ModalBottomSheet( - modifier = modifier.statusBarsPadding(), + BitchatBottomSheet( + modifier = modifier, onDismissRequest = onDismiss, - sheetState = sheetState, - containerColor = MaterialTheme.colorScheme.background, - dragHandle = null ) { Column( modifier = Modifier diff --git a/app/src/main/java/com/bitchat/android/ui/debug/DebugSettingsSheet.kt b/app/src/main/java/com/bitchat/android/ui/debug/DebugSettingsSheet.kt index 4b9f983a..f4f716ac 100644 --- a/app/src/main/java/com/bitchat/android/ui/debug/DebugSettingsSheet.kt +++ b/app/src/main/java/com/bitchat/android/ui/debug/DebugSettingsSheet.kt @@ -5,13 +5,11 @@ 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.items import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.layout.ExperimentalLayoutApi import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Bluetooth import androidx.compose.material.icons.filled.BugReport -import androidx.compose.material.icons.filled.Cancel import androidx.compose.material.icons.filled.Devices import androidx.compose.material.icons.filled.PowerSettingsNew import androidx.compose.material.icons.filled.SettingsEthernet @@ -31,8 +29,7 @@ import kotlinx.coroutines.launch import androidx.compose.ui.res.stringResource import com.bitchat.android.R import androidx.compose.ui.platform.LocalContext -import com.bitchat.android.service.MeshServicePreferences -import com.bitchat.android.service.MeshForegroundService +import com.bitchat.android.core.ui.component.sheet.BitchatBottomSheet private enum class GraphMode { OVERALL, PER_DEVICE, PER_PEER } @@ -43,7 +40,6 @@ fun DebugSettingsSheet( onDismiss: () -> Unit, meshService: BluetoothMeshService ) { - val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = false) val colorScheme = MaterialTheme.colorScheme val manager = remember { DebugSettingsManager.getInstance() } @@ -95,9 +91,8 @@ fun DebugSettingsSheet( if (!isPresented) return - ModalBottomSheet( + BitchatBottomSheet( onDismissRequest = onDismiss, - sheetState = sheetState ) { // Mark debug sheet visible/invisible to gate heavy work LaunchedEffect(Unit) { DebugSettingsManager.getInstance().setDebugSheetVisible(true) } @@ -107,8 +102,8 @@ fun DebugSettingsSheet( LazyColumn( modifier = Modifier .fillMaxWidth() - .padding(horizontal = 16.dp) - .padding(bottom = 24.dp), + .padding(horizontal = 16.dp), + contentPadding = PaddingValues(top = 80.dp), verticalArrangement = Arrangement.spacedBy(16.dp) ) { item {