permissions layout

This commit is contained in:
callebtc
2025-07-12 17:40:25 +02:00
parent d025d61af8
commit ad6dc3680b
4 changed files with 112 additions and 117 deletions
+5
View File
@@ -5,6 +5,11 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
### Fixed
- Permission onboarding screen UX: removed "Exit App" button and fixed "Grant Permissions" button positioning to always be visible
## [0.6] ## [0.6]
### Added ### Added
@@ -124,9 +124,6 @@ class MainActivity : ComponentActivity() {
onContinue = { onContinue = {
onboardingState = OnboardingState.PERMISSION_REQUESTING onboardingState = OnboardingState.PERMISSION_REQUESTING
onboardingCoordinator.requestPermissions() onboardingCoordinator.requestPermissions()
},
onCancel = {
finish()
} }
) )
} }
@@ -21,120 +21,130 @@ import androidx.compose.ui.unit.sp
@Composable @Composable
fun PermissionExplanationScreen( fun PermissionExplanationScreen(
permissionCategories: List<PermissionCategory>, permissionCategories: List<PermissionCategory>,
onContinue: () -> Unit, onContinue: () -> Unit
onCancel: () -> Unit
) { ) {
val colorScheme = MaterialTheme.colorScheme val colorScheme = MaterialTheme.colorScheme
val scrollState = rememberScrollState() val scrollState = rememberScrollState()
Column( Box(
modifier = Modifier modifier = Modifier.fillMaxSize()
.fillMaxSize()
.padding(horizontal = 24.dp)
.verticalScroll(scrollState),
verticalArrangement = Arrangement.spacedBy(16.dp)
) { ) {
Spacer(modifier = Modifier.height(24.dp)) // Scrollable content
// Header
Column( Column(
modifier = Modifier.fillMaxWidth(), modifier = Modifier
horizontalAlignment = Alignment.CenterHorizontally .fillMaxSize()
) { .padding(horizontal = 24.dp)
Text( .padding(bottom = 88.dp) // Leave space for the fixed button
text = "Welcome to bitchat*", .verticalScroll(scrollState),
style = MaterialTheme.typography.headlineMedium.copy( verticalArrangement = Arrangement.spacedBy(16.dp)
fontFamily = FontFamily.Monospace,
fontWeight = FontWeight.Bold,
color = colorScheme.primary
),
textAlign = TextAlign.Center
)
Spacer(modifier = Modifier.height(8.dp))
Text(
text = "Decentralized mesh messaging over Bluetooth",
style = MaterialTheme.typography.bodyMedium.copy(
fontFamily = FontFamily.Monospace,
color = colorScheme.onSurface.copy(alpha = 0.7f)
),
textAlign = TextAlign.Center
)
}
Spacer(modifier = Modifier.height(16.dp))
// Privacy assurance section
Card(
modifier = Modifier.fillMaxWidth(),
colors = CardDefaults.cardColors(
containerColor = colorScheme.surfaceVariant.copy(alpha = 0.3f)
),
elevation = CardDefaults.cardElevation(defaultElevation = 2.dp)
) { ) {
Spacer(modifier = Modifier.height(24.dp))
// Header
Column( Column(
modifier = Modifier.padding(16.dp), modifier = Modifier.fillMaxWidth(),
verticalArrangement = Arrangement.spacedBy(8.dp) horizontalAlignment = Alignment.CenterHorizontally
) { ) {
Row( Text(
verticalAlignment = Alignment.CenterVertically, text = "Welcome to bitchat*",
horizontalArrangement = Arrangement.spacedBy(8.dp) style = MaterialTheme.typography.headlineMedium.copy(
fontFamily = FontFamily.Monospace,
fontWeight = FontWeight.Bold,
color = colorScheme.primary
),
textAlign = TextAlign.Center
)
Spacer(modifier = Modifier.height(8.dp))
Text(
text = "Decentralized mesh messaging over Bluetooth",
style = MaterialTheme.typography.bodyMedium.copy(
fontFamily = FontFamily.Monospace,
color = colorScheme.onSurface.copy(alpha = 0.7f)
),
textAlign = TextAlign.Center
)
}
Spacer(modifier = Modifier.height(16.dp))
// Privacy assurance section
Card(
modifier = Modifier.fillMaxWidth(),
colors = CardDefaults.cardColors(
containerColor = colorScheme.surfaceVariant.copy(alpha = 0.3f)
),
elevation = CardDefaults.cardElevation(defaultElevation = 2.dp)
) {
Column(
modifier = Modifier.padding(16.dp),
verticalArrangement = Arrangement.spacedBy(8.dp)
) { ) {
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
Text(
text = "🔒",
style = MaterialTheme.typography.titleMedium,
modifier = Modifier.size(20.dp)
)
Text(
text = "Your Privacy is Protected",
style = MaterialTheme.typography.titleSmall.copy(
fontWeight = FontWeight.Bold,
color = colorScheme.onSurface
)
)
}
Text( Text(
text = "🔒", text = "• bitchat doesn't track you or collect personal data\n" +
style = MaterialTheme.typography.titleMedium, "• No servers, no internet required, no data logging\n" +
modifier = Modifier.size(20.dp) "• Location permission is only used by Android for Bluetooth scanning\n" +
) "• Your messages stay on your device and peer devices only",
Text( style = MaterialTheme.typography.bodySmall.copy(
text = "Your Privacy is Protected", fontFamily = FontFamily.Monospace,
style = MaterialTheme.typography.titleSmall.copy( color = colorScheme.onSurface.copy(alpha = 0.8f)
fontWeight = FontWeight.Bold,
color = colorScheme.onSurface
) )
) )
} }
}
Text(
text = "• bitchat doesn't track you or collect personal data\n" + Spacer(modifier = Modifier.height(8.dp))
"• No servers, no internet required, no data logging\n" +
"• Location permission is only used by Android for Bluetooth scanning\n" + Text(
"• Your messages stay on your device and peer devices only", text = "To work properly, bitchat needs these permissions:",
style = MaterialTheme.typography.bodySmall.copy( style = MaterialTheme.typography.bodyMedium.copy(
fontFamily = FontFamily.Monospace, fontWeight = FontWeight.Medium,
color = colorScheme.onSurface.copy(alpha = 0.8f) color = colorScheme.onSurface
) )
)
// Permission categories
permissionCategories.forEach { category ->
PermissionCategoryCard(
category = category,
colorScheme = colorScheme
) )
} }
Spacer(modifier = Modifier.height(24.dp))
} }
Spacer(modifier = Modifier.height(8.dp)) // Fixed button at bottom
Surface(
Text( modifier = Modifier
text = "To work properly, bitchat needs these permissions:", .align(Alignment.BottomCenter)
style = MaterialTheme.typography.bodyMedium.copy( .fillMaxWidth(),
fontWeight = FontWeight.Medium, color = colorScheme.surface,
color = colorScheme.onSurface shadowElevation = 8.dp
)
)
// Permission categories
permissionCategories.forEach { category ->
PermissionCategoryCard(
category = category,
colorScheme = colorScheme
)
}
Spacer(modifier = Modifier.height(16.dp))
// Action buttons
Column(
modifier = Modifier.fillMaxWidth(),
verticalArrangement = Arrangement.spacedBy(12.dp)
) { ) {
Button( Button(
onClick = onContinue, onClick = onContinue,
modifier = Modifier.fillMaxWidth(), modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 24.dp, vertical = 16.dp),
colors = ButtonDefaults.buttonColors( colors = ButtonDefaults.buttonColors(
containerColor = colorScheme.primary containerColor = colorScheme.primary
) )
@@ -148,24 +158,7 @@ fun PermissionExplanationScreen(
modifier = Modifier.padding(vertical = 4.dp) modifier = Modifier.padding(vertical = 4.dp)
) )
} }
OutlinedButton(
onClick = onCancel,
modifier = Modifier.fillMaxWidth(),
colors = ButtonDefaults.outlinedButtonColors(
contentColor = colorScheme.onSurface.copy(alpha = 0.7f)
)
) {
Text(
text = "Exit App",
style = MaterialTheme.typography.bodyMedium.copy(
fontFamily = FontFamily.Monospace
),
modifier = Modifier.padding(vertical = 4.dp)
)
}
} }
Spacer(modifier = Modifier.height(24.dp))
} }
} }
@@ -116,7 +116,7 @@ class PermissionManager(private val context: Context) {
categories.add( categories.add(
PermissionCategory( PermissionCategory(
name = "Nearby Devices", name = "Nearby Devices",
description = "Required to discover and connect to other bitchat users via Bluetooth", description = "Required to discover bitchat users via Bluetooth",
permissions = bluetoothPermissions, permissions = bluetoothPermissions,
isGranted = bluetoothPermissions.all { isPermissionGranted(it) }, isGranted = bluetoothPermissions.all { isPermissionGranted(it) },
systemDescription = "Allow bitchat to connect to nearby devices" systemDescription = "Allow bitchat to connect to nearby devices"
@@ -132,10 +132,10 @@ class PermissionManager(private val context: Context) {
categories.add( categories.add(
PermissionCategory( PermissionCategory(
name = "Precise Location", name = "Precise Location",
description = "Required by Android for Bluetooth scanning.", description = "Required by Android to discover nearby bitchat users via Bluetooth",
permissions = locationPermissions, permissions = locationPermissions,
isGranted = locationPermissions.all { isPermissionGranted(it) }, isGranted = locationPermissions.all { isPermissionGranted(it) },
systemDescription = "Allow bitchat to access this device's location" systemDescription = "bitchat needs this to scan for nearby devices"
) )
) )
@@ -144,7 +144,7 @@ class PermissionManager(private val context: Context) {
categories.add( categories.add(
PermissionCategory( PermissionCategory(
name = "Notifications", name = "Notifications",
description = "Show notifications when you receive private messages while the app is in background", description = "Notifications to keep you updated",
permissions = listOf(Manifest.permission.POST_NOTIFICATIONS), permissions = listOf(Manifest.permission.POST_NOTIFICATIONS),
isGranted = isPermissionGranted(Manifest.permission.POST_NOTIFICATIONS), isGranted = isPermissionGranted(Manifest.permission.POST_NOTIFICATIONS),
systemDescription = "Allow bitchat to send you notifications" systemDescription = "Allow bitchat to send you notifications"