243 lines
9.4 KiB
Kotlin
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
|
|
)
|
|
}
|
|
}
|