2025-07-10 13:15:28 +02:00

247 lines
8.5 KiB
Kotlin

package com.bitchat.android.onboarding
import androidx.compose.animation.core.*
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.rotate
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
/**
* Loading screen shown during app initialization after permissions are granted
*/
@Composable
fun InitializingScreen() {
val colorScheme = MaterialTheme.colorScheme
// Animated rotation for the loading indicator
val infiniteTransition = rememberInfiniteTransition(label = "loading")
val rotationAngle by infiniteTransition.animateFloat(
initialValue = 0f,
targetValue = 360f,
animationSpec = infiniteRepeatable(
animation = tween(durationMillis = 2000, easing = LinearEasing),
repeatMode = RepeatMode.Restart
),
label = "rotation"
)
// Animated dots for loading text
val dotCount = 3
val animationDelay = 300
val dots = (0 until dotCount).map { index ->
val alpha by infiniteTransition.animateFloat(
initialValue = 0.3f,
targetValue = 1f,
animationSpec = infiniteRepeatable(
animation = tween(durationMillis = animationDelay * dotCount),
repeatMode = RepeatMode.Reverse,
initialStartOffset = StartOffset(animationDelay * index)
),
label = "dot_$index"
)
alpha
}
Box(
modifier = Modifier
.fillMaxSize()
.padding(32.dp),
contentAlignment = Alignment.Center
) {
Column(
verticalArrangement = Arrangement.spacedBy(32.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
// App title
Text(
text = "bitchat*",
style = MaterialTheme.typography.headlineLarge.copy(
fontFamily = FontFamily.Monospace,
fontWeight = FontWeight.Bold,
color = colorScheme.primary
),
textAlign = TextAlign.Center
)
// Loading indicator
Box(
modifier = Modifier.size(60.dp),
contentAlignment = Alignment.Center
) {
CircularProgressIndicator(
modifier = Modifier
.fillMaxSize()
.rotate(rotationAngle),
color = colorScheme.primary,
strokeWidth = 3.dp
)
}
// Loading text with animated dots
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.Center
) {
Text(
text = "Initializing mesh network",
style = MaterialTheme.typography.bodyLarge.copy(
fontFamily = FontFamily.Monospace,
color = colorScheme.onSurface.copy(alpha = 0.7f)
)
)
// Animated dots
dots.forEach { alpha ->
Text(
text = ".",
style = MaterialTheme.typography.bodyLarge.copy(
fontFamily = FontFamily.Monospace,
color = colorScheme.onSurface.copy(alpha = alpha)
)
)
}
}
Spacer(modifier = Modifier.height(16.dp))
// Status message
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),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
text = "Setting up Bluetooth mesh networking...",
style = MaterialTheme.typography.bodyMedium.copy(
fontFamily = FontFamily.Monospace,
color = colorScheme.onSurface.copy(alpha = 0.8f)
),
textAlign = TextAlign.Center
)
Text(
text = "This should only take a few seconds",
style = MaterialTheme.typography.bodySmall.copy(
fontFamily = FontFamily.Monospace,
color = colorScheme.onSurface.copy(alpha = 0.6f)
),
textAlign = TextAlign.Center
)
}
}
}
}
}
/**
* Error screen shown if initialization fails
*/
@Composable
fun InitializationErrorScreen(
errorMessage: String,
onRetry: () -> Unit,
onOpenSettings: () -> Unit
) {
val colorScheme = MaterialTheme.colorScheme
Box(
modifier = Modifier
.fillMaxSize()
.padding(32.dp),
contentAlignment = Alignment.Center
) {
Column(
verticalArrangement = Arrangement.spacedBy(24.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
// Error indicator
Card(
colors = CardDefaults.cardColors(
containerColor = Color(0xFFFFEBEE)
),
elevation = CardDefaults.cardElevation(defaultElevation = 4.dp)
) {
Text(
text = "⚠️",
style = MaterialTheme.typography.headlineLarge,
modifier = Modifier.padding(16.dp)
)
}
Text(
text = "Setup Not Complete",
style = MaterialTheme.typography.headlineSmall.copy(
fontFamily = FontFamily.Monospace,
fontWeight = FontWeight.Bold,
color = colorScheme.error
),
textAlign = TextAlign.Center
)
Card(
modifier = Modifier.fillMaxWidth(),
colors = CardDefaults.cardColors(
containerColor = colorScheme.errorContainer.copy(alpha = 0.1f)
),
elevation = CardDefaults.cardElevation(defaultElevation = 2.dp)
) {
Text(
text = errorMessage,
style = MaterialTheme.typography.bodyMedium.copy(
fontFamily = FontFamily.Monospace,
color = colorScheme.onSurface
),
modifier = Modifier.padding(16.dp),
textAlign = TextAlign.Center
)
}
Column(
verticalArrangement = Arrangement.spacedBy(12.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Button(
onClick = onRetry,
modifier = Modifier.fillMaxWidth()
) {
Text(
text = "Try Again",
style = MaterialTheme.typography.bodyMedium.copy(
fontFamily = FontFamily.Monospace,
fontWeight = FontWeight.Bold
),
modifier = Modifier.padding(vertical = 4.dp)
)
}
OutlinedButton(
onClick = onOpenSettings,
modifier = Modifier.fillMaxWidth()
) {
Text(
text = "Open Settings",
style = MaterialTheme.typography.bodyMedium.copy(
fontFamily = FontFamily.Monospace
),
modifier = Modifier.padding(vertical = 4.dp)
)
}
}
}
}
}