mirror of
https://github.com/permissionlesstech/bitchat-android.git
synced 2026-07-25 01:05:20 +00:00
Add App Info Bottom Sheet (#406)
* Automated update of relay data - Sun Sep 7 06:20:11 UTC 2025 * Refactor(ui): Improve AboutSheet design and layout Ios Like This commit refactors the `AboutSheet` composable with several UI enhancements: - Updated the overall layout and styling for a more modern look and feel. - Introduced a collapsing top bar effect on scroll. - Replaced `FeatureCard` with individual `Row` layouts for feature descriptions. - Adjusted typography, spacing, and padding for better readability. - Updated color usage to align with `MaterialTheme.colorScheme`. - Made the bottom sheet skip the partially expanded state by default. - Added `statusBarsPadding` to the `ModalBottomSheet`. --------- Co-authored-by: GitHub Action <action@github.com>
This commit is contained in:
co-authored by
GitHub Action
parent
73c91b9509
commit
eba0d36015
@@ -1,7 +1,11 @@
|
|||||||
package com.bitchat.android.ui
|
package com.bitchat.android.ui
|
||||||
|
|
||||||
|
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.rememberLazyListState
|
||||||
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
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
|
||||||
@@ -16,6 +20,7 @@ import androidx.compose.ui.Modifier
|
|||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
import androidx.compose.ui.platform.LocalContext
|
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.FontFamily
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.text.style.BaselineShift
|
import androidx.compose.ui.text.style.BaselineShift
|
||||||
@@ -51,32 +56,45 @@ fun AboutSheet(
|
|||||||
// Bottom sheet state
|
// Bottom sheet state
|
||||||
|
|
||||||
val sheetState = rememberModalBottomSheetState(
|
val sheetState = rememberModalBottomSheetState(
|
||||||
skipPartiallyExpanded = false
|
skipPartiallyExpanded = true
|
||||||
|
)
|
||||||
|
|
||||||
|
val lazyListState = rememberLazyListState()
|
||||||
|
val isScrolled by remember {
|
||||||
|
derivedStateOf {
|
||||||
|
lazyListState.firstVisibleItemIndex > 0 || lazyListState.firstVisibleItemScrollOffset > 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val topBarAlpha by animateFloatAsState(
|
||||||
|
targetValue = if (isScrolled) 0.95f else 0f,
|
||||||
|
label = "topBarAlpha"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Color scheme matching LocationChannelsSheet
|
// Color scheme matching LocationChannelsSheet
|
||||||
val colorScheme = MaterialTheme.colorScheme
|
val colorScheme = MaterialTheme.colorScheme
|
||||||
val isDark = colorScheme.background.red + colorScheme.background.green + colorScheme.background.blue < 1.5f
|
val isDark = colorScheme.background.red + colorScheme.background.green + colorScheme.background.blue < 1.5f
|
||||||
val standardBlue = Color(0xFF007AFF) // iOS blue
|
|
||||||
val standardGreen = if (isDark) Color(0xFF32D74B) else Color(0xFF248A3D) // iOS green
|
|
||||||
|
|
||||||
if (isPresented) {
|
if (isPresented) {
|
||||||
ModalBottomSheet(
|
ModalBottomSheet(
|
||||||
|
modifier = modifier.statusBarsPadding(),
|
||||||
onDismissRequest = onDismiss,
|
onDismissRequest = onDismiss,
|
||||||
sheetState = sheetState,
|
sheetState = sheetState,
|
||||||
modifier = modifier
|
containerColor = MaterialTheme.colorScheme.background,
|
||||||
|
dragHandle = null
|
||||||
) {
|
) {
|
||||||
|
Box(modifier = Modifier.fillMaxWidth()) {
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
|
state = lazyListState,
|
||||||
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
contentPadding = PaddingValues(top = 80.dp, bottom = 20.dp)
|
||||||
|
) {
|
||||||
|
// Header Section
|
||||||
|
item(key = "header") {
|
||||||
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(horizontal = 16.dp)
|
.padding(horizontal = 24.dp)
|
||||||
.padding(bottom = 24.dp),
|
.padding(bottom = 16.dp),
|
||||||
verticalArrangement = Arrangement.spacedBy(16.dp)
|
|
||||||
) {
|
|
||||||
// Header
|
|
||||||
item {
|
|
||||||
Column(
|
|
||||||
modifier = Modifier.fillMaxWidth(),
|
|
||||||
verticalArrangement = Arrangement.spacedBy(8.dp)
|
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||||
) {
|
) {
|
||||||
Row(
|
Row(
|
||||||
@@ -85,17 +103,19 @@ fun AboutSheet(
|
|||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = "bitchat",
|
text = "bitchat",
|
||||||
fontSize = 18.sp,
|
style = TextStyle(
|
||||||
fontFamily = FontFamily.Monospace,
|
fontFamily = FontFamily.Monospace,
|
||||||
fontWeight = FontWeight.Medium,
|
fontWeight = FontWeight.Bold,
|
||||||
color = colorScheme.onSurface
|
fontSize = 32.sp
|
||||||
|
),
|
||||||
|
color = MaterialTheme.colorScheme.onBackground
|
||||||
)
|
)
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
text = "v$versionName",
|
text = "v$versionName",
|
||||||
fontSize = 11.sp,
|
fontSize = 11.sp,
|
||||||
fontFamily = FontFamily.Monospace,
|
fontFamily = FontFamily.Monospace,
|
||||||
color = colorScheme.onSurface.copy(alpha = 0.5f),
|
color = colorScheme.onBackground.copy(alpha = 0.5f),
|
||||||
style = MaterialTheme.typography.bodySmall.copy(
|
style = MaterialTheme.typography.bodySmall.copy(
|
||||||
baselineShift = BaselineShift(0.1f)
|
baselineShift = BaselineShift(0.1f)
|
||||||
)
|
)
|
||||||
@@ -106,55 +126,124 @@ fun AboutSheet(
|
|||||||
text = "decentralized mesh messaging with end-to-end encryption",
|
text = "decentralized mesh messaging with end-to-end encryption",
|
||||||
fontSize = 12.sp,
|
fontSize = 12.sp,
|
||||||
fontFamily = FontFamily.Monospace,
|
fontFamily = FontFamily.Monospace,
|
||||||
color = colorScheme.onSurface.copy(alpha = 0.7f)
|
color = MaterialTheme.colorScheme.onBackground.copy(alpha = 0.7f)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Features section
|
// Features section
|
||||||
item {
|
item(key = "feature_offline") {
|
||||||
Column(verticalArrangement = Arrangement.spacedBy(12.dp)) {
|
Row(
|
||||||
FeatureCard(
|
verticalAlignment = Alignment.Top,
|
||||||
icon = Icons.Filled.Bluetooth,
|
modifier = Modifier
|
||||||
iconColor = standardBlue,
|
.padding(horizontal = 24.dp)
|
||||||
title = "offline mesh chat",
|
.padding(vertical = 8.dp)
|
||||||
description = "communicate directly via bluetooth le without internet or servers. messages relay through nearby devices to extend range.",
|
|
||||||
modifier = Modifier.fillMaxWidth()
|
|
||||||
)
|
|
||||||
|
|
||||||
FeatureCard(
|
|
||||||
icon = Icons.Filled.Public,
|
|
||||||
iconColor = standardGreen,
|
|
||||||
title = "online geohash channels",
|
|
||||||
description = "connect with people in your area using geohash-based channels. extend the mesh using public internet relays.",
|
|
||||||
modifier = Modifier.fillMaxWidth()
|
|
||||||
)
|
|
||||||
|
|
||||||
FeatureCard(
|
|
||||||
icon = Icons.Filled.Lock,
|
|
||||||
iconColor = if (isDark) Color(0xFFFFD60A) else Color(0xFFF5A623),
|
|
||||||
title = "end-to-end encryption",
|
|
||||||
description = "private messages are encrypted. channel messages are public.",
|
|
||||||
modifier = Modifier.fillMaxWidth()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Appearance section (theme toggle)
|
|
||||||
item {
|
|
||||||
val themePref by com.bitchat.android.ui.theme.ThemePreferenceManager.themeFlow.collectAsState()
|
|
||||||
Column(
|
|
||||||
modifier = Modifier.fillMaxWidth(),
|
|
||||||
verticalArrangement = Arrangement.spacedBy(8.dp)
|
|
||||||
) {
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Filled.Bluetooth,
|
||||||
|
contentDescription = "Offline Mesh Chat",
|
||||||
|
tint = MaterialTheme.colorScheme.primary,
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(top = 2.dp)
|
||||||
|
.size(20.dp)
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.width(16.dp))
|
||||||
|
Column {
|
||||||
|
Text(
|
||||||
|
text = "Offline Mesh Chat",
|
||||||
|
style = MaterialTheme.typography.titleMedium,
|
||||||
|
fontWeight = FontWeight.Medium,
|
||||||
|
color = MaterialTheme.colorScheme.onBackground
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(4.dp))
|
||||||
|
Text(
|
||||||
|
text = "Communicate directly via Bluetooth LE without internet or servers. Messages relay through nearby devices to extend range.",
|
||||||
|
style = MaterialTheme.typography.bodySmall,
|
||||||
|
color = MaterialTheme.colorScheme.onBackground.copy(alpha = 0.8f)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
item(key = "feature_geohash") {
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.Top,
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(horizontal = 24.dp)
|
||||||
|
.padding(vertical = 8.dp)
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.Public,
|
||||||
|
contentDescription = "Online Geohash Channels",
|
||||||
|
tint = MaterialTheme.colorScheme.primary,
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(top = 2.dp)
|
||||||
|
.size(20.dp)
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.width(16.dp))
|
||||||
|
Column {
|
||||||
|
Text(
|
||||||
|
text = "Online Geohash Channels",
|
||||||
|
style = MaterialTheme.typography.titleMedium,
|
||||||
|
fontWeight = FontWeight.Medium,
|
||||||
|
color = MaterialTheme.colorScheme.onBackground
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(4.dp))
|
||||||
|
Text(
|
||||||
|
text = "Connect with people in your area using geohash-based channels. Extend the mesh using public internet relays.",
|
||||||
|
style = MaterialTheme.typography.bodySmall,
|
||||||
|
color = MaterialTheme.colorScheme.onBackground.copy(alpha = 0.8f)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
item(key = "feature_encryption") {
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.Top,
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(horizontal = 24.dp)
|
||||||
|
.padding(vertical = 8.dp)
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.Lock,
|
||||||
|
contentDescription = "End-to-End Encryption",
|
||||||
|
tint = MaterialTheme.colorScheme.primary,
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(top = 2.dp)
|
||||||
|
.size(20.dp)
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.width(16.dp))
|
||||||
|
Column {
|
||||||
|
Text(
|
||||||
|
text = "End-to-End Encryption",
|
||||||
|
style = MaterialTheme.typography.titleMedium,
|
||||||
|
fontWeight = FontWeight.Medium,
|
||||||
|
color = MaterialTheme.colorScheme.onBackground
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(4.dp))
|
||||||
|
Text(
|
||||||
|
text = "Private messages are encrypted. Channel messages are public.",
|
||||||
|
style = MaterialTheme.typography.bodySmall,
|
||||||
|
color = MaterialTheme.colorScheme.onBackground.copy(alpha = 0.8f)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Appearance Section
|
||||||
|
item(key = "appearance_section") {
|
||||||
Text(
|
Text(
|
||||||
text = "appearance",
|
text = "appearance",
|
||||||
fontSize = 12.sp,
|
style = MaterialTheme.typography.labelLarge,
|
||||||
fontFamily = FontFamily.Monospace,
|
color = MaterialTheme.colorScheme.onBackground.copy(alpha = 0.7f),
|
||||||
fontWeight = FontWeight.Medium,
|
modifier = Modifier
|
||||||
color = colorScheme.onSurface.copy(alpha = 0.8f)
|
.padding(horizontal = 24.dp)
|
||||||
|
.padding(top = 24.dp, bottom = 8.dp)
|
||||||
)
|
)
|
||||||
Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
|
val themePref by com.bitchat.android.ui.theme.ThemePreferenceManager.themeFlow.collectAsState()
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.padding(horizontal = 24.dp),
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
||||||
|
) {
|
||||||
FilterChip(
|
FilterChip(
|
||||||
selected = themePref.isSystem,
|
selected = themePref.isSystem,
|
||||||
onClick = { com.bitchat.android.ui.theme.ThemePreferenceManager.set(context, com.bitchat.android.ui.theme.ThemePreference.System) },
|
onClick = { com.bitchat.android.ui.theme.ThemePreferenceManager.set(context, com.bitchat.android.ui.theme.ThemePreference.System) },
|
||||||
@@ -172,13 +261,16 @@ fun AboutSheet(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
// Proof of Work Section
|
||||||
|
item(key = "pow_section") {
|
||||||
// Proof of Work section
|
Text(
|
||||||
item {
|
text = "proof of work",
|
||||||
val context = LocalContext.current
|
style = MaterialTheme.typography.labelLarge,
|
||||||
|
color = MaterialTheme.colorScheme.onBackground.copy(alpha = 0.7f),
|
||||||
// Initialize PoW preferences if not already done
|
modifier = Modifier
|
||||||
|
.padding(horizontal = 24.dp)
|
||||||
|
.padding(top = 24.dp, bottom = 8.dp)
|
||||||
|
)
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
PoWPreferenceManager.init(context)
|
PoWPreferenceManager.init(context)
|
||||||
}
|
}
|
||||||
@@ -187,17 +279,9 @@ fun AboutSheet(
|
|||||||
val powDifficulty by PoWPreferenceManager.powDifficulty.collectAsState()
|
val powDifficulty by PoWPreferenceManager.powDifficulty.collectAsState()
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.padding(horizontal = 24.dp),
|
||||||
verticalArrangement = Arrangement.spacedBy(8.dp)
|
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||||
) {
|
) {
|
||||||
Text(
|
|
||||||
text = "proof of work",
|
|
||||||
fontSize = 12.sp,
|
|
||||||
fontFamily = FontFamily.Monospace,
|
|
||||||
fontWeight = FontWeight.Medium,
|
|
||||||
color = colorScheme.onSurface.copy(alpha = 0.8f)
|
|
||||||
)
|
|
||||||
|
|
||||||
Row(
|
Row(
|
||||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||||
verticalAlignment = Alignment.CenterVertically
|
verticalAlignment = Alignment.CenterVertically
|
||||||
@@ -245,14 +329,13 @@ fun AboutSheet(
|
|||||||
text = "difficulty: $powDifficulty bits (~${NostrProofOfWork.estimateMiningTime(powDifficulty)})",
|
text = "difficulty: $powDifficulty bits (~${NostrProofOfWork.estimateMiningTime(powDifficulty)})",
|
||||||
fontSize = 11.sp,
|
fontSize = 11.sp,
|
||||||
fontFamily = FontFamily.Monospace,
|
fontFamily = FontFamily.Monospace,
|
||||||
color = colorScheme.onSurface.copy(alpha = 0.7f)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
Slider(
|
Slider(
|
||||||
value = powDifficulty.toFloat(),
|
value = powDifficulty.toFloat(),
|
||||||
onValueChange = { PoWPreferenceManager.setPowDifficulty(it.toInt()) },
|
onValueChange = { PoWPreferenceManager.setPowDifficulty(it.toInt()) },
|
||||||
valueRange = 0f..32f,
|
valueRange = 0f..32f,
|
||||||
steps = 33, // 33 discrete values (0-32)
|
steps = 33,
|
||||||
colors = SliderDefaults.colors(
|
colors = SliderDefaults.colors(
|
||||||
thumbColor = if (isDark) Color(0xFF32D74B) else Color(0xFF248A3D),
|
thumbColor = if (isDark) Color(0xFF32D74B) else Color(0xFF248A3D),
|
||||||
activeTrackColor = if (isDark) Color(0xFF32D74B) else Color(0xFF248A3D)
|
activeTrackColor = if (isDark) Color(0xFF32D74B) else Color(0xFF248A3D)
|
||||||
@@ -297,27 +380,27 @@ fun AboutSheet(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Network (Tor) section
|
// Network (Tor) section
|
||||||
item {
|
item(key = "network_section") {
|
||||||
val ctx = LocalContext.current
|
val torMode = remember { mutableStateOf(com.bitchat.android.net.TorPreferenceManager.get(context)) }
|
||||||
val torMode = remember { mutableStateOf(com.bitchat.android.net.TorPreferenceManager.get(ctx)) }
|
|
||||||
val torStatus by com.bitchat.android.net.TorManager.statusFlow.collectAsState()
|
val torStatus by com.bitchat.android.net.TorManager.statusFlow.collectAsState()
|
||||||
Column(
|
|
||||||
modifier = Modifier.fillMaxWidth(),
|
|
||||||
verticalArrangement = Arrangement.spacedBy(8.dp)
|
|
||||||
) {
|
|
||||||
Text(
|
Text(
|
||||||
text = "network",
|
text = "network",
|
||||||
fontSize = 12.sp,
|
style = MaterialTheme.typography.labelLarge,
|
||||||
fontFamily = FontFamily.Monospace,
|
color = MaterialTheme.colorScheme.onBackground.copy(alpha = 0.7f),
|
||||||
fontWeight = FontWeight.Medium,
|
modifier = Modifier
|
||||||
color = colorScheme.onSurface.copy(alpha = 0.8f)
|
.padding(horizontal = 24.dp)
|
||||||
|
.padding(top = 24.dp, bottom = 8.dp)
|
||||||
)
|
)
|
||||||
Row(horizontalArrangement = Arrangement.spacedBy(8.dp), verticalAlignment = Alignment.CenterVertically) {
|
Column(modifier = Modifier.padding(horizontal = 24.dp), verticalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||||
|
Row(
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
FilterChip(
|
FilterChip(
|
||||||
selected = torMode.value == com.bitchat.android.net.TorMode.OFF,
|
selected = torMode.value == com.bitchat.android.net.TorMode.OFF,
|
||||||
onClick = {
|
onClick = {
|
||||||
torMode.value = com.bitchat.android.net.TorMode.OFF
|
torMode.value = com.bitchat.android.net.TorMode.OFF
|
||||||
com.bitchat.android.net.TorPreferenceManager.set(ctx, torMode.value)
|
com.bitchat.android.net.TorPreferenceManager.set(context, torMode.value)
|
||||||
},
|
},
|
||||||
label = { Text("tor off", fontFamily = FontFamily.Monospace) }
|
label = { Text("tor off", fontFamily = FontFamily.Monospace) }
|
||||||
)
|
)
|
||||||
@@ -325,35 +408,33 @@ fun AboutSheet(
|
|||||||
selected = torMode.value == com.bitchat.android.net.TorMode.ON,
|
selected = torMode.value == com.bitchat.android.net.TorMode.ON,
|
||||||
onClick = {
|
onClick = {
|
||||||
torMode.value = com.bitchat.android.net.TorMode.ON
|
torMode.value = com.bitchat.android.net.TorMode.ON
|
||||||
com.bitchat.android.net.TorPreferenceManager.set(ctx, torMode.value)
|
com.bitchat.android.net.TorPreferenceManager.set(context, torMode.value)
|
||||||
},
|
},
|
||||||
label = {
|
label = {
|
||||||
Row(
|
Row(
|
||||||
horizontalArrangement = Arrangement.spacedBy(6.dp),
|
horizontalArrangement = Arrangement.spacedBy(6.dp),
|
||||||
verticalAlignment = Alignment.CenterVertically
|
verticalAlignment = Alignment.CenterVertically
|
||||||
) {
|
) {
|
||||||
Text("tor on", fontFamily = FontFamily.Monospace)
|
Text("Tor On", fontFamily = FontFamily.Monospace)
|
||||||
// Status indicator (red/orange/green) moved inside the "tor on" button
|
|
||||||
val statusColor = when {
|
val statusColor = when {
|
||||||
torStatus.running && torStatus.bootstrapPercent < 100 -> Color(0xFFFF9500)
|
torStatus.running && torStatus.bootstrapPercent < 100 -> Color(0xFFFF9500)
|
||||||
torStatus.running && torStatus.bootstrapPercent >= 100 -> if (isDark) Color(0xFF32D74B) else Color(0xFF248A3D)
|
torStatus.running && torStatus.bootstrapPercent >= 100 -> if (isDark) Color(0xFF32D74B) else Color(0xFF248A3D)
|
||||||
else -> Color.Red
|
else -> Color.Red
|
||||||
}
|
}
|
||||||
Surface(
|
Surface(color = statusColor, shape = CircleShape) {
|
||||||
color = statusColor,
|
Box(Modifier.size(8.dp))
|
||||||
shape = RoundedCornerShape(50)
|
}
|
||||||
) { Box(Modifier.size(8.dp)) }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Text(
|
Text(
|
||||||
text = "route internet over tor for enhanced privacy.",
|
text = "route internet over tor for enhanced privacy.",
|
||||||
fontSize = 10.sp,
|
style = MaterialTheme.typography.bodySmall,
|
||||||
fontFamily = FontFamily.Monospace,
|
color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.6f)
|
||||||
color = colorScheme.onSurface.copy(alpha = 0.6f)
|
|
||||||
)
|
)
|
||||||
|
if (torMode.value == com.bitchat.android.net.TorMode.ON) {
|
||||||
|
val statusText = if (torStatus.running) "Running" else "Stopped"
|
||||||
// Debug status (temporary)
|
// Debug status (temporary)
|
||||||
Surface(
|
Surface(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
@@ -365,19 +446,15 @@ fun AboutSheet(
|
|||||||
verticalArrangement = Arrangement.spacedBy(6.dp)
|
verticalArrangement = Arrangement.spacedBy(6.dp)
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = "tor status: " +
|
text = "tor Status: $statusText, bootstrap ${torStatus.bootstrapPercent}%",
|
||||||
(if (torStatus.running) "running" else "stopped") +
|
style = MaterialTheme.typography.bodySmall,
|
||||||
", bootstrap=" + torStatus.bootstrapPercent + "%",
|
|
||||||
fontSize = 11.sp,
|
|
||||||
fontFamily = FontFamily.Monospace,
|
|
||||||
color = colorScheme.onSurface.copy(alpha = 0.75f)
|
color = colorScheme.onSurface.copy(alpha = 0.75f)
|
||||||
)
|
)
|
||||||
val last = torStatus.lastLogLine
|
val lastLog = torStatus.lastLogLine
|
||||||
if (last.isNotEmpty()) {
|
if (lastLog.isNotEmpty()) {
|
||||||
Text(
|
Text(
|
||||||
text = "last: " + last.take(160),
|
text = "Last: ${lastLog.take(160)}",
|
||||||
fontSize = 10.sp,
|
style = MaterialTheme.typography.labelSmall,
|
||||||
fontFamily = FontFamily.Monospace,
|
|
||||||
color = colorScheme.onSurface.copy(alpha = 0.6f)
|
color = colorScheme.onSurface.copy(alpha = 0.6f)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -385,12 +462,18 @@ fun AboutSheet(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Emergency Warning Section
|
||||||
|
item(key = "warning_section") {
|
||||||
|
val colorScheme = MaterialTheme.colorScheme
|
||||||
|
val errorColor = colorScheme.error
|
||||||
|
|
||||||
// Emergency warning
|
|
||||||
item {
|
|
||||||
Surface(
|
Surface(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier
|
||||||
color = Color.Red.copy(alpha = 0.08f),
|
.padding(horizontal = 24.dp, vertical = 24.dp)
|
||||||
|
.fillMaxWidth(),
|
||||||
|
color = errorColor.copy(alpha = 0.1f),
|
||||||
shape = RoundedCornerShape(12.dp)
|
shape = RoundedCornerShape(12.dp)
|
||||||
) {
|
) {
|
||||||
Row(
|
Row(
|
||||||
@@ -401,66 +484,56 @@ fun AboutSheet(
|
|||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Filled.Warning,
|
imageVector = Icons.Filled.Warning,
|
||||||
contentDescription = "Warning",
|
contentDescription = "Warning",
|
||||||
tint = Color(0xFFBF1A1A),
|
tint = errorColor,
|
||||||
modifier = Modifier.size(16.dp)
|
modifier = Modifier.size(16.dp)
|
||||||
)
|
)
|
||||||
|
|
||||||
Column(verticalArrangement = Arrangement.spacedBy(4.dp)) {
|
Column(verticalArrangement = Arrangement.spacedBy(4.dp)) {
|
||||||
Text(
|
Text(
|
||||||
text = "emergency data deletion",
|
text = "Emergency Data Deletion",
|
||||||
fontSize = 12.sp,
|
fontSize = 12.sp,
|
||||||
fontFamily = FontFamily.Monospace,
|
fontFamily = FontFamily.Monospace,
|
||||||
fontWeight = FontWeight.Medium,
|
fontWeight = FontWeight.Bold,
|
||||||
color = Color(0xFFBF1A1A)
|
color = errorColor
|
||||||
)
|
)
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
text = "tip: triple-click the app title to emergency delete all stored data including messages, keys, and settings.",
|
text = "Tip: Triple-click the app title to emergency delete all stored data including messages, keys, and settings.",
|
||||||
fontSize = 11.sp,
|
fontSize = 11.sp,
|
||||||
fontFamily = FontFamily.Monospace,
|
fontFamily = FontFamily.Monospace,
|
||||||
color = colorScheme.onSurface.copy(alpha = 0.7f)
|
color = colorScheme.onSurface.copy(alpha = 0.8f)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Debug settings button
|
// Footer Section
|
||||||
item {
|
item(key = "footer") {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier
|
||||||
|
.padding(horizontal = 24.dp)
|
||||||
|
.fillMaxWidth(),
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
verticalArrangement = Arrangement.spacedBy(8.dp)
|
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||||
) {
|
) {
|
||||||
// Debug button styled to match the app aesthetic
|
if (onShowDebug != null) {
|
||||||
TextButton(
|
TextButton(
|
||||||
onClick = { onShowDebug?.invoke() },
|
onClick = onShowDebug,
|
||||||
colors = ButtonDefaults.textButtonColors(
|
colors = ButtonDefaults.textButtonColors(
|
||||||
contentColor = colorScheme.onSurface.copy(alpha = 0.6f)
|
contentColor = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.6f)
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = "debug settings",
|
text = "Debug Settings",
|
||||||
|
fontSize = 11.sp,
|
||||||
|
fontFamily = FontFamily.Monospace
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Text(
|
||||||
|
text = "Open Source • Privacy First • Decentralized",
|
||||||
fontSize = 11.sp,
|
fontSize = 11.sp,
|
||||||
fontFamily = FontFamily.Monospace,
|
fontFamily = FontFamily.Monospace,
|
||||||
color = colorScheme.onSurface.copy(alpha = 0.6f)
|
color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.7f),
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Version and footer space
|
|
||||||
item {
|
|
||||||
Column(
|
|
||||||
modifier = Modifier.fillMaxWidth(),
|
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
|
||||||
verticalArrangement = Arrangement.spacedBy(8.dp)
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
text = "open source • privacy first • decentralized",
|
|
||||||
fontSize = 10.sp,
|
|
||||||
fontFamily = FontFamily.Monospace,
|
|
||||||
color = colorScheme.onSurface.copy(alpha = 0.5f)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Add extra space at bottom for gesture area
|
// Add extra space at bottom for gesture area
|
||||||
@@ -468,79 +541,30 @@ fun AboutSheet(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
// TopBar
|
||||||
private fun FeatureCard(
|
Box(
|
||||||
icon: ImageVector,
|
modifier = Modifier
|
||||||
iconColor: Color,
|
.align(Alignment.TopCenter)
|
||||||
title: String,
|
.fillMaxWidth()
|
||||||
description: String,
|
.height(64.dp)
|
||||||
modifier: Modifier = Modifier
|
.background(MaterialTheme.colorScheme.background.copy(alpha = topBarAlpha))
|
||||||
) {
|
|
||||||
Surface(
|
|
||||||
modifier = modifier,
|
|
||||||
color = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.2f),
|
|
||||||
shape = RoundedCornerShape(12.dp)
|
|
||||||
) {
|
) {
|
||||||
Row(
|
TextButton(
|
||||||
modifier = Modifier.padding(16.dp),
|
onClick = onDismiss,
|
||||||
horizontalArrangement = Arrangement.spacedBy(12.dp),
|
modifier = Modifier
|
||||||
verticalAlignment = Alignment.Top
|
.align(Alignment.CenterEnd)
|
||||||
) {
|
.padding(horizontal = 16.dp)
|
||||||
Icon(
|
|
||||||
imageVector = icon,
|
|
||||||
contentDescription = title,
|
|
||||||
tint = iconColor,
|
|
||||||
modifier = Modifier.size(20.dp)
|
|
||||||
)
|
|
||||||
|
|
||||||
Column(
|
|
||||||
modifier = Modifier.weight(1f),
|
|
||||||
verticalArrangement = Arrangement.spacedBy(4.dp)
|
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = title,
|
text = "Close",
|
||||||
fontSize = 13.sp,
|
style = MaterialTheme.typography.labelMedium.copy(fontWeight = FontWeight.Bold),
|
||||||
fontFamily = FontFamily.Monospace,
|
color = MaterialTheme.colorScheme.onBackground
|
||||||
fontWeight = FontWeight.Medium,
|
|
||||||
color = MaterialTheme.colorScheme.onSurface
|
|
||||||
)
|
|
||||||
|
|
||||||
Text(
|
|
||||||
text = description,
|
|
||||||
fontSize = 11.sp,
|
|
||||||
fontFamily = FontFamily.Monospace,
|
|
||||||
color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.7f),
|
|
||||||
lineHeight = 15.sp
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
|
||||||
private fun FeatureItem(text: String) {
|
|
||||||
Row(
|
|
||||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
|
||||||
verticalAlignment = Alignment.Top
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
text = "•",
|
|
||||||
fontSize = 11.sp,
|
|
||||||
fontFamily = FontFamily.Monospace,
|
|
||||||
color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.6f)
|
|
||||||
)
|
|
||||||
|
|
||||||
Text(
|
|
||||||
text = text,
|
|
||||||
fontSize = 11.sp,
|
|
||||||
fontFamily = FontFamily.Monospace,
|
|
||||||
color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.7f),
|
|
||||||
modifier = Modifier.weight(1f)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user