android: switch privacy settings to dropdowns and simplify settings sections
This commit is contained in:
@@ -756,3 +756,12 @@
|
|||||||
- notifications (`global` + `preview`) wired to `NotificationSettingsRepository`,
|
- notifications (`global` + `preview`) wired to `NotificationSettingsRepository`,
|
||||||
- privacy update, blocked users management, sessions revoke/revoke-all, 2FA controls.
|
- privacy update, blocked users management, sessions revoke/revoke-all, 2FA controls.
|
||||||
- Updated `ProfileScreen` to follow current app theme colors instead of forced dark palette.
|
- 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.
|
||||||
|
|||||||
@@ -31,6 +31,10 @@ import androidx.compose.material.icons.filled.Visibility
|
|||||||
import androidx.compose.material3.AlertDialog
|
import androidx.compose.material3.AlertDialog
|
||||||
import androidx.compose.material3.Button
|
import androidx.compose.material3.Button
|
||||||
import androidx.compose.material3.CircularProgressIndicator
|
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.Icon
|
||||||
import androidx.compose.material3.IconButton
|
import androidx.compose.material3.IconButton
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
@@ -102,8 +106,6 @@ fun SettingsScreen(
|
|||||||
var privacyLastSeen by remember(profile?.privacyLastSeen) { mutableStateOf(profile?.privacyLastSeen ?: "everyone") }
|
var privacyLastSeen by remember(profile?.privacyLastSeen) { mutableStateOf(profile?.privacyLastSeen ?: "everyone") }
|
||||||
var privacyAvatar by remember(profile?.privacyAvatar) { mutableStateOf(profile?.privacyAvatar ?: "everyone") }
|
var privacyAvatar by remember(profile?.privacyAvatar) { mutableStateOf(profile?.privacyAvatar ?: "everyone") }
|
||||||
var privacyGroupInvites by remember(profile?.privacyGroupInvites) { mutableStateOf(profile?.privacyGroupInvites ?: "everyone") }
|
var privacyGroupInvites by remember(profile?.privacyGroupInvites) { mutableStateOf(profile?.privacyGroupInvites ?: "everyone") }
|
||||||
|
|
||||||
var blockUserIdInput by remember { mutableStateOf("") }
|
|
||||||
var twoFactorCode by remember { mutableStateOf("") }
|
var twoFactorCode by remember { mutableStateOf("") }
|
||||||
var recoveryRegenerateCode by remember { mutableStateOf("") }
|
var recoveryRegenerateCode by remember { mutableStateOf("") }
|
||||||
|
|
||||||
@@ -369,33 +371,25 @@ fun SettingsScreen(
|
|||||||
|
|
||||||
SettingsSectionCard {
|
SettingsSectionCard {
|
||||||
Text("Privacy", style = MaterialTheme.typography.titleSmall)
|
Text("Privacy", style = MaterialTheme.typography.titleSmall)
|
||||||
OutlinedTextField(
|
PrivacyDropdownField(
|
||||||
|
label = "Private messages",
|
||||||
value = privacyPm,
|
value = privacyPm,
|
||||||
onValueChange = { privacyPm = it },
|
onValueChange = { privacyPm = it },
|
||||||
label = { Text("Private messages") },
|
|
||||||
modifier = Modifier.fillMaxWidth(),
|
|
||||||
singleLine = true,
|
|
||||||
)
|
)
|
||||||
OutlinedTextField(
|
PrivacyDropdownField(
|
||||||
|
label = "Last seen",
|
||||||
value = privacyLastSeen,
|
value = privacyLastSeen,
|
||||||
onValueChange = { privacyLastSeen = it },
|
onValueChange = { privacyLastSeen = it },
|
||||||
label = { Text("Last seen") },
|
|
||||||
modifier = Modifier.fillMaxWidth(),
|
|
||||||
singleLine = true,
|
|
||||||
)
|
)
|
||||||
OutlinedTextField(
|
PrivacyDropdownField(
|
||||||
|
label = "Avatar",
|
||||||
value = privacyAvatar,
|
value = privacyAvatar,
|
||||||
onValueChange = { privacyAvatar = it },
|
onValueChange = { privacyAvatar = it },
|
||||||
label = { Text("Avatar") },
|
|
||||||
modifier = Modifier.fillMaxWidth(),
|
|
||||||
singleLine = true,
|
|
||||||
)
|
)
|
||||||
OutlinedTextField(
|
PrivacyDropdownField(
|
||||||
|
label = "Group invites",
|
||||||
value = privacyGroupInvites,
|
value = privacyGroupInvites,
|
||||||
onValueChange = { privacyGroupInvites = it },
|
onValueChange = { privacyGroupInvites = it },
|
||||||
label = { Text("Group invites") },
|
|
||||||
modifier = Modifier.fillMaxWidth(),
|
|
||||||
singleLine = true,
|
|
||||||
)
|
)
|
||||||
Button(
|
Button(
|
||||||
onClick = {
|
onClick = {
|
||||||
@@ -412,24 +406,10 @@ fun SettingsScreen(
|
|||||||
Icon(Icons.Filled.Lock, contentDescription = null)
|
Icon(Icons.Filled.Lock, contentDescription = null)
|
||||||
Text("Save privacy", modifier = Modifier.padding(start = 6.dp))
|
Text("Save privacy", modifier = Modifier.padding(start = 6.dp))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
OutlinedTextField(
|
SettingsSectionCard {
|
||||||
value = blockUserIdInput,
|
Text("Blocked users", style = MaterialTheme.typography.titleSmall)
|
||||||
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")
|
|
||||||
}
|
|
||||||
state.blockedUsers.forEach { blocked ->
|
state.blockedUsers.forEach { blocked ->
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
@@ -524,10 +504,6 @@ fun SettingsScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SettingsSectionCard {
|
|
||||||
SettingsActionRow(Icons.Filled.Email, "Profile", "Open profile") { onOpenProfile() }
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!state.message.isNullOrBlank()) {
|
if (!state.message.isNullOrBlank()) {
|
||||||
Text(state.message.orEmpty(), color = MaterialTheme.colorScheme.primary)
|
Text(state.message.orEmpty(), color = MaterialTheme.colorScheme.primary)
|
||||||
}
|
}
|
||||||
@@ -535,9 +511,6 @@ fun SettingsScreen(
|
|||||||
Text(state.errorMessage.orEmpty(), color = MaterialTheme.colorScheme.error)
|
Text(state.errorMessage.orEmpty(), color = MaterialTheme.colorScheme.error)
|
||||||
}
|
}
|
||||||
|
|
||||||
OutlinedButton(onClick = onBackToChats, modifier = Modifier.fillMaxWidth()) {
|
|
||||||
Text("Back to chats")
|
|
||||||
}
|
|
||||||
Button(onClick = onLogout, modifier = Modifier.fillMaxWidth()) {
|
Button(onClick = onLogout, modifier = Modifier.fillMaxWidth()) {
|
||||||
Text("Logout")
|
Text("Logout")
|
||||||
}
|
}
|
||||||
@@ -623,3 +596,44 @@ private fun ThemeButton(
|
|||||||
OutlinedButton(onClick = onClick) { Text(text) }
|
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
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user