diff --git a/android/CHANGELOG.md b/android/CHANGELOG.md index 6c42c32..b5a4932 100644 --- a/android/CHANGELOG.md +++ b/android/CHANGELOG.md @@ -756,3 +756,12 @@ - notifications (`global` + `preview`) wired to `NotificationSettingsRepository`, - privacy update, blocked users management, sessions revoke/revoke-all, 2FA controls. - Updated `ProfileScreen` to follow current app theme colors instead of forced dark palette. + +### Step 112 - Settings cleanup (privacy dropdowns + removed extra blocks) +- Replaced free-text privacy inputs with dropdown selectors (`everyone`, `contacts`, `nobody`) for: + - private messages, + - last seen, + - avatar visibility, + - group invites. +- Removed direct `block by user id` controls from Settings UI as requested. +- Removed extra bottom Settings actions (`Profile` row and `Back to chats` button) and kept categorized section layout. diff --git a/android/app/src/main/java/ru/daemonlord/messenger/ui/settings/SettingsScreen.kt b/android/app/src/main/java/ru/daemonlord/messenger/ui/settings/SettingsScreen.kt index 81a156f..cfcd4c4 100644 --- a/android/app/src/main/java/ru/daemonlord/messenger/ui/settings/SettingsScreen.kt +++ b/android/app/src/main/java/ru/daemonlord/messenger/ui/settings/SettingsScreen.kt @@ -31,6 +31,10 @@ import androidx.compose.material.icons.filled.Visibility import androidx.compose.material3.AlertDialog import androidx.compose.material3.Button import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.DropdownMenuItem +import androidx.compose.material3.ExposedDropdownMenuBox +import androidx.compose.material3.ExposedDropdownMenuDefaults +import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme @@ -102,8 +106,6 @@ fun SettingsScreen( var privacyLastSeen by remember(profile?.privacyLastSeen) { mutableStateOf(profile?.privacyLastSeen ?: "everyone") } var privacyAvatar by remember(profile?.privacyAvatar) { mutableStateOf(profile?.privacyAvatar ?: "everyone") } var privacyGroupInvites by remember(profile?.privacyGroupInvites) { mutableStateOf(profile?.privacyGroupInvites ?: "everyone") } - - var blockUserIdInput by remember { mutableStateOf("") } var twoFactorCode by remember { mutableStateOf("") } var recoveryRegenerateCode by remember { mutableStateOf("") } @@ -369,33 +371,25 @@ fun SettingsScreen( SettingsSectionCard { Text("Privacy", style = MaterialTheme.typography.titleSmall) - OutlinedTextField( + PrivacyDropdownField( + label = "Private messages", value = privacyPm, onValueChange = { privacyPm = it }, - label = { Text("Private messages") }, - modifier = Modifier.fillMaxWidth(), - singleLine = true, ) - OutlinedTextField( + PrivacyDropdownField( + label = "Last seen", value = privacyLastSeen, onValueChange = { privacyLastSeen = it }, - label = { Text("Last seen") }, - modifier = Modifier.fillMaxWidth(), - singleLine = true, ) - OutlinedTextField( + PrivacyDropdownField( + label = "Avatar", value = privacyAvatar, onValueChange = { privacyAvatar = it }, - label = { Text("Avatar") }, - modifier = Modifier.fillMaxWidth(), - singleLine = true, ) - OutlinedTextField( + PrivacyDropdownField( + label = "Group invites", value = privacyGroupInvites, onValueChange = { privacyGroupInvites = it }, - label = { Text("Group invites") }, - modifier = Modifier.fillMaxWidth(), - singleLine = true, ) Button( onClick = { @@ -412,24 +406,10 @@ fun SettingsScreen( Icon(Icons.Filled.Lock, contentDescription = null) Text("Save privacy", modifier = Modifier.padding(start = 6.dp)) } + } - OutlinedTextField( - value = blockUserIdInput, - onValueChange = { blockUserIdInput = it.filter(Char::isDigit) }, - label = { Text("User ID to block") }, - modifier = Modifier.fillMaxWidth(), - singleLine = true, - ) - OutlinedButton( - onClick = { - blockUserIdInput.toLongOrNull()?.let(viewModel::blockUser) - blockUserIdInput = "" - }, - enabled = blockUserIdInput.isNotBlank() && !state.isSaving, - modifier = Modifier.fillMaxWidth(), - ) { - Text("Block user") - } + SettingsSectionCard { + Text("Blocked users", style = MaterialTheme.typography.titleSmall) state.blockedUsers.forEach { blocked -> Row( modifier = Modifier.fillMaxWidth(), @@ -524,10 +504,6 @@ fun SettingsScreen( } } - SettingsSectionCard { - SettingsActionRow(Icons.Filled.Email, "Profile", "Open profile") { onOpenProfile() } - } - if (!state.message.isNullOrBlank()) { Text(state.message.orEmpty(), color = MaterialTheme.colorScheme.primary) } @@ -535,9 +511,6 @@ fun SettingsScreen( Text(state.errorMessage.orEmpty(), color = MaterialTheme.colorScheme.error) } - OutlinedButton(onClick = onBackToChats, modifier = Modifier.fillMaxWidth()) { - Text("Back to chats") - } Button(onClick = onLogout, modifier = Modifier.fillMaxWidth()) { Text("Logout") } @@ -623,3 +596,44 @@ private fun ThemeButton( OutlinedButton(onClick = onClick) { Text(text) } } } + +@Composable +@OptIn(ExperimentalMaterial3Api::class) +private fun PrivacyDropdownField( + label: String, + value: String, + onValueChange: (String) -> Unit, +) { + val options = listOf("everyone", "contacts", "nobody") + var expanded by remember { mutableStateOf(false) } + ExposedDropdownMenuBox( + expanded = expanded, + onExpandedChange = { expanded = !expanded }, + ) { + OutlinedTextField( + value = value, + onValueChange = {}, + readOnly = true, + label = { Text(label) }, + trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded) }, + modifier = Modifier + .menuAnchor() + .fillMaxWidth(), + singleLine = true, + ) + ExposedDropdownMenu( + expanded = expanded, + onDismissRequest = { expanded = false }, + ) { + options.forEach { option -> + DropdownMenuItem( + text = { Text(option) }, + onClick = { + onValueChange(option) + expanded = false + }, + ) + } + } + } +}