diff --git a/app/src/main/java/swiss/qpq/gajumobile/MainActivity.kt b/app/src/main/java/swiss/qpq/gajumobile/MainActivity.kt index 15ea0e3..0d0d5df 100644 --- a/app/src/main/java/swiss/qpq/gajumobile/MainActivity.kt +++ b/app/src/main/java/swiss/qpq/gajumobile/MainActivity.kt @@ -520,7 +520,7 @@ fun GajuRouter( val status = withContext(Dispatchers.IO) { client.status() } val reportedNetworkId = status["network_id"] as? String - if ((reportedNetworkId != null && reportedNetworkId != wallet.networkId)) { + if ((reportedNetworkId != null) && (reportedNetworkId != wallet.networkId)) { val allWallets = walletRepo.listWallets().mapNotNull { walletRepo.loadWallet(it) } val targetWallet = allWallets.find { it.networkId == reportedNetworkId } @@ -556,7 +556,7 @@ fun GajuRouter( val status = withContext(Dispatchers.IO) { client.status() } val reportedNetworkId = status["network_id"] as? String - if ((reportedNetworkId != null && reportedNetworkId != wallet.networkId)) { + if ((reportedNetworkId != null) && (reportedNetworkId != wallet.networkId)) { // Mismatch logic val allWallets = walletRepo.listWallets().mapNotNull { walletRepo.loadWallet(it) } val targetWallet = allWallets.find { it.networkId == reportedNetworkId } @@ -837,7 +837,7 @@ fun GajuRouter( // If request specifies an ID, try to find that account val signAccount = if (request.publicId != null && request.publicId != "false") { - wallets.flatMap { it.accounts }.find { it.gajuId == request.publicId } + wallets.asSequence().flatMap { it.accounts }.find { it.gajuId == request.publicId } } else { activeAccount } diff --git a/app/src/main/java/swiss/qpq/gajumobile/data/WalletRepository.kt b/app/src/main/java/swiss/qpq/gajumobile/data/WalletRepository.kt index 225d558..0cbca42 100644 --- a/app/src/main/java/swiss/qpq/gajumobile/data/WalletRepository.kt +++ b/app/src/main/java/swiss/qpq/gajumobile/data/WalletRepository.kt @@ -4,7 +4,6 @@ import android.content.Context import kotlinx.serialization.json.Json import swiss.qpq.gajumobile.data.models.Account import swiss.qpq.gajumobile.data.models.Wallet -import swiss.qpq.gajumobile.security.AccountAirlock import swiss.qpq.gajumobile.security.EncryptionService import swiss.qpq.gajumobile.security.KeyManager import swiss.qpq.gajumaru.core.tools.NodeClient @@ -69,7 +68,6 @@ class WalletRepository(private val context: Context) { } val balance = accountInfo["balance"]?.toString() ?: "0" - val nonce = (accountInfo["nonce"] as? Number)?.toLong() ?: 0L val updatedAccount = account.copy( cachedBalance = CachedBalance( @@ -90,28 +88,6 @@ class WalletRepository(private val context: Context) { } } - suspend fun getStatus(wallet: Wallet): Map? { - val client = NodeClient(wallet.endpoints.map { NodeClient.Endpoint(it.host, it.port, it.useTls) }) - return try { - withContext(Dispatchers.IO) { - client.status() - } - } catch (e: Exception) { - null - } - } - - suspend fun postTransaction(wallet: Wallet, signedTx: String): Map? { - val client = NodeClient(wallet.endpoints.map { NodeClient.Endpoint(it.host, it.port, it.useTls) }) - return try { - withContext(Dispatchers.IO) { - client.postTx(signedTx) - } - } catch (e: Exception) { - null - } - } - fun listWallets(): List { val dir = File(context.filesDir, "wallets") if (!dir.exists()) return emptyList() diff --git a/app/src/main/java/swiss/qpq/gajumobile/security/AccountAirlock.java b/app/src/main/java/swiss/qpq/gajumobile/security/AccountAirlock.java index 5c22aba..0d7f1c0 100644 --- a/app/src/main/java/swiss/qpq/gajumobile/security/AccountAirlock.java +++ b/app/src/main/java/swiss/qpq/gajumobile/security/AccountAirlock.java @@ -4,7 +4,6 @@ import java.nio.charset.StandardCharsets; import java.security.SecureRandom; import java.util.UUID; import javax.crypto.SecretKey; -import swiss.qpq.gajumaru.core.crypto.Vault; import swiss.qpq.gajumaru.core.encoding.Mnemonic; import swiss.qpq.gajumaru.core.tools.CryptoUtils; import swiss.qpq.gajumaru.core.tools.TransactionService; @@ -191,22 +190,10 @@ public final class AccountAirlock { try { return Mnemonic.encode(plaintextPrivateKey); } finally { - if (plaintextPrivateKey != null) safeMemzero(plaintextPrivateKey); + safeMemzero(plaintextPrivateKey); } } - /** - * Utility to convert a UI String into the internal airlock byte[][] format. - */ - public static byte[][] stringToPhrase(String phrase) { - String[] words = phrase.trim().split("\\s+"); - byte[][] result = new byte[words.length][]; - for (int i = 0; i < words.length; i++) { - result[i] = words[i].getBytes(StandardCharsets.UTF_8); - } - return result; - } - /** * Utility to wipe a phrase returned by the airlock. */ diff --git a/app/src/main/java/swiss/qpq/gajumobile/ui/screens/CreateWalletScreen.kt b/app/src/main/java/swiss/qpq/gajumobile/ui/screens/CreateWalletScreen.kt index 6fd3ca8..130c536 100644 --- a/app/src/main/java/swiss/qpq/gajumobile/ui/screens/CreateWalletScreen.kt +++ b/app/src/main/java/swiss/qpq/gajumobile/ui/screens/CreateWalletScreen.kt @@ -33,7 +33,7 @@ import swiss.qpq.gajumobile.ui.components.GajuTextField @Composable fun CreateWalletScreen( onWalletCreated: (name: String, networkId: String) -> Unit, - onBack: (() -> Unit)? = null + onBack: (() -> Unit)? = null, ) { var walletName by remember { mutableStateOf("") } var selectedNetwork by remember { mutableStateOf("groot.mainnet") } 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 b4712c6..1601cef 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 @@ -2,7 +2,7 @@ package swiss.qpq.gajumobile.ui.screens import android.content.ClipData import android.content.Intent -import android.net.Uri +import androidx.core.net.toUri import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box @@ -267,7 +267,7 @@ fun DashboardScreen( androidx.compose.material3.TextButton( onClick = { val url = "https://${currentWallet.networkId}.gajumaru.io/account/${account.gajuId}" - val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url)) + val intent = Intent(Intent.ACTION_VIEW, url.toUri()) context.startActivity(intent) }, modifier = Modifier.padding(bottom = 12.dp) 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 55f4cb4..5155abf 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 @@ -72,7 +72,7 @@ fun ManageAccountScreen( Surface( shape = RoundedCornerShape(16.dp), color = MaterialTheme.colorScheme.surface, - tonalElevation = 8.dp + tonalElevation = 8.dp, ) { Column(modifier = Modifier.padding(24.dp)) { Text(stringResource(R.string.rename_account_title), style = MaterialTheme.typography.headlineSmall) @@ -84,12 +84,20 @@ fun ManageAccountScreen( ) Spacer(modifier = Modifier.height(24.dp)) Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.End) { - TextButton(onClick = { showRenameDialog = false }) { Text(stringResource(R.string.cancel)) } + TextButton( + onClick = { showRenameDialog = false } + ) { + Text(stringResource(R.string.cancel)) + } Spacer(modifier = Modifier.width(8.dp)) - TextButton(onClick = { - onRename(newName) - showRenameDialog = false - }) { Text(stringResource(R.string.save_button_caps)) } + TextButton( + onClick = { + onRename(newName) + showRenameDialog = false + } + ) { + Text(stringResource(R.string.save_button_caps)) + } } } } diff --git a/app/src/main/java/swiss/qpq/gajumobile/ui/screens/MnemonicRecoveryScreen.kt b/app/src/main/java/swiss/qpq/gajumobile/ui/screens/MnemonicRecoveryScreen.kt index 2b55585..c1a0c28 100644 --- a/app/src/main/java/swiss/qpq/gajumobile/ui/screens/MnemonicRecoveryScreen.kt +++ b/app/src/main/java/swiss/qpq/gajumobile/ui/screens/MnemonicRecoveryScreen.kt @@ -47,11 +47,11 @@ import swiss.qpq.gajumobile.ui.components.GajuTextField @Composable fun MnemonicRecoveryScreen( onMnemonicConfirmed: (Array) -> Unit, - onBack: () -> Unit + onBack: () -> Unit, ) { var committedWords by remember { mutableStateOf(listOf()) } var currentDraft by remember { mutableStateOf("") } - var isAddingWord by remember { mutableStateOf(true) } + var isAddingWord by remember { mutableStateOf(value = true) } val allWords = remember { AccountAirlock.getWordList().toList() } val focusRequester = remember { FocusRequester() } @@ -61,7 +61,7 @@ fun MnemonicRecoveryScreen( } val suggestions = if (currentDraft.length >= 2) { - allWords.filter { it.startsWith(currentDraft) }.take(5) + allWords.asSequence().filter { it.startsWith(currentDraft) }.take(5).toList() } else emptyList() Scaffold( @@ -72,7 +72,7 @@ fun MnemonicRecoveryScreen( Surface( modifier = Modifier.fillMaxWidth(), color = MaterialTheme.colorScheme.surfaceVariant, - tonalElevation = 8.dp + tonalElevation = 8.dp, ) { FlowRow( modifier = Modifier.padding(8.dp).fillMaxWidth(), @@ -81,7 +81,7 @@ fun MnemonicRecoveryScreen( suggestions.forEach { suggestion -> SuggestionChip( onClick = { - committedWords = committedWords + suggestion + committedWords += suggestion currentDraft = "" isAddingWord = false }, @@ -109,7 +109,7 @@ fun MnemonicRecoveryScreen( Spacer(modifier = Modifier.width(16.dp)) GajuButton( text = stringResource(R.string.recover_button_caps), - enabled = committedWords.size >= 21 && !isAddingWord, + enabled = (committedWords.size >= 21) && !isAddingWord, onClick = { val phrase = committedWords.map { it.toByteArray(Charsets.UTF_8) }.toTypedArray() onMnemonicConfirmed(phrase) @@ -160,12 +160,12 @@ fun MnemonicRecoveryScreen( ) } - if (isAddingWord && committedWords.size < 23) { + if ((isAddingWord) && (committedWords.size < 23)) { Box(modifier = Modifier.width(120.dp)) { GajuTextField( value = currentDraft, onValueChange = { currentDraft = it.lowercase() }, - label = "${committedWords.size + 1}", + label = (committedWords.size + 1).toString(), placeholder = "...", modifier = Modifier.focusRequester(focusRequester) ) diff --git a/app/src/main/java/swiss/qpq/gajumobile/ui/screens/MnemonicVerifyScreen.kt b/app/src/main/java/swiss/qpq/gajumobile/ui/screens/MnemonicVerifyScreen.kt index 325d724..ce43578 100644 --- a/app/src/main/java/swiss/qpq/gajumobile/ui/screens/MnemonicVerifyScreen.kt +++ b/app/src/main/java/swiss/qpq/gajumobile/ui/screens/MnemonicVerifyScreen.kt @@ -49,11 +49,11 @@ fun MnemonicVerifyScreen( label: String, expectedPhrase: Array, onVerified: () -> Unit, - onBack: () -> Unit + onBack: () -> Unit, ) { var committedWords by remember { mutableStateOf(listOf()) } var currentDraft by remember { mutableStateOf("") } - var isAddingWord by remember { mutableStateOf(true) } + var isAddingWord by remember { mutableStateOf(value = true) } var verificationError by remember { mutableStateOf(false) } val allWords = remember { AccountAirlock.getWordList().toList() } @@ -64,7 +64,7 @@ fun MnemonicVerifyScreen( } val suggestions = if (currentDraft.length >= 2) { - allWords.filter { it.startsWith(currentDraft) }.take(5) + allWords.asSequence().filter { it.startsWith(currentDraft) }.take(5).toList() } else emptyList() Scaffold( @@ -84,7 +84,7 @@ fun MnemonicVerifyScreen( suggestions.forEach { suggestion -> SuggestionChip( onClick = { - committedWords = committedWords + suggestion + committedWords += suggestion currentDraft = "" isAddingWord = false verificationError = false @@ -113,7 +113,7 @@ fun MnemonicVerifyScreen( Spacer(modifier = Modifier.width(16.dp)) GajuButton( text = stringResource(R.string.verify_button_caps), - enabled = committedWords.size == expectedPhrase.size && !isAddingWord, + enabled = (committedWords.size == expectedPhrase.size) && !isAddingWord, onClick = { val inputPhrase = committedWords.map { it.toByteArray(Charsets.UTF_8) } var match = true @@ -179,7 +179,7 @@ fun MnemonicVerifyScreen( GajuTextField( value = currentDraft, onValueChange = { currentDraft = it.lowercase() }, - label = "${committedWords.size + 1}", + label = (committedWords.size + 1).toString(), placeholder = "...", modifier = Modifier.focusRequester(focusRequester) ) diff --git a/app/src/main/java/swiss/qpq/gajumobile/ui/screens/SendReviewScreen.kt b/app/src/main/java/swiss/qpq/gajumobile/ui/screens/SendReviewScreen.kt index 45f1dec..32d0be2 100644 --- a/app/src/main/java/swiss/qpq/gajumobile/ui/screens/SendReviewScreen.kt +++ b/app/src/main/java/swiss/qpq/gajumobile/ui/screens/SendReviewScreen.kt @@ -62,7 +62,9 @@ fun SendReviewScreen( ) { Row( verticalAlignment = Alignment.CenterVertically, - modifier = Modifier.clickable { confirmed = !confirmed }.padding(bottom = 24.dp) + modifier = Modifier + .clickable { confirmed = !confirmed } + .padding(bottom = 24.dp), ) { Checkbox(checked = confirmed, onCheckedChange = { confirmed = it }) Text( diff --git a/app/src/main/java/swiss/qpq/gajumobile/ui/screens/SettingsScreen.kt b/app/src/main/java/swiss/qpq/gajumobile/ui/screens/SettingsScreen.kt index dbd7881..a8171ad 100644 --- a/app/src/main/java/swiss/qpq/gajumobile/ui/screens/SettingsScreen.kt +++ b/app/src/main/java/swiss/qpq/gajumobile/ui/screens/SettingsScreen.kt @@ -19,7 +19,6 @@ import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.AssistChip import androidx.compose.material3.AssistChipDefaults import androidx.compose.material3.ButtonDefaults -import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme @@ -50,12 +49,12 @@ import swiss.qpq.gajumaru.core.formatting.GajuFormat fun SettingsScreen( balanceFormat: GajuFormat.Type, onFormatChange: (GajuFormat.Type) -> Unit, - onNavigate: (String) -> Unit + onNavigate: (String) -> Unit, ) { val context = LocalContext.current val localeManager = remember { context.getSystemService(LocaleManager::class.java) } val currentLocales = localeManager.applicationLocales - val currentLanguage = if (currentLocales.isEmpty) "en" else currentLocales.get(0).language + val currentLanguage = if (currentLocales.isEmpty) "en" else currentLocales[0].language Scaffold( topBar = { GajuTopBar(onNavigate = onNavigate) }, @@ -161,7 +160,7 @@ fun SettingsScreen( Spacer(modifier = Modifier.weight(1f)) - var showWipeConfirm by remember { mutableStateOf(false) } + var showWipeConfirm by remember { mutableStateOf(value = false) } if (showWipeConfirm) { Surface( diff --git a/app/src/main/java/swiss/qpq/gajumobile/ui/screens/TransactionSuccessScreen.kt b/app/src/main/java/swiss/qpq/gajumobile/ui/screens/TransactionSuccessScreen.kt index 418af1e..d540275 100644 --- a/app/src/main/java/swiss/qpq/gajumobile/ui/screens/TransactionSuccessScreen.kt +++ b/app/src/main/java/swiss/qpq/gajumobile/ui/screens/TransactionSuccessScreen.kt @@ -1,7 +1,7 @@ package swiss.qpq.gajumobile.ui.screens import android.content.Intent -import android.net.Uri +import androidx.core.net.toUri import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.height @@ -68,7 +68,7 @@ fun TransactionSuccessScreen( modifier = Modifier .clickable { val url = "https://$networkId.gajumaru.io/tx/$txHash" - val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url)) + val intent = Intent(Intent.ACTION_VIEW, url.toUri()) context.startActivity(intent) } .padding(8.dp) diff --git a/gm-java b/gm-java index 6714353..381c8f1 160000 --- a/gm-java +++ b/gm-java @@ -1 +1 @@ -Subproject commit 6714353f8ce0af7cdcbf9941036f559650f78efe +Subproject commit 381c8f1b9ab4210146fb968abbecba26f1d771db