This commit is contained in:
2026-08-26 14:51:01 +09:00
parent 77a9f5f380
commit 223e95ace6
35 changed files with 1795 additions and 339 deletions
+4 -3
View File
@@ -50,6 +50,10 @@ android {
compose = true
}
androidResources {
generateLocaleConfig = true
}
sourceSets {
getByName("main") {
java.srcDir("../gm-java/src/main/java")
@@ -61,16 +65,13 @@ dependencies {
implementation(platform(libs.androidx.compose.bom))
implementation(libs.androidx.activity.compose)
implementation(libs.androidx.compose.material3)
implementation(libs.androidx.compose.material3.adaptive.navigation.suite)
implementation(libs.androidx.compose.ui)
implementation(libs.androidx.compose.ui.graphics)
implementation(libs.androidx.compose.ui.tooling.preview)
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.core.splashscreen)
implementation(libs.androidx.biometric)
implementation(libs.play.services.code.scanner)
implementation(libs.androidx.lifecycle.process)
implementation(libs.androidx.lifecycle.runtime.ktx)
implementation(libs.kotlinx.serialization.json)
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.compose.ui.test.junit4)
@@ -7,7 +7,6 @@ import androidx.activity.compose.BackHandler
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
@@ -28,7 +27,10 @@ import kotlinx.coroutines.withContext
import swiss.qpq.gajumobile.data.AppStateManager
import swiss.qpq.gajumobile.data.WalletRepository
import swiss.qpq.gajumobile.data.models.Account
import swiss.qpq.gajumobile.data.models.GridsSignRequest
import swiss.qpq.gajumobile.data.models.GridsSignType
import swiss.qpq.gajumobile.data.models.Wallet
import swiss.qpq.gajumobile.data.models.toGridsSignRequest
import swiss.qpq.gajumobile.security.AppLifecycleObserver
import swiss.qpq.gajumobile.security.BiometricHelper
import swiss.qpq.gajumobile.security.SecurityManager
@@ -97,9 +99,9 @@ class MainActivity : FragmentActivity() {
}
} else {
val routerError: (String) -> Unit = { message ->
Toast.makeText(context, message, Toast.LENGTH_LONG).show()
Toast.makeText(this@MainActivity, message, Toast.LENGTH_LONG).show()
}
GajuRouter(walletRepo, appStateManager, routerError)
GajuRouter(this@MainActivity, walletRepo, appStateManager, routerError)
}
}
}
@@ -130,11 +132,11 @@ enum class Screen {
@Composable
fun GajuRouter(
context: android.content.Context,
walletRepo: WalletRepository,
appStateManager: AppStateManager,
onError: (String) -> Unit,
) {
val context = LocalContext.current
val appState by appStateManager.state.collectAsState()
val scope = rememberCoroutineScope()
@@ -192,7 +194,7 @@ fun GajuRouter(
var pendingGasPrice by rememberSaveable { mutableStateOf("") }
var pendingTTL by rememberSaveable { mutableStateOf("") }
var pendingSignRequest by remember { mutableStateOf<Map<String, Any?>?>(null) }
var pendingSignRequest by remember { mutableStateOf<GridsSignRequest?>(null) }
var pendingSignUrl by rememberSaveable { mutableStateOf("") }
var activeFetchJob by remember { mutableStateOf<Job?>(null) }
@@ -222,7 +224,7 @@ fun GajuRouter(
navigateTo(Screen.ACCOUNT_NAMING)
} catch (e: Throwable) {
val msg = e.message ?: e.toString()
onError("Failed to generate account: $msg")
onError(context.getString(R.string.err_generate_account, msg))
android.util.Log.e("GajuRouter", "Account generation failed", e)
}
},
@@ -244,7 +246,7 @@ fun GajuRouter(
pendingAccount = account
navigateTo(Screen.ACCOUNT_NAMING)
} catch (e: Exception) {
onError("Failed to recover account: ${e.message}")
onError(context.getString(R.string.err_recover_account, e.message ?: ""))
}
},
onBack = { navigateBack() },
@@ -330,8 +332,10 @@ fun GajuRouter(
walletRepo.deleteAccount(selectedWalletId, selectedAccountId)
}
appStateManager.notifyWalletsChanged()
screenStack.removeAt(screenStack.size - 1)
screenStack.removeAt(screenStack.size - 1)
// Pop back to Dashboard by removing the confirmation and the management screen
repeat(2) {
if (screenStack.size > 1) screenStack.removeAt(screenStack.size - 1)
}
},
onCancel = { navigateBack() }
)
@@ -367,7 +371,7 @@ fun GajuRouter(
if (updated != null) {
appStateManager.notifyWalletsChanged()
} else {
onError("Refresh failed. Check network endpoints.")
onError(context.getString(R.string.err_refresh_failed))
}
}
},
@@ -441,15 +445,15 @@ fun GajuRouter(
val targetEndpoints = targetWallet.endpoints + endpoint
walletRepo.saveWallet(targetWallet.copy(endpoints = targetEndpoints))
appStateManager.notifyWalletsChanged()
onError("Network mismatch: Node reports '$reportedNetworkId'. Added to wallet '${targetWallet.name}'.")
onError(context.getString(R.string.err_network_mismatch_added, reportedNetworkId, targetWallet.name))
} else {
nodeStatusError = "CRITICAL MISMATCH: Node reports '$reportedNetworkId' but wallet is '${wallet.networkId}'. Please create a wallet for '$reportedNetworkId' first."
nodeStatusError = context.getString(R.string.err_critical_mismatch_create, reportedNetworkId, wallet.networkId)
}
} else {
val newList = wallet.endpoints + endpoint
walletRepo.saveWallet(wallet.copy(endpoints = newList))
appStateManager.notifyWalletsChanged()
onError("Endpoint verified and added.")
onError(context.getString(R.string.msg_endpoint_verified))
}
} catch (e: Exception) {
// Even if status check fails, we might still want to add it?
@@ -483,10 +487,10 @@ fun GajuRouter(
walletRepo.saveWallet(targetWallet.copy(endpoints = targetEndpoints))
appStateManager.notifyWalletsChanged()
onError("Network mismatch: Node reports '$reportedNetworkId'. Moved to wallet '${targetWallet.name}'.")
onError(context.getString(R.string.err_network_mismatch_moved, reportedNetworkId, targetWallet.name))
} else {
// Warn for discard
nodeStatusError = "CRITICAL MISMATCH: Node reports '$reportedNetworkId' but wallet is configured for '${wallet.networkId}'. Fix this endpoint or it will be discarded from this wallet."
nodeStatusError = context.getString(R.string.err_critical_mismatch_fix, reportedNetworkId, wallet.networkId)
}
} else {
nodeStatusResult = status
@@ -526,7 +530,7 @@ fun GajuRouter(
viewMnemonicPhrase = phrase
navigateTo(Screen.VIEW_MNEMONIC)
} catch (e: Exception) {
onError("Authentication failed: ${e.message}")
onError(context.getString(R.string.err_auth_failed, e.message ?: ""))
}
},
onVerifyMnemonic = {
@@ -537,7 +541,7 @@ fun GajuRouter(
verifyMnemonicPhrase = phrase
navigateTo(Screen.VERIFY_MNEMONIC)
} catch (e: Exception) {
onError("Authentication failed: ${e.message}")
onError(context.getString(R.string.err_auth_failed, e.message ?: ""))
}
},
onRename = { newName ->
@@ -605,21 +609,22 @@ fun GajuRouter(
activeFetchJob = scope.launch {
try {
android.util.Log.i("GajuRouter", "Fetching GRIDS request from: ${result.url}")
val request = withContext(Dispatchers.IO) {
@Suppress("UNCHECKED_CAST")
val response = withContext(Dispatchers.IO) {
Http.get(result.url) as? Map<String, Any?>
}
if (request != null) {
pendingSignRequest = request
if (response != null) {
pendingSignRequest = response.toGridsSignRequest()
// Remove fetching screen and add request screen
screenStack.removeAt(screenStack.size - 1)
navigateTo(Screen.SIGN_REQUEST)
} else {
onError("Failed to fetch signature request.")
onError(context.getString(R.string.err_fetch_sig_failed))
navigateBack()
}
} catch (e: Exception) {
if (activeFetchJob?.isCancelled == false) {
onError("Fetch failed: ${e.message}")
onError(context.getString(R.string.err_fetch_failed, e.message ?: ""))
navigateBack()
}
} finally {
@@ -631,7 +636,7 @@ fun GajuRouter(
navigateTo(Screen.SEND_FORM)
}
} catch (e: Exception) {
onError("Invalid GRIDS URL: ${e.message}")
onError(context.getString(R.string.err_invalid_grids_url, e.message ?: ""))
}
},
onGenerate = { navigateTo(Screen.QR_RECEIVE) },
@@ -648,7 +653,7 @@ fun GajuRouter(
val activeAccount = activeWallet?.accounts?.getOrNull(activeAccountIndex)
if (activeAccount == null) {
onError("No active account selected.")
onError(context.getString(R.string.err_no_active_account))
navigateBack()
return
}
@@ -687,7 +692,7 @@ fun GajuRouter(
val activeAccount = activeWallet?.accounts?.getOrNull(activeAccountIndex)
if (activeAccount == null) {
onError("No active account selected.")
onError(context.getString(R.string.err_no_active_account))
navigateBack()
return
}
@@ -735,14 +740,14 @@ fun GajuRouter(
}
val hash = result["hash"] as? String ?: "Unknown"
onError("Transaction posted! Hash: $hash")
onError(context.getString(R.string.msg_tx_posted, hash))
// Success! Go back to dashboard
screenStack.clear()
screenStack.add(Screen.DASHBOARD)
} catch (e: Throwable) {
val msg = e.message ?: e.toString()
onError("Send failed: $msg")
onError(context.getString(R.string.err_send_failed, msg))
android.util.Log.e("GajuRouter", "Send failed", e)
}
}
@@ -756,29 +761,25 @@ fun GajuRouter(
val activeAccount = activeWallet?.accounts?.getOrNull(activeAccountIndex)
val request = pendingSignRequest ?: return
val type = request["type"] as? String ?: ""
val payload = request["payload"] as? String ?: ""
val publicId = request["public_id"] as? String
// If request specifies an ID, try to find that account
val signAccount = if (publicId != null && publicId != "false") {
wallets.flatMap { it.accounts }.find { it.gajuId == publicId }
val signAccount = if (request.publicId != null && request.publicId != "false") {
wallets.flatMap { it.accounts }.find { it.gajuId == request.publicId }
} else {
activeAccount
}
if (signAccount == null) {
onError("No matching account found for signature.")
onError(context.getString(R.string.err_no_matching_account))
navigateBack()
return
}
SignRequestScreen(
type = type,
request = request,
originUrl = pendingSignUrl,
accountLabel = signAccount.label,
accountId = signAccount.gajuId,
payload = payload,
onSign = {
scope.launch {
try {
@@ -786,30 +787,33 @@ fun GajuRouter(
val signedRequest = mutableMapOf<String, Any?>()
// Essential keys present in all GRIDS responses
signedRequest["grids"] = request["grids"]
signedRequest["chain"] = request["chain"]
signedRequest["network_id"] = request["network_id"]
signedRequest["type"] = type
signedRequest["grids"] = request.grids
signedRequest["chain"] = request.chain
signedRequest["network_id"] = request.networkId
signedRequest["type"] = request.type.toProtocolString()
signedRequest["public_id"] = signAccount.gajuId // Must be the actual ID string, never 'false'
when (type) {
"message" -> {
val sig = AccountAirlock.signMessage(signAccount.privateKeyEnvelope, masterKey, payload)
signedRequest["payload"] = payload
when (request.type) {
GridsSignType.MESSAGE -> {
val sig = AccountAirlock.signMessage(signAccount.privateKeyEnvelope, masterKey, request.payload)
signedRequest["payload"] = request.payload
signedRequest["signature"] = android.util.Base64.encodeToString(sig, android.util.Base64.NO_WRAP)
}
"binary" -> {
val binary = android.util.Base64.decode(payload, android.util.Base64.DEFAULT)
GridsSignType.BINARY -> {
val binary = android.util.Base64.decode(request.payload, android.util.Base64.DEFAULT)
val sig = AccountAirlock.signBinary(signAccount.privateKeyEnvelope, masterKey, binary)
signedRequest["payload"] = payload
signedRequest["payload"] = request.payload
signedRequest["signature"] = android.util.Base64.encodeToString(sig, android.util.Base64.NO_WRAP)
}
"tx" -> {
val nid = request["network_id"] as? String ?: activeWallet?.networkId ?: "groot.mainnet"
val txBinary = android.util.Base64.decode(payload, android.util.Base64.DEFAULT)
GridsSignType.TX -> {
val nid = request.networkId ?: activeWallet?.networkId ?: "groot.mainnet"
val txBinary = android.util.Base64.decode(request.payload, android.util.Base64.DEFAULT)
signedRequest["payload"] = AccountAirlock.signTx(signAccount.privateKeyEnvelope, masterKey, txBinary, nid)
signedRequest["signed"] = true
}
else -> {
throw Exception("Cannot sign unknown request type")
}
}
android.util.Log.i("GajuRouter", "POSTing GRIDS response to $pendingSignUrl")
@@ -817,12 +821,12 @@ fun GajuRouter(
Http.post(pendingSignUrl, signedRequest)
}
onError("Signature submitted successfully.")
onError(context.getString(R.string.msg_sig_submitted))
screenStack.clear()
screenStack.add(Screen.DASHBOARD)
} catch (e: Throwable) {
val msg = e.message ?: e.toString()
onError("Signing failed: $msg")
onError(context.getString(R.string.err_sig_failed, msg))
android.util.Log.e("GajuRouter", "Signing failed", e)
}
}
@@ -836,7 +840,7 @@ fun GajuRouter(
val activeAccount = activeWallet?.accounts?.getOrNull(activeAccountIndex)
if (activeAccount == null) {
onError("No active account selected.")
onError(context.getString(R.string.err_no_active_account))
navigateBack()
return
}
@@ -0,0 +1,51 @@
package swiss.qpq.gajumobile.data.models
import kotlinx.serialization.Serializable
@Serializable
enum class GridsSignType {
MESSAGE,
BINARY,
TX,
UNKNOWN;
companion object {
fun fromString(type: String?): GridsSignType = when (type) {
"message" -> MESSAGE
"binary" -> BINARY
"tx" -> TX
else -> UNKNOWN
}
}
fun toProtocolString(): String = when (this) {
MESSAGE -> "message"
BINARY -> "binary"
TX -> "tx"
UNKNOWN -> "unknown"
}
}
@Serializable
data class GridsSignRequest(
val type: GridsSignType,
val payload: String,
val publicId: String?,
val networkId: String?,
val grids: String?,
val chain: String?
)
/**
* Safely maps a raw Map (typically from ZJ.decode) to a typed GridsSignRequest.
*/
fun Map<String, Any?>.toGridsSignRequest(): GridsSignRequest {
return GridsSignRequest(
type = GridsSignType.fromString(this["type"] as? String),
payload = this["payload"] as? String ?: "",
publicId = this["public_id"] as? String,
networkId = this["network_id"] as? String,
grids = this["grids"] as? String,
chain = this["chain"] as? String
)
}
@@ -4,7 +4,6 @@ import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.UUID;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import swiss.qpq.gajumaru.core.crypto.Vault;
import swiss.qpq.gajumaru.core.encoding.Mnemonic;
import swiss.qpq.gajumaru.core.tools.CryptoUtils;
@@ -52,7 +51,6 @@ public final class AccountAirlock {
) throws Exception {
byte[] seed = null;
byte[] dekBytes = null;
try {
// 1. Decode mnemonic to seed
@@ -72,30 +70,15 @@ public final class AccountAirlock {
GajuNative.memzero(keypair);
// 3. Generate random Data Encryption Key (DEK)
SecureRandom random = new SecureRandom();
dekBytes = new byte[32];
random.nextBytes(dekBytes);
SecretKey dek = new SecretKeySpec(dekBytes, "AES");
// 4. Encrypt Private Key (seed) with DEK
Vault.Ciphertext dataCiphertext = Vault.encrypt(dek, seed);
// 5. Encrypt DEK with Master Key
Vault.Ciphertext dekCiphertext = Vault.encrypt(masterKey, dekBytes);
EncryptedEnvelope envelope = new EncryptedEnvelope(
dataCiphertext.getData(),
dekCiphertext.getData(),
dataCiphertext.getIv(),
dekCiphertext.getIv()
);
EncryptedEnvelope envelope = EncryptionService.encrypt(masterKey, seed);
String id = UUID.randomUUID().toString();
return new Account(id, label, publicKey, envelope, null);
} finally {
if (seed != null) GajuNative.memzero(seed);
if (dekBytes != null) CryptoUtils.wipe(dekBytes);
}
}
@@ -183,23 +166,7 @@ public final class AccountAirlock {
EncryptedEnvelope envelope,
SecretKey masterKey
) throws Exception {
byte[] plaintextDek = null;
try {
plaintextDek = Vault.decrypt(
masterKey,
envelope.getDekIv(),
envelope.getEncryptedDek()
);
SecretKey dek = new SecretKeySpec(plaintextDek, "AES");
return Vault.decrypt(
dek,
envelope.getDataIv(),
envelope.getEncryptedData()
);
} finally {
if (plaintextDek != null) CryptoUtils.wipe(plaintextDek);
}
return EncryptionService.decrypt(masterKey, envelope);
}
/**
@@ -8,6 +8,7 @@ import javax.crypto.KeyGenerator
import javax.crypto.SecretKey
import javax.crypto.spec.GCMParameterSpec
import javax.crypto.spec.SecretKeySpec
import swiss.qpq.gajumaru.core.tools.CryptoUtils
@Serializable
data class EncryptedEnvelope(
@@ -42,47 +43,87 @@ object EncryptionService {
private const val GCM_TAG_LENGTH = 128
private const val IV_LENGTH = 12
@JvmStatic
fun encrypt(context: Context, data: ByteArray): EncryptedEnvelope {
val masterKey = KeyManager.getMasterKey(context)
return encrypt(masterKey, data)
}
@JvmStatic
fun encrypt(masterKey: SecretKey, data: ByteArray): EncryptedEnvelope {
// 1. Generate a random Data Encryption Key (DEK) in software
val dek = generateDek()
val dekBytes = dek.encoded
// 2. Encrypt the data with the DEK
val dataCipher = Cipher.getInstance(AES_GCM)
val dataIv = ByteArray(IV_LENGTH).apply { SecureRandom().nextBytes(this) }
dataCipher.init(Cipher.ENCRYPT_MODE, dek, GCMParameterSpec(GCM_TAG_LENGTH, dataIv))
val encryptedData = dataCipher.doFinal(data)
try {
// 2. Encrypt the data with the DEK
val (encryptedData, dataIv) = encryptRaw(dek, data)
// 3. Encrypt the DEK with the Master Key (Hardware-backed)
val masterKey = KeyManager.getMasterKey(context)
val dekCipher = Cipher.getInstance(AES_GCM)
val dekIv = ByteArray(IV_LENGTH).apply { SecureRandom().nextBytes(this) }
// Now using manual IV for hardware key to ensure tag length consistency
dekCipher.init(Cipher.ENCRYPT_MODE, masterKey, GCMParameterSpec(GCM_TAG_LENGTH, dekIv))
val encryptedDek = dekCipher.doFinal(dek.encoded)
// 3. Encrypt the DEK with the Master Key (Hardware-backed)
val (encryptedDek, dekIv) = encryptRaw(masterKey, dekBytes)
return EncryptedEnvelope(
encryptedData = encryptedData,
encryptedDek = encryptedDek,
dataIv = dataIv,
dekIv = dekIv
)
return EncryptedEnvelope(
encryptedData = encryptedData,
encryptedDek = encryptedDek,
dataIv = dataIv,
dekIv = dekIv
)
} finally {
CryptoUtils.wipe(dekBytes)
}
}
@JvmStatic
fun decrypt(context: Context, envelope: EncryptedEnvelope): ByteArray {
// 1. Decrypt the DEK using the Master Key
val masterKey = KeyManager.getMasterKey(context)
val dekCipher = Cipher.getInstance(AES_GCM)
dekCipher.init(Cipher.DECRYPT_MODE, masterKey, GCMParameterSpec(GCM_TAG_LENGTH, envelope.dekIv))
val decryptedDekBytes = dekCipher.doFinal(envelope.encryptedDek)
val dek = SecretKeySpec(decryptedDekBytes, "AES")
// 2. Decrypt the data using the DEK
val dataCipher = Cipher.getInstance(AES_GCM)
dataCipher.init(Cipher.DECRYPT_MODE, dek, GCMParameterSpec(GCM_TAG_LENGTH, envelope.dataIv))
return dataCipher.doFinal(envelope.encryptedData)
return decrypt(masterKey, envelope)
}
private fun generateDek(): SecretKey {
@JvmStatic
fun decrypt(masterKey: SecretKey, envelope: EncryptedEnvelope): ByteArray {
var decryptedDekBytes: ByteArray? = null
try {
// 1. Decrypt the DEK using the Master Key
decryptedDekBytes = decryptRaw(masterKey, envelope.dekIv, envelope.encryptedDek)
val dek = SecretKeySpec(decryptedDekBytes, "AES")
// 2. Decrypt the data using the DEK
return decryptRaw(dek, envelope.dataIv, envelope.encryptedData)
} catch (e: Exception) {
val msg = e.message ?: e.toString()
throw Exception("EncryptionService.decrypt failed: $msg", e)
} finally {
if (decryptedDekBytes != null) CryptoUtils.wipe(decryptedDekBytes)
}
}
@JvmStatic
fun encryptRaw(key: SecretKey, data: ByteArray): Pair<ByteArray, ByteArray> {
try {
val cipher = Cipher.getInstance(AES_GCM)
val iv = ByteArray(IV_LENGTH).apply { SecureRandom().nextBytes(this) }
cipher.init(Cipher.ENCRYPT_MODE, key, GCMParameterSpec(GCM_TAG_LENGTH, iv))
val ciphertext = cipher.doFinal(data)
return ciphertext to iv
} catch (e: Exception) {
throw Exception("encryptRaw failed: ${e.message}", e)
}
}
@JvmStatic
fun decryptRaw(key: SecretKey, iv: ByteArray, encryptedData: ByteArray): ByteArray {
try {
val cipher = Cipher.getInstance(AES_GCM)
cipher.init(Cipher.DECRYPT_MODE, key, GCMParameterSpec(GCM_TAG_LENGTH, iv))
return cipher.doFinal(encryptedData)
} catch (e: Exception) {
val msg = e.message ?: e.toString()
throw Exception("decryptRaw failed [${e.javaClass.simpleName}]: $msg", e)
}
}
@JvmStatic
fun generateDek(): SecretKey {
val keyGen = KeyGenerator.getInstance("AES")
keyGen.init(256)
return keyGen.generateKey()
@@ -7,10 +7,8 @@ object GajuNative {
init {
try {
System.loadLibrary("gaju-native")
android.util.Log.i("GajuNative", "Native library loaded successfully.")
} catch (e: Throwable) {
loadError = e.message ?: e.toString()
android.util.Log.e("GajuNative", "Failed to load library: $loadError", e)
}
}
@@ -44,6 +44,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
@@ -130,7 +131,7 @@ fun GajuTopBar(
onDismissRequest = { menuExpanded = false }
) {
DropdownMenuItem(
text = { Text("Manage Wallets") },
text = { Text(stringResource(R.string.menu_manage_wallets)) },
onClick = {
menuExpanded = false
onNavigate("manage_wallets")
@@ -138,7 +139,7 @@ fun GajuTopBar(
leadingIcon = { Icon(painterResource(R.drawable.ic_account_box), null, modifier = Modifier.size(18.dp)) }
)
DropdownMenuItem(
text = { Text("Transactions") },
text = { Text(stringResource(R.string.menu_transactions)) },
onClick = {
menuExpanded = false
onNavigate("transactions")
@@ -146,7 +147,7 @@ fun GajuTopBar(
leadingIcon = { Icon(painterResource(R.drawable.gajumobile_icon), null, modifier = Modifier.size(18.dp), tint = Color.Unspecified) }
)
DropdownMenuItem(
text = { Text("Settings") },
text = { Text(stringResource(R.string.menu_settings)) },
onClick = {
menuExpanded = false
onNavigate("settings")
@@ -154,7 +155,7 @@ fun GajuTopBar(
leadingIcon = { Icon(painterResource(R.drawable.settings), null, modifier = Modifier.size(18.dp)) }
)
DropdownMenuItem(
text = { Text("Environment Info") },
text = { Text(stringResource(R.string.menu_environment_info)) },
onClick = {
menuExpanded = false
onNavigate("environment_info")
@@ -243,7 +244,7 @@ fun MnemonicReveal(
tint = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.6f),
)
Text(
text = "TAP TO REVEAL",
text = stringResource(R.string.tap_to_reveal),
color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.6f),
fontWeight = FontWeight.Bold,
)
@@ -294,7 +295,7 @@ fun SuccessLayout(
title: String,
content: @Composable ColumnScope.() -> Unit,
onProceed: () -> Unit,
proceedText: String = "Proceed to Dashboard",
proceedText: String = stringResource(R.string.proceed_to_dashboard),
) {
var checked by remember { mutableStateOf(value = false) }
@@ -322,7 +323,7 @@ fun SuccessLayout(
),
)
Text(
text = "I understand and fully assume the risks.",
text = stringResource(R.string.understand_risks_success_label),
color = MaterialTheme.colorScheme.onBackground,
fontSize = 14.sp,
modifier = Modifier.padding(start = 8.dp),
@@ -26,6 +26,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalClipboardManager
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
@@ -61,14 +62,14 @@ fun AccountNamingScreen(
) {
GajuHeader()
Text(
"Name your account",
stringResource(R.string.name_account_title),
style = MaterialTheme.typography.headlineMedium,
color = MaterialTheme.colorScheme.onBackground
)
Spacer(modifier = Modifier.height(24.dp))
Text(
"Account ID:",
stringResource(R.string.account_id_label),
style = MaterialTheme.typography.labelLarge,
color = MaterialTheme.colorScheme.onSurface
)
@@ -101,7 +102,7 @@ fun AccountNamingScreen(
) {
Icon(
painter = painterResource(id = R.drawable.ic_content_copy),
contentDescription = "Copy ID",
contentDescription = stringResource(R.string.copy_id_content_desc),
tint = MaterialTheme.colorScheme.primary,
modifier = Modifier.size(16.dp)
)
@@ -113,8 +114,8 @@ fun AccountNamingScreen(
GajuTextField(
value = name,
onValueChange = { name = it },
label = "Account Name",
placeholder = "Optional (defaults to ID)"
label = stringResource(R.string.account_name_label),
placeholder = stringResource(R.string.account_name_placeholder)
)
Spacer(modifier = Modifier.weight(1f))
@@ -122,7 +123,7 @@ fun AccountNamingScreen(
Row(modifier = Modifier.fillMaxWidth()) {
if (onBack != null) {
GajuButton(
text = "Back",
text = stringResource(R.string.back_button),
onClick = onBack,
modifier = Modifier.weight(1f),
containerColor = MaterialTheme.colorScheme.secondary,
@@ -131,7 +132,7 @@ fun AccountNamingScreen(
Spacer(modifier = Modifier.width(16.dp))
}
GajuButton(
text = "Finish",
text = stringResource(R.string.finish_button),
onClick = { onAccountNamed(name.ifBlank { publicKey }) },
modifier = Modifier.weight(1f)
)
@@ -22,8 +22,10 @@ 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.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import swiss.qpq.gajumobile.R
import swiss.qpq.gajumobile.ui.components.GajuButton
import swiss.qpq.gajumobile.ui.components.GajuHeader
import swiss.qpq.gajumobile.ui.components.GajuTextField
@@ -47,13 +49,13 @@ fun CreateWalletScreen(
GajuHeader()
Spacer(modifier = Modifier.height(32.dp))
Text(
"Create Wallet",
stringResource(R.string.create_wallet_title),
style = MaterialTheme.typography.headlineMedium,
color = MaterialTheme.colorScheme.onBackground
)
Spacer(modifier = Modifier.height(16.dp))
Text(
"A wallet is a collection of accounts, like a folder for your identities.",
stringResource(R.string.create_wallet_description),
style = MaterialTheme.typography.bodyMedium,
textAlign = TextAlign.Center,
color = MaterialTheme.colorScheme.onSurfaceVariant
@@ -63,15 +65,15 @@ fun CreateWalletScreen(
GajuTextField(
value = walletName,
onValueChange = { walletName = it },
label = "Wallet Name",
placeholder = "e.g. Personal, Savings",
label = stringResource(R.string.wallet_name_label),
placeholder = stringResource(R.string.wallet_name_placeholder),
singleLine = true
)
Spacer(modifier = Modifier.height(24.dp))
Text(
"NETWORK",
stringResource(R.string.network_label),
style = MaterialTheme.typography.labelMedium,
color = MaterialTheme.colorScheme.onBackground,
modifier = Modifier.align(Alignment.Start)
@@ -81,7 +83,10 @@ fun CreateWalletScreen(
modifier = Modifier.fillMaxWidth().padding(vertical = 12.dp),
horizontalArrangement = Arrangement.spacedBy(16.dp)
) {
listOf("groot.mainnet" to "Mainnet", "groot.testnet" to "Testnet").forEach { (id, label) ->
listOf(
"groot.mainnet" to stringResource(R.string.network_mainnet),
"groot.testnet" to stringResource(R.string.network_testnet)
).forEach { (id, label) ->
val isSelected = selectedNetwork == id
AssistChip(
onClick = { selectedNetwork = id },
@@ -99,7 +104,7 @@ fun CreateWalletScreen(
Row(modifier = Modifier.fillMaxWidth()) {
if (onBack != null) {
GajuButton(
text = "Back",
text = stringResource(R.string.back_button),
onClick = onBack,
modifier = Modifier.weight(1f),
containerColor = MaterialTheme.colorScheme.secondary,
@@ -108,7 +113,7 @@ fun CreateWalletScreen(
Spacer(modifier = Modifier.width(16.dp))
}
GajuButton(
text = "Continue",
text = stringResource(R.string.continue_button),
enabled = walletName.isNotBlank(),
onClick = { onWalletCreated(walletName, selectedNetwork) },
modifier = Modifier.weight(1f)
@@ -35,6 +35,7 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.ClipEntry
import androidx.compose.ui.platform.LocalClipboard
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
@@ -67,17 +68,17 @@ fun DashboardScreen(
if (wallets.isEmpty()) {
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
Column(horizontalAlignment = Alignment.CenterHorizontally) {
Text("No wallets found. Please create one.")
Text(stringResource(R.string.no_wallets_message))
Spacer(modifier = Modifier.height(16.dp))
ActionCircle(
text = "Create",
text = stringResource(R.string.create_button),
containerColor = MaterialTheme.colorScheme.primary,
contentColor = MaterialTheme.colorScheme.onPrimary,
onClick = { onNavigate("CREATE_WALLET") }
)
Spacer(modifier = Modifier.height(32.dp))
Text(
text = "If you created a wallet but don't see it, it may be corrupted.",
text = stringResource(R.string.wallets_corrupted_message),
style = MaterialTheme.typography.labelSmall,
color = MaterialTheme.colorScheme.error,
textAlign = TextAlign.Center,
@@ -86,7 +87,7 @@ fun DashboardScreen(
androidx.compose.material3.TextButton(
onClick = { onNavigate("WIPE_DATA") }
) {
Text("Wipe Broken Wallets", color = MaterialTheme.colorScheme.error)
Text(stringResource(R.string.wipe_broken_wallets_button), color = MaterialTheme.colorScheme.error)
}
}
}
@@ -95,6 +96,7 @@ fun DashboardScreen(
val clipboard = LocalClipboard.current
val scope = rememberCoroutineScope()
val accountIdLabel = stringResource(R.string.account_id_label_clipboard)
val walletPagerState = rememberPagerState(initialPage = selectedWalletIndex.coerceIn(0, wallets.size - 1)) { wallets.size }
// Sync pager state back to router
@@ -203,7 +205,7 @@ fun DashboardScreen(
text = {
Icon(
painter = painterResource(id = R.drawable.ic_add),
contentDescription = "Add Account",
contentDescription = stringResource(R.string.add_account_content_desc),
tint = MaterialTheme.colorScheme.primary,
modifier = Modifier.size(20.dp)
)
@@ -234,14 +236,14 @@ fun DashboardScreen(
IconButton(
onClick = {
scope.launch {
clipboard.setClipEntry(ClipEntry(ClipData.newPlainText("Account ID", account.gajuId)))
clipboard.setClipEntry(ClipEntry(ClipData.newPlainText(accountIdLabel, account.gajuId)))
}
},
modifier = Modifier.size(24.dp)
) {
Icon(
painter = painterResource(id = R.drawable.ic_content_copy),
contentDescription = "Copy ID",
contentDescription = stringResource(R.string.copy_id_content_desc),
tint = MaterialTheme.colorScheme.primary,
modifier = Modifier.size(16.dp)
)
@@ -264,9 +266,9 @@ fun DashboardScreen(
verticalAlignment = Alignment.CenterVertically,
) {
Column {
Text("BALANCE", color = MaterialTheme.colorScheme.onSurfaceVariant, fontSize = 14.sp)
Text(stringResource(R.string.balance_label), color = MaterialTheme.colorScheme.onSurfaceVariant, fontSize = 14.sp)
Text(
text = "ON ${currentWallet.networkId.uppercase()}",
text = stringResource(R.string.on_network_label, currentWallet.networkId.uppercase()),
style = MaterialTheme.typography.labelSmall,
color = MaterialTheme.colorScheme.primary.copy(alpha = 0.8f),
fontWeight = FontWeight.Bold
@@ -281,7 +283,7 @@ fun DashboardScreen(
) {
Icon(
painter = painterResource(id = R.drawable.ic_refresh),
contentDescription = "Refresh Balance",
contentDescription = stringResource(R.string.refresh_balance_content_desc),
tint = MaterialTheme.colorScheme.onSurfaceVariant,
modifier = Modifier.size(20.dp),
)
@@ -295,7 +297,7 @@ fun DashboardScreen(
) {
Icon(
painter = painterResource(id = R.drawable.settings),
contentDescription = "Account Settings",
contentDescription = stringResource(R.string.account_settings_content_desc),
tint = MaterialTheme.colorScheme.onSurfaceVariant,
modifier = Modifier.size(24.dp),
)
@@ -326,19 +328,19 @@ fun DashboardScreen(
horizontalArrangement = Arrangement.SpaceEvenly,
) {
ActionCircle(
text = "Send",
text = stringResource(R.string.send_action),
containerColor = MaterialTheme.colorScheme.secondary,
contentColor = MaterialTheme.colorScheme.onSecondary,
onClick = onSend,
)
ActionCircle(
text = "GRIDS",
text = stringResource(R.string.grids_action),
containerColor = MaterialTheme.colorScheme.tertiary,
contentColor = MaterialTheme.colorScheme.onTertiary,
onClick = onGrids,
)
ActionCircle(
text = "Receive",
text = stringResource(R.string.receive_action),
containerColor = MaterialTheme.colorScheme.primary,
contentColor = MaterialTheme.colorScheme.onPrimary,
onClick = onReceive,
@@ -28,10 +28,12 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
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.GajuButton
import swiss.qpq.gajumobile.ui.components.GajuHeader
@@ -42,6 +44,11 @@ fun DeleteConfirmationScreen(
onConfirm: () -> Unit,
onCancel: () -> Unit,
) {
val localizedType = when (type) {
"WALLET" -> stringResource(R.string.wallet)
"ACCOUNT" -> stringResource(R.string.account)
else -> type
}
Scaffold(
modifier = Modifier.fillMaxSize(),
bottomBar = {
@@ -52,7 +59,7 @@ fun DeleteConfirmationScreen(
.padding(24.dp),
) {
GajuButton(
text = "CANCEL",
text = stringResource(R.string.cancel),
onClick = onCancel,
modifier = Modifier.fillMaxWidth(),
containerColor = MaterialTheme.colorScheme.secondary,
@@ -60,7 +67,7 @@ fun DeleteConfirmationScreen(
)
Spacer(modifier = Modifier.height(16.dp))
GajuButton(
text = "CONFIRM\nDELETE",
text = stringResource(R.string.confirm_delete_button),
onClick = onConfirm,
modifier = Modifier.fillMaxWidth(),
containerColor = Color(0xFFF44336),
@@ -80,7 +87,7 @@ fun DeleteConfirmationScreen(
GajuHeader()
Text(
text = "DELETE $type",
text = stringResource(R.string.delete_type_title, localizedType),
color = MaterialTheme.colorScheme.onBackground,
fontSize = 20.sp,
fontWeight = FontWeight.Bold,
@@ -104,14 +111,14 @@ fun DeleteConfirmationScreen(
Spacer(modifier = Modifier.height(32.dp))
Text("Accounts within this wallet", color = MaterialTheme.colorScheme.onSurfaceVariant, fontSize = 14.sp)
Text(stringResource(R.string.accounts_within_this_wallet_label), color = MaterialTheme.colorScheme.onSurfaceVariant, fontSize = 14.sp)
// TODO: Use real account/balance if possible
Text("Daily account", color = MaterialTheme.colorScheme.onBackground, modifier = Modifier.padding(top = 16.dp))
Text(stringResource(R.string.daily_account_placeholder), color = MaterialTheme.colorScheme.onBackground, modifier = Modifier.padding(top = 16.dp))
Spacer(modifier = Modifier.height(32.dp))
Text(
text = "WARNING: Deleting a $type will delete all accounts within it.",
text = stringResource(R.string.delete_warning_message, localizedType),
color = MaterialTheme.colorScheme.error,
fontWeight = FontWeight.Bold,
fontSize = 12.sp,
@@ -119,15 +126,7 @@ fun DeleteConfirmationScreen(
)
Text(
text = """
To recover a deleted account, you will need your mnemonic phrase. Lost mnemonic phrases cannot be retrieved.
All funds within a lost account are also lost.
Back up your mnemonic phrases for every account before making any changes here to be safe.
This action cannot be undone.
""".trimIndent(),
text = stringResource(R.string.delete_risks_disclaimer),
color = MaterialTheme.colorScheme.onBackground,
fontSize = 12.sp,
textAlign = TextAlign.Center,
@@ -138,7 +137,7 @@ fun DeleteConfirmationScreen(
Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.clickable { checked = !checked }) {
Checkbox(checked = checked, onCheckedChange = { checked = it })
Text(
"I understand and assume all risks from this action. I would like to proceed.",
stringResource(R.string.understand_risks_checkbox),
fontSize = 12.sp,
color = MaterialTheme.colorScheme.onBackground,
)
@@ -14,7 +14,9 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import swiss.qpq.gajumobile.R
import swiss.qpq.gajumobile.ui.components.GajuButton
import swiss.qpq.gajumobile.ui.components.GajuHeader
import swiss.qpq.gajumobile.ui.components.SecurityDataSection
@@ -49,7 +51,7 @@ fun EnvironmentInfoScreen(
) {
GajuHeader()
Text(
"Environment Info",
stringResource(R.string.menu_environment_info),
style = MaterialTheme.typography.headlineMedium,
color = MaterialTheme.colorScheme.onBackground
)
@@ -57,43 +59,43 @@ fun EnvironmentInfoScreen(
Spacer(modifier = Modifier.height(24.dp))
SecurityDataSection(
title = "Security Hardware",
title = stringResource(R.string.security_hardware_title),
data = listOf(
"Keystore" to if (hasStrongBox) "StrongBox (Secure Element)" else "Hardware TEE",
"Auth Enforcement" to "OS Lock Required",
"Encryption" to "Hardware-Generated IVs"
stringResource(R.string.keystore_label) to if (hasStrongBox) stringResource(R.string.strongbox_label) else stringResource(R.string.hardware_tee_label),
stringResource(R.string.auth_enforcement_label) to stringResource(R.string.os_lock_required_label),
stringResource(R.string.encryption_label) to stringResource(R.string.hw_generated_ivs_label)
)
)
SecurityDataSection(
title = "Device Identity",
title = stringResource(R.string.device_identity_title),
data = listOf(
"Manufacturer" to android.os.Build.MANUFACTURER,
"Model" to android.os.Build.MODEL,
"Board" to android.os.Build.BOARD,
"Hardware" to android.os.Build.HARDWARE
stringResource(R.string.manufacturer_label) to android.os.Build.MANUFACTURER,
stringResource(R.string.model_label) to android.os.Build.MODEL,
stringResource(R.string.board_label) to android.os.Build.BOARD,
stringResource(R.string.hardware_label) to android.os.Build.HARDWARE
)
)
SecurityDataSection(
title = "System Build",
title = stringResource(R.string.system_build_title),
data = listOf(
"Android Version" to "${android.os.Build.VERSION.RELEASE} (API ${android.os.Build.VERSION.SDK_INT})",
"Security Patch" to android.os.Build.VERSION.SECURITY_PATCH,
"Fingerprint" to android.os.Build.FINGERPRINT
stringResource(R.string.android_version_label) to "${android.os.Build.VERSION.RELEASE} (API ${android.os.Build.VERSION.SDK_INT})",
stringResource(R.string.security_patch_label) to android.os.Build.VERSION.SECURITY_PATCH,
stringResource(R.string.fingerprint_label) to android.os.Build.FINGERPRINT
)
)
SecurityDataSection(
title = "GajuMobile",
data = listOf(
"App Version" to appVersion,
"Theme" to "Arboreal (Gajumaru)"
stringResource(R.string.app_version_label) to appVersion,
stringResource(R.string.theme_label) to stringResource(R.string.theme_name)
)
)
Spacer(modifier = Modifier.weight(1f))
GajuButton(text = "Done", onClick = onBack)
GajuButton(text = stringResource(R.string.done_button), onClick = onBack)
}
}
@@ -16,10 +16,9 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
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.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import swiss.qpq.gajumobile.R
import swiss.qpq.gajumobile.ui.components.GajuTopBar
@Composable
@@ -37,13 +36,13 @@ fun ExplorerScreen(
horizontalAlignment = Alignment.CenterHorizontally,
) {
Text(
text = "Transactions",
text = stringResource(R.string.explorer_title),
color = MaterialTheme.colorScheme.onBackground,
style = MaterialTheme.typography.headlineMedium,
modifier = Modifier.padding(vertical = 16.dp),
)
Text("Loading Groot", color = MaterialTheme.colorScheme.primary, fontStyle = androidx.compose.ui.text.font.FontStyle.Italic)
Text(stringResource(R.string.loading_groot), color = MaterialTheme.colorScheme.primary, fontStyle = androidx.compose.ui.text.font.FontStyle.Italic)
Spacer(modifier = Modifier.height(16.dp))
@@ -53,7 +52,7 @@ fun ExplorerScreen(
shape = RoundedCornerShape(4.dp),
) {
Box(contentAlignment = Alignment.Center) {
Text("Gaju Explorer Content", color = MaterialTheme.colorScheme.onSurfaceVariant)
Text(stringResource(R.string.explorer_content_placeholder), color = MaterialTheme.colorScheme.onSurfaceVariant)
}
}
}
@@ -1,15 +1,26 @@
package swiss.qpq.gajumobile.ui.screens
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
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.material3.CircularProgressIndicator
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
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.GajuButton
import swiss.qpq.gajumobile.ui.components.GajuHeader
@@ -43,7 +54,7 @@ fun FetchingScreen(
Spacer(modifier = Modifier.height(32.dp))
Text(
text = "RETRIEVING REQUEST",
text = stringResource(R.string.retrieving_request_title),
style = MaterialTheme.typography.headlineSmall,
color = MaterialTheme.colorScheme.onBackground,
fontWeight = FontWeight.Bold
@@ -52,7 +63,7 @@ fun FetchingScreen(
Spacer(modifier = Modifier.height(16.dp))
Text(
text = "Connecting to:",
text = stringResource(R.string.connecting_to_label),
style = MaterialTheme.typography.labelLarge,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
@@ -68,7 +79,7 @@ fun FetchingScreen(
Spacer(modifier = Modifier.weight(1f))
GajuButton(
text = "CANCEL",
text = stringResource(R.string.cancel),
onClick = onCancel,
modifier = Modifier.fillMaxWidth(),
containerColor = MaterialTheme.colorScheme.secondary,
@@ -17,6 +17,7 @@ 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.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
@@ -47,14 +48,14 @@ fun LockScreen(
)
Spacer(modifier = Modifier.height(48.dp))
Text(
text = "App Locked",
text = stringResource(R.string.app_locked_title),
color = MaterialTheme.colorScheme.onBackground,
fontSize = 24.sp,
fontWeight = FontWeight.Bold,
)
Spacer(modifier = Modifier.height(16.dp))
Text(
text = "Please authenticate to continue.",
text = stringResource(R.string.auth_request_message),
color = MaterialTheme.colorScheme.onBackground.copy(alpha = 0.7f),
fontSize = 16.sp,
)
@@ -72,7 +73,7 @@ fun LockScreen(
Spacer(modifier = Modifier.height(48.dp))
Button(onClick = onUnlockRequest) {
Text("Unlock")
Text(stringResource(R.string.unlock_button))
}
}
}
@@ -36,6 +36,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.ClipEntry
import androidx.compose.ui.platform.LocalClipboard
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
@@ -62,6 +63,7 @@ fun ManageAccountScreen(
) {
val clipboard = LocalClipboard.current
val scope = rememberCoroutineScope()
val accountIdLabel = stringResource(R.string.account_id_label_clipboard)
var showRenameDialog by remember { mutableStateOf(value = false) }
var newName by remember(account.label) { mutableStateOf(value = account.label) }
@@ -73,21 +75,21 @@ fun ManageAccountScreen(
tonalElevation = 8.dp
) {
Column(modifier = Modifier.padding(24.dp)) {
Text("Rename Account", style = MaterialTheme.typography.headlineSmall)
Text(stringResource(R.string.rename_account_title), style = MaterialTheme.typography.headlineSmall)
Spacer(modifier = Modifier.height(16.dp))
GajuTextField(
value = newName,
onValueChange = { newName = it },
label = "New Name"
label = stringResource(R.string.new_name_label)
)
Spacer(modifier = Modifier.height(24.dp))
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.End) {
TextButton(onClick = { showRenameDialog = false }) { Text("CANCEL") }
TextButton(onClick = { showRenameDialog = false }) { Text(stringResource(R.string.cancel)) }
Spacer(modifier = Modifier.width(8.dp))
TextButton(onClick = {
onRename(newName)
showRenameDialog = false
}) { Text("SAVE") }
}) { Text(stringResource(R.string.save_button_caps)) }
}
}
}
@@ -105,12 +107,12 @@ fun ManageAccountScreen(
horizontalAlignment = Alignment.CenterHorizontally,
) {
if (isUnverified) {
ManageAction(label = "Verify mnemonic backup", icon = R.drawable.ic_check_circle, onClick = onVerifyMnemonic)
ManageAction(label = stringResource(R.string.verify_mnemonic_backup_action), icon = R.drawable.ic_check_circle, onClick = onVerifyMnemonic)
Spacer(modifier = Modifier.height(8.dp))
}
ManageAction(label = "View mnemonic phrase", icon = R.drawable.ic_visibility, onClick = onViewMnemonic)
ManageAction(label = stringResource(R.string.view_mnemonic_phrase_action), icon = R.drawable.ic_visibility, onClick = onViewMnemonic)
Spacer(modifier = Modifier.height(8.dp))
ManageAction(label = "Delete this account", icon = R.drawable.ic_delete, isDestructive = true, onClick = onDelete)
ManageAction(label = stringResource(R.string.delete_this_account_action), icon = R.drawable.ic_delete, isDestructive = true, onClick = onDelete)
}
},
) { innerPadding ->
@@ -125,7 +127,7 @@ fun ManageAccountScreen(
GajuHeader()
Text(
text = "Manage Account",
text = stringResource(R.string.manage_account_title),
color = MaterialTheme.colorScheme.onBackground,
style = MaterialTheme.typography.headlineMedium,
modifier = Modifier.padding(vertical = 16.dp),
@@ -175,7 +177,7 @@ fun ManageAccountScreen(
Spacer(modifier = Modifier.height(24.dp))
Text(
text = "Account ID:",
text = stringResource(R.string.account_id_label),
style = MaterialTheme.typography.labelSmall,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
@@ -197,14 +199,14 @@ fun ManageAccountScreen(
IconButton(
onClick = {
scope.launch {
clipboard.setClipEntry(ClipEntry(ClipData.newPlainText("Account ID", account.gajuId)))
clipboard.setClipEntry(ClipEntry(ClipData.newPlainText(accountIdLabel, account.gajuId)))
}
},
modifier = Modifier.size(24.dp)
) {
Icon(
painter = painterResource(id = R.drawable.ic_content_copy),
contentDescription = "Copy ID",
contentDescription = stringResource(R.string.copy_id_content_desc),
tint = MaterialTheme.colorScheme.primary,
modifier = Modifier.size(16.dp)
)
@@ -32,6 +32,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
@@ -74,10 +75,10 @@ fun ManageWalletsScreen(
tonalElevation = 8.dp,
) {
Column(modifier = Modifier.padding(24.dp)) {
Text("Node Status", style = MaterialTheme.typography.headlineSmall)
Text(stringResource(R.string.node_status_title), style = MaterialTheme.typography.headlineSmall)
Spacer(modifier = Modifier.height(16.dp))
if (statusError != null) {
Text("Error: $statusError", color = MaterialTheme.colorScheme.error)
Text(stringResource(R.string.error_with_value, statusError), color = MaterialTheme.colorScheme.error)
} else if (statusResult != null) {
val scrollState = rememberScrollState()
Column(modifier = Modifier.height(300.dp).verticalScroll(scrollState)) {
@@ -91,7 +92,7 @@ fun ManageWalletsScreen(
}
Spacer(modifier = Modifier.height(24.dp))
TextButton(onClick = onClearStatus, modifier = Modifier.align(Alignment.End)) {
Text("CLOSE")
Text(stringResource(R.string.close_button_caps))
}
}
}
@@ -106,23 +107,23 @@ fun ManageWalletsScreen(
tonalElevation = 8.dp,
) {
Column(modifier = Modifier.padding(24.dp)) {
Text("Rename Wallet", style = MaterialTheme.typography.headlineSmall)
Text(stringResource(R.string.rename_wallet_title), style = MaterialTheme.typography.headlineSmall)
Spacer(modifier = Modifier.height(16.dp))
GajuTextField(
value = newName,
onValueChange = { newName = it },
label = "New Name",
label = stringResource(R.string.new_name_label),
)
Spacer(modifier = Modifier.height(24.dp))
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.End) {
TextButton(onClick = { walletToRename = null }) { Text("CANCEL") }
TextButton(onClick = { walletToRename = null }) { Text(stringResource(R.string.cancel)) }
Spacer(modifier = Modifier.width(8.dp))
TextButton(
onClick = {
walletToRename?.let { onRenameWallet(it.id, newName) }
walletToRename = null
}
) { Text("SAVE") }
) { Text(stringResource(R.string.save_button_caps)) }
}
}
}
@@ -138,12 +139,12 @@ fun ManageWalletsScreen(
tonalElevation = 8.dp,
) {
Column(modifier = Modifier.padding(24.dp)) {
Text("Add Endpoint", style = MaterialTheme.typography.headlineSmall)
Text(stringResource(R.string.add_endpoint_title), style = MaterialTheme.typography.headlineSmall)
Spacer(modifier = Modifier.height(16.dp))
GajuTextField(
value = newHost,
onValueChange = { newHost = it },
label = "Host (IP or Domain)",
label = stringResource(R.string.host_label),
singleLine = true,
placeholder = placeholderHost,
)
@@ -151,7 +152,7 @@ fun ManageWalletsScreen(
GajuTextField(
value = newPort,
onValueChange = { newPort = it },
label = "Port",
label = stringResource(R.string.port_label),
singleLine = true,
placeholder = "3013"
)
@@ -162,11 +163,11 @@ fun ManageWalletsScreen(
onCheckedChange = { newUseTls = it }
)
Spacer(Modifier.width(12.dp))
Text("Use TLS (HTTPS)", style = MaterialTheme.typography.bodyMedium)
Text(stringResource(R.string.use_tls_label), style = MaterialTheme.typography.bodyMedium)
}
Spacer(modifier = Modifier.height(24.dp))
Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.End) {
TextButton(onClick = { walletForNewEndpoint = null }) { Text("CANCEL") }
TextButton(onClick = { walletForNewEndpoint = null }) { Text(stringResource(R.string.cancel)) }
Spacer(modifier = Modifier.width(8.dp))
TextButton(
enabled = (newHost.isNotBlank() && newPort.toIntOrNull() != null),
@@ -180,7 +181,7 @@ fun ManageWalletsScreen(
newPort = "3013"
newUseTls = false
}
) { Text("ADD") }
) { Text(stringResource(R.string.add_button_caps)) }
}
}
}
@@ -199,7 +200,7 @@ fun ManageWalletsScreen(
) {
GajuHeader()
Text(
"Manage Wallets",
stringResource(R.string.manage_wallets_title),
style = MaterialTheme.typography.headlineMedium,
color = MaterialTheme.colorScheme.onBackground
)
@@ -240,7 +241,7 @@ fun ManageWalletsScreen(
Spacer(modifier = Modifier.height(24.dp))
ManageAction(
label = "Add new wallet",
label = stringResource(R.string.add_new_wallet_action),
icon = R.drawable.ic_add,
onClick = onAddWallet
)
@@ -248,7 +249,7 @@ fun ManageWalletsScreen(
Spacer(modifier = Modifier.height(32.dp))
TextButton(onClick = onBack) {
Text("Done")
Text(stringResource(R.string.done_button))
}
}
}
@@ -292,7 +293,7 @@ private fun WalletManagementCard(
IconButton(onClick = onDelete) {
Icon(
painter = painterResource(id = R.drawable.ic_delete),
contentDescription = "Delete Wallet",
contentDescription = stringResource(R.string.delete_wallet_content_desc),
tint = MaterialTheme.colorScheme.error,
modifier = Modifier.size(20.dp),
)
@@ -302,7 +303,7 @@ private fun WalletManagementCard(
Spacer(modifier = Modifier.height(16.dp))
Text(
text = "NETWORK ENDPOINTS",
text = stringResource(R.string.network_endpoints_label),
style = MaterialTheme.typography.labelSmall,
color = MaterialTheme.colorScheme.primary.copy(alpha = 0.7f)
)
@@ -332,7 +333,7 @@ private fun WalletManagementCard(
if (wallet.endpoints.size > 1) {
Icon(
painter = painterResource(id = R.drawable.ic_delete),
contentDescription = "Remove Endpoint",
contentDescription = stringResource(R.string.remove_endpoint_content_desc),
modifier = Modifier.size(16.dp).clickable { onDeleteEndpoint(index) },
tint = MaterialTheme.colorScheme.error.copy(alpha = 0.6f)
)
@@ -347,7 +348,7 @@ private fun WalletManagementCard(
) {
Icon(painterResource(R.drawable.ic_check_circle), null, modifier = Modifier.size(14.dp))
Spacer(Modifier.width(6.dp))
Text("CHECK STATUS", fontSize = 10.sp, fontWeight = FontWeight.Bold)
Text(stringResource(R.string.check_status_button_caps), fontSize = 10.sp, fontWeight = FontWeight.Bold)
}
}
}
@@ -359,13 +360,13 @@ private fun WalletManagementCard(
) {
Icon(painterResource(R.drawable.ic_add), null, modifier = Modifier.size(14.dp))
Spacer(Modifier.width(4.dp))
Text("ADD ENDPOINT", fontSize = 11.sp)
Text(stringResource(R.string.add_endpoint_button_caps), fontSize = 11.sp)
}
HorizontalDivider(modifier = Modifier.padding(vertical = 8.dp), color = MaterialTheme.colorScheme.outlineVariant.copy(alpha = 0.5f))
Text(
text = "${wallet.accounts.size} account(s)",
text = stringResource(R.string.accounts_count_label, wallet.accounts.size),
style = MaterialTheme.typography.labelSmall,
color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.6f),
)
@@ -34,7 +34,9 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import swiss.qpq.gajumobile.R
import swiss.qpq.gajumobile.security.AccountAirlock
import swiss.qpq.gajumobile.ui.components.CommittedWordChip
import swiss.qpq.gajumobile.ui.components.GajuButton
@@ -98,7 +100,7 @@ fun MnemonicRecoveryScreen(
horizontalArrangement = Arrangement.SpaceBetween
) {
GajuButton(
text = "BACK",
text = stringResource(R.string.back_button_caps),
onClick = onBack,
modifier = Modifier.weight(1f),
containerColor = MaterialTheme.colorScheme.secondary,
@@ -106,7 +108,7 @@ fun MnemonicRecoveryScreen(
)
Spacer(modifier = Modifier.width(16.dp))
GajuButton(
text = "RECOVER",
text = stringResource(R.string.recover_button_caps),
enabled = committedWords.size >= 21 && !isAddingWord,
onClick = {
val phrase = committedWords.map { it.toByteArray(Charsets.UTF_8) }.toTypedArray()
@@ -127,14 +129,14 @@ fun MnemonicRecoveryScreen(
) {
GajuHeader()
Text(
"RECOVER ACCOUNT",
stringResource(R.string.recover_account_title),
style = MaterialTheme.typography.headlineMedium,
color = MaterialTheme.colorScheme.onBackground
)
Spacer(modifier = Modifier.height(16.dp))
Text(
"Mnemonic Phrase:",
stringResource(R.string.mnemonic_phrase_label),
style = MaterialTheme.typography.labelLarge,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
@@ -171,7 +173,7 @@ fun MnemonicRecoveryScreen(
} else if (committedWords.size < 23) {
AssistChip(
onClick = { isAddingWord = true },
label = { Text("+ NEXT WORD") },
label = { Text(stringResource(R.string.add_next_word_button)) },
colors = AssistChipDefaults.assistChipColors(
containerColor = MaterialTheme.colorScheme.primaryContainer,
labelColor = MaterialTheme.colorScheme.onPrimaryContainer
@@ -34,7 +34,9 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import swiss.qpq.gajumobile.R
import swiss.qpq.gajumobile.security.AccountAirlock
import swiss.qpq.gajumobile.ui.components.CommittedWordChip
import swiss.qpq.gajumobile.ui.components.GajuButton
@@ -102,7 +104,7 @@ fun MnemonicVerifyScreen(
horizontalArrangement = Arrangement.SpaceBetween
) {
GajuButton(
text = "BACK",
text = stringResource(R.string.back_button_caps),
onClick = onBack,
modifier = Modifier.weight(1f),
containerColor = MaterialTheme.colorScheme.secondary,
@@ -110,7 +112,7 @@ fun MnemonicVerifyScreen(
)
Spacer(modifier = Modifier.width(16.dp))
GajuButton(
text = "VERIFY",
text = stringResource(R.string.verify_button_caps),
enabled = committedWords.size == expectedPhrase.size && !isAddingWord,
onClick = {
val inputPhrase = committedWords.map { it.toByteArray(Charsets.UTF_8) }
@@ -143,7 +145,7 @@ fun MnemonicVerifyScreen(
) {
GajuHeader()
Text(
"VERIFY BACKUP",
stringResource(R.string.verify_backup_title),
style = MaterialTheme.typography.headlineMedium,
color = MaterialTheme.colorScheme.onBackground
)
@@ -185,7 +187,7 @@ fun MnemonicVerifyScreen(
} else if (committedWords.size < expectedPhrase.size) {
AssistChip(
onClick = { isAddingWord = true },
label = { Text("+ NEXT WORD") },
label = { Text(stringResource(R.string.add_next_word_button)) },
colors = AssistChipDefaults.assistChipColors(
containerColor = MaterialTheme.colorScheme.primaryContainer,
labelColor = MaterialTheme.colorScheme.onPrimaryContainer
@@ -197,7 +199,7 @@ fun MnemonicVerifyScreen(
if (verificationError) {
Spacer(modifier = Modifier.height(16.dp))
Text(
"Mnemonic phrase does not match. Please check again.",
stringResource(R.string.err_mnemonic_mismatch),
color = MaterialTheme.colorScheme.error,
style = MaterialTheme.typography.bodySmall
)
@@ -44,6 +44,7 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import kotlinx.coroutines.launch
import androidx.compose.ui.res.stringResource
import swiss.qpq.gajumobile.R
import swiss.qpq.gajumobile.ui.components.GajuButton
import swiss.qpq.gajumobile.ui.components.GajuHeader
@@ -65,6 +66,7 @@ fun QRReceiveScreen(
var isGenerated by remember { mutableStateOf(value = false) }
val clipboard = LocalClipboard.current
val scope = rememberCoroutineScope()
val gridsUrlLabel = stringResource(R.string.grids_url_label_clipboard)
val amountPucks = remember(amountStr) {
try {
@@ -110,7 +112,7 @@ fun QRReceiveScreen(
.padding(24.dp),
) {
GajuButton(
text = if (isGenerated) "EDIT" else "BACK",
text = if (isGenerated) stringResource(id = R.string.edit_button_caps) else stringResource(id = R.string.back_button_caps),
onClick = { if (isGenerated) isGenerated = false else onDone() },
modifier = Modifier.weight(1f),
containerColor = MaterialTheme.colorScheme.secondary,
@@ -118,7 +120,7 @@ fun QRReceiveScreen(
)
Spacer(modifier = Modifier.width(16.dp))
GajuButton(
text = if (isGenerated) "DONE" else "GENERATE",
text = if (isGenerated) stringResource(id = R.string.done_button_caps) else stringResource(id = R.string.generate_button_caps),
onClick = { if (isGenerated) onDone() else isGenerated = true },
modifier = Modifier.weight(1f),
)
@@ -137,7 +139,7 @@ fun QRReceiveScreen(
GajuHeader()
Text(
text = if (isGenerated) "TRANSFER REQUEST" else "RECEIVE",
text = if (isGenerated) stringResource(id = R.string.transfer_request_title) else stringResource(id = R.string.receive_title),
color = MaterialTheme.colorScheme.onBackground,
fontSize = 24.sp,
fontWeight = FontWeight.Bold,
@@ -147,7 +149,7 @@ fun QRReceiveScreen(
if (!isGenerated) {
// Input Phase
Column(modifier = Modifier.fillMaxWidth()) {
Text("RECIPIENT", color = MaterialTheme.colorScheme.onSurfaceVariant, fontSize = 14.sp)
Text(stringResource(id = R.string.recipient_label), color = MaterialTheme.colorScheme.onSurfaceVariant, fontSize = 14.sp)
Spacer(modifier = Modifier.height(4.dp))
Surface(
color = MaterialTheme.colorScheme.surfaceVariant,
@@ -178,8 +180,8 @@ fun QRReceiveScreen(
GajuTextField(
value = amountStr,
onValueChange = { amountStr = it },
label = "REQUESTED AMOUNT (OPTIONAL)",
placeholder = "0.0",
label = stringResource(id = R.string.requested_amount_label),
placeholder = stringResource(id = R.string.requested_amount_placeholder),
modifier = Modifier.fillMaxWidth(),
trailingIcon = { Text(unitLabel, color = MaterialTheme.colorScheme.primary, fontWeight = FontWeight.Bold, fontSize = 12.sp) },
singleLine = true,
@@ -190,8 +192,8 @@ fun QRReceiveScreen(
GajuTextField(
value = payload,
onValueChange = { payload = it },
label = "PAYLOAD / MESSAGE (OPTIONAL)",
placeholder = "Add a note...",
label = stringResource(id = R.string.payload_optional_label),
placeholder = stringResource(id = R.string.payload_optional_placeholder),
modifier = Modifier.fillMaxWidth(),
)
} else {
@@ -202,7 +204,7 @@ fun QRReceiveScreen(
.background(MaterialTheme.colorScheme.surfaceVariant, RoundedCornerShape(12.dp))
.padding(16.dp),
) {
DetailRow(label = "RECIPIENT", value = account.label)
DetailRow(label = stringResource(id = R.string.recipient_label), value = account.label)
Text(
text = account.gajuId,
color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.7f),
@@ -213,13 +215,13 @@ fun QRReceiveScreen(
modifier = Modifier.padding(vertical = 8.dp),
color = MaterialTheme.colorScheme.outlineVariant.copy(alpha = 0.5f),
)
DetailRow(label = "AMOUNT", value = formattedAmount)
DetailRow(label = stringResource(id = R.string.amount_label), value = formattedAmount)
if (payload.isNotBlank()) {
HorizontalDivider(
modifier = Modifier.padding(vertical = 8.dp),
color = MaterialTheme.colorScheme.outlineVariant.copy(alpha = 0.5f),
)
DetailRow(label = "MESSAGE", value = payload)
DetailRow(label = stringResource(id = R.string.message_label), value = payload)
}
}
@@ -236,7 +238,7 @@ fun QRReceiveScreen(
} else {
Icon(
painter = painterResource(id = R.drawable.ic_qr_code),
contentDescription = "QR Code",
contentDescription = stringResource(id = R.string.qr_code_content_desc),
modifier = Modifier.size(180.dp),
tint = Color.Black.copy(alpha = 0.1f),
)
@@ -252,18 +254,18 @@ fun QRReceiveScreen(
horizontalArrangement = Arrangement.SpaceBetween,
) {
Text(
text = "GRIDS URL",
text = stringResource(id = R.string.grids_url_label),
color = MaterialTheme.colorScheme.onSurfaceVariant,
fontSize = 14.sp,
)
Icon(
painter = painterResource(id = R.drawable.ic_content_copy),
contentDescription = "Copy URL",
contentDescription = stringResource(id = R.string.copy_url_content_desc),
modifier = Modifier
.size(20.dp)
.clickable {
scope.launch {
clipboard.setClipEntry(ClipEntry(ClipData.newPlainText("GRIDS URL", generatedUrl)))
clipboard.setClipEntry(ClipEntry(ClipData.newPlainText(gridsUrlLabel, generatedUrl)))
}
},
tint = MaterialTheme.colorScheme.primary,
@@ -286,7 +288,7 @@ fun QRReceiveScreen(
Spacer(modifier = Modifier.height(24.dp))
Text(
text = "Scan to send to this account",
text = stringResource(id = R.string.scan_to_send_hint),
color = MaterialTheme.colorScheme.onBackground,
fontSize = 14.sp,
fontWeight = FontWeight.Light,
@@ -30,6 +30,7 @@ import androidx.compose.ui.unit.sp
import com.google.mlkit.vision.barcode.common.Barcode
import com.google.mlkit.vision.codescanner.GmsBarcodeScanning
import com.google.mlkit.vision.codescanner.GmsBarcodeScannerOptions
import androidx.compose.ui.res.stringResource
import swiss.qpq.gajumobile.R
import swiss.qpq.gajumobile.ui.components.GajuHeader
import swiss.qpq.gajumobile.ui.components.ScannerAction
@@ -75,7 +76,7 @@ fun QRScannerScreen(
GajuHeader()
Text(
text = "SCAN QR",
text = stringResource(id = R.string.scan_qr_title),
color = MaterialTheme.colorScheme.onBackground,
fontSize = 20.sp,
fontWeight = FontWeight.Light,
@@ -103,7 +104,7 @@ fun QRScannerScreen(
)
Spacer(modifier = Modifier.height(16.dp))
Text(
text = "TAP TO SCAN",
text = stringResource(id = R.string.tap_to_scan),
color = MaterialTheme.colorScheme.primary,
fontWeight = FontWeight.Bold,
fontSize = 16.sp,
@@ -114,7 +115,7 @@ fun QRScannerScreen(
Spacer(modifier = Modifier.weight(0.5f))
GajuButton(
text = "MANUAL ENTRY",
text = stringResource(id = R.string.manual_entry_button),
onClick = onManualEntry,
modifier = Modifier.padding(horizontal = 48.dp),
)
@@ -127,9 +128,9 @@ fun QRScannerScreen(
.padding(bottom = 48.dp),
horizontalArrangement = Arrangement.SpaceEvenly,
) {
ScannerAction(label = "Back", icon = R.drawable.ic_home, onClick = onBack)
ScannerAction(label = "Generate QR", icon = R.drawable.ic_qr_code, onClick = onGenerate)
ScannerAction(label = "Upload QR", icon = R.drawable.ic_qr_code, onClick = onUpload)
ScannerAction(label = stringResource(id = R.string.back_action), icon = R.drawable.ic_home, onClick = onBack)
ScannerAction(label = stringResource(id = R.string.generate_qr_action), icon = R.drawable.ic_qr_code, onClick = onGenerate)
ScannerAction(label = stringResource(id = R.string.upload_qr_action), icon = R.drawable.ic_qr_code, onClick = onUpload)
}
}
}
@@ -32,6 +32,8 @@ 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 androidx.compose.ui.res.stringResource
import swiss.qpq.gajumobile.R
import swiss.qpq.gajumobile.ui.components.GajuButton
import swiss.qpq.gajumobile.ui.components.GajuHeader
import swiss.qpq.gajumobile.ui.components.GajuTextField
@@ -66,7 +68,7 @@ fun SendFormScreen(
.padding(24.dp),
) {
GajuButton(
text = "BACK",
text = stringResource(id = R.string.back_button_caps),
onClick = onBack,
modifier = Modifier.weight(1f),
containerColor = MaterialTheme.colorScheme.secondary,
@@ -74,7 +76,7 @@ fun SendFormScreen(
)
Spacer(modifier = Modifier.width(16.dp))
GajuButton(
text = "REVIEW",
text = stringResource(id = R.string.review_button_caps),
onClick = { onReview(toAddress, amount, payload, gas, gasPrice, ttl) },
modifier = Modifier.weight(1f),
enabled = toAddress.isNotBlank() && amount.isNotBlank(),
@@ -94,7 +96,7 @@ fun SendFormScreen(
GajuHeader()
Text(
text = "SEND",
text = stringResource(id = R.string.send_title),
color = MaterialTheme.colorScheme.onBackground,
fontSize = 24.sp,
fontWeight = FontWeight.Bold,
@@ -103,7 +105,7 @@ fun SendFormScreen(
// 0. Sender Account (Read-only)
Column(modifier = Modifier.fillMaxWidth()) {
Text("SENDING FROM", color = MaterialTheme.colorScheme.onSurfaceVariant, fontSize = 14.sp)
Text(stringResource(id = R.string.sending_from_label), color = MaterialTheme.colorScheme.onSurfaceVariant, fontSize = 14.sp)
Spacer(modifier = Modifier.height(4.dp))
Surface(
color = MaterialTheme.colorScheme.surfaceVariant,
@@ -118,7 +120,7 @@ fun SendFormScreen(
fontSize = 16.sp,
)
Text(
text = "Balance: ${fromAccount.formattedBalance(balanceFormat, balanceUnit)}",
text = stringResource(id = R.string.balance_with_value, fromAccount.formattedBalance(balanceFormat, balanceUnit)),
color = MaterialTheme.colorScheme.onSurfaceVariant,
fontSize = 14.sp,
fontWeight = FontWeight.Medium,
@@ -139,8 +141,8 @@ fun SendFormScreen(
GajuTextField(
value = toAddress,
onValueChange = { toAddress = it },
label = "RECIPIENT ACCOUNT",
placeholder = "ak_...",
label = stringResource(id = R.string.recipient_account_label),
placeholder = stringResource(id = R.string.recipient_account_placeholder),
modifier = Modifier.fillMaxWidth(),
singleLine = true,
)
@@ -152,8 +154,8 @@ fun SendFormScreen(
GajuTextField(
value = amount,
onValueChange = { amount = it },
label = "AMOUNT",
placeholder = "0.0",
label = stringResource(id = R.string.amount_label),
placeholder = stringResource(id = R.string.amount_placeholder),
modifier = Modifier.fillMaxWidth(),
trailingIcon = { Text(unitLabel, color = MaterialTheme.colorScheme.primary, fontWeight = FontWeight.Bold, fontSize = 12.sp) },
singleLine = true,
@@ -165,15 +167,15 @@ fun SendFormScreen(
GajuTextField(
value = payload,
onValueChange = { payload = it },
label = "PAYLOAD / MESSAGE",
placeholder = "Optional message...",
label = stringResource(id = R.string.payload_label),
placeholder = stringResource(id = R.string.payload_placeholder),
modifier = Modifier.fillMaxWidth(),
)
Spacer(modifier = Modifier.height(24.dp))
Text(
text = if (showAdvanced) "HIDE DETAILS" else "SHOW DETAILS",
text = if (showAdvanced) stringResource(id = R.string.hide_details) else stringResource(id = R.string.show_details),
color = MaterialTheme.colorScheme.primary,
fontWeight = FontWeight.Bold,
fontSize = 14.sp,
@@ -191,7 +193,7 @@ fun SendFormScreen(
GajuTextField(
value = gas,
onValueChange = { gas = it },
label = "GAS",
label = stringResource(id = R.string.gas_label),
modifier = Modifier.fillMaxWidth(),
singleLine = true,
)
@@ -203,7 +205,7 @@ fun SendFormScreen(
GajuTextField(
value = gasPrice,
onValueChange = { gasPrice = it },
label = "GAS PRICE",
label = stringResource(id = R.string.gas_price_label),
modifier = Modifier.weight(1f),
singleLine = true,
)
@@ -212,7 +214,7 @@ fun SendFormScreen(
GajuTextField(
value = ttl,
onValueChange = { ttl = it },
label = "TTL",
label = stringResource(id = R.string.ttl_label),
modifier = Modifier.weight(1f),
singleLine = true,
)
@@ -32,6 +32,8 @@ 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 androidx.compose.ui.res.stringResource
import swiss.qpq.gajumobile.R
import swiss.qpq.gajumobile.ui.components.GajuButton
import swiss.qpq.gajumobile.ui.components.GajuHeader
@@ -61,7 +63,7 @@ fun SendReviewScreen(
) {
Checkbox(checked = confirmed, onCheckedChange = { confirmed = it })
Text(
"I confirm that the above details are correct and I would like to proceed.",
stringResource(id = R.string.confirm_details_checkbox),
fontSize = 12.sp,
color = MaterialTheme.colorScheme.onBackground,
)
@@ -69,7 +71,7 @@ fun SendReviewScreen(
Row(modifier = Modifier.fillMaxWidth()) {
GajuButton(
text = "BACK",
text = stringResource(id = R.string.back_button_caps),
onClick = onBack,
modifier = Modifier.weight(1f),
containerColor = MaterialTheme.colorScheme.secondary,
@@ -77,7 +79,7 @@ fun SendReviewScreen(
)
Spacer(modifier = Modifier.width(16.dp))
GajuButton(
text = "SEND",
text = stringResource(id = R.string.send_button_caps),
onClick = onSend,
modifier = Modifier.weight(1f),
enabled = confirmed,
@@ -98,19 +100,19 @@ fun SendReviewScreen(
GajuHeader()
Text(
text = "REVIEW SEND",
text = stringResource(id = R.string.review_send_title),
color = MaterialTheme.colorScheme.onBackground,
fontSize = 24.sp,
fontWeight = FontWeight.Bold,
modifier = Modifier.padding(vertical = 16.dp),
)
Text("SENDING FROM", color = MaterialTheme.colorScheme.onSurfaceVariant, fontSize = 12.sp)
Text(stringResource(id = R.string.sending_from_label), color = MaterialTheme.colorScheme.onSurfaceVariant, fontSize = 12.sp)
Text(senderLabel, color = MaterialTheme.colorScheme.primary, fontWeight = FontWeight.Bold)
Spacer(modifier = Modifier.height(16.dp))
Text("SENDING TO", color = MaterialTheme.colorScheme.onSurfaceVariant, fontSize = 12.sp)
Text(stringResource(id = R.string.sending_to_label), color = MaterialTheme.colorScheme.onSurfaceVariant, fontSize = 12.sp)
Text(recipientLabel, fontWeight = FontWeight.Bold, color = MaterialTheme.colorScheme.onBackground)
Text(
text = recipientId,
@@ -128,14 +130,14 @@ fun SendReviewScreen(
shape = RoundedCornerShape(16.dp),
) {
Column(modifier = Modifier.padding(24.dp), horizontalAlignment = Alignment.CenterHorizontally) {
Text("You are sending a payment of", fontSize = 14.sp, color = MaterialTheme.colorScheme.onSurfaceVariant)
Text(stringResource(id = R.string.payment_summary_prefix), fontSize = 14.sp, color = MaterialTheme.colorScheme.onSurfaceVariant)
Text(amountStr, fontSize = 24.sp, fontWeight = FontWeight.Bold, color = MaterialTheme.colorScheme.primary)
Text("to", fontSize = 14.sp, color = MaterialTheme.colorScheme.onSurfaceVariant)
Text(stringResource(id = R.string.payment_summary_to), fontSize = 14.sp, color = MaterialTheme.colorScheme.onSurfaceVariant)
Text(recipientId.take(12) + "...", fontSize = 12.sp, color = MaterialTheme.colorScheme.onSurfaceVariant)
Spacer(modifier = Modifier.height(16.dp))
Text("THIS ACTION CANNOT BE UNDONE.", fontWeight = FontWeight.ExtraBold, color = MaterialTheme.colorScheme.error)
Text("Are you sure you want to proceed?", fontStyle = androidx.compose.ui.text.font.FontStyle.Italic, color = MaterialTheme.colorScheme.onSurfaceVariant)
Text(stringResource(id = R.string.cannot_be_undone_warning), fontWeight = FontWeight.ExtraBold, color = MaterialTheme.colorScheme.error)
Text(stringResource(id = R.string.proceed_confirmation_question), fontStyle = androidx.compose.ui.text.font.FontStyle.Italic, color = MaterialTheme.colorScheme.onSurfaceVariant)
}
}
}
@@ -1,8 +1,12 @@
package swiss.qpq.gajumobile.ui.screens
import android.app.LocaleManager
import android.os.LocaleList
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ExperimentalLayoutApi
import androidx.compose.foundation.layout.FlowRow
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
@@ -30,7 +34,9 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
@@ -39,12 +45,18 @@ import swiss.qpq.gajumobile.R
import swiss.qpq.gajumobile.ui.components.GajuTopBar
import swiss.qpq.gajumaru.core.formatting.GajuFormat
@OptIn(ExperimentalLayoutApi::class)
@Composable
fun SettingsScreen(
balanceFormat: GajuFormat.Type,
onFormatChange: (GajuFormat.Type) -> 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
Scaffold(
topBar = { GajuTopBar(onNavigate = onNavigate) },
) { innerPadding ->
@@ -57,7 +69,7 @@ fun SettingsScreen(
horizontalAlignment = Alignment.CenterHorizontally,
) {
Text(
text = "Settings",
text = stringResource(R.string.settings_title),
color = MaterialTheme.colorScheme.onBackground,
style = MaterialTheme.typography.headlineMedium,
modifier = Modifier.padding(vertical = 16.dp),
@@ -78,7 +90,7 @@ fun SettingsScreen(
shape = RoundedCornerShape(8.dp),
) {
Text(
text = "DISPLAY PREFERENCES",
text = stringResource(R.string.display_preferences),
textAlign = TextAlign.Center,
color = MaterialTheme.colorScheme.onSurfaceVariant,
modifier = Modifier.padding(16.dp),
@@ -88,7 +100,7 @@ fun SettingsScreen(
Spacer(modifier = Modifier.height(24.dp))
Text(
text = "BALANCE FORMAT",
text = stringResource(R.string.balance_format),
style = MaterialTheme.typography.labelMedium,
color = MaterialTheme.colorScheme.onBackground,
modifier = Modifier.align(Alignment.Start)
@@ -111,6 +123,42 @@ fun SettingsScreen(
}
}
Spacer(modifier = Modifier.height(16.dp))
Text(
text = stringResource(R.string.select_language),
style = MaterialTheme.typography.labelMedium,
color = MaterialTheme.colorScheme.onBackground,
modifier = Modifier.align(Alignment.Start)
)
FlowRow(
modifier = Modifier.fillMaxWidth().padding(vertical = 16.dp),
horizontalArrangement = Arrangement.spacedBy(8.dp),
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
val languages = listOf(
"en" to R.string.lang_en,
"ja" to R.string.lang_ja,
"de" to R.string.lang_de,
"fr" to R.string.lang_fr,
"it" to R.string.lang_it
)
languages.forEach { (tag, nameRes) ->
val isSelected = currentLanguage == tag
AssistChip(
onClick = {
localeManager.applicationLocales = LocaleList.forLanguageTags(tag)
},
label = { Text(stringResource(nameRes)) },
colors = AssistChipDefaults.assistChipColors(
containerColor = if (isSelected) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.surfaceVariant,
labelColor = if (isSelected) MaterialTheme.colorScheme.onPrimary else MaterialTheme.colorScheme.onSurfaceVariant
)
)
}
}
Spacer(modifier = Modifier.weight(1f))
var showWipeConfirm by remember { mutableStateOf(false) }
@@ -126,12 +174,12 @@ fun SettingsScreen(
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
"WIPE ALL DATA?",
stringResource(R.string.wipe_data_confirm_title),
fontWeight = FontWeight.Bold,
color = MaterialTheme.colorScheme.onErrorContainer
)
Text(
"This will permanently delete all wallets, accounts, and keys. This action cannot be undone.",
stringResource(R.string.wipe_data_confirm_message),
style = MaterialTheme.typography.bodySmall,
textAlign = TextAlign.Center,
color = MaterialTheme.colorScheme.onErrorContainer,
@@ -145,13 +193,13 @@ fun SettingsScreen(
onClick = { showWipeConfirm = false },
colors = ButtonDefaults.outlinedButtonColors(contentColor = MaterialTheme.colorScheme.onErrorContainer)
) {
Text("CANCEL")
Text(stringResource(R.string.cancel))
}
androidx.compose.material3.Button(
onClick = { onNavigate("WIPE_DATA") },
colors = ButtonDefaults.buttonColors(containerColor = MaterialTheme.colorScheme.error)
) {
Text("WIPE EVERYTHING")
Text(stringResource(R.string.wipe_everything))
}
}
}
@@ -169,7 +217,7 @@ fun SettingsScreen(
modifier = Modifier.size(18.dp)
)
Spacer(modifier = Modifier.width(8.dp))
Text("WIPE ALL DATA")
Text(stringResource(R.string.wipe_all_data))
}
}
@@ -18,6 +18,7 @@ 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.res.stringResource
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
@@ -50,7 +51,7 @@ fun SetupChoiceScreen(
Spacer(modifier = Modifier.height(48.dp))
GajuButton(
text = "Create Account",
text = stringResource(R.string.create_account_button),
onClick = onCreate,
containerColor = MaterialTheme.colorScheme.primary,
contentColor = MaterialTheme.colorScheme.onPrimary,
@@ -59,7 +60,7 @@ fun SetupChoiceScreen(
Spacer(modifier = Modifier.height(16.dp))
GajuButton(
text = "Recover Account",
text = stringResource(R.string.recover_account_button),
onClick = onRecover,
containerColor = MaterialTheme.colorScheme.secondary,
contentColor = MaterialTheme.colorScheme.onSecondary,
@@ -68,7 +69,7 @@ fun SetupChoiceScreen(
Spacer(modifier = Modifier.height(24.dp))
Text(
text = "To recover an existing account, you will need your mnemonic phrase.",
text = stringResource(R.string.recover_mnemonic_hint),
color = MaterialTheme.colorScheme.onSurfaceVariant,
fontSize = 12.sp,
textAlign = TextAlign.Center,
@@ -78,7 +79,7 @@ fun SetupChoiceScreen(
if (onBack != null) {
Spacer(modifier = Modifier.height(32.dp))
TextButton(onClick = onBack) {
Text("Cancel")
Text(stringResource(R.string.cancel))
}
}
}
@@ -1,28 +1,45 @@
package swiss.qpq.gajumobile.ui.screens
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
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.heightIn
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.*
import androidx.compose.runtime.*
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
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.data.models.GridsSignRequest
import swiss.qpq.gajumobile.data.models.GridsSignType
import swiss.qpq.gajumobile.ui.components.GajuButton
import swiss.qpq.gajumobile.ui.components.GajuHeader
@Composable
fun SignRequestScreen(
type: String,
request: GridsSignRequest,
originUrl: String,
accountLabel: String,
accountId: String,
payload: String,
onSign: () -> Unit,
onCancel: () -> Unit,
) {
@@ -36,7 +53,7 @@ fun SignRequestScreen(
.padding(24.dp)
) {
GajuButton(
text = "CANCEL",
text = stringResource(R.string.cancel),
onClick = onCancel,
modifier = Modifier.weight(1f),
containerColor = MaterialTheme.colorScheme.secondary,
@@ -44,7 +61,7 @@ fun SignRequestScreen(
)
Spacer(modifier = Modifier.width(16.dp))
GajuButton(
text = "SIGN",
text = stringResource(R.string.sign_button_caps),
onClick = onSign,
modifier = Modifier.weight(1f),
)
@@ -70,11 +87,11 @@ fun SignRequestScreen(
// function name, and args. This would be significantly more robust to abuse than
// the current "TX signature request" where the TX internals are opaque.
Text(
text = when (type) {
"message" -> "MESSAGE SIGNATURE REQUEST"
"binary" -> "BINARY DATA SIGNATURE REQUEST"
"tx" -> "TRANSACTION SIGNATURE REQUEST"
else -> "SIGNATURE REQUEST"
text = when (request.type) {
GridsSignType.MESSAGE -> stringResource(R.string.msg_sig_req)
GridsSignType.BINARY -> stringResource(R.string.bin_sig_req)
GridsSignType.TX -> stringResource(R.string.tx_sig_req)
else -> stringResource(R.string.generic_sig_req)
},
color = MaterialTheme.colorScheme.onBackground,
fontSize = 20.sp,
@@ -84,7 +101,7 @@ fun SignRequestScreen(
)
Text(
"The server at the URL below is requesting you sign the following.",
stringResource(R.string.sig_req_description),
fontSize = 12.sp,
color = MaterialTheme.colorScheme.onSurfaceVariant,
textAlign = TextAlign.Center
@@ -92,22 +109,22 @@ fun SignRequestScreen(
Spacer(modifier = Modifier.height(24.dp))
SectionLabel("SIGNATURE ACCOUNT")
SectionLabel(stringResource(R.string.sig_account_label))
Text(accountLabel, color = MaterialTheme.colorScheme.primary, fontWeight = FontWeight.Bold)
Text(accountId, fontSize = 10.sp, color = MaterialTheme.colorScheme.onSurfaceVariant, fontFamily = androidx.compose.ui.text.font.FontFamily.Monospace)
Spacer(modifier = Modifier.height(16.dp))
SectionLabel("ORIGINATING URL")
SectionLabel(stringResource(R.string.originating_url_label))
Text(originUrl, fontSize = 10.sp, color = MaterialTheme.colorScheme.onSurfaceVariant, textAlign = TextAlign.Center)
Spacer(modifier = Modifier.height(24.dp))
SectionLabel(when (type) {
"message" -> "MESSAGE"
"binary" -> "BASE-64 DATA"
"tx" -> "TRANSACTION DATA"
else -> "PAYLOAD"
SectionLabel(when (request.type) {
GridsSignType.MESSAGE -> stringResource(R.string.payload_type_message)
GridsSignType.BINARY -> stringResource(R.string.payload_type_base64)
GridsSignType.TX -> stringResource(R.string.payload_type_tx)
else -> stringResource(R.string.payload_type_generic)
})
Surface(
@@ -116,7 +133,7 @@ fun SignRequestScreen(
shape = RoundedCornerShape(8.dp),
) {
Text(
text = payload,
text = request.payload,
modifier = Modifier.padding(16.dp).verticalScroll(rememberScrollState()),
fontSize = 12.sp,
fontFamily = androidx.compose.ui.text.font.FontFamily.Monospace,
@@ -5,12 +5,13 @@ import androidx.compose.foundation.layout.height
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.res.stringResource
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.SuccessLayout
@Composable
@@ -18,23 +19,23 @@ fun TransactionSuccessScreen(
onExit: () -> Unit,
) {
SuccessLayout(
title = "SEND",
proceedText = "EXIT",
title = stringResource(R.string.send_title),
proceedText = stringResource(R.string.exit_button_caps),
onProceed = onExit,
content = {
Text("Transaction Successful!", color = MaterialTheme.colorScheme.primary, fontWeight = FontWeight.Bold)
Text(stringResource(R.string.transaction_success_title), color = MaterialTheme.colorScheme.primary, fontWeight = FontWeight.Bold)
Spacer(modifier = Modifier.height(32.dp))
Text("You have successfully sent a payment of", fontSize = 14.sp, color = MaterialTheme.colorScheme.onBackground)
Text(stringResource(R.string.transaction_success_payment_prefix), fontSize = 14.sp, color = MaterialTheme.colorScheme.onBackground)
Text("木 22,980.78991", fontSize = 24.sp, fontWeight = FontWeight.Bold, color = MaterialTheme.colorScheme.primary)
Text("to", fontSize = 14.sp, color = MaterialTheme.colorScheme.onBackground)
Text(stringResource(R.string.transaction_success_to), fontSize = 14.sp, color = MaterialTheme.colorScheme.onBackground)
Text("ak_9jzm...", fontSize = 12.sp, color = MaterialTheme.colorScheme.onBackground)
Spacer(modifier = Modifier.height(32.dp))
Text("The amount has been subtracted from the DAILY account in your PRIMARY WALLET.", textAlign = TextAlign.Center, fontSize = 12.sp, color = MaterialTheme.colorScheme.onBackground)
Text(stringResource(R.string.transaction_success_subtracted_msg), textAlign = TextAlign.Center, fontSize = 12.sp, color = MaterialTheme.colorScheme.onBackground)
Spacer(modifier = Modifier.height(32.dp))
Text("You can track this transaction on-chain here.", fontSize = 12.sp, color = MaterialTheme.colorScheme.onBackground)
Text("VIEW TRANSACTION ON-CHAIN", color = MaterialTheme.colorScheme.primary, fontWeight = FontWeight.Bold, fontSize = 12.sp)
Text(stringResource(R.string.transaction_success_track_hint), fontSize = 12.sp, color = MaterialTheme.colorScheme.onBackground)
Text(stringResource(R.string.view_transaction_on_chain), color = MaterialTheme.colorScheme.primary, fontWeight = FontWeight.Bold, fontSize = 12.sp)
},
)
}
+1
View File
@@ -0,0 +1 @@
unqualifiedResLocale=en
+249
View File
@@ -0,0 +1,249 @@
<resources>
<string name="app_name">GajuMobile</string>
<string name="settings_title">Einstellungen</string>
<string name="display_preferences">ANZEIGEEINSTELLUNGEN</string>
<string name="balance_format">SALDOFORMAT</string>
<string name="wipe_data_confirm_title">ALLE DATEN LÖSCHEN?</string>
<string name="wipe_data_confirm_message">Dies wird alle Wallets, Konten und Schlüssel dauerhaft löschen. Diese Aktion kann nicht rückgängig gemacht werden.</string>
<string name="cancel">ABBRECHEN</string>
<string name="wipe_everything">ALLES LÖSCHEN</string>
<string name="wipe_all_data">ALLE DATEN LÖSCHEN</string>
<string name="select_language">SPRACHE WÄHLEN</string>
<string name="lang_en">English</string>
<string name="lang_ja">日本語 (Japanisch)</string>
<string name="lang_de">Deutsch</string>
<string name="lang_fr">Français (Französisch)</string>
<string name="lang_it">Italiano (Italienisch)</string>
<!-- General / Shared -->
<string name="menu_manage_wallets">Wallets verwalten</string>
<string name="menu_transactions">Transaktionen</string>
<string name="menu_settings">Einstellungen</string>
<string name="menu_environment_info">Umgebungsinformationen</string>
<string name="tap_to_reveal">ZUM ANZEIGEN TIPPEN</string>
<string name="add_next_word_button">+ NÄCHSTES WORT</string>
<string name="exit_button_caps">BEENDEN</string>
<string name="proceed_to_dashboard">Zum Dashboard weiterleiten</string>
<string name="err_generate_account">Konto konnte nicht erstellt werden: %1$s</string>
<string name="err_recover_account">Konto konnte nicht wiederhergestellt werden: %1$s</string>
<string name="err_refresh_failed">Aktualisierung fehlgeschlagen. Prüfen Sie die Netzwerk-Endpunkte.</string>
<string name="msg_endpoint_verified">Endpunkt verifiziert und hinzugefügt.</string>
<string name="err_auth_failed">Authentifizierung fehlgeschlagen: %1$s</string>
<string name="msg_tx_posted">Transaktion gepostet! Hash: %1$s</string>
<string name="err_send_failed">Senden fehlgeschlagen: %1$s</string>
<string name="msg_sig_submitted">Signatur erfolgreich übermittelt.</string>
<string name="err_sig_failed">Signatur fehlgeschlagen: %1$s</string>
<string name="err_no_active_account">Kein aktives Konto ausgewählt.</string>
<string name="err_no_matching_account">Kein passendes Konto für Signatur gefunden.</string>
<string name="err_fetch_sig_failed">Signaturanfrage konnte nicht abgerufen werden.</string>
<string name="err_fetch_failed">Abruf fehlgeschlagen: %1$s</string>
<string name="err_invalid_grids_url">Ungültige GRIDS-URL: %1$s</string>
<string name="err_network_mismatch_added">Netzwerk-Abweichung: Knoten meldet \'%1$s\'. Zu Wallet \'%2$s\' hinzugefügt.</string>
<string name="err_critical_mismatch_create">KRITISCHE ABWEICHUNG: Knoten meldet \'%1$s\', aber Wallet ist \'%2$s\'. Bitte erstellen Sie zuerst eine Wallet für \'%1$s\'.</string>
<string name="err_network_mismatch_moved">Netzwerk-Abweichung: Knoten meldet \'%1$s\'. Zu Wallet \'%2$s\' verschoben.</string>
<string name="err_critical_mismatch_fix">KRITISCHE ABWEICHUNG: Knoten meldet \'%1$s\', aber Wallet ist für \'%2$s\' konfiguriert. Korrigieren Sie diesen Endpunkt, sonst wird er aus dieser Wallet entfernt.</string>
<!-- SignRequestScreen -->
<string name="msg_sig_req">NACHRICHTEN-SIGNATURANFRAGE</string>
<string name="bin_sig_req">BINÄRDATEN-SIGNATURANFRAGE</string>
<string name="tx_sig_req">TRANSAKTIONS-SIGNATURANFRAGE</string>
<string name="generic_sig_req">SIGNATURANFRAGE</string>
<string name="sig_req_description">Der Server unter der folgenden URL bittet Sie, Folgendes zu signieren.</string>
<string name="sig_account_label">SIGNATUR-KONTO</string>
<string name="originating_url_label">URSPRÜNGLICHE URL</string>
<string name="sign_button_caps">SIGNIEREN</string>
<string name="payload_type_message">NACHRICHT</string>
<string name="payload_type_base64">BASE-64 DATEN</string>
<string name="payload_type_tx">TRANSAKTIONSDATEN</string>
<string name="payload_type_generic">PAYLOAD</string>
<!-- EnvironmentInfoScreen -->
<string name="security_hardware_title">Sicherheits-Hardware</string>
<string name="keystore_label">Keystore</string>
<string name="strongbox_label">StrongBox (Sicheres Element)</string>
<string name="hardware_tee_label">Hardware-TEE</string>
<string name="auth_enforcement_label">Authentifizierungs-Erzwingung</string>
<string name="os_lock_required_label">OS-Sperre erforderlich</string>
<string name="encryption_label">Verschlüsselung</string>
<string name="hw_generated_ivs_label">Hardware-generierte IVs</string>
<string name="device_identity_title">Geräteidentität</string>
<string name="manufacturer_label">Hersteller</string>
<string name="model_label">Modell</string>
<string name="board_label">Board</string>
<string name="hardware_label">Hardware</string>
<string name="system_build_title">System-Build</string>
<string name="android_version_label">Android-Version</string>
<string name="security_patch_label">Sicherheitspatch</string>
<string name="fingerprint_label">Fingerabdruck</string>
<string name="app_version_label">App-Version</string>
<string name="theme_label">Thema</string>
<string name="theme_name">Arboreal (Gajumaru)</string>
<!-- DashboardScreen -->
<string name="no_wallets_message">Keine Wallets gefunden. Bitte erstelle eine.</string>
<string name="create_button">Erstellen</string>
<string name="wallets_corrupted_message">Wenn du eine Wallet erstellt hast, sie aber nicht siehst, ist sie möglicherweise beschädigt.</string>
<string name="wipe_broken_wallets_button">Beschädigte Wallets löschen</string>
<string name="balance_label">SALDO</string>
<string name="on_network_label">AUF %1$s</string>
<string name="refresh_balance_content_desc">Saldo aktualisieren</string>
<string name="account_settings_content_desc">Kontoeinstellungen</string>
<string name="send_action">Senden</string>
<string name="grids_action">GRIDS</string>
<string name="receive_action">Empfangen</string>
<string name="add_account_content_desc">Konto hinzufügen</string>
<string name="copy_id_content_desc">ID kopieren</string>
<!-- CreateWalletScreen -->
<string name="create_wallet_title">Wallet erstellen</string>
<string name="create_wallet_description">Eine Wallet ist eine Sammlung von Konten, wie ein Ordner für deine Identitäten.</string>
<string name="wallet_name_label">Wallet-Name</string>
<string name="wallet_name_placeholder">z.B. Privat, Ersparnisse</string>
<string name="network_label">NETZWERK</string>
<string name="back_button">Zurück</string>
<string name="continue_button">Weiter</string>
<string name="network_mainnet">Mainnet</string>
<string name="network_testnet">Testnet</string>
<!-- ExplorerScreen -->
<string name="explorer_title">Transaktionen</string>
<string name="loading_groot">Groot wird geladen</string>
<string name="explorer_content_placeholder">Gaju Explorer Inhalt</string>
<!-- SetupChoiceScreen -->
<string name="create_account_button">Konto erstellen</string>
<string name="recover_account_button">Konto wiederherstellen</string>
<string name="recover_mnemonic_hint">Um ein bestehendes Konto wiederherzustellen, benötigst du deine mnemonische Phrase.</string>
<!-- Mnemonic Screens -->
<string name="recover_button_caps">WIEDERHERSTELLEN</string>
<string name="recover_account_title">KONTO WIEDERHERSTELLEN</string>
<string name="mnemonic_phrase_label">Mnemonic-Phrase:</string>
<string name="verify_button_caps">VERIFIZIEREN</string>
<string name="verify_backup_title">BACKUP VERIFIZIEREN</string>
<string name="err_mnemonic_mismatch">Mnemonic-Phrase stimmt nicht überein. Bitte erneut prüfen.</string>
<!-- AccountNamingScreen -->
<string name="name_account_title">Benenne dein Konto</string>
<string name="account_id_label">Konto-ID:</string>
<string name="account_name_label">Kontoname</string>
<string name="account_name_placeholder">Optional (Standard ist die ID)</string>
<string name="finish_button">Fertigstellen</string>
<!-- LockScreen -->
<string name="app_locked_title">App gesperrt</string>
<string name="auth_request_message">Bitte authentifiziere dich, um fortzufahren.</string>
<string name="unlock_button">Entsperren</string>
<!-- FetchingScreen -->
<string name="retrieving_request_title">ANFRAGE WIRD ABRUFEN</string>
<string name="connecting_to_label">Verbindung zu:</string>
<!-- SendFormScreen -->
<string name="send_title">SENDEN</string>
<string name="sending_from_label">SENDEN VON</string>
<string name="balance_with_value">Saldo: %1$s</string>
<string name="recipient_account_label">EMPFÄNGERKONTO</string>
<string name="recipient_account_placeholder">ak_...</string>
<string name="amount_label">BETRAG</string>
<string name="amount_placeholder">0.0</string>
<string name="payload_label">PAYLOAD / NACHRICHT</string>
<string name="payload_placeholder">Optionale Nachricht...</string>
<string name="show_details">DETAILS ANZEIGEN</string>
<string name="hide_details">DETAILS AUSBLENDEN</string>
<string name="gas_label">GAS</string>
<string name="gas_price_label">GASPREIS</string>
<string name="ttl_label">TTL</string>
<string name="back_button_caps">ZURÜCK</string>
<string name="review_button_caps">PRÜFEN</string>
<!-- SendReviewScreen -->
<string name="review_send_title">SENDEN PRÜFEN</string>
<string name="sending_to_label">SENDEN AN</string>
<string name="confirm_details_checkbox">Ich bestätige, dass die oben genannten Details korrekt sind und ich fortfahren möchte.</string>
<string name="send_button_caps">SENDEN</string>
<string name="payment_summary_prefix">Sie senden eine Zahlung von</string>
<string name="payment_summary_to">an</string>
<string name="cannot_be_undone_warning">DIESE AKTION KANN NICHT RÜCKGÄNGIG GEMACHT WERDEN.</string>
<string name="proceed_confirmation_question">Sind Sie sicher, dass Sie fortfahren möchten?</string>
<!-- TransactionSuccessScreen -->
<string name="transaction_success_title">Transaktion erfolgreich!</string>
<string name="transaction_success_payment_prefix">Sie haben erfolgreich eine Zahlung gesendet von</string>
<string name="transaction_success_to">an</string>
<string name="transaction_success_subtracted_msg">Der Betrag wurde vom TÄGLICHEN Konto in Ihrer PRIMÄREN WALLET abgezogen.</string>
<string name="transaction_success_track_hint">Sie können diese Transaktion hier on-chain verfolgen.</string>
<string name="view_transaction_on_chain">TRANSAKTION ON-CHAIN ANZEIGEN</string>
<string name="understand_risks_success_label">Ich verstehe und übernehme alle Risiken.</string>
<!-- QRScannerScreen -->
<string name="scan_qr_title">QR SCANNEN</string>
<string name="tap_to_scan">ZUM SCANNEN TIPPEN</string>
<string name="manual_entry_button">MANUELLE EINGABE</string>
<string name="generate_qr_action">QR-Code generieren</string>
<string name="upload_qr_action">QR-Code hochladen</string>
<string name="back_action">Zurück</string>
<!-- QRReceiveScreen -->
<string name="transfer_request_title">TRANSFERANFRAGE</string>
<string name="receive_title">EMPFANGEN</string>
<string name="recipient_label">EMPFÄNGER</string>
<string name="requested_amount_label">ANGEFORDERTER BETRAG (OPTIONAL)</string>
<string name="requested_amount_placeholder">0.0</string>
<string name="payload_optional_label">PAYLOAD / NACHRICHT (OPTIONAL)</string>
<string name="payload_optional_placeholder">Notiz hinzufügen...</string>
<string name="edit_button_caps">BEARBEITEN</string>
<string name="done_button_caps">FERTIG</string>
<string name="generate_button_caps">GENERIEREN</string>
<string name="message_label">NACHRICHT</string>
<string name="qr_code_content_desc">QR-Code</string>
<string name="grids_url_label">GRIDS URL</string>
<string name="copy_url_content_desc">URL kopieren</string>
<string name="scan_to_send_hint">Scannen, um an dieses Konto zu senden</string>
<!-- Clipboard -->
<string name="account_id_label_clipboard">Konto-ID</string>
<string name="grids_url_label_clipboard">GRIDS-URL</string>
<!-- ManageAccountScreen -->
<string name="manage_account_title">Konto verwalten</string>
<string name="rename_account_title">Konto umbenennen</string>
<string name="new_name_label">Neuer Name</string>
<string name="save_button_caps">SPEICHERN</string>
<string name="verify_mnemonic_backup_action">Mnemonic-Backup verifizieren</string>
<string name="view_mnemonic_phrase_action">Mnemonic-Phrase anzeigen</string>
<string name="delete_this_account_action">Dieses Konto löschen</string>
<!-- ManageWalletsScreen -->
<string name="manage_wallets_title">Wallets verwalten</string>
<string name="node_status_title">Knotenstatus</string>
<string name="error_with_value">Fehler: %1$s</string>
<string name="close_button_caps">SCHLIESSEN</string>
<string name="rename_wallet_title">Wallet umbenennen</string>
<string name="add_endpoint_title">Endpunkt hinzufügen</string>
<string name="host_label">Host (IP oder Domain)</string>
<string name="port_label">Port</string>
<string name="use_tls_label">TLS verwenden (HTTPS)</string>
<string name="add_button_caps">HINZUFÜGEN</string>
<string name="delete_wallet_content_desc">Wallet löschen</string>
<string name="network_endpoints_label">NETZWERK-ENDPUNKTE</string>
<string name="remove_endpoint_content_desc">Endpunkt entfernen</string>
<string name="check_status_button_caps">STATUS PRÜFEN</string>
<string name="add_endpoint_button_caps">ENDPUNKT HINZUFÜGEN</string>
<string name="accounts_count_label">%1$d Konto/Konten</string>
<string name="add_new_wallet_action">Neue Wallet hinzufügen</string>
<string name="done_button">Fertig</string>
<!-- DeleteConfirmationScreen -->
<string name="delete_type_title">%1$s LÖSCHEN</string>
<string name="accounts_within_this_wallet_label">Konten in dieser Wallet</string>
<string name="daily_account_placeholder">Tägliches Konto</string>
<string name="delete_warning_message">WARNUNG: Das Löschen eines %1$s löscht alle darin enthaltenen Konten.</string>
<string name="delete_risks_disclaimer">Um ein gelöschtes Konto wiederherzustellen, benötigen Sie Ihre Mnemonic-Phrase. Verlorene Mnemonic-Phrasen können nicht wiederhergestellt werden.\n\nAlle Gelder in einem verlorenen Konto gehen ebenfalls verloren.\n\nSichern Sie Ihre Mnemonic-Phrasen für jedes Konto, bevor Sie hier Änderungen vornehmen, um sicherzugehen.\n\nDiese Aktion kann nicht rückgängig gemacht werden.</string>
<string name="understand_risks_checkbox">Ich verstehe und übernehme alle Risiken dieser Aktion. Ich möchte fortfahren.</string>
<string name="confirm_delete_button">LÖSCHEN\nBESTÄTIGEN</string>
<string name="wallet">WALLET</string>
<string name="account">KONTO</string>
</resources>
+249
View File
@@ -0,0 +1,249 @@
<resources>
<string name="app_name">GajuMobile</string>
<string name="settings_title">Paramètres</string>
<string name="display_preferences">PRÉFÉRENCES D\'AFFICHAGE</string>
<string name="balance_format">FORMAT DU SOLDE</string>
<string name="wipe_data_confirm_title">SUPPRIMER TOUTES LES DONNÉES ?</string>
<string name="wipe_data_confirm_message">Cela supprimera définitivement tous les portefeuilles, comptes et clés. Cette action est irréversible.</string>
<string name="cancel">ANNULER</string>
<string name="wipe_everything">TOUT SUPPRIMER</string>
<string name="wipe_all_data">SUPPRIMER TOUTES LES DONNÉES</string>
<string name="select_language">CHOISIR LA LANGUE</string>
<string name="lang_en">English (Anglais)</string>
<string name="lang_ja">日本語 (Japonais)</string>
<string name="lang_de">Deutsch (Allemand)</string>
<string name="lang_fr">Français</string>
<string name="lang_it">Italiano (Italien)</string>
<!-- General / Shared -->
<string name="menu_manage_wallets">Gérer les portefeuilles</string>
<string name="menu_transactions">Transactions</string>
<string name="menu_settings">Paramètres</string>
<string name="menu_environment_info">Informations sur l\'environnement</string>
<string name="tap_to_reveal">APPUYER POUR RÉVÉLER</string>
<string name="add_next_word_button">+ MOT SUIVANT</string>
<string name="exit_button_caps">QUITTER</string>
<string name="proceed_to_dashboard">Accéder au tableau de bord</string>
<string name="err_generate_account">Échec de la génération du compte : %1$s</string>
<string name="err_recover_account">Échec de la récupération du compte : %1$s</string>
<string name="err_refresh_failed">Échec de l\'actualisation. Vérifiez les points de terminaison du réseau.</string>
<string name="msg_endpoint_verified">Point de terminaison vérifié et ajouté.</string>
<string name="err_auth_failed">Échec de l\'authentification : %1$s</string>
<string name="msg_tx_posted">Transaction publiée ! Hash : %1$s</string>
<string name="err_send_failed">Échec de l\'envoi : %1$s</string>
<string name="msg_sig_submitted">Signature soumise avec succès.</string>
<string name="err_sig_failed">Échec de la signature : %1$s</string>
<string name="err_no_active_account">Aucun compte actif sélectionné.</string>
<string name="err_no_matching_account">Aucun compte correspondant trouvé pour la signature.</string>
<string name="err_fetch_sig_failed">Échec de la récupération de la demande de signature.</string>
<string name="err_fetch_failed">Échec de la récupération : %1$s</string>
<string name="err_invalid_grids_url">URL GRIDS invalide : %1$s</string>
<string name="err_network_mismatch_added">Incohérence du réseau : le nœud signale \'%1$s\'. Ajouté au portefeuille \'%2$s\'.</string>
<string name="err_critical_mismatch_create">INCOHÉRENCE CRITIQUE : le nœud signale \'%1$s\' mais le portefeuille est \'%2$s\'. Veuillez d\'abord créer un portefeuille pour \'%1$s\'.</string>
<string name="err_network_mismatch_moved">Incohérence du réseau : le nœud signale \'%1$s\'. Déplacé vers le portefeuille \'%2$s\'.</string>
<string name="err_critical_mismatch_fix">INCOHÉRENCE CRITIQUE : le nœud signale \'%1$s\' mais le portefeuille est configuré pour \'%2$s\'. Corrigez ce point de terminaison ou il sera supprimé de ce portefeuille.</string>
<!-- SignRequestScreen -->
<string name="msg_sig_req">DEMANDE DE SIGNATURE DE MESSAGE</string>
<string name="bin_sig_req">DEMANDE DE SIGNATURE DE DONNÉES BINAIRES</string>
<string name="tx_sig_req">DEMANDE DE SIGNATURE DE TRANSACTION</string>
<string name="generic_sig_req">DEMANDE DE SIGNATURE</string>
<string name="sig_req_description">Le serveur à l\'URL ci-dessous demande que vous signiez ce qui suit.</string>
<string name="sig_account_label">COMPTE DE SIGNATURE</string>
<string name="originating_url_label">URL D\'ORIGINE</string>
<string name="sign_button_caps">SIGNER</string>
<string name="payload_type_message">MESSAGE</string>
<string name="payload_type_base64">DONNÉES BASE-64</string>
<string name="payload_type_tx">DONNÉES DE TRANSACTION</string>
<string name="payload_type_generic">PAYLOAD</string>
<!-- EnvironmentInfoScreen -->
<string name="security_hardware_title">Matériel de sécurité</string>
<string name="keystore_label">Keystore</string>
<string name="strongbox_label">StrongBox (élément sécurisé)</string>
<string name="hardware_tee_label">Hardware TEE</string>
<string name="auth_enforcement_label">Application de l\'authentification</string>
<string name="os_lock_required_label">Verrouillage de l\'OS requis</string>
<string name="encryption_label">Chiffrement</string>
<string name="hw_generated_ivs_label">IV générés par le matériel</string>
<string name="device_identity_title">Identité de l\'appareil</string>
<string name="manufacturer_label">Fabricant</string>
<string name="model_label">Modèle</string>
<string name="board_label">Carte</string>
<string name="hardware_label">Matériel</string>
<string name="system_build_title">Build du système</string>
<string name="android_version_label">Version Android</string>
<string name="security_patch_label">Correctif de sécurité</string>
<string name="fingerprint_label">Empreinte digitale</string>
<string name="app_version_label">Version de l\'application</string>
<string name="theme_label">Thème</string>
<string name="theme_name">Arboreal (Gajumaru)</string>
<!-- DashboardScreen -->
<string name="no_wallets_message">Aucun portefeuille trouvé. Veuillez en créer un.</string>
<string name="create_button">Créer</string>
<string name="wallets_corrupted_message">Si vous avez créé un portefeuille mais qu\'il n\'apparaît pas, il est peut-être corrompu.</string>
<string name="wipe_broken_wallets_button">Effacer les portefeuilles corrompus</string>
<string name="balance_label">SOLDE</string>
<string name="on_network_label">SUR %1$s</string>
<string name="refresh_balance_content_desc">Actualiser le solde</string>
<string name="account_settings_content_desc">Paramètres du compte</string>
<string name="send_action">Envoyer</string>
<string name="grids_action">GRIDS</string>
<string name="receive_action">Recevoir</string>
<string name="add_account_content_desc">Ajouter un compte</string>
<string name="copy_id_content_desc">Copier l\'ID</string>
<!-- CreateWalletScreen -->
<string name="create_wallet_title">Créer un portefeuille</string>
<string name="create_wallet_description">Un portefeuille est une collection de comptes, comme un dossier pour vos identités.</string>
<string name="wallet_name_label">Nom du portefeuille</string>
<string name="wallet_name_placeholder">ex. Personnel, Épargne</string>
<string name="network_label">RÉSEAU</string>
<string name="back_button">Retour</string>
<string name="continue_button">Continuer</string>
<string name="network_mainnet">Mainnet</string>
<string name="network_testnet">Testnet</string>
<!-- ExplorerScreen -->
<string name="explorer_title">Transactions</string>
<string name="loading_groot">Chargement de Groot</string>
<string name="explorer_content_placeholder">Contenu de l\'explorateur Gaju</string>
<!-- SetupChoiceScreen -->
<string name="create_account_button">Créer un compte</string>
<string name="recover_account_button">Récupérer un compte</string>
<string name="recover_mnemonic_hint">Pour récupérer un compte existant, vous aurez besoin de votre phrase mnémonique.</string>
<!-- Mnemonic Screens -->
<string name="recover_button_caps">RÉCUPÉRER</string>
<string name="recover_account_title">RÉCUPÉRER LE COMPTE</string>
<string name="mnemonic_phrase_label">Phrase mnémonique :</string>
<string name="verify_button_caps">VÉRIFIER</string>
<string name="verify_backup_title">VÉRIFIER LA SAUVEGARDE</string>
<string name="err_mnemonic_mismatch">La phrase mnémonique ne correspond pas. Veuillez vérifier à nouveau.</string>
<!-- AccountNamingScreen -->
<string name="name_account_title">Nommez votre compte</string>
<string name="account_id_label">ID du compte :</string>
<string name="account_name_label">Nom du compte</string>
<string name="account_name_placeholder">Optionnel (par défaut l\'ID)</string>
<string name="finish_button">Terminer</string>
<!-- LockScreen -->
<string name="app_locked_title">Application verrouillée</string>
<string name="auth_request_message">Veuillez vous authentifier pour continuer.</string>
<string name="unlock_button">Déverrouiller</string>
<!-- FetchingScreen -->
<string name="retrieving_request_title">RÉCUPÉRATION DE LA REQUÊTE</string>
<string name="connecting_to_label">Connexion à :</string>
<!-- SendFormScreen -->
<string name="send_title">ENVOYER</string>
<string name="sending_from_label">ENVOI DEPUIS</string>
<string name="balance_with_value">Solde : %1$s</string>
<string name="recipient_account_label">COMPTE DESTINATAIRE</string>
<string name="recipient_account_placeholder">ak_...</string>
<string name="amount_label">MONTANT</string>
<string name="amount_placeholder">0.0</string>
<string name="payload_label">PAYLOAD / MESSAGE</string>
<string name="payload_placeholder">Message optionnel...</string>
<string name="show_details">AFFICHER LES DÉTAILS</string>
<string name="hide_details">MASQUER LES DÉTAILS</string>
<string name="gas_label">GAZ</string>
<string name="gas_price_label">PRIX DU GAZ</string>
<string name="ttl_label">TTL</string>
<string name="back_button_caps">RETOUR</string>
<string name="review_button_caps">VÉRIFIER</string>
<!-- SendReviewScreen -->
<string name="review_send_title">VÉRIFIER L\'ENVOI</string>
<string name="sending_to_label">ENVOI À</string>
<string name="confirm_details_checkbox">Je confirme que les informations ci-dessus sont correctes et je souhaite continuer.</string>
<string name="send_button_caps">ENVOYER</string>
<string name="payment_summary_prefix">Vous envoyez un paiement de</string>
<string name="payment_summary_to">à</string>
<string name="cannot_be_undone_warning">CETTE ACTION EST IRRÉVERSIBLE.</string>
<string name="proceed_confirmation_question">Êtes-vous sûr de vouloir continuer ?</string>
<!-- TransactionSuccessScreen -->
<string name="transaction_success_title">Transaction réussie !</string>
<string name="transaction_success_payment_prefix">Vous avez envoyé avec succès un paiement de</string>
<string name="transaction_success_to">à</string>
<string name="transaction_success_subtracted_msg">Le montant a été déduit du compte QUOTIDIEN de votre PORTEFEUILLE PRINCIPAL.</string>
<string name="transaction_success_track_hint">Vous pouvez suivre cette transaction sur la chaîne ici.</string>
<string name="view_transaction_on_chain">VOIR LA TRANSACTION SUR LA CHAÎNE</string>
<string name="understand_risks_success_label">Je comprends et assume pleinement les risques.</string>
<!-- QRScannerScreen -->
<string name="scan_qr_title">SCANNER QR</string>
<string name="tap_to_scan">APPUYER POUR SCANNER</string>
<string name="manual_entry_button">SAISIE MANUELLE</string>
<string name="generate_qr_action">Générer QR</string>
<string name="upload_qr_action">Télécharger QR</string>
<string name="back_action">Retour</string>
<!-- QRReceiveScreen -->
<string name="transfer_request_title">DEMANDE DE TRANSFERT</string>
<string name="receive_title">RECEVOIR</string>
<string name="recipient_label">DESTINATAIRE</string>
<string name="requested_amount_label">MONTANT DEMANDÉ (OPTIONNEL)</string>
<string name="requested_amount_placeholder">0.0</string>
<string name="payload_optional_label">PAYLOAD / MESSAGE (OPTIONNEL)</string>
<string name="payload_optional_placeholder">Ajouter une note...</string>
<string name="edit_button_caps">MODIFIER</string>
<string name="done_button_caps">TERMINÉ</string>
<string name="generate_button_caps">GÉNÉRER</string>
<string name="message_label">MESSAGE</string>
<string name="qr_code_content_desc">Code QR</string>
<string name="grids_url_label">URL GRIDS</string>
<string name="copy_url_content_desc">Copier l\'URL</string>
<string name="scan_to_send_hint">Scannez pour envoyer à ce compte</string>
<!-- Clipboard -->
<string name="account_id_label_clipboard">ID du compte</string>
<string name="grids_url_label_clipboard">URL GRIDS</string>
<!-- ManageAccountScreen -->
<string name="manage_account_title">Gérer le compte</string>
<string name="rename_account_title">Renommer le compte</string>
<string name="new_name_label">Nouveau nom</string>
<string name="save_button_caps">ENREGISTRER</string>
<string name="verify_mnemonic_backup_action">Vérifier la sauvegarde mnémonique</string>
<string name="view_mnemonic_phrase_action">Voir la phrase mnémonique</string>
<string name="delete_this_account_action">Supprimer ce compte</string>
<!-- ManageWalletsScreen -->
<string name="manage_wallets_title">Gérer les portefeuilles</string>
<string name="node_status_title">État du nœud</string>
<string name="error_with_value">Erreur : %1$s</string>
<string name="close_button_caps">FERMER</string>
<string name="rename_wallet_title">Renommer le portefeuille</string>
<string name="add_endpoint_title">Ajouter un point de terminaison</string>
<string name="host_label">Hôte (IP ou domaine)</string>
<string name="port_label">Port</string>
<string name="use_tls_label">Utiliser TLS (HTTPS)</string>
<string name="add_button_caps">AJOUTER</string>
<string name="delete_wallet_content_desc">Supprimer le portefeuille</string>
<string name="network_endpoints_label">POINTS DE TERMINAISON RÉSEAU</string>
<string name="remove_endpoint_content_desc">Supprimer le point de terminaison</string>
<string name="check_status_button_caps">VÉRIFIER L\'ÉTAT</string>
<string name="add_endpoint_button_caps">AJOUTER UN POINT DE TERMINAISON</string>
<string name="accounts_count_label">%1$d compte(s)</string>
<string name="add_new_wallet_action">Ajouter un nouveau portefeuille</string>
<string name="done_button">Terminé</string>
<!-- DeleteConfirmationScreen -->
<string name="delete_type_title">SUPPRIMER %1$s</string>
<string name="accounts_within_this_wallet_label">Comptes dans ce portefeuille</string>
<string name="daily_account_placeholder">Compte quotidien</string>
<string name="delete_warning_message">AVERTISSEMENT : La suppression d\'un %1$s supprimera tous les comptes qu\'il contient.</string>
<string name="delete_risks_disclaimer">Pour récupérer un compte supprimé, vous aurez besoin de votre phrase mnémonique. Les phrases mnémoniques perdues ne peuvent pas être récupérées.\n\nTous les fonds dans un compte perdu sont également perdus.\n\nSauvegardez vos phrases mnémoniques pour chaque compte avant d\'apporter des modifications ici pour plus de sécurité.\n\nCette action ne peut pas être annulée.</string>
<string name="understand_risks_checkbox">Je comprends et assume tous les risques de cette action. Je souhaite continuer.</string>
<string name="confirm_delete_button">CONFIRMER LA\nSUPPRESSION</string>
<string name="wallet">PORTEFEUILLE</string>
<string name="account">COMPTE</string>
</resources>
+249
View File
@@ -0,0 +1,249 @@
<resources>
<string name="app_name">GajuMobile</string>
<string name="settings_title">Impostazioni</string>
<string name="display_preferences">PREFERENZE DI VISUALIZZAZIONE</string>
<string name="balance_format">FORMATO DEL SALDO</string>
<string name="wipe_data_confirm_title">CANCELLARE TUTTI I DATI?</string>
<string name="wipe_data_confirm_message">Questa azione eliminerà permanentemente tutti i portafogli, account e chiavi. L\'operazione non può essere annullata.</string>
<string name="cancel">ANNULLA</string>
<string name="wipe_everything">CANCELLA TUTTO</string>
<string name="wipe_all_data">CANCELLA TUTTI I DATI</string>
<string name="select_language">SELEZIONA LINGUA</string>
<string name="lang_en">English (Inglese)</string>
<string name="lang_ja">日本語 (Giapponese)</string>
<string name="lang_de">Deutsch (Tedesco)</string>
<string name="lang_fr">Français (Francese)</string>
<string name="lang_it">Italiano</string>
<!-- General / Shared -->
<string name="menu_manage_wallets">Gestisci portafogli</string>
<string name="menu_transactions">Transazioni</string>
<string name="menu_settings">Impostazioni</string>
<string name="menu_environment_info">Informazioni sull\'ambiente</string>
<string name="tap_to_reveal">TOCCA PER RIVELARE</string>
<string name="add_next_word_button">+ PROSSIMA PAROLA</string>
<string name="exit_button_caps">ESCI</string>
<string name="proceed_to_dashboard">Procedi alla dashboard</string>
<string name="err_generate_account">Impossibile generare l\'account: %1$s</string>
<string name="err_recover_account">Impossibile recuperare l\'account: %1$s</string>
<string name="err_refresh_failed">Aggiornamento fallito. Controlla gli endpoint di rete.</string>
<string name="msg_endpoint_verified">Endpoint verificato e aggiunto.</string>
<string name="err_auth_failed">Autenticazione fallita: %1$s</string>
<string name="msg_tx_posted">Transazione inviata! Hash: %1$s</string>
<string name="err_send_failed">Invio fallito: %1$s</string>
<string name="msg_sig_submitted">Firma inviata con successo.</string>
<string name="err_sig_failed">Firma fallita: %1$s</string>
<string name="err_no_active_account">Nessun account attivo selezionato.</string>
<string name="err_no_matching_account">Nessun account corrispondente trovato per la firma.</string>
<string name="err_fetch_sig_failed">Impossibile recuperare la richiesta di firma.</string>
<string name="err_fetch_failed">Recupero fallito: %1$s</string>
<string name="err_invalid_grids_url">URL GRIDS non valido: %1$s</string>
<string name="err_network_mismatch_added">Discrepanza di rete: il nodo segnala \'%1$s\'. Aggiunto al portafoglio \'%2$s\'.</string>
<string name="err_critical_mismatch_create">DISCREPANZA CRITICA: il nodo segnala \'%1$s\' ma il portafoglio è \'%2$s\'. Crea prima un portafoglio per \'%1$s\'.</string>
<string name="err_network_mismatch_moved">Discrepanza di rete: il nodo segnala \'%1$s\'. Spostato nel portafoglio \'%2$s\'.</string>
<string name="err_critical_mismatch_fix">DISCREPANZA CRITICA: il nodo segnala \'%1$s\' ma il portafoglio è configurato per \'%2$s\'. Correggi questo endpoint o verrà rimosso da questo portafoglio.</string>
<!-- SignRequestScreen -->
<string name="msg_sig_req">RICHIESTA DI FIRMA DEL MESSAGGIO</string>
<string name="bin_sig_req">RICHIESTA DI FIRMA DATI BINARI</string>
<string name="tx_sig_req">RICHIESTA DI FIRMA TRANSAZIONE</string>
<string name="generic_sig_req">RICHIESTA DI FIRMA</string>
<string name="sig_req_description">Il server all\'URL sottostante ti sta chiedendo di firmare quanto segue.</string>
<string name="sig_account_label">ACCOUNT DI FIRMA</string>
<string name="originating_url_label">URL DI ORIGINE</string>
<string name="sign_button_caps">FIRMA</string>
<string name="payload_type_message">MESSAGGIO</string>
<string name="payload_type_base64">DATI BASE-64</string>
<string name="payload_type_tx">DATI TRANSAZIONE</string>
<string name="payload_type_generic">PAYLOAD</string>
<!-- EnvironmentInfoScreen -->
<string name="security_hardware_title">Hardware di sicurezza</string>
<string name="keystore_label">Keystore</string>
<string name="strongbox_label">StrongBox (elemento sicuro)</string>
<string name="hardware_tee_label">TEE hardware</string>
<string name="auth_enforcement_label">Applicazione autenticazione</string>
<string name="os_lock_required_label">Blocco OS richiesto</string>
<string name="encryption_label">Crittografia</string>
<string name="hw_generated_ivs_label">IV generati dall\'hardware</string>
<string name="device_identity_title">Identità dispositivo</string>
<string name="manufacturer_label">Produttore</string>
<string name="model_label">Modello</string>
<string name="board_label">Scheda</string>
<string name="hardware_label">Hardware</string>
<string name="system_build_title">Build di sistema</string>
<string name="android_version_label">Versione Android</string>
<string name="security_patch_label">Patch di sicurezza</string>
<string name="fingerprint_label">Impronta digitale</string>
<string name="app_version_label">Versione app</string>
<string name="theme_label">Tema</string>
<string name="theme_name">Arboreal (Gajumaru)</string>
<!-- DashboardScreen -->
<string name="no_wallets_message">Nessun portafoglio trovato. Creane uno.</string>
<string name="create_button">Crea</string>
<string name="wallets_corrupted_message">Se hai creato un portafoglio ma non lo vedi, potrebbe essere danneggiato.</string>
<string name="wipe_broken_wallets_button">Cancella i portafogli danneggiati</string>
<string name="balance_label">SALDO</string>
<string name="on_network_label">SU %1$s</string>
<string name="refresh_balance_content_desc">Aggiorna saldo</string>
<string name="account_settings_content_desc">Impostazioni account</string>
<string name="send_action">Invia</string>
<string name="grids_action">GRIDS</string>
<string name="receive_action">Ricevi</string>
<string name="add_account_content_desc">Aggiungi account</string>
<string name="copy_id_content_desc">Copia ID</string>
<!-- CreateWalletScreen -->
<string name="create_wallet_title">Crea portafoglio</string>
<string name="create_wallet_description">Un portafoglio è una raccolta di account, come una cartella per le tue identità.</string>
<string name="wallet_name_label">Nome portafoglio</string>
<string name="wallet_name_placeholder">es. Personale, Risparmi</string>
<string name="network_label">RETE</string>
<string name="back_button">Indietro</string>
<string name="continue_button">Continua</string>
<string name="network_mainnet">Mainnet</string>
<string name="network_testnet">Testnet</string>
<!-- ExplorerScreen -->
<string name="explorer_title">Transazioni</string>
<string name="loading_groot">Caricamento di Groot</string>
<string name="explorer_content_placeholder">Contenuto dell\'explorer Gaju</string>
<!-- SetupChoiceScreen -->
<string name="create_account_button">Crea account</string>
<string name="recover_account_button">Recupera account</string>
<string name="recover_mnemonic_hint">Per recuperare un account esistente, avrai bisogno della tua frase mnemonica.</string>
<!-- Mnemonic Screens -->
<string name="recover_button_caps">RECUPERA</string>
<string name="recover_account_title">RECUPERA ACCOUNT</string>
<string name="mnemonic_phrase_label">Frase mnemonica:</string>
<string name="verify_button_caps">VERIFICA</string>
<string name="verify_backup_title">VERIFICA BACKUP</string>
<string name="err_mnemonic_mismatch">La frase mnemonica non corrisponde. Controlla di nuovo.</string>
<!-- AccountNamingScreen -->
<string name="name_account_title">Dai un nome al tuo account</string>
<string name="account_id_label">ID account:</string>
<string name="account_name_label">Nome account</string>
<string name="account_name_placeholder">Opzionale (predefinito è ID)</string>
<string name="finish_button">Fine</string>
<!-- LockScreen -->
<string name="app_locked_title">App bloccata</string>
<string name="auth_request_message">Autenticati per continuare.</string>
<string name="unlock_button">Sblocca</string>
<!-- FetchingScreen -->
<string name="retrieving_request_title">RECUPERO DELLA RICHIESTA</string>
<string name="connecting_to_label">Connessione a:</string>
<!-- SendFormScreen -->
<string name="send_title">INVIA</string>
<string name="sending_from_label">INVIO DA</string>
<string name="balance_with_value">Saldo: %1$s</string>
<string name="recipient_account_label">ACCOUNT DESTINATARIO</string>
<string name="recipient_account_placeholder">ak_...</string>
<string name="amount_label">IMPORTO</string>
<string name="amount_placeholder">0.0</string>
<string name="payload_label">PAYLOAD / MESSAGGIO</string>
<string name="payload_placeholder">Messaggio opzionale...</string>
<string name="show_details">MOSTRA DETTAGLI</string>
<string name="hide_details">NASCONDI DETTAGLI</string>
<string name="gas_label">GAS</string>
<string name="gas_price_label">PREZZO GAS</string>
<string name="ttl_label">TTL</string>
<string name="back_button_caps">INDIETRO</string>
<string name="review_button_caps">RIVEDI</string>
<!-- SendReviewScreen -->
<string name="review_send_title">RIVEDI INVIO</string>
<string name="sending_to_label">INVIO A</string>
<string name="confirm_details_checkbox">Confermo che i dettagli sopra riportati sono corretti e desidero procedere.</string>
<string name="send_button_caps">INVIA</string>
<string name="payment_summary_prefix">Stai inviando un pagamento di</string>
<string name="payment_summary_to">a</string>
<string name="cannot_be_undone_warning">QUESTA AZIONE NON PUÒ ESSERE ANNULLATA.</string>
<string name="proceed_confirmation_question">Sei sicuro di voler procedere?</string>
<!-- TransactionSuccessScreen -->
<string name="transaction_success_title">Transazione riuscita!</string>
<string name="transaction_success_payment_prefix">Hai inviato con successo un pagamento di</string>
<string name="transaction_success_to">a</string>
<string name="transaction_success_subtracted_msg">L\'importo è stato detratto dal conto GIORNALIERO nel tuo PORTAFOGLIO PRINCIPALE.</string>
<string name="transaction_success_track_hint">Puoi tracciare questa transazione on-chain qui.</string>
<string name="view_transaction_on_chain">VISUALIZZA TRANSAZIONE ON-CHAIN</string>
<string name="understand_risks_success_label">Comprendo e mi assumo pienamente i rischi.</string>
<!-- QRScannerScreen -->
<string name="scan_qr_title">SCANSIONA QR</string>
<string name="tap_to_scan">TOCCA PER SCANSIONARE</string>
<string name="manual_entry_button">INSERIMENTO MANUALE</string>
<string name="generate_qr_action">Genera QR</string>
<string name="upload_qr_action">Carica QR</string>
<string name="back_action">Indietro</string>
<!-- QRReceiveScreen -->
<string name="transfer_request_title">RICHIESTA DI TRASFERIMENTO</string>
<string name="receive_title">RICEVI</string>
<string name="recipient_label">DESTINATARIO</string>
<string name="requested_amount_label">IMPORTO RICHIESTO (OPZIONALE)</string>
<string name="requested_amount_placeholder">0.0</string>
<string name="payload_optional_label">PAYLOAD / MESSAGGIO (OPZIONALE)</string>
<string name="payload_optional_placeholder">Aggiungi una nota...</string>
<string name="edit_button_caps">MODIFICA</string>
<string name="done_button_caps">FATTO</string>
<string name="generate_button_caps">GENERA</string>
<string name="message_label">MESSAGGIO</string>
<string name="qr_code_content_desc">Codice QR</string>
<string name="grids_url_label">URL GRIDS</string>
<string name="copy_url_content_desc">Copia URL</string>
<string name="scan_to_send_hint">Scansiona per inviare a questo account</string>
<!-- Clipboard -->
<string name="account_id_label_clipboard">ID account</string>
<string name="grids_url_label_clipboard">URL GRIDS</string>
<!-- ManageAccountScreen -->
<string name="manage_account_title">Gestisci account</string>
<string name="rename_account_title">Rinomina account</string>
<string name="new_name_label">Nuovo nome</string>
<string name="save_button_caps">SALVA</string>
<string name="verify_mnemonic_backup_action">Verifica backup mnemonico</string>
<string name="view_mnemonic_phrase_action">Visualizza frase mnemonica</string>
<string name="delete_this_account_action">Elimina questo account</string>
<!-- ManageWalletsScreen -->
<string name="manage_wallets_title">Gestisci portafogli</string>
<string name="node_status_title">Stato del nodo</string>
<string name="error_with_value">Errore: %1$s</string>
<string name="close_button_caps">CHIUDI</string>
<string name="rename_wallet_title">Rinomina portafoglio</string>
<string name="add_endpoint_title">Aggiungi endpoint</string>
<string name="host_label">Host (IP o dominio)</string>
<string name="port_label">Porta</string>
<string name="use_tls_label">Usa TLS (HTTPS)</string>
<string name="add_button_caps">AGGIUNGI</string>
<string name="delete_wallet_content_desc">Elimina portafoglio</string>
<string name="network_endpoints_label">ENDPOINT DI RETE</string>
<string name="remove_endpoint_content_desc">Rimuovi endpoint</string>
<string name="check_status_button_caps">CONTROLLA STATO</string>
<string name="add_endpoint_button_caps">AGGIUNGI ENDPOINT</string>
<string name="accounts_count_label">%1$d account</string>
<string name="add_new_wallet_action">Aggiungi nuovo portafoglio</string>
<string name="done_button">Fatto</string>
<!-- DeleteConfirmationScreen -->
<string name="delete_type_title">ELIMINA %1$s</string>
<string name="accounts_within_this_wallet_label">Account in questo portafoglio</string>
<string name="daily_account_placeholder">Account giornaliero</string>
<string name="delete_warning_message">ATTENZIONE: L\'eliminazione di un %1$s eliminerà tutti gli account in esso contenuti.</string>
<string name="delete_risks_disclaimer">Per recuperare un account eliminato, avrai bisogno della tua frase mnemonica. Le frasi mnemoniche perse non possono essere recuperate.\n\nTutti i fondi in un account perso vanno anch\'essi persi.\n\nEsegui il backup delle tue frasi mnemoniche per ogni account prima di apportare modifiche qui per sicurezza.\n\nQuesta azione non può essere annullata.</string>
<string name="understand_risks_checkbox">Comprendo e mi assumo tutti i rischi di questa azione. Desidero procedere.</string>
<string name="confirm_delete_button">CONFERMA\nELIMINA</string>
<string name="wallet">PORTAFOGLIO</string>
<string name="account">ACCOUNT</string>
</resources>
+249
View File
@@ -0,0 +1,249 @@
<resources>
<string name="app_name">GajuMobile</string>
<string name="settings_title">設定</string>
<string name="display_preferences">表示設定</string>
<string name="balance_format">残高表示形式</string>
<string name="wipe_data_confirm_title">全データを消去しますか?</string>
<string name="wipe_data_confirm_message">すべてのウォレット、アカウント、およびキーが永久に削除されます。この操作は取り消せません。</string>
<string name="cancel">キャンセル</string>
<string name="wipe_everything">すべて消去</string>
<string name="wipe_all_data">全データを消去</string>
<string name="select_language">言語を選択</string>
<string name="lang_en">English (英語)</string>
<string name="lang_ja">日本語</string>
<string name="lang_de">Deutsch (ドイツ語)</string>
<string name="lang_fr">Français (フランス語)</string>
<string name="lang_it">Italiano (イタリア語)</string>
<!-- General / Shared -->
<string name="menu_manage_wallets">ウォレットを管理</string>
<string name="menu_transactions">トランザクション</string>
<string name="menu_settings">設定</string>
<string name="menu_environment_info">環境情報</string>
<string name="tap_to_reveal">タップして表示</string>
<string name="add_next_word_button">+ 次の単語</string>
<string name="exit_button_caps">終了</string>
<string name="proceed_to_dashboard">ダッシュボードへ進む</string>
<string name="err_generate_account">アカウントの生成に失敗しました: %1$s</string>
<string name="err_recover_account">アカウントの復元に失敗しました: %1$s</string>
<string name="err_refresh_failed">更新に失敗しました。ネットワークエンドポイントを確認してください。</string>
<string name="msg_endpoint_verified">エンドポイントが確認され、追加されました。</string>
<string name="err_auth_failed">認証に失敗しました: %1$s</string>
<string name="msg_tx_posted">トランザクションが送信されました! ハッシュ: %1$s</string>
<string name="err_send_failed">送信に失敗しました: %1$s</string>
<string name="msg_sig_submitted">署名が正常に送信されました。</string>
<string name="err_sig_failed">署名に失敗しました: %1$s</string>
<string name="err_no_active_account">有効なアカウントが選択されていません。</string>
<string name="err_no_matching_account">署名に一致するアカウントが見つかりません。</string>
<string name="err_fetch_sig_failed">署名リクエストの取得に失敗しました。</string>
<string name="err_fetch_failed">取得に失敗しました: %1$s</string>
<string name="err_invalid_grids_url">無効なGRIDS URLです: %1$s</string>
<string name="err_network_mismatch_added">ネットワークの不一致: ノードが \'%1$s\' を報告しています。ウォレット \'%2$s\' に追加されました。</string>
<string name="err_critical_mismatch_create">致命的な不一致: ノードが \'%1$s\' を報告していますが、ウォレットは \'%2$s\' です。まず \'%1$s\' のウォレットを作成してください。</string>
<string name="err_network_mismatch_moved">ネットワークの不一致: ノードが \'%1$s\' を報告しています。ウォレット \'%2$s\' に移動されました。</string>
<string name="err_critical_mismatch_fix">致命的な不一致: ノードが \'%1$s\' を報告していますが、ウォレットは \'%2$s\' 用に設定されています。このエンドポイントを修正してください。修正されない場合は、このウォレットから破棄されます。</string>
<!-- SignRequestScreen -->
<string name="msg_sig_req">メッセージ署名リクエスト</string>
<string name="bin_sig_req">バイナリデータ署名リクエスト</string>
<string name="tx_sig_req">トランザクション署名リクエスト</string>
<string name="generic_sig_req">署名リクエスト</string>
<string name="sig_req_description">以下のURLのサーバーが署名を要求しています。</string>
<string name="sig_account_label">署名アカウント</string>
<string name="originating_url_label">リクエスト元URL</string>
<string name="sign_button_caps">署名</string>
<string name="payload_type_message">メッセージ</string>
<string name="payload_type_base64">BASE-64 データ</string>
<string name="payload_type_tx">トランザクションデータ</string>
<string name="payload_type_generic">ペイロード</string>
<!-- EnvironmentInfoScreen -->
<string name="security_hardware_title">セキュリティハードウェア</string>
<string name="keystore_label">キーストア</string>
<string name="strongbox_label">StrongBox (セキュアエレメント)</string>
<string name="hardware_tee_label">ハードウェア TEE</string>
<string name="auth_enforcement_label">認証の強制</string>
<string name="os_lock_required_label">OSロック必須</string>
<string name="encryption_label">暗号化</string>
<string name="hw_generated_ivs_label">ハードウェア生成のIV</string>
<string name="device_identity_title">デバイスID</string>
<string name="manufacturer_label">メーカー</string>
<string name="model_label">モデル</string>
<string name="board_label">ボード</string>
<string name="hardware_label">ハードウェア</string>
<string name="system_build_title">システムビルド</string>
<string name="android_version_label">Android バージョン</string>
<string name="security_patch_label">セキュリティパッチ</string>
<string name="fingerprint_label">フィンガープリント</string>
<string name="app_version_label">アプリバージョン</string>
<string name="theme_label">テーマ</string>
<string name="theme_name">Arboreal (Gajumaru)</string>
<!-- DashboardScreen -->
<string name="no_wallets_message">ウォレットが見つかりません。作成してください。</string>
<string name="create_button">作成</string>
<string name="wallets_corrupted_message">ウォレットを作成したのに表示されない場合は、データが破損している可能性があります。</string>
<string name="wipe_broken_wallets_button">破損したウォレットを消去</string>
<string name="balance_label">残高</string>
<string name="on_network_label">%1$s ネットワーク上</string>
<string name="refresh_balance_content_desc">残高を更新</string>
<string name="account_settings_content_desc">アカウント設定</string>
<string name="send_action">送信</string>
<string name="grids_action">GRIDS</string>
<string name="receive_action">受信</string>
<string name="add_account_content_desc">アカウントを追加</string>
<string name="copy_id_content_desc">IDをコピー</string>
<!-- CreateWalletScreen -->
<string name="create_wallet_title">ウォレットを作成</string>
<string name="create_wallet_description">ウォレットは、IDを整理するためのフォルダのような、アカウントの集合体です。</string>
<string name="wallet_name_label">ウォレット名</string>
<string name="wallet_name_placeholder">例:個人用、貯蓄用</string>
<string name="network_label">ネットワーク</string>
<string name="back_button">戻る</string>
<string name="continue_button">次へ</string>
<string name="network_mainnet">メインネット</string>
<string name="network_testnet">テストネット</string>
<!-- ExplorerScreen -->
<string name="explorer_title">トランザクション</string>
<string name="loading_groot">Grootを読み込み中</string>
<string name="explorer_content_placeholder">Gajuエクスプローラーのコンテンツ</string>
<!-- SetupChoiceScreen -->
<string name="create_account_button">アカウントを作成</string>
<string name="recover_account_button">アカウントを復元</string>
<string name="recover_mnemonic_hint">既存のアカウントを復元するには、ニーモニックフレーズが必要です。</string>
<!-- Mnemonic Screens -->
<string name="recover_button_caps">復元</string>
<string name="recover_account_title">アカウントを復元</string>
<string name="mnemonic_phrase_label">ニーモニックフレーズ:</string>
<string name="verify_button_caps">確認</string>
<string name="verify_backup_title">バックアップを確認</string>
<string name="err_mnemonic_mismatch">ニーモニックフレーズが一致しません。もう一度確認してください。</string>
<!-- AccountNamingScreen -->
<string name="name_account_title">アカウントに名前を付ける</string>
<string name="account_id_label">アカウントID:</string>
<string name="account_name_label">アカウント名</string>
<string name="account_name_placeholder">オプション(デフォルトはID</string>
<string name="finish_button">完了</string>
<!-- LockScreen -->
<string name="app_locked_title">アプリがロックされています</string>
<string name="auth_request_message">続行するには認証してください。</string>
<string name="unlock_button">ロック解除</string>
<!-- FetchingScreen -->
<string name="retrieving_request_title">リクエストを取得中</string>
<string name="connecting_to_label">接続先:</string>
<!-- SendFormScreen -->
<string name="send_title">送信</string>
<string name="sending_from_label">送信元</string>
<string name="balance_with_value">残高: %1$s</string>
<string name="recipient_account_label">送信先アカウント</string>
<string name="recipient_account_placeholder">ak_...</string>
<string name="amount_label">金額</string>
<string name="amount_placeholder">0.0</string>
<string name="payload_label">ペイロード / メッセージ</string>
<string name="payload_placeholder">メッセージ(任意)...</string>
<string name="show_details">詳細を表示</string>
<string name="hide_details">詳細を隠す</string>
<string name="gas_label">ガス</string>
<string name="gas_price_label">ガス価格</string>
<string name="ttl_label">TTL</string>
<string name="back_button_caps">戻る</string>
<string name="review_button_caps">確認</string>
<!-- SendReviewScreen -->
<string name="review_send_title">送信内容を確認</string>
<string name="sending_to_label">送信先</string>
<string name="confirm_details_checkbox">上記の詳細が正しいことを確認し、続行します。</string>
<string name="send_button_caps">送信</string>
<string name="payment_summary_prefix">送金額</string>
<string name="payment_summary_to">送信先</string>
<string name="cannot_be_undone_warning">この操作は取り消せません。</string>
<string name="proceed_confirmation_question">本当に続行しますか?</string>
<!-- TransactionSuccessScreen -->
<string name="transaction_success_title">トランザクション成功!</string>
<string name="transaction_success_payment_prefix">以下の送金に成功しました</string>
<string name="transaction_success_to">送信先</string>
<string name="transaction_success_subtracted_msg">金額はプライマリウォレットの日常アカウントから差し引かれました。</string>
<string name="transaction_success_track_hint">ここでチェーン上のトランザクションを追跡できます。</string>
<string name="view_transaction_on_chain">チェーン上でトランザクションを表示</string>
<string name="understand_risks_success_label">私はリスクを理解し、完全に引き受けます。</string>
<!-- QRScannerScreen -->
<string name="scan_qr_title">QRコードをスキャン</string>
<string name="tap_to_scan">タップしてスキャン</string>
<string name="manual_entry_button">手動入力</string>
<string name="generate_qr_action">QRコードを生成</string>
<string name="upload_qr_action">QRコードをアップロード</string>
<string name="back_action">戻る</string>
<!-- QRReceiveScreen -->
<string name="transfer_request_title">送金リクエスト</string>
<string name="receive_title">受信</string>
<string name="recipient_label">受信者</string>
<string name="requested_amount_label">リクエスト金額(任意)</string>
<string name="requested_amount_placeholder">0.0</string>
<string name="payload_optional_label">ペイロード / メッセージ(任意)</string>
<string name="payload_optional_placeholder">メモを追加...</string>
<string name="edit_button_caps">編集</string>
<string name="done_button_caps">完了</string>
<string name="generate_button_caps">生成</string>
<string name="message_label">メッセージ</string>
<string name="qr_code_content_desc">QRコード</string>
<string name="grids_url_label">GRIDS URL</string>
<string name="copy_url_content_desc">URLをコピー</string>
<string name="scan_to_send_hint">スキャンしてこのアカウントに送信します</string>
<!-- Clipboard -->
<string name="account_id_label_clipboard">アカウントID</string>
<string name="grids_url_label_clipboard">GRIDS URL</string>
<!-- ManageAccountScreen -->
<string name="manage_account_title">アカウントを管理</string>
<string name="rename_account_title">アカウントの名前を変更</string>
<string name="new_name_label">新しい名前</string>
<string name="save_button_caps">保存</string>
<string name="verify_mnemonic_backup_action">ニーモニックのバックアップを確認</string>
<string name="view_mnemonic_phrase_action">ニーモニックフレーズを表示</string>
<string name="delete_this_account_action">このアカウントを削除</string>
<!-- ManageWalletsScreen -->
<string name="manage_wallets_title">ウォレットを管理</string>
<string name="node_status_title">ノードの状態</string>
<string name="error_with_value">エラー: %1$s</string>
<string name="close_button_caps">閉じる</string>
<string name="rename_wallet_title">ウォレットの名前を変更</string>
<string name="add_endpoint_title">エンドポイントを追加</string>
<string name="host_label">ホスト (IP またはドメイン)</string>
<string name="port_label">ポート</string>
<string name="use_tls_label">TLS (HTTPS) を使用</string>
<string name="add_button_caps">追加</string>
<string name="delete_wallet_content_desc">ウォレットを削除</string>
<string name="network_endpoints_label">ネットワークエンドポイント</string>
<string name="remove_endpoint_content_desc">エンドポイントを削除</string>
<string name="check_status_button_caps">状態を確認</string>
<string name="add_endpoint_button_caps">エンドポイントを追加</string>
<string name="accounts_count_label">%1$d 個のアカウント</string>
<string name="add_new_wallet_action">新しいウォレットを追加</string>
<string name="done_button">完了</string>
<!-- DeleteConfirmationScreen -->
<string name="delete_type_title">%1$s を削除</string>
<string name="accounts_within_this_wallet_label">このウォレット内のアカウント</string>
<string name="daily_account_placeholder">日常アカウント</string>
<string name="delete_warning_message">警告: %1$s を削除すると、その中のすべてのアカウントが削除されます。</string>
<string name="delete_risks_disclaimer">削除されたアカウントを復元するには、ニーモニックフレーズが必要です。失われたニーモニックフレーズは取得できません。\n\n失われたアカウント内のすべての資金も失われます。\n\n安全のため、変更を加える前にすべてのアカウントのニーモニックフレーズをバックアップしてください。\n\nこの操作は取り消せません。</string>
<string name="understand_risks_checkbox">私はこの操作によるすべてのリスクを理解し、引き受けます。続行します。</string>
<string name="confirm_delete_button">削除を確定</string>
<string name="wallet">ウォレット</string>
<string name="account">アカウント</string>
</resources>
+247 -1
View File
@@ -1,3 +1,249 @@
<resources>
<string name="app_name">GajuMobile</string>
</resources>
<string name="settings_title">Settings</string>
<string name="display_preferences">DISPLAY PREFERENCES</string>
<string name="balance_format">BALANCE FORMAT</string>
<string name="wipe_data_confirm_title">WIPE ALL DATA?</string>
<string name="wipe_data_confirm_message">This will permanently delete all wallets, accounts, and keys. This action cannot be undone.</string>
<string name="cancel">CANCEL</string>
<string name="wipe_everything">WIPE EVERYTHING</string>
<string name="wipe_all_data">WIPE ALL DATA</string>
<string name="select_language">SELECT LANGUAGE</string>
<string name="err_generate_account">Failed to generate account: %1$s</string>
<string name="err_recover_account">Failed to recover account: %1$s</string>
<string name="err_refresh_failed">Refresh failed. Check network endpoints.</string>
<string name="msg_endpoint_verified">Endpoint verified and added.</string>
<string name="err_auth_failed">Authentication failed: %1$s</string>
<string name="msg_tx_posted">Transaction posted! Hash: %1$s</string>
<string name="err_send_failed">Send failed: %1$s</string>
<string name="msg_sig_submitted">Signature submitted successfully.</string>
<string name="err_sig_failed">Signing failed: %1$s</string>
<string name="err_no_active_account">No active account selected.</string>
<string name="err_no_matching_account">No matching account found for signature.</string>
<string name="err_fetch_sig_failed">Failed to fetch signature request.</string>
<string name="err_fetch_failed">Fetch failed: %1$s</string>
<string name="err_invalid_grids_url">Invalid GRIDS URL: %1$s</string>
<string name="err_network_mismatch_added">Network mismatch: Node reports \'%1$s\'. Added to wallet \'%2$s\'.</string>
<string name="err_critical_mismatch_create">CRITICAL MISMATCH: Node reports \'%1$s\' but wallet is \'%2$s\'. Please create a wallet for \'%1$s\' first.</string>
<string name="err_network_mismatch_moved">Network mismatch: Node reports \'%1$s\'. Moved to wallet \'%2$s\'.</string>
<string name="err_critical_mismatch_fix">CRITICAL MISMATCH: Node reports \'%1$s\' but wallet is configured for \'%2$s\'. Fix this endpoint or it will be discarded from this wallet.</string>
<string name="lang_en">English</string>
<string name="lang_ja">日本語 (Japanese)</string>
<string name="lang_de">Deutsch (German)</string>
<string name="lang_fr">Français (French)</string>
<string name="lang_it">Italiano (Italian)</string>
<!-- General / Shared -->
<string name="menu_manage_wallets">Manage Wallets</string>
<string name="menu_transactions">Transactions</string>
<string name="menu_settings">Settings</string>
<string name="menu_environment_info">Environment Info</string>
<string name="tap_to_reveal">TAP TO REVEAL</string>
<string name="add_next_word_button">+ NEXT WORD</string>
<string name="exit_button_caps">EXIT</string>
<string name="proceed_to_dashboard">Proceed to Dashboard</string>
<!-- SignRequestScreen -->
<string name="msg_sig_req">MESSAGE SIGNATURE REQUEST</string>
<string name="bin_sig_req">BINARY DATA SIGNATURE REQUEST</string>
<string name="tx_sig_req">TRANSACTION SIGNATURE REQUEST</string>
<string name="generic_sig_req">SIGNATURE REQUEST</string>
<string name="sig_req_description">The server at the URL below is requesting you sign the following.</string>
<string name="sig_account_label">SIGNATURE ACCOUNT</string>
<string name="originating_url_label">ORIGINATING URL</string>
<string name="sign_button_caps">SIGN</string>
<string name="payload_type_message">MESSAGE</string>
<string name="payload_type_base64">BASE-64 DATA</string>
<string name="payload_type_tx">TRANSACTION DATA</string>
<string name="payload_type_generic">PAYLOAD</string>
<!-- EnvironmentInfoScreen -->
<string name="security_hardware_title">Security Hardware</string>
<string name="keystore_label">Keystore</string>
<string name="strongbox_label">StrongBox (Secure Element)</string>
<string name="hardware_tee_label">Hardware TEE</string>
<string name="auth_enforcement_label">Auth Enforcement</string>
<string name="os_lock_required_label">OS Lock Required</string>
<string name="encryption_label">Encryption</string>
<string name="hw_generated_ivs_label">Hardware-Generated IVs</string>
<string name="device_identity_title">Device Identity</string>
<string name="manufacturer_label">Manufacturer</string>
<string name="model_label">Model</string>
<string name="board_label">Board</string>
<string name="hardware_label">Hardware</string>
<string name="system_build_title">System Build</string>
<string name="android_version_label">Android Version</string>
<string name="security_patch_label">Security Patch</string>
<string name="fingerprint_label">Fingerprint</string>
<string name="app_version_label">App Version</string>
<string name="theme_label">Theme</string>
<string name="theme_name">Arboreal (Gajumaru)</string>
<!-- DashboardScreen -->
<string name="no_wallets_message">No wallets found. Please create one.</string>
<string name="create_button">Create</string>
<string name="wallets_corrupted_message">If you created a wallet but don\'t see it, it may be corrupted.</string>
<string name="wipe_broken_wallets_button">Wipe Broken Wallets</string>
<string name="balance_label">BALANCE</string>
<string name="on_network_label">ON %1$s</string>
<string name="refresh_balance_content_desc">Refresh Balance</string>
<string name="account_settings_content_desc">Account Settings</string>
<string name="send_action">Send</string>
<string name="grids_action">GRIDS</string>
<string name="receive_action">Receive</string>
<string name="add_account_content_desc">Add Account</string>
<string name="copy_id_content_desc">Copy ID</string>
<!-- CreateWalletScreen -->
<string name="create_wallet_title">Create Wallet</string>
<string name="create_wallet_description">A wallet is a collection of accounts, like a folder for your identities.</string>
<string name="wallet_name_label">Wallet Name</string>
<string name="wallet_name_placeholder">e.g. Personal, Savings</string>
<string name="network_label">NETWORK</string>
<string name="back_button">Back</string>
<string name="continue_button">Continue</string>
<string name="network_mainnet">Mainnet</string>
<string name="network_testnet">Testnet</string>
<!-- ExplorerScreen -->
<string name="explorer_title">Transactions</string>
<string name="loading_groot">Loading Groot</string>
<string name="explorer_content_placeholder">Gaju Explorer Content</string>
<!-- SetupChoiceScreen -->
<string name="create_account_button">Create Account</string>
<string name="recover_account_button">Recover Account</string>
<string name="recover_mnemonic_hint">To recover an existing account, you will need your mnemonic phrase.</string>
<!-- Mnemonic Screens -->
<string name="recover_button_caps">RECOVER</string>
<string name="recover_account_title">RECOVER ACCOUNT</string>
<string name="mnemonic_phrase_label">Mnemonic Phrase:</string>
<string name="verify_button_caps">VERIFY</string>
<string name="verify_backup_title">VERIFY BACKUP</string>
<string name="err_mnemonic_mismatch">Mnemonic phrase does not match. Please check again.</string>
<!-- AccountNamingScreen -->
<string name="name_account_title">Name your account</string>
<string name="account_id_label">Account ID:</string>
<string name="account_name_label">Account Name</string>
<string name="account_name_placeholder">Optional (defaults to ID)</string>
<string name="finish_button">Finish</string>
<!-- LockScreen -->
<string name="app_locked_title">App Locked</string>
<string name="auth_request_message">Please authenticate to continue.</string>
<string name="unlock_button">Unlock</string>
<!-- FetchingScreen -->
<string name="retrieving_request_title">RETRIEVING REQUEST</string>
<string name="connecting_to_label">Connecting to:</string>
<!-- SendFormScreen -->
<string name="send_title">SEND</string>
<string name="sending_from_label">SENDING FROM</string>
<string name="balance_with_value">Balance: %1$s</string>
<string name="recipient_account_label">RECIPIENT ACCOUNT</string>
<string name="recipient_account_placeholder">ak_...</string>
<string name="amount_label">AMOUNT</string>
<string name="amount_placeholder">0.0</string>
<string name="payload_label">PAYLOAD / MESSAGE</string>
<string name="payload_placeholder">Optional message...</string>
<string name="show_details">SHOW DETAILS</string>
<string name="hide_details">HIDE DETAILS</string>
<string name="gas_label">GAS</string>
<string name="gas_price_label">GAS PRICE</string>
<string name="ttl_label">TTL</string>
<string name="back_button_caps">BACK</string>
<string name="review_button_caps">REVIEW</string>
<!-- SendReviewScreen -->
<string name="review_send_title">REVIEW SEND</string>
<string name="sending_to_label">SENDING TO</string>
<string name="confirm_details_checkbox">I confirm that the above details are correct and I would like to proceed.</string>
<string name="send_button_caps">SEND</string>
<string name="payment_summary_prefix">You are sending a payment of</string>
<string name="payment_summary_to">to</string>
<string name="cannot_be_undone_warning">THIS ACTION CANNOT BE UNDONE.</string>
<string name="proceed_confirmation_question">Are you sure you want to proceed?</string>
<!-- TransactionSuccessScreen -->
<string name="transaction_success_title">Transaction Successful!</string>
<string name="transaction_success_payment_prefix">You have successfully sent a payment of</string>
<string name="transaction_success_to">to</string>
<string name="transaction_success_subtracted_msg">The amount has been subtracted from the DAILY account in your PRIMARY WALLET.</string>
<string name="transaction_success_track_hint">You can track this transaction on-chain here.</string>
<string name="view_transaction_on_chain">VIEW TRANSACTION ON-CHAIN</string>
<string name="understand_risks_success_label">I understand and fully assume the risks.</string>
<!-- QRScannerScreen -->
<string name="scan_qr_title">SCAN QR</string>
<string name="tap_to_scan">TAP TO SCAN</string>
<string name="manual_entry_button">MANUAL ENTRY</string>
<string name="generate_qr_action">Generate QR</string>
<string name="upload_qr_action">Upload QR</string>
<string name="back_action">Back</string>
<!-- QRReceiveScreen -->
<string name="transfer_request_title">TRANSFER REQUEST</string>
<string name="receive_title">RECEIVE</string>
<string name="recipient_label">RECIPIENT</string>
<string name="requested_amount_label">REQUESTED AMOUNT (OPTIONAL)</string>
<string name="requested_amount_placeholder">0.0</string>
<string name="payload_optional_label">PAYLOAD / MESSAGE (OPTIONAL)</string>
<string name="payload_optional_placeholder">Add a note...</string>
<string name="edit_button_caps">EDIT</string>
<string name="done_button_caps">DONE</string>
<string name="generate_button_caps">GENERATE</string>
<string name="message_label">MESSAGE</string>
<string name="qr_code_content_desc">QR Code</string>
<string name="grids_url_label">GRIDS URL</string>
<string name="copy_url_content_desc">Copy URL</string>
<string name="scan_to_send_hint">Scan to send to this account</string>
<!-- Clipboard -->
<string name="account_id_label_clipboard">Account ID</string>
<string name="grids_url_label_clipboard">GRIDS URL</string>
<!-- ManageAccountScreen -->
<string name="manage_account_title">Manage Account</string>
<string name="rename_account_title">Rename Account</string>
<string name="new_name_label">New Name</string>
<string name="save_button_caps">SAVE</string>
<string name="verify_mnemonic_backup_action">Verify mnemonic backup</string>
<string name="view_mnemonic_phrase_action">View mnemonic phrase</string>
<string name="delete_this_account_action">Delete this account</string>
<!-- ManageWalletsScreen -->
<string name="manage_wallets_title">Manage Wallets</string>
<string name="node_status_title">Node Status</string>
<string name="error_with_value">Error: %1$s</string>
<string name="close_button_caps">CLOSE</string>
<string name="rename_wallet_title">Rename Wallet</string>
<string name="add_endpoint_title">Add Endpoint</string>
<string name="host_label">Host (IP or Domain)</string>
<string name="port_label">Port</string>
<string name="use_tls_label">Use TLS (HTTPS)</string>
<string name="add_button_caps">ADD</string>
<string name="delete_wallet_content_desc">Delete Wallet</string>
<string name="network_endpoints_label">NETWORK ENDPOINTS</string>
<string name="remove_endpoint_content_desc">Remove Endpoint</string>
<string name="check_status_button_caps">CHECK STATUS</string>
<string name="add_endpoint_button_caps">ADD ENDPOINT</string>
<string name="accounts_count_label">%1$d account(s)</string>
<string name="add_new_wallet_action">Add new wallet</string>
<string name="done_button">Done</string>
<!-- DeleteConfirmationScreen -->
<string name="delete_type_title">DELETE %1$s</string>
<string name="accounts_within_this_wallet_label">Accounts within this wallet</string>
<string name="daily_account_placeholder">Daily account</string>
<string name="delete_warning_message">WARNING: Deleting a %1$s will delete all accounts within it.</string>
<string name="delete_risks_disclaimer">To recover a deleted account, you will need your mnemonic phrase. Lost mnemonic phrases cannot be retrieved.\n\nAll funds within a lost account are also lost.\n\nBack up your mnemonic phrases for every account before making any changes here to be safe.\n\nThis action cannot be undone.</string>
<string name="understand_risks_checkbox">I understand and assume all risks from this action. I would like to proceed.</string>
<string name="confirm_delete_button">CONFIRM\nDELETE</string>
<string name="wallet">WALLET</string>
<string name="account">ACCOUNT</string>
</resources>
@@ -0,0 +1,49 @@
package swiss.qpq.gajumobile.data.models
import org.junit.Assert.assertEquals
import org.junit.Test
class GridsModelsTest {
@Test
fun testMapToGridsSignRequest() {
val rawMap = mapOf(
"type" to "message",
"payload" to "Hello world",
"public_id" to "ak_123",
"network_id" to "groot.mainnet",
"grids" to "v1",
"chain" to "groot"
)
val request = rawMap.toGridsSignRequest()
assertEquals(GridsSignType.MESSAGE, request.type)
assertEquals("Hello world", request.payload)
assertEquals("ak_123", request.publicId)
assertEquals("groot.mainnet", request.networkId)
assertEquals("v1", request.grids)
assertEquals("groot", request.chain)
}
@Test
fun testMapWithUnknownType() {
val rawMap = mapOf(
"type" to "something_new",
"payload" to "secret"
)
val request = rawMap.toGridsSignRequest()
assertEquals(GridsSignType.UNKNOWN, request.type)
assertEquals("secret", request.payload)
}
@Test
fun testToProtocolString() {
assertEquals("message", GridsSignType.MESSAGE.toProtocolString())
assertEquals("binary", GridsSignType.BINARY.toProtocolString())
assertEquals("tx", GridsSignType.TX.toProtocolString())
assertEquals("unknown", GridsSignType.UNKNOWN.toProtocolString())
}
}
@@ -60,7 +60,7 @@ class AccountAirlockTest {
// Verify we can sign with this account
val message = "Test sign".toByteArray()
val signature = AccountAirlock.sign(account.privateKeyEnvelope, masterKey, message)
val signature = AccountAirlock.signBinary(account.privateKeyEnvelope, masterKey, message)
assertNotNull(signature)
assertTrue(Ed25519.verify(account.publicKey, message, signature))