Files
forkmessager/client-mobile/core/presentation/settings/SettingsScreen.kt
2026-04-17 16:23:52 +03:00

243 lines
9.4 KiB
Kotlin

package core.presentation.settings
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
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.graphics.vector.ImageVector
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.hilt.navigation.compose.hiltViewModel
import ru.knot.messager.R
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun SettingsScreen(
onBack: () -> Unit,
onLogout: () -> Unit = {},
viewModel: SettingsViewModel = hiltViewModel()
) {
val state by viewModel.state.collectAsState()
var baseUrl by remember(state.baseUrl) { mutableStateOf(state.baseUrl) }
// Убран автоматический вызов loadConfig() - теперь только по кнопке Refresh
Scaffold(
containerColor = Color(0xFF0F0F10),
topBar = {
TopAppBar(
title = { Text(stringResource(R.string.settings), fontWeight = FontWeight.Bold) },
navigationIcon = {
IconButton(onClick = onBack) {
Icon(Icons.Default.ArrowBack, contentDescription = stringResource(R.string.back), tint = Color.White)
}
},
actions = {
IconButton(onClick = { viewModel.loadConfig() }) {
Icon(Icons.Default.Sync, contentDescription = "Refresh", tint = Color.White)
}
},
colors = TopAppBarDefaults.topAppBarColors(
containerColor = Color(0xFF0F0F10),
titleContentColor = Color.White
)
)
}
) { paddingValues ->
Column(
modifier = Modifier
.fillMaxSize()
.padding(paddingValues)
.verticalScroll(rememberScrollState())
.padding(16.dp)
) {
if (state.isLoading) {
LinearProgressIndicator(
modifier = Modifier.fillMaxWidth().padding(bottom = 16.dp),
color = Color(0xFF3390EC)
)
}
if (state.error != null) {
Text(
text = "Ошибка обновления: ${state.error}",
color = Color.Red,
style = MaterialTheme.typography.labelSmall,
modifier = Modifier.padding(bottom = 16.dp)
)
}
// Server Section
SettingsSection(title = stringResource(R.string.server_connection)) {
Column(modifier = Modifier.padding(12.dp)) {
Text(
text = stringResource(R.string.api_base_url),
style = MaterialTheme.typography.labelMedium,
color = Color(0xFF3390EC)
)
Row(verticalAlignment = Alignment.CenterVertically) {
TextField(
value = baseUrl,
onValueChange = { baseUrl = it },
modifier = Modifier.weight(1f),
colors = TextFieldDefaults.colors(
focusedContainerColor = Color.Transparent,
unfocusedContainerColor = Color.Transparent,
focusedTextColor = Color.White,
unfocusedTextColor = Color.White,
focusedIndicatorColor = Color(0xFF3390EC),
unfocusedIndicatorColor = Color.Gray.copy(alpha = 0.5f)
),
placeholder = {
Text("Например: http://192.168.1.100:5034/api/", color = Color.Gray.copy(alpha = 0.5f))
}
)
IconButton(onClick = { viewModel.saveBaseUrl(baseUrl) }) {
Icon(Icons.Default.Save, contentDescription = null, tint = Color(0xFF3390EC))
}
}
}
}
Spacer(modifier = Modifier.height(24.dp))
// Features Section
SettingsSection(title = stringResource(R.string.server_features)) {
Column {
SettingsToggleItem(
icon = Icons.Default.History,
label = stringResource(R.string.stories),
enabled = state.config.features.stories
)
SettingsToggleItem(
icon = Icons.Default.Poll,
label = stringResource(R.string.polls),
enabled = state.config.features.polls
)
SettingsToggleItem(
icon = Icons.Default.Call,
label = stringResource(R.string.calls),
enabled = state.config.features.calls
)
SettingsToggleItem(
icon = Icons.Default.Group,
label = stringResource(R.string.groups),
enabled = state.config.features.groups
)
}
}
Spacer(modifier = Modifier.height(24.dp))
// Limits Section
SettingsSection(title = stringResource(R.string.limits)) {
Column {
SettingsInfoItem(
icon = Icons.Default.Storage,
label = stringResource(R.string.max_file_size),
value = "${state.config.limits.maxFileSize / (1024 * 1024)} MB"
)
SettingsInfoItem(
icon = Icons.Default.People,
label = stringResource(R.string.max_group_members),
value = state.config.limits.maxGroupMembers.toString()
)
}
}
Spacer(modifier = Modifier.height(32.dp))
// Logout Button
Button(
onClick = onLogout,
modifier = Modifier.fillMaxWidth(),
colors = ButtonDefaults.buttonColors(containerColor = Color(0xFFE53935)),
shape = RoundedCornerShape(12.dp)
) {
Icon(Icons.Default.Logout, contentDescription = null)
Spacer(modifier = Modifier.width(8.dp))
Text(stringResource(R.string.log_out), fontWeight = FontWeight.Bold)
}
Spacer(modifier = Modifier.height(80.dp)) // Space for bottom bar
}
}
}
@Composable
fun SettingsSection(title: String, content: @Composable () -> Unit) {
Column {
Text(
text = title.uppercase(),
style = MaterialTheme.typography.labelSmall,
color = Color(0xFF3390EC),
fontWeight = FontWeight.Bold,
modifier = Modifier.padding(start = 8.dp, bottom = 8.dp)
)
Surface(
color = Color(0xFF1C1C1E),
shape = RoundedCornerShape(16.dp),
modifier = Modifier.fillMaxWidth()
) {
content()
}
}
}
@Composable
fun SettingsToggleItem(icon: ImageVector, label: String, enabled: Boolean) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween
) {
Row(verticalAlignment = Alignment.CenterVertically) {
Icon(icon, contentDescription = null, tint = Color.Gray, modifier = Modifier.size(24.dp))
Spacer(modifier = Modifier.width(16.dp))
Text(label, color = Color.White, fontSize = 16.sp)
}
Text(
text = if (enabled) stringResource(R.string.enabled) else stringResource(R.string.disabled),
color = if (enabled) Color(0xFF3390EC) else Color(0xFFE53935),
fontWeight = FontWeight.Bold,
fontSize = 14.sp
)
}
}
@Composable
fun SettingsInfoItem(icon: ImageVector, label: String, value: String) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween
) {
Row(verticalAlignment = Alignment.CenterVertically) {
Icon(icon, contentDescription = null, tint = Color.Gray, modifier = Modifier.size(24.dp))
Spacer(modifier = Modifier.width(16.dp))
Text(label, color = Color.White, fontSize = 16.sp)
}
Text(
text = value,
color = Color.White,
fontWeight = FontWeight.Medium,
fontSize = 14.sp
)
}
}