android: switch privacy settings to dropdowns and simplify settings sections
Some checks failed
Android CI / android (push) Failing after 5m16s
Android Release / release (push) Has started running
CI / test (push) Has started running

This commit is contained in:
Codex
2026-03-10 00:02:40 +03:00
parent 0bd7e1cd21
commit 09a77bd4d7
2 changed files with 65 additions and 42 deletions

View File

@@ -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.

View File

@@ -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
},
)
}
}
}
}