feat: add account card animation and disconnect dialogs in settings

This commit is contained in:
Paweł Orzech 2026-03-19 14:24:21 +01:00
parent a6429f16d3
commit 5183862533
No known key found for this signature in database

View file

@ -1,5 +1,7 @@
package com.swoosh.microblog.ui.settings package com.swoosh.microblog.ui.settings
import androidx.compose.animation.*
import androidx.compose.animation.core.*
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
@ -18,6 +20,8 @@ import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.swoosh.microblog.data.AccountManager import com.swoosh.microblog.data.AccountManager
import com.swoosh.microblog.data.api.ApiClient import com.swoosh.microblog.data.api.ApiClient
import com.swoosh.microblog.ui.animation.SwooshMotion
import com.swoosh.microblog.ui.components.AnimatedDialog
import com.swoosh.microblog.ui.feed.AccountAvatar import com.swoosh.microblog.ui.feed.AccountAvatar
import com.swoosh.microblog.ui.theme.ThemeMode import com.swoosh.microblog.ui.theme.ThemeMode
import com.swoosh.microblog.ui.theme.ThemeViewModel import com.swoosh.microblog.ui.theme.ThemeViewModel
@ -36,6 +40,9 @@ fun SettingsScreen(
val currentThemeMode = themeViewModel?.themeMode?.collectAsStateWithLifecycle() val currentThemeMode = themeViewModel?.themeMode?.collectAsStateWithLifecycle()
var showDisconnectDialog by remember { mutableStateOf(false) }
var showDisconnectAllDialog by remember { mutableStateOf(false) }
Scaffold( Scaffold(
topBar = { topBar = {
TopAppBar( TopAppBar(
@ -74,7 +81,13 @@ fun SettingsScreen(
Text("Current Account", style = MaterialTheme.typography.titleMedium) Text("Current Account", style = MaterialTheme.typography.titleMedium)
Spacer(modifier = Modifier.height(12.dp)) Spacer(modifier = Modifier.height(12.dp))
if (activeAccount != null) { var cardVisible by remember { mutableStateOf(false) }
LaunchedEffect(Unit) { cardVisible = true }
AnimatedVisibility(
visible = cardVisible && activeAccount != null,
enter = fadeIn(SwooshMotion.quick()) + scaleIn(initialScale = 0.95f, animationSpec = SwooshMotion.quick())
) {
Card( Card(
modifier = Modifier.fillMaxWidth() modifier = Modifier.fillMaxWidth()
) { ) {
@ -84,7 +97,7 @@ fun SettingsScreen(
.padding(16.dp), .padding(16.dp),
horizontalArrangement = Arrangement.spacedBy(12.dp) horizontalArrangement = Arrangement.spacedBy(12.dp)
) { ) {
AccountAvatar(account = activeAccount, size = 40) AccountAvatar(account = activeAccount!!, size = 40)
Column { Column {
Text( Text(
text = activeAccount.name, text = activeAccount.name,
@ -137,19 +150,7 @@ fun SettingsScreen(
// Disconnect current account // Disconnect current account
OutlinedButton( OutlinedButton(
onClick = { onClick = { showDisconnectDialog = true },
activeAccount?.let { account ->
accountManager.removeAccount(account.id)
ApiClient.reset()
val remaining = accountManager.getAccounts()
if (remaining.isEmpty()) {
onLogout()
} else {
// There are still accounts, go back to feed with the next one
onBack()
}
}
},
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
colors = ButtonDefaults.outlinedButtonColors( colors = ButtonDefaults.outlinedButtonColors(
contentColor = MaterialTheme.colorScheme.error contentColor = MaterialTheme.colorScheme.error
@ -163,11 +164,7 @@ fun SettingsScreen(
// Disconnect all // Disconnect all
if (accountManager.getAccounts().size > 1) { if (accountManager.getAccounts().size > 1) {
TextButton( TextButton(
onClick = { onClick = { showDisconnectAllDialog = true },
accountManager.clearAll()
ApiClient.reset()
onLogout()
},
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
colors = ButtonDefaults.textButtonColors( colors = ButtonDefaults.textButtonColors(
contentColor = MaterialTheme.colorScheme.error contentColor = MaterialTheme.colorScheme.error
@ -178,6 +175,66 @@ fun SettingsScreen(
} }
} }
} }
if (showDisconnectDialog) {
AnimatedDialog(onDismissRequest = { showDisconnectDialog = false }) {
Card(modifier = Modifier.padding(horizontal = 24.dp)) {
Column(modifier = Modifier.padding(24.dp)) {
Text("Disconnect Account?", style = MaterialTheme.typography.headlineSmall)
Spacer(modifier = Modifier.height(16.dp))
Text("Remove \"${activeAccount?.name ?: ""}\"? You'll need to set up again.")
Spacer(modifier = Modifier.height(24.dp))
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.End
) {
TextButton(onClick = { showDisconnectDialog = false }) { Text("Cancel") }
Spacer(modifier = Modifier.width(8.dp))
Button(
onClick = {
showDisconnectDialog = false
activeAccount?.let { account ->
accountManager.removeAccount(account.id)
ApiClient.reset()
if (accountManager.getAccounts().isEmpty()) onLogout() else onBack()
}
},
colors = ButtonDefaults.buttonColors(containerColor = MaterialTheme.colorScheme.error)
) { Text("Disconnect") }
}
}
}
}
}
if (showDisconnectAllDialog) {
AnimatedDialog(onDismissRequest = { showDisconnectAllDialog = false }) {
Card(modifier = Modifier.padding(horizontal = 24.dp)) {
Column(modifier = Modifier.padding(24.dp)) {
Text("Disconnect All?", style = MaterialTheme.typography.headlineSmall)
Spacer(modifier = Modifier.height(16.dp))
Text("Remove all accounts? You'll need to set up from scratch.")
Spacer(modifier = Modifier.height(24.dp))
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.End
) {
TextButton(onClick = { showDisconnectAllDialog = false }) { Text("Cancel") }
Spacer(modifier = Modifier.width(8.dp))
Button(
onClick = {
showDisconnectAllDialog = false
accountManager.clearAll()
ApiClient.reset()
onLogout()
},
colors = ButtonDefaults.buttonColors(containerColor = MaterialTheme.colorScheme.error)
) { Text("Disconnect All") }
}
}
}
}
}
} }
@Composable @Composable