refactor(multi-account): in-app overlay dialog for Add Account

Replaced DialogWindow (OS native window with title bar, minimize/maximize)
with Dialog composable (in-app overlay with scrim). Matches the
ComposeNoteDialog pattern used elsewhere in the desktop app.

- Card wrapper with 480dp width, 24dp padding
- Title row with 'Add Account' + Close (✕) icon
- No OS window chrome — clean in-app feel
- Click outside or ✕ to dismiss

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
nrobi144
2026-04-30 10:00:43 +03:00
parent 09cb08e5c7
commit ec3a4adb46
@@ -20,36 +20,31 @@
*/ */
package com.vitorpamplona.amethyst.desktop.ui.account package com.vitorpamplona.amethyst.desktop.ui.account
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material.icons.filled.Close
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Card
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
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.DialogWindow import androidx.compose.ui.window.Dialog
import androidx.compose.ui.window.rememberDialogState
import com.vitorpamplona.amethyst.desktop.account.AccountManager import com.vitorpamplona.amethyst.desktop.account.AccountManager
import com.vitorpamplona.amethyst.desktop.ui.auth.LoginCard import com.vitorpamplona.amethyst.desktop.ui.auth.LoginCard
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
@OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
fun AddAccountDialog( fun AddAccountDialog(
accountManager: AccountManager, accountManager: AccountManager,
@@ -59,86 +54,75 @@ fun AddAccountDialog(
val scope = rememberCoroutineScope() val scope = rememberCoroutineScope()
val loginProgress by accountManager.loginProgress.collectAsState() val loginProgress by accountManager.loginProgress.collectAsState()
DialogWindow( Dialog(onDismissRequest = onDismiss) {
onCloseRequest = onDismiss, Card(modifier = Modifier.width(480.dp).padding(16.dp)) {
title = "Add Account", Column(modifier = Modifier.padding(24.dp)) {
state = rememberDialogState(size = DpSize(480.dp, 600.dp)), // Header with title + close button
resizable = false, Row(verticalAlignment = Alignment.CenterVertically) {
) { Text(
MaterialTheme { "Add Account",
Scaffold( style = MaterialTheme.typography.headlineSmall,
topBar = { color = MaterialTheme.colorScheme.onSurface,
TopAppBar( modifier = Modifier.weight(1f),
title = { Text("Add Account") },
navigationIcon = {
IconButton(onClick = onDismiss) {
Icon(
Icons.AutoMirrored.Filled.ArrowBack,
contentDescription = "Back",
)
}
},
) )
}, IconButton(onClick = onDismiss) {
) { padding -> Icon(
Column( Icons.Default.Close,
modifier = Modifier.fillMaxSize().padding(padding).padding(24.dp), contentDescription = "Close",
horizontalAlignment = Alignment.CenterHorizontally, tint = MaterialTheme.colorScheme.onSurfaceVariant,
verticalArrangement = Arrangement.Center, )
) { }
LoginCard( }
onLogin = { keyInput ->
// All steps must be sequential — no fire-and-forget LoginCard(
scope.launch { onLogin = { keyInput ->
withContext(Dispatchers.IO) { scope.launch {
accountManager.ensureCurrentAccountInStorage() withContext(Dispatchers.IO) {
} accountManager.ensureCurrentAccountInStorage()
val result = accountManager.loginWithKey(keyInput)
if (result.isSuccess) {
withContext(Dispatchers.IO) {
accountManager.saveCurrentAccount()
}
onAccountAdded()
}
} }
// Return success to dismiss any error in LoginCard val result = accountManager.loginWithKey(keyInput)
Result.success(Unit) if (result.isSuccess) {
},
onGenerateNew = {
scope.launch {
withContext(Dispatchers.IO) {
accountManager.ensureCurrentAccountInStorage()
}
accountManager.generateNewAccount()
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
accountManager.saveCurrentAccount() accountManager.saveCurrentAccount()
} }
onAccountAdded() onAccountAdded()
} }
}, }
onLoginBunker = { bunkerUri -> Result.success(Unit)
// ensureCurrentAccountInStorage first, then bunker login },
accountManager.ensureCurrentAccountInStorage() onGenerateNew = {
val result = accountManager.loginWithBunker(bunkerUri) scope.launch {
if (result.isSuccess) { withContext(Dispatchers.IO) {
onAccountAdded() accountManager.ensureCurrentAccountInStorage()
} }
result.map { } accountManager.generateNewAccount()
}, withContext(Dispatchers.IO) {
onLoginNostrConnect = { onUriGenerated -> accountManager.saveCurrentAccount()
accountManager.ensureCurrentAccountInStorage()
val result = accountManager.loginWithNostrConnect(onUriGenerated)
if (result.isSuccess) {
onAccountAdded()
} }
result.map { } onAccountAdded()
}, }
loginProgress = loginProgress, },
cardWidth = 420.dp, onLoginBunker = { bunkerUri ->
title = "Import Account", accountManager.ensureCurrentAccountInStorage()
subtitle = "Paste nsec, npub (view-only), or use a remote signer", val result = accountManager.loginWithBunker(bunkerUri)
) if (result.isSuccess) {
} onAccountAdded()
}
result.map { }
},
onLoginNostrConnect = { onUriGenerated ->
accountManager.ensureCurrentAccountInStorage()
val result = accountManager.loginWithNostrConnect(onUriGenerated)
if (result.isSuccess) {
onAccountAdded()
}
result.map { }
},
loginProgress = loginProgress,
cardWidth = 420.dp,
title = "Import Account",
subtitle = "Paste nsec, npub (view-only), or use a remote signer",
)
} }
} }
} }