From 521784b3594470948424470c389f41e02a01b930 Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Mon, 27 Jul 2026 03:44:13 +0200 Subject: [PATCH] nicer --- .../android/ui/LocationChannelsSheet.kt | 173 ++++++++++++------ app/src/main/res/values/strings.xml | 5 +- 2 files changed, 120 insertions(+), 58 deletions(-) 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 76b3c020..43038419 100644 --- a/app/src/main/java/com/bitchat/android/ui/LocationChannelsSheet.kt +++ b/app/src/main/java/com/bitchat/android/ui/LocationChannelsSheet.kt @@ -2,6 +2,7 @@ package com.bitchat.android.ui import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Bookmark +import androidx.compose.material.icons.filled.Hub import androidx.compose.material.icons.filled.Map import androidx.compose.material.icons.filled.PinDrop import androidx.compose.material.icons.filled.Security @@ -147,31 +148,6 @@ fun LocationChannelsSheet( contentPadding = PaddingValues(top = 72.dp, bottom = 32.dp), verticalArrangement = Arrangement.spacedBy(0.dp) ) { - item(key = "header") { - Column( - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = AboutHorizontalPadding), - verticalArrangement = Arrangement.spacedBy(10.dp) - ) { - SheetHeaderBadge(icon = Icons.Outlined.Public) - Text( - text = stringResource(R.string.location_channels_heading), - fontSize = 20.sp, - fontFamily = FontFamily.Monospace, - fontWeight = FontWeight.Medium, - color = colorScheme.primary - ) - Text( - text = stringResource(R.string.location_channels_desc), - fontSize = 12.sp, - lineHeight = 17.sp, - fontFamily = FontFamily.Monospace, - color = palette.textSecondary - ) - } - } - if (locationServicesEnabled && permissionState == LocationChannelManager.PermissionState.DENIED ) { @@ -180,7 +156,7 @@ fun LocationChannelsSheet( modifier = Modifier .fillMaxWidth() .padding(horizontal = AboutHorizontalPadding) - .padding(top = 16.dp), + .padding(top = 8.dp), verticalArrangement = Arrangement.spacedBy(4.dp) ) { Text( @@ -208,38 +184,64 @@ fun LocationChannelsSheet( } } - // Channels card: mesh + nearby + teleport input - item(key = "channels_card") { + // Mesh section: icon + title header, offline subtitle, then selection card + item(key = "mesh_card") { Column { - AboutSectionLabel(text = stringResource(R.string.channels)) + ChannelSectionHeader( + icon = Icons.Filled.Hub, + title = stringResource(R.string.mesh_title), + subtitle = stringResource(R.string.mesh_section_subtitle), + modifier = Modifier.padding(top = 8.dp) + ) Surface( modifier = Modifier .fillMaxWidth() - .padding(horizontal = AboutHorizontalPadding), + .padding(horizontal = AboutHorizontalPadding) + .padding(top = 10.dp), + color = palette.surface, + shape = AboutCardShape + ) { + ChannelOptionRow( + title = meshTitleWithCount(viewModel), + subtitle = stringResource( + R.string.location_bluetooth_subtitle, + bluetoothRangeString() + ), + isSelected = selectedChannel is ChannelID.Mesh, + participantCount = meshCount(viewModel), + titleColor = standardBlue, + titleBold = meshCount(viewModel) > 0, + onClick = { + locationManager.select(ChannelID.Mesh) + onDismiss() + } + ) + } + } + } + + // Location channels: globe + title, geohash subtitle, nearby levels + teleport + item(key = "channels_card") { + Column { + ChannelSectionHeader( + icon = Icons.Outlined.Public, + title = stringResource(R.string.location_channels_heading), + subtitle = stringResource(R.string.location_channels_desc), + modifier = Modifier.padding(top = 20.dp) + ) + Surface( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = AboutHorizontalPadding) + .padding(top = 10.dp), color = palette.surface, shape = AboutCardShape ) { Column { - ChannelOptionRow( - title = meshTitleWithCount(viewModel), - subtitle = stringResource( - R.string.location_bluetooth_subtitle, - bluetoothRangeString() - ), - isSelected = selectedChannel is ChannelID.Mesh, - participantCount = meshCount(viewModel), - titleColor = standardBlue, - titleBold = meshCount(viewModel) > 0, - onClick = { - locationManager.select(ChannelID.Mesh) - onDismiss() - } - ) - if (locationServicesEnabled) { if (nearbyChannels.isNotEmpty()) { - nearbyChannels.forEach { channel -> - ChannelCardDivider() + nearbyChannels.forEachIndexed { index, channel -> + if (index > 0) ChannelCardDivider() val coverage = coverageString(channel.geohash.length) val nameBase = locationNames[channel.level] val namePart = nameBase?.let { formattedNamePrefix(channel.level) + it } @@ -267,13 +269,13 @@ fun LocationChannelsSheet( } ) } - } else if (showNearbyLoading) { ChannelCardDivider() + } else if (showNearbyLoading) { ChannelLoadingRow() + ChannelCardDivider() } } - ChannelCardDivider() CustomGeohashRow( customGeohash = customGeohash, onGeohashChange = { value -> @@ -506,6 +508,53 @@ private fun ChannelCardDivider() { ) } +/** + * Section title row: icon + name on one line, optional short subtitle beneath. + */ +@Composable +private fun ChannelSectionHeader( + icon: ImageVector, + title: String, + subtitle: String, + modifier: Modifier = Modifier +) { + val colorScheme = MaterialTheme.colorScheme + val palette = LocalBitchatPalette.current + + Column( + modifier = modifier + .fillMaxWidth() + .padding(horizontal = AboutHorizontalPadding), + verticalArrangement = Arrangement.spacedBy(6.dp) + ) { + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(10.dp) + ) { + Icon( + imageVector = icon, + contentDescription = null, + tint = colorScheme.primary, + modifier = Modifier.size(22.dp) + ) + Text( + text = title, + fontSize = 17.sp, + fontFamily = FontFamily.Monospace, + fontWeight = FontWeight.SemiBold, + color = colorScheme.primary + ) + } + Text( + text = subtitle, + fontSize = 12.sp, + lineHeight = 17.sp, + fontFamily = FontFamily.Monospace, + color = palette.textSecondary + ) + } +} + /** * Single channel option — settings-row geometry: 22.dp leading slot, title + subtitle, trailing. * Selected state is a 12.dp green dot centered in the leading slot (icon-sized footprint). @@ -518,9 +567,11 @@ private fun ChannelOptionRow( participantCount: Int, titleColor: Color? = null, titleBold: Boolean = false, + leadingIcon: ImageVector? = null, trailingContent: (@Composable (() -> Unit))? = null, onClick: () -> Unit ) { + val colorScheme = MaterialTheme.colorScheme val palette = LocalBitchatPalette.current val (baseTitle, countSuffix) = splitTitleAndCount(title) @@ -535,12 +586,22 @@ private fun ChannelOptionRow( modifier = Modifier.size(ChannelLeadingSlot), contentAlignment = Alignment.Center ) { - if (isSelected) { - Box( - modifier = Modifier - .size(ChannelSelectedDot) - .background(palette.accentGreen, CircleShape) - ) + when { + isSelected -> { + Box( + modifier = Modifier + .size(ChannelSelectedDot) + .background(palette.accentGreen, CircleShape) + ) + } + leadingIcon != null -> { + Icon( + imageVector = leadingIcon, + contentDescription = null, + tint = colorScheme.primary, + modifier = Modifier.size(22.dp) + ) + } } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3b7a7022..d0987249 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -241,9 +241,10 @@ - #Location Channels + Channels Location Channels - Chat with people near you using geohash channels. Only a coarse geohash is shared, never exact GPS. Do not screenshot or share this screen to protect your privacy. + Chat nearby over geohash channels. Only a coarse location is shared, never exact GPS. + Offline mesh via Bluetooth. No internet required. Nearby