diff --git a/app/src/main/java/swiss/qpq/gajumobile/MainActivity.kt b/app/src/main/java/swiss/qpq/gajumobile/MainActivity.kt index c4743bd..00a7412 100644 --- a/app/src/main/java/swiss/qpq/gajumobile/MainActivity.kt +++ b/app/src/main/java/swiss/qpq/gajumobile/MainActivity.kt @@ -9,6 +9,7 @@ import androidx.activity.enableEdgeToEdge import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateListOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -35,7 +36,7 @@ import swiss.qpq.gajumobile.ui.screens.EnvironmentInfoScreen import swiss.qpq.gajumobile.ui.screens.ExplorerScreen import swiss.qpq.gajumobile.ui.screens.LockScreen import swiss.qpq.gajumobile.ui.screens.ManageAccountScreen -import swiss.qpq.gajumobile.ui.screens.ManageWalletScreen +import swiss.qpq.gajumobile.ui.screens.ManageWalletsScreen import swiss.qpq.gajumobile.ui.screens.MnemonicRecoveryScreen import swiss.qpq.gajumobile.ui.screens.MnemonicVerifyScreen import swiss.qpq.gajumobile.ui.screens.QRReceiveScreen @@ -99,8 +100,8 @@ enum class Screen { QR_SCANNER, QR_RECEIVE, SETTINGS, - MANAGE_WALLET, MANAGE_ACCOUNT, + MANAGE_WALLETS, DELETE_CONFIRM, EXPLORER, VIEW_MNEMONIC, @@ -154,6 +155,9 @@ fun GajuRouter( var verifyMnemonicAccount by remember { mutableStateOf(null) } var verifyMnemonicPhrase by remember { mutableStateOf?>(null) } + var activeWalletIndex by rememberSaveable { mutableIntStateOf(0) } + var activeAccountIndex by rememberSaveable { mutableIntStateOf(0) } + when (currentScreen) { Screen.CREATE_WALLET -> { CreateWalletScreen( @@ -294,14 +298,14 @@ fun GajuRouter( } DashboardScreen( wallets = wallets, + selectedWalletIndex = activeWalletIndex, + onWalletIndexChange = { activeWalletIndex = it }, + selectedAccountIndex = activeAccountIndex, + onAccountIndexChange = { activeAccountIndex = it }, balanceFormat = GajuFormat.Type.valueOf(appState.balanceFormat), balanceUnit = GajuFormat.Unit.valueOf(appState.balanceUnit), onSend = { navigateTo(Screen.QR_SCANNER) }, onReceive = { navigateTo(Screen.QR_RECEIVE) }, - onAddWallet = { - selectedWalletId = "" - navigateTo(Screen.CREATE_WALLET) - }, onAddAccount = { walletId -> selectedWalletId = walletId navigateTo(Screen.SETUP_CHOICE) @@ -316,27 +320,47 @@ fun GajuRouter( "settings" -> Screen.SETTINGS "transactions" -> Screen.EXPLORER "environment_info" -> Screen.ENVIRONMENT_INFO + "manage_wallets" -> Screen.MANAGE_WALLETS else -> null } if (screen != null) navigateTo(screen) }, ) } - Screen.MANAGE_WALLET -> { - val wallet = remember(selectedWalletId, appState.walletsVersion) { - walletRepo.loadWallet(selectedWalletId) - } ?: return - ManageWalletScreen( - walletName = wallet.name, - onRename = { newName -> - walletRepo.saveWallet(wallet.copy(name = newName)) - appStateManager.notifyWalletsChanged() + Screen.MANAGE_WALLETS -> { + val wallets = remember(appState.walletsVersion) { + walletRepo.listWallets().mapNotNull { walletRepo.loadWallet(it) } + } + ManageWalletsScreen( + wallets = wallets, + onAddWallet = { + selectedWalletId = "" + navigateTo(Screen.CREATE_WALLET) }, - onDelete = { - deleteType = "WALLET" - deleteName = wallet.name - navigateTo(Screen.DELETE_CONFIRM) - } + onRenameWallet = { id, newName -> + val wallet = walletRepo.loadWallet(id) + wallet?.let { + walletRepo.saveWallet(it.copy(name = newName)) + appStateManager.notifyWalletsChanged() + } + }, + onDeleteWallet = { id -> + val wallet = walletRepo.loadWallet(id) + wallet?.let { + selectedWalletId = id + deleteType = "WALLET" + deleteName = it.name + navigateTo(Screen.DELETE_CONFIRM) + } + }, + onUpdateNetwork = { id, network -> + val wallet = walletRepo.loadWallet(id) + wallet?.let { + walletRepo.saveWallet(it.copy(network = network)) + appStateManager.notifyWalletsChanged() + } + }, + onBack = { navigateBack() } ) } Screen.MANAGE_ACCOUNT -> { @@ -399,6 +423,7 @@ fun GajuRouter( "dashboard" -> Screen.DASHBOARD "transactions" -> Screen.EXPLORER "environment_info" -> Screen.ENVIRONMENT_INFO + "manage_wallets" -> Screen.MANAGE_WALLETS else -> null } if (screen != null) { @@ -417,6 +442,7 @@ fun GajuRouter( val screen = when (dest) { "dashboard" -> Screen.DASHBOARD "settings" -> Screen.SETTINGS + "manage_wallets" -> Screen.MANAGE_WALLETS else -> null } if (screen != null) { diff --git a/app/src/main/java/swiss/qpq/gajumobile/data/models/Wallet.kt b/app/src/main/java/swiss/qpq/gajumobile/data/models/Wallet.kt index 925c8b0..4a037d4 100644 --- a/app/src/main/java/swiss/qpq/gajumobile/data/models/Wallet.kt +++ b/app/src/main/java/swiss/qpq/gajumobile/data/models/Wallet.kt @@ -7,5 +7,6 @@ data class Wallet( val id: String, val name: String, val accounts: List = emptyList(), - val createdAt: Long = System.currentTimeMillis() + val createdAt: Long = System.currentTimeMillis(), + val network: String = "Mainnet" ) diff --git a/app/src/main/java/swiss/qpq/gajumobile/ui/components/GajuComponents.kt b/app/src/main/java/swiss/qpq/gajumobile/ui/components/GajuComponents.kt index 3d39876..83d997e 100644 --- a/app/src/main/java/swiss/qpq/gajumobile/ui/components/GajuComponents.kt +++ b/app/src/main/java/swiss/qpq/gajumobile/ui/components/GajuComponents.kt @@ -129,6 +129,14 @@ fun GajuTopBar( expanded = menuExpanded, onDismissRequest = { menuExpanded = false } ) { + DropdownMenuItem( + text = { Text("Manage Wallets") }, + onClick = { + menuExpanded = false + onNavigate("manage_wallets") + }, + leadingIcon = { Icon(painterResource(R.drawable.ic_account_box), null, modifier = Modifier.size(18.dp)) } + ) DropdownMenuItem( text = { Text("Transactions") }, onClick = { diff --git a/app/src/main/java/swiss/qpq/gajumobile/ui/screens/DashboardScreen.kt b/app/src/main/java/swiss/qpq/gajumobile/ui/screens/DashboardScreen.kt index 0ddcfed..e23d32a 100644 --- a/app/src/main/java/swiss/qpq/gajumobile/ui/screens/DashboardScreen.kt +++ b/app/src/main/java/swiss/qpq/gajumobile/ui/screens/DashboardScreen.kt @@ -1,5 +1,6 @@ package swiss.qpq.gajumobile.ui.screens +import android.content.ClipData import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box @@ -24,24 +25,22 @@ import androidx.compose.material3.SecondaryScrollableTabRow import androidx.compose.material3.Surface import androidx.compose.material3.Tab import androidx.compose.material3.TabRowDefaults -import androidx.compose.material3.TabRowDefaults.tabIndicatorOffset import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableIntStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.platform.LocalClipboardManager +import androidx.compose.ui.platform.ClipEntry +import androidx.compose.ui.platform.LocalClipboard import androidx.compose.ui.res.painterResource -import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import kotlinx.coroutines.launch import swiss.qpq.gajumobile.R import swiss.qpq.gajumobile.data.models.Wallet import swiss.qpq.gajumaru.core.formatting.GajuFormat @@ -51,11 +50,14 @@ import swiss.qpq.gajumobile.ui.components.GajuTopBar @Composable fun DashboardScreen( wallets: List, + selectedWalletIndex: Int, + onWalletIndexChange: (Int) -> Unit, + selectedAccountIndex: Int, + onAccountIndexChange: (Int) -> Unit, balanceFormat: GajuFormat.Type = GajuFormat.Type.US, balanceUnit: GajuFormat.Unit = GajuFormat.Unit.GAJU, onSend: () -> Unit, onReceive: () -> Unit, - onAddWallet: () -> Unit, onAddAccount: (String) -> Unit, onAccountSettings: (String, String) -> Unit, onNavigate: (String) -> Unit, @@ -67,15 +69,20 @@ fun DashboardScreen( return } - val clipboardManager = LocalClipboardManager.current - val walletPagerState = rememberPagerState(pageCount = { wallets.size }) - val currentWallet = wallets[walletPagerState.currentPage] + val clipboard = LocalClipboard.current + val scope = rememberCoroutineScope() + val walletPagerState = rememberPagerState(initialPage = selectedWalletIndex.coerceIn(0, wallets.size - 1)) { wallets.size } - var selectedAccountIndex by remember(walletPagerState.currentPage) { mutableIntStateOf(0) } + // Sync pager state back to router + LaunchedEffect(walletPagerState.currentPage) { + onWalletIndexChange(walletPagerState.currentPage) + } + + val currentWallet = wallets[walletPagerState.currentPage] val currentAccount = currentWallet.accounts.getOrNull(selectedAccountIndex) Scaffold( - topBar = { GajuTopBar(onNavigate = onNavigate) } + topBar = { GajuTopBar(onNavigate = onNavigate) }, ) { innerPadding -> Column( modifier = Modifier @@ -91,30 +98,6 @@ fun DashboardScreen( .padding(vertical = 8.dp), horizontalAlignment = Alignment.CenterHorizontally ) { - Row( - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.Center, - modifier = Modifier.fillMaxWidth() - ) { - Text( - text = "WALLET", - style = MaterialTheme.typography.labelSmall, - color = MaterialTheme.colorScheme.primary - ) - Spacer(modifier = Modifier.width(8.dp)) - IconButton( - onClick = onAddWallet, - modifier = Modifier.size(24.dp) - ) { - Icon( - painter = painterResource(id = R.drawable.ic_add), - contentDescription = "Add Wallet", - tint = MaterialTheme.colorScheme.primary, - modifier = Modifier.size(16.dp) - ) - } - } - HorizontalPager( state = walletPagerState, modifier = Modifier.fillMaxWidth().height(48.dp), @@ -148,7 +131,7 @@ fun DashboardScreen( } } - // Account Tabs - Inset below wallet + // Account Tabs if (currentWallet.accounts.isNotEmpty()) { Surface( modifier = Modifier @@ -174,7 +157,7 @@ fun DashboardScreen( val isSelected = selectedAccountIndex == index Tab( selected = isSelected, - onClick = { selectedAccountIndex = index }, + onClick = { onAccountIndexChange(index) }, text = { Text( text = account.label, @@ -225,7 +208,11 @@ fun DashboardScreen( ) Spacer(modifier = Modifier.width(8.dp)) IconButton( - onClick = { clipboardManager.setText(AnnotatedString(account.gajuId)) }, + onClick = { + scope.launch { + clipboard.setClipEntry(ClipEntry(ClipData.newPlainText("Account ID", account.gajuId))) + } + }, modifier = Modifier.size(24.dp) ) { Icon( diff --git a/app/src/main/java/swiss/qpq/gajumobile/ui/screens/LockScreen.kt b/app/src/main/java/swiss/qpq/gajumobile/ui/screens/LockScreen.kt index 39f257a..721796b 100644 --- a/app/src/main/java/swiss/qpq/gajumobile/ui/screens/LockScreen.kt +++ b/app/src/main/java/swiss/qpq/gajumobile/ui/screens/LockScreen.kt @@ -9,13 +9,13 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.safeDrawingPadding -import androidx.compose.foundation.layout.size import androidx.compose.material3.Button import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp @@ -34,13 +34,16 @@ fun LockScreen( contentAlignment = Alignment.Center, ) { Column( - modifier = Modifier.safeDrawingPadding(), + modifier = Modifier + .safeDrawingPadding() + .padding(horizontal = 32.dp), horizontalAlignment = Alignment.CenterHorizontally ) { Image( - painter = painterResource(id = R.drawable.gajumobile_icon_colored), - contentDescription = null, - modifier = Modifier.size(100.dp), + painter = painterResource(id = R.drawable.gajumobile_horizontal_colored), + contentDescription = "GajuMobile", + modifier = Modifier.height(64.dp), + contentScale = ContentScale.Fit ) Spacer(modifier = Modifier.height(48.dp)) Text( diff --git a/app/src/main/java/swiss/qpq/gajumobile/ui/screens/ManageAccountScreen.kt b/app/src/main/java/swiss/qpq/gajumobile/ui/screens/ManageAccountScreen.kt index 2504ccd..1cb32cf 100644 --- a/app/src/main/java/swiss/qpq/gajumobile/ui/screens/ManageAccountScreen.kt +++ b/app/src/main/java/swiss/qpq/gajumobile/ui/screens/ManageAccountScreen.kt @@ -1,5 +1,6 @@ package swiss.qpq.gajumobile.ui.screens +import android.content.ClipData import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement @@ -28,16 +29,18 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalClipboardManager +import androidx.compose.ui.platform.ClipEntry +import androidx.compose.ui.platform.LocalClipboard import androidx.compose.ui.res.painterResource -import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import kotlinx.coroutines.launch import swiss.qpq.gajumobile.R import swiss.qpq.gajumobile.data.models.Account import swiss.qpq.gajumobile.ui.components.GajuHeader @@ -55,11 +58,12 @@ fun ManageAccountScreen( onViewMnemonic: () -> Unit, onVerifyMnemonic: () -> Unit, onRename: (String) -> Unit, - onDelete: () -> Unit + onDelete: () -> Unit, ) { - val clipboardManager = LocalClipboardManager.current - var showRenameDialog by remember { mutableStateOf(false) } - var newName by remember(account.label) { mutableStateOf(account.label) } + val clipboard = LocalClipboard.current + val scope = rememberCoroutineScope() + var showRenameDialog by remember { mutableStateOf(value = false) } + var newName by remember(account.label) { mutableStateOf(value = account.label) } if (showRenameDialog) { androidx.compose.ui.window.Dialog(onDismissRequest = { showRenameDialog = false }) { @@ -191,7 +195,11 @@ fun ManageAccountScreen( ) Spacer(modifier = Modifier.width(8.dp)) IconButton( - onClick = { clipboardManager.setText(AnnotatedString(account.gajuId)) }, + onClick = { + scope.launch { + clipboard.setClipEntry(ClipEntry(ClipData.newPlainText("Account ID", account.gajuId))) + } + }, modifier = Modifier.size(24.dp) ) { Icon( diff --git a/app/src/main/java/swiss/qpq/gajumobile/ui/screens/ManageWalletScreen.kt b/app/src/main/java/swiss/qpq/gajumobile/ui/screens/ManageWalletScreen.kt deleted file mode 100644 index 2e79fce..0000000 --- a/app/src/main/java/swiss/qpq/gajumobile/ui/screens/ManageWalletScreen.kt +++ /dev/null @@ -1,146 +0,0 @@ -package swiss.qpq.gajumobile.ui.screens - -import androidx.compose.foundation.background -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.WindowInsets -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.navigationBars -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.width -import androidx.compose.foundation.layout.windowInsetsPadding -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.foundation.verticalScroll -import androidx.compose.material3.Icon -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Scaffold -import androidx.compose.material3.Surface -import androidx.compose.material3.Text -import androidx.compose.material3.TextButton -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp -import swiss.qpq.gajumobile.R -import swiss.qpq.gajumobile.ui.components.GajuHeader -import swiss.qpq.gajumobile.ui.components.GajuTextField -import swiss.qpq.gajumobile.ui.components.ManageAction - -@Composable -fun ManageWalletScreen( - walletName: String, - onRename: (String) -> Unit, - onDelete: () -> Unit -) { - var showRenameDialog by remember { mutableStateOf(false) } - var newName by remember { mutableStateOf(walletName) } - - if (showRenameDialog) { - androidx.compose.ui.window.Dialog(onDismissRequest = { showRenameDialog = false }) { - Surface( - shape = RoundedCornerShape(16.dp), - color = MaterialTheme.colorScheme.surface, - tonalElevation = 8.dp - ) { - Column(modifier = Modifier.padding(24.dp)) { - Text("Rename Wallet", style = MaterialTheme.typography.headlineSmall) - Spacer(modifier = Modifier.height(16.dp)) - GajuTextField( - value = newName, - onValueChange = { newName = it }, - label = "New Name" - ) - Spacer(modifier = Modifier.height(24.dp)) - Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.End) { - TextButton(onClick = { showRenameDialog = false }) { Text("CANCEL") } - Spacer(modifier = Modifier.width(8.dp)) - TextButton(onClick = { - onRename(newName) - showRenameDialog = false - }) { Text("SAVE") } - } - } - } - } - } - - Scaffold( - modifier = Modifier.fillMaxSize(), - bottomBar = { - Column( - modifier = Modifier - .fillMaxWidth() - .windowInsetsPadding(WindowInsets.navigationBars) - .padding(24.dp), - horizontalAlignment = Alignment.CenterHorizontally, - ) { - ManageAction(label = "Delete this wallet", icon = R.drawable.ic_delete, isDestructive = true, onClick = onDelete) - } - }, - ) { innerPadding -> - Column( - modifier = Modifier - .fillMaxSize() - .background(MaterialTheme.colorScheme.background) - .padding(innerPadding) - .padding(horizontal = 24.dp) - .verticalScroll(rememberScrollState()), - horizontalAlignment = Alignment.CenterHorizontally, - ) { - GajuHeader() - - Text( - text = "Manage Wallet", - color = MaterialTheme.colorScheme.onBackground, - style = MaterialTheme.typography.headlineMedium, - modifier = Modifier.padding(vertical = 16.dp), - ) - - Surface( - modifier = Modifier.fillMaxWidth(), - color = MaterialTheme.colorScheme.surfaceVariant, - shape = RoundedCornerShape(8.dp), - ) { - Row( - modifier = Modifier.padding(16.dp), - horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.CenterVertically, - ) { - Spacer(modifier = Modifier.width(32.dp)) - Text(text = walletName, color = MaterialTheme.colorScheme.onSurfaceVariant, fontWeight = FontWeight.Bold) - Icon(painterResource(R.drawable.settings), null, tint = MaterialTheme.colorScheme.onSurfaceVariant) - } - } - - Spacer(modifier = Modifier.height(32.dp)) - - Text("Accounts within this wallet", color = MaterialTheme.colorScheme.onSurfaceVariant, fontSize = 14.sp) - // Real wallets will be iterated in Overview, here we just show a placeholder or we should pass account list - Text("Select an account from the MANAGE screen to configure individual account settings.", - color = MaterialTheme.colorScheme.onSurfaceVariant, - fontSize = 12.sp, - textAlign = TextAlign.Center, - modifier = Modifier.padding(top = 16.dp) - ) - - Spacer(modifier = Modifier.height(48.dp)) - - Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceEvenly) { - ManageAction(label = "Rename this wallet", icon = R.drawable.ic_edit, onClick = { showRenameDialog = true }) - } - } - } -} diff --git a/app/src/main/java/swiss/qpq/gajumobile/ui/screens/ManageWalletsScreen.kt b/app/src/main/java/swiss/qpq/gajumobile/ui/screens/ManageWalletsScreen.kt new file mode 100644 index 0000000..2138934 --- /dev/null +++ b/app/src/main/java/swiss/qpq/gajumobile/ui/screens/ManageWalletsScreen.kt @@ -0,0 +1,184 @@ +package swiss.qpq.gajumobile.ui.screens + +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.material3.TextButton +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import swiss.qpq.gajumobile.R +import swiss.qpq.gajumobile.data.models.Wallet +import swiss.qpq.gajumobile.ui.components.GajuHeader +import swiss.qpq.gajumobile.ui.components.GajuTextField +import swiss.qpq.gajumobile.ui.components.ManageAction + +@Composable +fun ManageWalletsScreen( + wallets: List, + onAddWallet: () -> Unit, + onRenameWallet: (String, String) -> Unit, + onDeleteWallet: (String) -> Unit, + onUpdateNetwork: (String, String) -> Unit, + onBack: () -> Unit +) { + var walletToRename by remember { mutableStateOf(null) } + var newName by remember { mutableStateOf("") } + + if (walletToRename != null) { + androidx.compose.ui.window.Dialog(onDismissRequest = { walletToRename = null }) { + Surface( + shape = RoundedCornerShape(16.dp), + color = MaterialTheme.colorScheme.surface, + tonalElevation = 8.dp + ) { + Column(modifier = Modifier.padding(24.dp)) { + Text("Rename Wallet", style = MaterialTheme.typography.headlineSmall) + Spacer(modifier = Modifier.height(16.dp)) + GajuTextField( + value = newName, + onValueChange = { newName = it }, + label = "New Name" + ) + Spacer(modifier = Modifier.height(24.dp)) + Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.End) { + TextButton(onClick = { walletToRename = null }) { Text("CANCEL") } + Spacer(modifier = Modifier.width(8.dp)) + TextButton(onClick = { + walletToRename?.let { onRenameWallet(it.id, newName) } + walletToRename = null + }) { Text("SAVE") } + } + } + } + } + } + + Scaffold { innerPadding -> + Column( + modifier = Modifier + .fillMaxSize() + .background(MaterialTheme.colorScheme.background) + .padding(innerPadding) + .padding(horizontal = 24.dp) + .verticalScroll(rememberScrollState()), + horizontalAlignment = Alignment.CenterHorizontally + ) { + GajuHeader() + Text( + "Manage Wallets", + style = MaterialTheme.typography.headlineMedium, + color = MaterialTheme.colorScheme.onBackground + ) + + Spacer(modifier = Modifier.height(24.dp)) + + wallets.forEach { wallet -> + WalletManagementCard( + wallet = wallet, + onRename = { + newName = wallet.name + walletToRename = wallet + }, + onDelete = { onDeleteWallet(wallet.id) }, + onUpdateNetwork = { onUpdateNetwork(wallet.id, it) } + ) + Spacer(modifier = Modifier.height(16.dp)) + } + + Spacer(modifier = Modifier.height(24.dp)) + + ManageAction( + label = "Add new wallet", + icon = R.drawable.ic_add, + onClick = onAddWallet + ) + + Spacer(modifier = Modifier.height(32.dp)) + + TextButton(onClick = onBack) { + Text("Done") + } + } + } +} + +@Composable +private fun WalletManagementCard( + wallet: Wallet, + onRename: () -> Unit, + onDelete: () -> Unit, + onUpdateNetwork: (String) -> Unit +) { + Surface( + color = MaterialTheme.colorScheme.surfaceVariant, + shape = RoundedCornerShape(12.dp), + modifier = Modifier.fillMaxWidth() + ) { + Column(modifier = Modifier.padding(16.dp)) { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = wallet.name, + style = MaterialTheme.typography.titleMedium, + fontWeight = FontWeight.Bold, + modifier = Modifier.clickable { onRename() } + ) + IconButton(onClick = onDelete) { + Icon( + painter = painterResource(id = R.drawable.ic_delete), + contentDescription = "Delete Wallet", + tint = MaterialTheme.colorScheme.error, + modifier = Modifier.size(20.dp) + ) + } + } + + Spacer(modifier = Modifier.height(8.dp)) + + GajuTextField( + value = wallet.network, + onValueChange = onUpdateNetwork, + label = "Network", + placeholder = "e.g. Mainnet, Testnet" + ) + + Spacer(modifier = Modifier.height(8.dp)) + + Text( + text = "${wallet.accounts.size} account(s)", + style = MaterialTheme.typography.labelSmall, + color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.6f) + ) + } + } +} diff --git a/app/src/main/java/swiss/qpq/gajumobile/ui/screens/SetupChoiceScreen.kt b/app/src/main/java/swiss/qpq/gajumobile/ui/screens/SetupChoiceScreen.kt index ae8247d..2006674 100644 --- a/app/src/main/java/swiss/qpq/gajumobile/ui/screens/SetupChoiceScreen.kt +++ b/app/src/main/java/swiss/qpq/gajumobile/ui/screens/SetupChoiceScreen.kt @@ -16,6 +16,7 @@ import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.font.FontStyle import androidx.compose.ui.text.style.TextAlign @@ -40,9 +41,10 @@ fun SetupChoiceScreen( verticalArrangement = Arrangement.Center ) { Image( - painter = painterResource(id = R.drawable.gajumobile_icon_colored), - contentDescription = null, - modifier = Modifier.size(100.dp), + painter = painterResource(id = R.drawable.gajumobile_horizontal_colored), + contentDescription = "GajuMobile", + modifier = Modifier.height(80.dp).padding(horizontal = 16.dp), + contentScale = ContentScale.Fit ) Spacer(modifier = Modifier.height(48.dp))