Merge pull request #604 from dmnyc/feat/multi-account-switcher

feat(accounts): multi-account switcher + cancel add-account flow
This commit is contained in:
Barry Deen
2026-06-30 17:30:50 -04:00
committed by GitHub
4 changed files with 92 additions and 12 deletions
+22 -1
View File
@@ -281,6 +281,7 @@ fun WispNavHost(
}
val onAddAccount: () -> Unit = {
authViewModel.previousAccountPubkey = authViewModel.keyRepo.getPubkeyHex()
authViewModel.isAddingAccount = true
feedViewModel.resetForAccountSwitch()
walletViewModel.suspendForAccountSwitch() // disconnect only, preserve credentials
@@ -652,7 +653,27 @@ fun WispNavHost(
},
onContinueWithGoogle = {
navController.navigate(Routes.GOOGLE_AUTH)
}
},
onCancel = if (authViewModel.isAddingAccount) {
{
val prev = authViewModel.previousAccountPubkey
authViewModel.isAddingAccount = false
authViewModel.previousAccountPubkey = null
if (prev != null) {
authViewModel.keyRepo.switchToAccount(prev)
authViewModel.keyRepo.reloadPrefs(prev)
}
feedViewModel.reloadForNewAccount()
relayViewModel.reload()
blossomServersViewModel.reload()
composeViewModel.reloadBlossomRepo()
feedViewModel.initRelays()
walletViewModel.refreshState()
navController.navigate(Routes.LOADING) {
popUpTo(Routes.SPLASH) { inclusive = true }
}
}
} else null
)
}
@@ -2,6 +2,8 @@ package com.wisp.app.ui.component
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.background
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.ui.draw.clip
import androidx.compose.material3.HorizontalDivider
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.layout.Arrangement
@@ -147,6 +149,54 @@ fun WispDrawerContent(
}) {
ProfilePicture(url = profile?.picture, size = 64)
}
Spacer(modifier = Modifier.width(8.dp))
val otherAccountCount = (accounts.size - 1).coerceAtLeast(0)
if (otherAccountCount == 0) {
Box(
modifier = Modifier
.size(26.dp)
.clip(CircleShape)
.background(MaterialTheme.colorScheme.surfaceVariant)
.clickable { onAddAccount() },
contentAlignment = Alignment.Center
) {
Icon(
Icons.Filled.Add,
contentDescription = "Add account",
modifier = Modifier.size(16.dp),
tint = MaterialTheme.colorScheme.onSurfaceVariant
)
}
} else {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.clickable { accountPickerExpanded = !accountPickerExpanded }
) {
Box(
modifier = Modifier
.height(26.dp)
.clip(CircleShape)
.background(MaterialTheme.colorScheme.surfaceVariant)
.padding(horizontal = 10.dp),
contentAlignment = Alignment.Center
) {
Text(
text = "+ $otherAccountCount",
style = MaterialTheme.typography.labelSmall,
fontWeight = androidx.compose.ui.text.font.FontWeight.Bold,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
Spacer(modifier = Modifier.width(2.dp))
Icon(
if (accountPickerExpanded) Icons.Outlined.KeyboardArrowDown
else Icons.Outlined.KeyboardArrowRight,
contentDescription = null,
modifier = Modifier.size(18.dp),
tint = MaterialTheme.colorScheme.onSurfaceVariant
)
}
}
Spacer(modifier = Modifier.weight(1f))
IconButton(onClick = onToggleTheme) {
Icon(
@@ -168,7 +218,7 @@ fun WispDrawerContent(
Row(
modifier = Modifier
.fillMaxWidth()
.clickable(enabled = accounts.size > 1 || accounts.isNotEmpty()) {
.clickable(enabled = accounts.isNotEmpty()) {
accountPickerExpanded = !accountPickerExpanded
},
verticalAlignment = Alignment.CenterVertically
@@ -179,15 +229,6 @@ fun WispDrawerContent(
color = MaterialTheme.colorScheme.onSurface,
modifier = Modifier.weight(1f, fill = false)
)
if (accounts.size > 1 || accounts.isNotEmpty()) {
Icon(
if (accountPickerExpanded) Icons.Outlined.KeyboardArrowDown
else Icons.Outlined.KeyboardArrowRight,
contentDescription = stringResource(R.string.cd_switch_account),
modifier = Modifier.size(20.dp),
tint = MaterialTheme.colorScheme.onSurfaceVariant
)
}
}
Spacer(Modifier.height(2.dp))
if (!profile?.nip05.isNullOrBlank()) {
@@ -17,6 +17,7 @@ import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.clickable
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.QrCodeScanner
import androidx.compose.material.icons.outlined.Visibility
@@ -84,7 +85,8 @@ fun SplashScreen(
authViewModel: AuthViewModel,
onAccountCreated: () -> Unit,
onLoggedIn: () -> Unit,
onContinueWithGoogle: () -> Unit
onContinueWithGoogle: () -> Unit,
onCancel: (() -> Unit)? = null
) {
val profilePictures by viewModel.profilePictures.collectAsState()
val liveMetrics by viewModel.liveMetrics.collectAsState()
@@ -146,6 +148,21 @@ fun SplashScreen(
)
)
if (onCancel != null) {
Text(
text = "Cancel",
style = MaterialTheme.typography.labelLarge,
color = androidx.compose.ui.graphics.Color.White,
modifier = Modifier
.align(Alignment.BottomCenter)
.padding(bottom = 120.dp)
.clip(androidx.compose.foundation.shape.CircleShape)
.background(androidx.compose.ui.graphics.Color.White.copy(alpha = 0.15f))
.clickable(onClick = onCancel)
.padding(horizontal = 28.dp, vertical = 12.dp)
)
}
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier
@@ -31,6 +31,7 @@ class AuthViewModel(app: Application) : AndroidViewModel(app) {
val accountsFlow: StateFlow<List<AccountInfo>> = keyRepo.accountsFlow
var isAddingAccount: Boolean = false
var previousAccountPubkey: String? = null
val isLoggedIn: Boolean get() = keyRepo.isLoggedIn()