summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cashier/src/main/res/values-ru/strings.xml43
-rwxr-xr-ximport-svg-assets.sh51
-rw-r--r--merchant-terminal/src/main/res/values-ru/strings.xml72
-rw-r--r--wallet/build.gradle6
-rw-r--r--wallet/src/main/java/net/taler/wallet/HandleUriFragment.kt6
-rw-r--r--wallet/src/main/java/net/taler/wallet/MainViewModel.kt43
-rw-r--r--wallet/src/main/java/net/taler/wallet/ReceiveFundsFragment.kt4
-rw-r--r--wallet/src/main/java/net/taler/wallet/SendFundsFragment.kt4
-rw-r--r--wallet/src/main/java/net/taler/wallet/Utils.kt6
-rw-r--r--wallet/src/main/java/net/taler/wallet/backend/WalletBackendApi.kt14
-rw-r--r--wallet/src/main/java/net/taler/wallet/balances/BalanceAdapter.kt17
-rw-r--r--wallet/src/main/java/net/taler/wallet/deposit/MakeBitcoinDepositComposable.kt18
-rw-r--r--wallet/src/main/java/net/taler/wallet/deposit/MakeDepositComposable.kt16
-rw-r--r--wallet/src/main/java/net/taler/wallet/deposit/PayToUriFragment.kt4
-rw-r--r--wallet/src/main/java/net/taler/wallet/deposit/TransactionDepositComposable.kt6
-rw-r--r--wallet/src/main/java/net/taler/wallet/exchanges/ExchangeAdapter.kt5
-rw-r--r--wallet/src/main/java/net/taler/wallet/exchanges/ExchangeListFragment.kt11
-rw-r--r--wallet/src/main/java/net/taler/wallet/exchanges/ExchangeManager.kt19
-rw-r--r--wallet/src/main/java/net/taler/wallet/payment/PayTemplateComposable.kt8
-rw-r--r--wallet/src/main/java/net/taler/wallet/payment/PayTemplateOrderComposable.kt4
-rw-r--r--wallet/src/main/java/net/taler/wallet/payment/TransactionPaymentComposable.kt6
-rw-r--r--wallet/src/main/java/net/taler/wallet/peer/IncomingComposable.kt32
-rw-r--r--wallet/src/main/java/net/taler/wallet/peer/OutgoingPullComposable.kt6
-rw-r--r--wallet/src/main/java/net/taler/wallet/peer/OutgoingPushComposable.kt2
-rw-r--r--wallet/src/main/java/net/taler/wallet/peer/TransactionPeerPullCredit.kt8
-rw-r--r--wallet/src/main/java/net/taler/wallet/peer/TransactionPeerPullDebit.kt6
-rw-r--r--wallet/src/main/java/net/taler/wallet/peer/TransactionPeerPushCredit.kt6
-rw-r--r--wallet/src/main/java/net/taler/wallet/peer/TransactionPeerPushDebit.kt6
-rw-r--r--wallet/src/main/java/net/taler/wallet/refund/TransactionRefundComposable.kt6
-rw-r--r--wallet/src/main/java/net/taler/wallet/settings/SettingsFragment.kt5
-rw-r--r--wallet/src/main/java/net/taler/wallet/transactions/TransactionAdapter.kt3
-rw-r--r--wallet/src/main/java/net/taler/wallet/transactions/TransactionLossFragment.kt163
-rw-r--r--wallet/src/main/java/net/taler/wallet/transactions/TransactionRefreshFragment.kt2
-rw-r--r--wallet/src/main/java/net/taler/wallet/transactions/Transactions.kt80
-rw-r--r--wallet/src/main/java/net/taler/wallet/transactions/TransactionsFragment.kt16
-rw-r--r--wallet/src/main/java/net/taler/wallet/withdraw/PromptWithdrawFragment.kt4
-rw-r--r--wallet/src/main/java/net/taler/wallet/withdraw/TransactionWithdrawalComposable.kt21
-rw-r--r--wallet/src/main/java/net/taler/wallet/withdraw/manual/ScreenTransfer.kt44
-rw-r--r--wallet/src/main/java/net/taler/wallet/withdraw/manual/TransferIBAN.kt24
-rw-r--r--wallet/src/main/java/net/taler/wallet/withdraw/manual/TransferTaler.kt22
-rw-r--r--wallet/src/main/res/drawable/badge.xml26
-rw-r--r--wallet/src/main/res/drawable/ic_funds_receive.xml5
-rw-r--r--wallet/src/main/res/drawable/ic_funds_send.xml5
-rw-r--r--wallet/src/main/res/drawable/ic_sync.xml9
-rw-r--r--wallet/src/main/res/drawable/pending_border.xml31
-rw-r--r--wallet/src/main/res/drawable/transaction_loss.xml (renamed from wallet/src/main/res/drawable/transaction_tip_accepted.xml)8
-rw-r--r--wallet/src/main/res/layout-w550dp/payment_bottom_bar.xml2
-rw-r--r--wallet/src/main/res/layout/balance_actions.xml117
-rw-r--r--wallet/src/main/res/layout/fragment_prompt_withdraw.xml4
-rw-r--r--wallet/src/main/res/layout/fragment_transactions.xml109
-rw-r--r--wallet/src/main/res/layout/fragment_uri_input.xml2
-rw-r--r--wallet/src/main/res/layout/list_item_balance.xml51
-rw-r--r--wallet/src/main/res/layout/list_item_transaction.xml10
-rw-r--r--wallet/src/main/res/layout/payment_bottom_bar.xml2
-rw-r--r--wallet/src/main/res/menu/exchange.xml3
-rw-r--r--wallet/src/main/res/navigation/nav_graph.xml7
-rw-r--r--wallet/src/main/res/values-de/strings.xml4
-rw-r--r--wallet/src/main/res/values-it/strings.xml2
-rw-r--r--wallet/src/main/res/values/strings.xml370
-rw-r--r--wallet/src/main/res/values/styles.xml14
60 files changed, 1076 insertions, 524 deletions
diff --git a/cashier/src/main/res/values-ru/strings.xml b/cashier/src/main/res/values-ru/strings.xml
new file mode 100644
index 0000000..8d6fff9
--- /dev/null
+++ b/cashier/src/main/res/values-ru/strings.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="app_name">Taler Кассир</string>
+ <string name="config_bank_url">API адрес банка</string>
+ <string name="config_username">Имя пользователя</string>
+ <string name="config_password">Пароль</string>
+ <string name="config_button_save">Сохранить</string>
+ <string name="config_error_auth">Неправильное имя пользователя или пароль!</string>
+ <string name="config_demo_hint">Для тестирования, вы можете &lt;a href=%s&gt;создать тестовую учётную запист в демонстрационном банке&lt;/a&gt;.</string>
+ <string name="balance_current_label">Теущий баланс</string>
+ <string name="balance_error">ОШИБКА: %s</string>
+ <string name="balance_offline">Нет связи. Пожалуйста подключитесь к интернету.</string>
+ <string name="action_reconfigure">Переконфигурировать</string>
+ <string name="action_lock">Заблокировать</string>
+ <string name="action_about">О программе</string>
+ <string name="withdraw_input_amount">Количество</string>
+ <string name="ok">OK</string>
+ <string name="config_bank_url_error">Адрес неправильный.</string>
+ <string name="config_username_error">Пожалуйста введите ваше имя пользователя!</string>
+ <string name="config_error">Ошибка при получении конфигурации</string>
+ <string name="withdraw_into">Сколько e-cash должно быть списано?</string>
+ <string name="withdraw_error_zero">Введите позитивное количество!</string>
+ <string name="withdraw_error_insufficient_balance">Недостаточный баланс</string>
+ <string name="withdraw_error_currency_mismatch">Ошибка: Банк использует другую валюту</string>
+ <string name="withdraw_error_fetch">Ошибка при связи с банком: %s</string>
+ <string name="withdraw_error_timeout">Никакой кошелёк не попробоавл списать. Пожалуйста попробуйте ещё раз.</string>
+ <string name="withdraw_button_confirm">Списание</string>
+ <string name="transaction_intro">Отсканируйте код приложением Кошелька Taler чтобы списать:</string>
+ <string name="transaction_intro_nfc">Отсканируйте код или используйте NFC в приложении Кошелька Taler чтобы списать:</string>
+ <string name="transaction_intro_scanned">Пожалуйста подтвердите транзакцию!</string>
+ <string name="transaction_confirm">Подтвердить</string>
+ <string name="transaction_abort">Подробности</string>
+ <string name="transaction_aborted">Транзакция прервана</string>
+ <string name="transaction_button_back">Перейти назад</string>
+ <string name="transaction_last_success">Последняя Транзакция: %s списано</string>
+ <string name="transaction_last_aborted">Последняя Транзакция: Прервана</string>
+ <string name="transaction_last_error">Последняя Транзакция: Неуспешна</string>
+ <string name="about_title">Кассир GNU Taler</string>
+ <string name="about_version">Версия: %s</string>
+ <string name="about_license">Лицензия: %s</string>
+ <string name="about_copyright">Авторские права: %s</string>
+ <string name="about_supported_bank_api">Версия API банка: %s</string>
+</resources> \ No newline at end of file
diff --git a/import-svg-assets.sh b/import-svg-assets.sh
new file mode 100755
index 0000000..19f0923
--- /dev/null
+++ b/import-svg-assets.sh
@@ -0,0 +1,51 @@
+#!/bin/bash
+#
+# This file is part of GNU Taler
+# (C) 2024 Taler Systems S.A.
+#
+# GNU Taler is free software; you can redistribute it and/or modify it under the
+# terms of the GNU General Public License as published by the Free Software
+# Foundation; either version 3, or (at your option) any later version.
+#
+# GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+#
+
+# To get the s2v command, do this:
+#
+# $ npm install svg2vectordrawable -g
+#
+
+ASSETS_DIR="../taler-assets/svg"
+TMP_DIR="../taler-assets/s2v-tmp"
+OUTPUT_DIR="./wallet/src/main/res/drawable/"
+
+set -ex
+
+mkdir -p "$TMP_DIR"
+
+for d in "$ASSETS_DIR"/*; do
+ s2v --folder="$d" --output="$TMP_DIR" --tint="?attr/colorControlNormal"
+done
+
+# remove unneeded icons
+rm "$TMP_DIR/taler_logo_2021_plain.xml"
+rm "$TMP_DIR/taler_logo_2022.xml"
+rm "$TMP_DIR/logo_2021.xml"
+
+# add tint
+sed -i 's@android:viewportWidth@android:tint="?attr/colorControlNormal"\n android:viewportWidth@g' "$TMP_DIR"/*.xml
+# reduce size
+sed -i 's@"1200dp"@"24dp"@g' "$TMP_DIR"/*.xml
+# add path fillColor
+sed -i 's@<path@<path\n android:fillColor="#FF000000"@g' "$TMP_DIR"/*.xml
+
+# move final files
+mv "$TMP_DIR"/*.xml "$OUTPUT_DIR"
+
+# remove tmp dir
+rm -rf "$TMP_DIR"
diff --git a/merchant-terminal/src/main/res/values-ru/strings.xml b/merchant-terminal/src/main/res/values-ru/strings.xml
new file mode 100644
index 0000000..4a92343
--- /dev/null
+++ b/merchant-terminal/src/main/res/values-ru/strings.xml
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="config_error_unknown">Ошибка: Неправильная конфигурация</string>
+ <string name="config_fetching">Получение конфигурации…</string>
+ <string name="config_forget_password">Не сохранять пароль</string>
+ <string name="payment_intro_nfc">Для совершения платежа покупателем, разрешите сканирование QR-кода или использование NFC.</string>
+ <string name="payment_intro">Пожалуйста позвольте клиенту отсканировать QR-код для платежа.</string>
+ <string name="payment_cancel">Отменить оплату</string>
+ <string name="payment_received">Платёж получен</string>
+ <string name="payment_back_button">Продолжить</string>
+ <string name="payment_process_label">Требуется оплата</string>
+ <string name="payment_canceled">Оплата отменена</string>
+ <string name="history_label">История платежей</string>
+ <string name="history_unpaid">Неоплачено</string>
+ <string name="history_refund">Возврат</string>
+ <string name="refund_reason">Причина возврата</string>
+ <string name="refund_abort">Отменить</string>
+ <string name="refund_complete">Получено</string>
+ <string name="refund_confirm">Подтвердить возврат</string>
+ <string name="app_name">GNU Taler Точка Продажи</string>
+ <string name="app_name_short">Терминал продавца</string>
+ <string name="project_name">GNU Taler</string>
+ <string name="menu_order">Заказы</string>
+ <string name="menu_history">История</string>
+ <string name="menu_settings">Настройки</string>
+ <string name="order_label_title">Заказ №%s</string>
+ <string name="order_total">Итого: %s</string>
+ <string name="order_restart">Перезапустить</string>
+ <string name="order_undo">Отменить</string>
+ <string name="order_previous">Предыдущая</string>
+ <string name="order_next">Следующая</string>
+ <string name="order_custom">Добавить свой продукт</string>
+ <string name="order_complete">Выполнено</string>
+ <string name="order_custom_product">Название своего продукта</string>
+ <string name="order_custom_product_default">Чаевые</string>
+ <string name="order_custom_add_button">Добавить</string>
+ <string name="config_label">Настройки Продавца</string>
+ <string name="config_url">URL конфигурации</string>
+ <string name="config_username">Имя пользователя</string>
+ <string name="config_password">Пароль</string>
+ <string name="config_ok">Получить конфигурацию</string>
+ <string name="config_auth_error">Ошибка: Неверное имя пользователя или пароль</string>
+ <string name="config_error_network">Ошибка: не удается подключиться к серверу конфигурации</string>
+ <string name="config_error_category">Ошибка: не удается найти категорию товара</string>
+ <string name="config_error_malformed">Ошибка: Битый JSON конфигурации</string>
+ <string name="config_error_currency">Ошибка: Продукт %1$s имеет валюту %2$s, но ожидалось %3$s</string>
+ <string name="config_error_product_category_id">Ошибка: Продукт %1$s ссылается на неизвестную категорию с ID %2$d</string>
+ <string name="config_error_product_zero">Ошибка: не удается найти товар</string>
+ <string name="config_save_password">Запомнить пароль</string>
+ <string name="config_changed">Изменено на нового продавца используя %s</string>
+ <string name="config_fetching_label">Получение конфигурации</string>
+ <string name="config_docs">Пожалуйста перейдите к <a href="https://docs.taler.net/taler-merchant-pos-terminal.html#apis-and-data-formats">документации</a> по формату конфигурации</string>
+ <string name="payment_claimed">Ожидание пока клиент подтвердит платёж…</string>
+ <string name="payment_order_id">Чек №%s</string>
+ <string name="refund_amount">Сумма</string>
+ <string name="refund_error_max_amount">Сумма возврата превосходит сумму заказа %s</string>
+ <string name="refund_error_invalid_amount">Неправильное количество</string>
+ <string name="refund_error_zero">Сумма должна быть положительным числом</string>
+ <string name="refund_error_backend">Ошибка при обработке возврата</string>
+ <string name="refund_error_deadline">Возврат просрочен</string>
+ <string name="refund_error_already_refunded">Уже возвращено</string>
+ <string name="refund_intro_nfc">Пожалуйста дайте клиенту отсканировать QR-код или используйте NFC чтобы предложить возврат</string>
+ <string name="refund_intro">Пожалуйста дайте клиенту отсканировать QR-код чтобы предложить возврат</string>
+ <string name="refund_order_ref">Номер вашего заказа: %1$s
+\n
+\n%2$s</string>
+ <string name="error_payment">Ошибка: Никакого платежа не получено</string>
+ <string name="error_timeout">Платеж не был сделан за срок оплаты, пожалуйста попробуйте снова!</string>
+ <string name="error_cancelled">Платеж отменен</string>
+ <string name="error_history">Ошибка получения истории платежей</string>
+ <string name="toast_back_to_exit">Нажмите «назад» ещё раз чтобы выйти</string>
+</resources> \ No newline at end of file
diff --git a/wallet/build.gradle b/wallet/build.gradle
index f78d919..93f4a49 100644
--- a/wallet/build.gradle
+++ b/wallet/build.gradle
@@ -19,7 +19,7 @@ plugins {
id "kotlinx-serialization"
}
-def qtart_version = "0.10.1"
+def qtart_version = "0.10.6"
static def versionCodeEpoch() {
return (new Date().getTime() / 1000).toInteger()
@@ -41,8 +41,8 @@ android {
applicationId "net.taler.wallet"
minSdkVersion 24
targetSdkVersion 33
- versionCode 39
- versionName "0.9.4+p2"
+ versionCode 41
+ versionName "0.10.2"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
diff --git a/wallet/src/main/java/net/taler/wallet/HandleUriFragment.kt b/wallet/src/main/java/net/taler/wallet/HandleUriFragment.kt
index f0b502b..6b8db78 100644
--- a/wallet/src/main/java/net/taler/wallet/HandleUriFragment.kt
+++ b/wallet/src/main/java/net/taler/wallet/HandleUriFragment.kt
@@ -143,6 +143,12 @@ class HandleUriFragment: Fragment() {
val bundle = bundleOf("uri" to u2)
findNavController().navigate(R.id.action_handleUri_to_promptPayTemplate, bundle)
}
+ action.startsWith("dev-experiment/", ignoreCase = true) -> {
+ model.applyDevExperiment(u2) { error ->
+ showError(error)
+ }
+ findNavController().navigate(R.id.nav_main)
+ }
else -> {
showError(R.string.error_unsupported_uri, "From: $from\nURI: $u2")
findNavController().popBackStack()
diff --git a/wallet/src/main/java/net/taler/wallet/MainViewModel.kt b/wallet/src/main/java/net/taler/wallet/MainViewModel.kt
index 0f4b94a..82eb8d7 100644
--- a/wallet/src/main/java/net/taler/wallet/MainViewModel.kt
+++ b/wallet/src/main/java/net/taler/wallet/MainViewModel.kt
@@ -37,9 +37,12 @@ import net.taler.wallet.accounts.AccountManager
import net.taler.wallet.backend.BackendManager
import net.taler.wallet.backend.NotificationPayload
import net.taler.wallet.backend.NotificationReceiver
+import net.taler.wallet.backend.TalerErrorInfo
import net.taler.wallet.backend.VersionReceiver
import net.taler.wallet.backend.WalletBackendApi
import net.taler.wallet.backend.WalletCoreVersion
+import net.taler.wallet.backend.WalletRunConfig
+import net.taler.wallet.backend.WalletRunConfig.Testing
import net.taler.wallet.balances.BalanceManager
import net.taler.wallet.balances.ScopeInfo
import net.taler.wallet.deposit.DepositManager
@@ -69,7 +72,9 @@ class MainViewModel(
app: Application,
) : AndroidViewModel(app), VersionReceiver, NotificationReceiver {
- val devMode = MutableLiveData(BuildConfig.DEBUG)
+ private val mDevMode = MutableLiveData(BuildConfig.DEBUG)
+ val devMode: LiveData<Boolean> = mDevMode
+
val showProgressBar = MutableLiveData<Boolean>()
var walletVersion: String? = null
private set
@@ -80,7 +85,15 @@ class MainViewModel(
var merchantVersion: String? = null
private set
- private val api = WalletBackendApi(app, this, this)
+ @set:Synchronized
+ private var walletConfig = WalletRunConfig(
+ testing = Testing(
+ emitObservabilityEvents = true,
+ devModeActive = devMode.value ?: false,
+ )
+ )
+
+ private val api = WalletBackendApi(app, walletConfig, this, this)
val networkManager = NetworkManager(app.applicationContext)
val withdrawManager = WithdrawManager(api, viewModelScope)
@@ -200,6 +213,24 @@ class MainViewModel(
mScanCodeEvent.value = true.toEvent()
}
+ fun setDevMode(enabled: Boolean, onError: (error: TalerErrorInfo) -> Unit) {
+ mDevMode.postValue(enabled)
+ viewModelScope.launch {
+ val config = walletConfig.copy(
+ testing = walletConfig.testing?.copy(
+ devModeActive = enabled,
+ ) ?: Testing(
+ devModeActive = enabled,
+ ),
+ )
+
+ api.setWalletConfig(config)
+ .onSuccess {
+ walletConfig = config
+ }.onError(onError)
+ }
+ }
+
fun runIntegrationTest() {
viewModelScope.launch {
api.request<Unit>("runIntegrationTestV2") {
@@ -213,6 +244,14 @@ class MainViewModel(
}
}
+ fun applyDevExperiment(uri: String, onError: (error: TalerErrorInfo) -> Unit) {
+ viewModelScope.launch {
+ api.request<Unit>("applyDevExperiment") {
+ put("devExperimentUri", uri)
+ }.onError(onError)
+ }
+ }
+
}
sealed class AmountResult {
diff --git a/wallet/src/main/java/net/taler/wallet/ReceiveFundsFragment.kt b/wallet/src/main/java/net/taler/wallet/ReceiveFundsFragment.kt
index 2accaaf..25d35ec 100644
--- a/wallet/src/main/java/net/taler/wallet/ReceiveFundsFragment.kt
+++ b/wallet/src/main/java/net/taler/wallet/ReceiveFundsFragment.kt
@@ -144,9 +144,9 @@ private fun ReceiveFundsIntro(
isError = false
text = input
},
- label = { Text(stringResource(R.string.receive_amount)) },
+ label = { Text(stringResource(R.string.amount_receive)) },
supportingText = {
- if (isError) Text(stringResource(R.string.receive_amount_invalid))
+ if (isError) Text(stringResource(R.string.amount_invalid))
},
isError = isError,
numberOfDecimals = spec?.numFractionalInputDigits ?: DEFAULT_INPUT_DECIMALS,
diff --git a/wallet/src/main/java/net/taler/wallet/SendFundsFragment.kt b/wallet/src/main/java/net/taler/wallet/SendFundsFragment.kt
index 2581979..ca72a64 100644
--- a/wallet/src/main/java/net/taler/wallet/SendFundsFragment.kt
+++ b/wallet/src/main/java/net/taler/wallet/SendFundsFragment.kt
@@ -126,9 +126,9 @@ private fun SendFundsIntro(
insufficientBalance = false
text = input
},
- label = { Text(stringResource(R.string.send_amount)) },
+ label = { Text(stringResource(R.string.amount_send)) },
supportingText = {
- if (isError) Text(stringResource(R.string.receive_amount_invalid))
+ if (isError) Text(stringResource(R.string.amount_invalid))
else if (insufficientBalance) {
Text(stringResource(R.string.payment_balance_insufficient))
}
diff --git a/wallet/src/main/java/net/taler/wallet/Utils.kt b/wallet/src/main/java/net/taler/wallet/Utils.kt
index 8b34531..5c4fedc 100644
--- a/wallet/src/main/java/net/taler/wallet/Utils.kt
+++ b/wallet/src/main/java/net/taler/wallet/Utils.kt
@@ -139,3 +139,9 @@ fun FragmentActivity.showError(error: TalerErrorInfo) {
val message = json.encodeToString(error)
showError(message)
}
+
+fun Context.getThemeColor(attr: Int): Int {
+ val typedValue = TypedValue()
+ theme.resolveAttribute(attr, typedValue, true)
+ return typedValue.data
+} \ No newline at end of file
diff --git a/wallet/src/main/java/net/taler/wallet/backend/WalletBackendApi.kt b/wallet/src/main/java/net/taler/wallet/backend/WalletBackendApi.kt
index 0619a4e..fba9885 100644
--- a/wallet/src/main/java/net/taler/wallet/backend/WalletBackendApi.kt
+++ b/wallet/src/main/java/net/taler/wallet/backend/WalletBackendApi.kt
@@ -29,13 +29,13 @@ import kotlinx.serialization.json.decodeFromJsonElement
import net.taler.wallet.backend.TalerErrorCode.NONE
import org.json.JSONObject
import java.io.File
-import net.taler.wallet.backend.WalletRunConfig.*
private const val WALLET_DB = "talerwalletdb.sqlite3"
@OptIn(DelicateCoroutinesApi::class)
class WalletBackendApi(
private val app: Application,
+ private val initialConfig: WalletRunConfig,
private val versionReceiver: VersionReceiver,
notificationReceiver: NotificationReceiver,
) {
@@ -57,14 +57,10 @@ class WalletBackendApi(
"${app.filesDir}/${WALLET_DB}"
}
- val config = WalletRunConfig(testing = Testing(
- emitObservabilityEvents = true,
- ))
-
request("init", InitResponse.serializer()) {
put("persistentStoragePath", db)
put("logLevel", "INFO")
- put("config", JSONObject(BackendManager.json.encodeToString(config)))
+ put("config", JSONObject(BackendManager.json.encodeToString(initialConfig)))
}.onSuccess { response ->
versionReceiver.onVersionReceived(response.versionInfo)
}.onError { error ->
@@ -73,6 +69,12 @@ class WalletBackendApi(
}
}
+ suspend fun setWalletConfig(config: WalletRunConfig): WalletResponse<InitResponse> {
+ return request("initWallet", InitResponse.serializer()) {
+ put("config", JSONObject(BackendManager.json.encodeToString(config)))
+ }
+ }
+
suspend fun sendRequest(operation: String, args: JSONObject? = null): ApiResponse {
return backendManager.send(operation, args)
}
diff --git a/wallet/src/main/java/net/taler/wallet/balances/BalanceAdapter.kt b/wallet/src/main/java/net/taler/wallet/balances/BalanceAdapter.kt
index f40def4..aabef4b 100644
--- a/wallet/src/main/java/net/taler/wallet/balances/BalanceAdapter.kt
+++ b/wallet/src/main/java/net/taler/wallet/balances/BalanceAdapter.kt
@@ -61,8 +61,7 @@ class BalanceAdapter(private val listener: BalanceClickListener) : Adapter<Balan
private val amountView: TextView = v.findViewById(R.id.balanceAmountView)
private val scopeView: TextView = v.findViewById(R.id.scopeView)
private val balanceInboundAmount: TextView = v.findViewById(R.id.balanceInboundAmount)
- private val balanceInboundLabel: TextView = v.findViewById(R.id.balanceInboundLabel)
- private val pendingView: TextView = v.findViewById(R.id.pendingView)
+ private val balanceOutboundAmount: TextView = v.findViewById(R.id.balanceOutboundAmount)
fun bind(item: BalanceItem) {
v.setOnClickListener { listener.onBalanceClick(item.scopeInfo) }
@@ -71,11 +70,17 @@ class BalanceAdapter(private val listener: BalanceClickListener) : Adapter<Balan
val amountIncoming = item.pendingIncoming
if (amountIncoming.isZero()) {
balanceInboundAmount.visibility = GONE
- balanceInboundLabel.visibility = GONE
} else {
balanceInboundAmount.visibility = VISIBLE
- balanceInboundLabel.visibility = VISIBLE
- balanceInboundAmount.text = v.context.getString(R.string.amount_positive, amountIncoming.toString(showSymbol = false))
+ balanceInboundAmount.text = v.context.getString(R.string.balances_inbound_amount, amountIncoming.toString(showSymbol = false))
+ }
+
+ val amountOutgoing = item.pendingOutgoing
+ if (amountOutgoing.isZero()) {
+ balanceOutboundAmount.visibility = GONE
+ } else {
+ balanceOutboundAmount.visibility = VISIBLE
+ balanceOutboundAmount.text = v.context.getString(R.string.balances_outbound_amount, amountOutgoing.toString(showSymbol = false))
}
val scopeInfo = item.scopeInfo
@@ -90,8 +95,6 @@ class BalanceAdapter(private val listener: BalanceClickListener) : Adapter<Balan
VISIBLE
}
}
-
- pendingView.visibility = if (item.hasPending) VISIBLE else GONE
}
}
diff --git a/wallet/src/main/java/net/taler/wallet/deposit/MakeBitcoinDepositComposable.kt b/wallet/src/main/java/net/taler/wallet/deposit/MakeBitcoinDepositComposable.kt
index 3fa0d98..d356051 100644
--- a/wallet/src/main/java/net/taler/wallet/deposit/MakeBitcoinDepositComposable.kt
+++ b/wallet/src/main/java/net/taler/wallet/deposit/MakeBitcoinDepositComposable.kt
@@ -91,7 +91,7 @@ fun MakeBitcoinDepositComposable(
}
val amountTitle = if (state.effectiveDepositAmount == null) {
R.string.amount_chosen
- } else R.string.send_deposit_amount_effective
+ } else R.string.amount_effective
TransactionAmountComposable(
label = stringResource(id = amountTitle),
amount = state.effectiveDepositAmount ?: amount,
@@ -104,14 +104,16 @@ fun MakeBitcoinDepositComposable(
) {
val totalAmount = state.totalDepositCost ?: amount
val effectiveAmount = state.effectiveDepositAmount ?: Amount.zero(amount.currency)
- val fee = totalAmount - effectiveAmount
+ if (totalAmount > effectiveAmount) {
+ val fee = totalAmount - effectiveAmount
+ TransactionAmountComposable(
+ label = stringResource(id = R.string.amount_fee),
+ amount = fee,
+ amountType = AmountType.Negative,
+ )
+ }
TransactionAmountComposable(
- label = stringResource(id = R.string.withdraw_fees),
- amount = fee,
- amountType = AmountType.Negative,
- )
- TransactionAmountComposable(
- label = stringResource(id = R.string.send_amount),
+ label = stringResource(id = R.string.amount_send),
amount = totalAmount,
amountType = AmountType.Positive,
)
diff --git a/wallet/src/main/java/net/taler/wallet/deposit/MakeDepositComposable.kt b/wallet/src/main/java/net/taler/wallet/deposit/MakeDepositComposable.kt
index 9333ce1..2f9fd88 100644
--- a/wallet/src/main/java/net/taler/wallet/deposit/MakeDepositComposable.kt
+++ b/wallet/src/main/java/net/taler/wallet/deposit/MakeDepositComposable.kt
@@ -134,16 +134,18 @@ fun MakeDepositComposable(
) {
val totalAmount = state.totalDepositCost ?: amount
val effectiveAmount = state.effectiveDepositAmount ?: Amount.zero(amount.currency)
- val fee = totalAmount - effectiveAmount
+ if (totalAmount > effectiveAmount) {
+ val fee = totalAmount - effectiveAmount
- TransactionAmountComposable(
- label = stringResource(R.string.withdraw_fees),
- amount = fee.withSpec(amount.spec),
- amountType = if (fee.isZero()) Positive else Negative,
- )
+ TransactionAmountComposable(
+ label = stringResource(R.string.amount_fee),
+ amount = fee.withSpec(amount.spec),
+ amountType = Negative,
+ )
+ }
TransactionAmountComposable(
- label = stringResource(R.string.send_amount),
+ label = stringResource(R.string.amount_send),
amount = effectiveAmount.withSpec(amount.spec),
amountType = Positive,
)
diff --git a/wallet/src/main/java/net/taler/wallet/deposit/PayToUriFragment.kt b/wallet/src/main/java/net/taler/wallet/deposit/PayToUriFragment.kt
index 8961016..0dd3abd 100644
--- a/wallet/src/main/java/net/taler/wallet/deposit/PayToUriFragment.kt
+++ b/wallet/src/main/java/net/taler/wallet/deposit/PayToUriFragment.kt
@@ -140,7 +140,7 @@ private fun PayToComposable(
amountError = ""
amountText = input
},
- label = { Text(stringResource(R.string.send_amount)) },
+ label = { Text(stringResource(R.string.amount_send)) },
supportingText = {
if (amountError.isNotBlank()) Text(amountError)
},
@@ -158,7 +158,7 @@ private fun PayToComposable(
}
val focusManager = LocalFocusManager.current
- val errorStrInvalidAmount = stringResource(id = R.string.receive_amount_invalid)
+ val errorStrInvalidAmount = stringResource(id = R.string.amount_invalid)
val errorStrInsufficientBalance = stringResource(id = R.string.payment_balance_insufficient)
Button(
modifier = Modifier.padding(16.dp),
diff --git a/wallet/src/main/java/net/taler/wallet/deposit/TransactionDepositComposable.kt b/wallet/src/main/java/net/taler/wallet/deposit/TransactionDepositComposable.kt
index 817dfac..11264a1 100644
--- a/wallet/src/main/java/net/taler/wallet/deposit/TransactionDepositComposable.kt
+++ b/wallet/src/main/java/net/taler/wallet/deposit/TransactionDepositComposable.kt
@@ -77,10 +77,10 @@ fun TransactionDepositComposable(
amountType = AmountType.Neutral,
)
- val fee = t.amountEffective - t.amountRaw
- if (!fee.isZero()) {
+ if (t.amountEffective > t.amountRaw) {
+ val fee = t.amountEffective - t.amountRaw
TransactionAmountComposable(
- label = stringResource(id = R.string.withdraw_fees),
+ label = stringResource(id = R.string.amount_fee),
amount = fee.withSpec(spec),
amountType = AmountType.Negative,
)
diff --git a/wallet/src/main/java/net/taler/wallet/exchanges/ExchangeAdapter.kt b/wallet/src/main/java/net/taler/wallet/exchanges/ExchangeAdapter.kt
index cb294ac..674632e 100644
--- a/wallet/src/main/java/net/taler/wallet/exchanges/ExchangeAdapter.kt
+++ b/wallet/src/main/java/net/taler/wallet/exchanges/ExchangeAdapter.kt
@@ -33,6 +33,7 @@ interface ExchangeClickListener {
fun onExchangeSelected(item: ExchangeItem)
fun onManualWithdraw(item: ExchangeItem)
fun onPeerReceive(item: ExchangeItem)
+ fun onExchangeReload(item: ExchangeItem)
fun onExchangeDelete(item: ExchangeItem)
}
@@ -99,6 +100,10 @@ internal class ExchangeAdapter(
listener.onPeerReceive(item)
true
}
+ R.id.action_reload -> {
+ listener.onExchangeReload(item)
+ true
+ }
R.id.action_delete -> {
listener.onExchangeDelete(item)
true
diff --git a/wallet/src/main/java/net/taler/wallet/exchanges/ExchangeListFragment.kt b/wallet/src/main/java/net/taler/wallet/exchanges/ExchangeListFragment.kt
index 5482b5a..8a40bff 100644
--- a/wallet/src/main/java/net/taler/wallet/exchanges/ExchangeListFragment.kt
+++ b/wallet/src/main/java/net/taler/wallet/exchanges/ExchangeListFragment.kt
@@ -110,6 +110,13 @@ open class ExchangeListFragment : Fragment(), ExchangeClickListener {
showError(error.userFacingMsg)
}
})
+ exchangeManager.reloadError.observe(viewLifecycleOwner, EventObserver { error ->
+ if (model.devMode.value == true) {
+ showError(error)
+ } else {
+ showError(error.userFacingMsg)
+ }
+ })
}
protected open fun onExchangeUpdate(exchanges: List<ExchangeItem>) {
@@ -145,6 +152,10 @@ open class ExchangeListFragment : Fragment(), ExchangeClickListener {
findNavController().navigate(R.id.action_global_receiveFunds)
}
+ override fun onExchangeReload(item: ExchangeItem) {
+ exchangeManager.reload(item.exchangeBaseUrl)
+ }
+
override fun onExchangeDelete(item: ExchangeItem) {
val optionsArray = arrayOf(getString(R.string.exchange_delete_force))
val checkedArray = BooleanArray(1) { false }
diff --git a/wallet/src/main/java/net/taler/wallet/exchanges/ExchangeManager.kt b/wallet/src/main/java/net/taler/wallet/exchanges/ExchangeManager.kt
index eb01cab..fa357b5 100644
--- a/wallet/src/main/java/net/taler/wallet/exchanges/ExchangeManager.kt
+++ b/wallet/src/main/java/net/taler/wallet/exchanges/ExchangeManager.kt
@@ -62,6 +62,9 @@ class ExchangeManager(
private val mDeleteError = MutableLiveData<Event<TalerErrorInfo>>()
val deleteError: LiveData<Event<TalerErrorInfo>> = mDeleteError
+ private val mReloadError = MutableLiveData<Event<TalerErrorInfo>>()
+ val reloadError: LiveData<Event<TalerErrorInfo>> = mReloadError
+
var withdrawalExchange: ExchangeItem? = null
private fun list(): LiveData<List<ExchangeItem>> {
@@ -95,6 +98,22 @@ class ExchangeManager(
}
}
+ fun reload(exchangeUrl: String, force: Boolean = true) = scope.launch {
+ mProgress.value = true
+ api.request<Unit>("updateExchangeEntry") {
+ put("exchangeBaseUrl", exchangeUrl)
+ put("force", force)
+ }.onError {
+ Log.e(TAG, "Error reloading exchange: $it")
+ mProgress.value = false
+ mReloadError.value = it.toEvent()
+ }.onSuccess {
+ mProgress.value = false
+ Log.d(TAG, "Exchange $exchangeUrl reloaded")
+ list()
+ }
+ }
+
fun delete(exchangeUrl: String, purge: Boolean = false) = scope.launch {
mProgress.value = true
api.request<Unit>("deleteExchange") {
diff --git a/wallet/src/main/java/net/taler/wallet/payment/PayTemplateComposable.kt b/wallet/src/main/java/net/taler/wallet/payment/PayTemplateComposable.kt
index 3ea04cc..9107dc9 100644
--- a/wallet/src/main/java/net/taler/wallet/payment/PayTemplateComposable.kt
+++ b/wallet/src/main/java/net/taler/wallet/payment/PayTemplateComposable.kt
@@ -18,6 +18,7 @@ package net.taler.wallet.payment
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.padding
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
@@ -25,6 +26,7 @@ import androidx.compose.ui.Alignment.Companion.Center
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
import net.taler.common.Amount
import net.taler.common.ContractTerms
import net.taler.wallet.AmountResult
@@ -54,7 +56,7 @@ fun PayTemplateComposable(
) {
// If wallet is empty, there's no way the user can pay something
if (amountStatus is AmountFieldStatus.Invalid) {
- PayTemplateError(stringResource(R.string.receive_amount_invalid))
+ PayTemplateError(stringResource(R.string.amount_invalid))
} else if (currencies.isEmpty()) {
PayTemplateError(stringResource(R.string.payment_balance_insufficient))
} else when (val p = payStatus) {
@@ -86,7 +88,7 @@ fun PayTemplateComposable(
@Composable
fun PayTemplateError(message: String) {
Box(
- modifier = Modifier.fillMaxSize(),
+ modifier = Modifier.padding(16.dp).fillMaxSize(),
contentAlignment = Center,
) {
Text(
@@ -144,7 +146,7 @@ fun PayTemplateInsufficientBalancePreview() {
}
}
-@Preview
+@Preview(widthDp = 300)
@Composable
fun PayTemplateAlreadyPaidPreview() {
TalerSurface {
diff --git a/wallet/src/main/java/net/taler/wallet/payment/PayTemplateOrderComposable.kt b/wallet/src/main/java/net/taler/wallet/payment/PayTemplateOrderComposable.kt
index d6131c7..9647c42 100644
--- a/wallet/src/main/java/net/taler/wallet/payment/PayTemplateOrderComposable.kt
+++ b/wallet/src/main/java/net/taler/wallet/payment/PayTemplateOrderComposable.kt
@@ -85,7 +85,7 @@ fun PayTemplateOrderComposable(
onClick = {
when (val res = onCreateAmount(amount, currency)) {
is AmountResult.InsufficientBalance -> onError(R.string.payment_balance_insufficient)
- is AmountResult.InvalidAmount -> onError(R.string.receive_amount_invalid)
+ is AmountResult.InvalidAmount -> onError(R.string.amount_invalid)
is AmountResult.Success -> onSubmit(summary, res.amount)
}
},
@@ -113,7 +113,7 @@ private fun AmountField(
.weight(1f),
value = amount,
onValueChange = { onAmountChosen(it, currency) },
- label = { Text(stringResource(R.string.send_amount)) }
+ label = { Text(stringResource(R.string.amount_send)) }
)
CurrencyDropdown(
modifier = Modifier.weight(1f),
diff --git a/wallet/src/main/java/net/taler/wallet/payment/TransactionPaymentComposable.kt b/wallet/src/main/java/net/taler/wallet/payment/TransactionPaymentComposable.kt
index 0f6d661..beb37d9 100644
--- a/wallet/src/main/java/net/taler/wallet/payment/TransactionPaymentComposable.kt
+++ b/wallet/src/main/java/net/taler/wallet/payment/TransactionPaymentComposable.kt
@@ -82,10 +82,10 @@ fun TransactionPaymentComposable(
amountType = AmountType.Neutral,
)
- val fee = t.amountEffective - t.amountRaw
- if (!fee.isZero()) {
+ if (t.amountEffective > t.amountRaw) {
+ val fee = t.amountEffective - t.amountRaw
TransactionAmountComposable(
- label = stringResource(id = R.string.withdraw_fees),
+ label = stringResource(id = R.string.amount_fee),
amount = fee.withSpec(spec),
amountType = AmountType.Negative,
)
diff --git a/wallet/src/main/java/net/taler/wallet/peer/IncomingComposable.kt b/wallet/src/main/java/net/taler/wallet/peer/IncomingComposable.kt
index 1ce0175..609629e 100644
--- a/wallet/src/main/java/net/taler/wallet/peer/IncomingComposable.kt
+++ b/wallet/src/main/java/net/taler/wallet/peer/IncomingComposable.kt
@@ -134,7 +134,7 @@ fun ColumnScope.PeerPullTermsComposable(
modifier = Modifier.align(End),
) {
Text(
- text = stringResource(id = R.string.payment_label_amount_total),
+ text = stringResource(id = R.string.amount_total_label),
style = MaterialTheme.typography.bodyLarge,
)
Text(
@@ -145,22 +145,26 @@ fun ColumnScope.PeerPullTermsComposable(
)
}
// this gets used for credit and debit, so fee calculation differs
- val fee = if (data.isCredit) {
+ val fee = if (data.isCredit && terms.amountRaw > terms.amountEffective) {
terms.amountRaw - terms.amountEffective
- } else {
+ } else if (terms.amountEffective > terms.amountRaw) {
terms.amountEffective - terms.amountRaw
+ } else null
+
+ if (fee != null) {
+ val feeStr = if (data.isCredit) {
+ stringResource(R.string.amount_negative, fee)
+ } else {
+ stringResource(R.string.amount_positive, fee)
+ }
+ Text(
+ modifier = Modifier.align(End),
+ text = feeStr,
+ style = MaterialTheme.typography.bodyLarge,
+ color = MaterialTheme.colorScheme.error,
+ )
}
- val feeStr = if (data.isCredit) {
- stringResource(R.string.amount_negative, fee)
- } else {
- stringResource(R.string.amount_positive, fee)
- }
- if (!fee.isZero()) Text(
- modifier = Modifier.align(End),
- text = feeStr,
- style = MaterialTheme.typography.bodyLarge,
- color = MaterialTheme.colorScheme.error,
- )
+
if (terms is IncomingAccepting) {
CircularProgressIndicator(
modifier = Modifier
diff --git a/wallet/src/main/java/net/taler/wallet/peer/OutgoingPullComposable.kt b/wallet/src/main/java/net/taler/wallet/peer/OutgoingPullComposable.kt
index 90b520e..f3d569f 100644
--- a/wallet/src/main/java/net/taler/wallet/peer/OutgoingPullComposable.kt
+++ b/wallet/src/main/java/net/taler/wallet/peer/OutgoingPullComposable.kt
@@ -148,10 +148,10 @@ fun OutgoingPullIntroComposable(
amountType = AmountType.Positive,
)
- if (state is OutgoingChecked) {
+ if (state is OutgoingChecked && state.amountRaw > state.amountEffective) {
val fee = state.amountRaw - state.amountEffective
- if (!fee.isZero()) TransactionAmountComposable(
- label = stringResource(id = R.string.withdraw_fees),
+ TransactionAmountComposable(
+ label = stringResource(id = R.string.amount_fee),
amount = fee.withSpec(amount.spec),
amountType = AmountType.Negative,
)
diff --git a/wallet/src/main/java/net/taler/wallet/peer/OutgoingPushComposable.kt b/wallet/src/main/java/net/taler/wallet/peer/OutgoingPushComposable.kt
index d39fdc8..7eba733 100644
--- a/wallet/src/main/java/net/taler/wallet/peer/OutgoingPushComposable.kt
+++ b/wallet/src/main/java/net/taler/wallet/peer/OutgoingPushComposable.kt
@@ -89,7 +89,7 @@ fun OutgoingPushIntroComposable(
style = MaterialTheme.typography.titleLarge,
)
- if (state is OutgoingChecked) {
+ if (state is OutgoingChecked && state.amountEffective > state.amountRaw) {
val fee = state.amountEffective - state.amountRaw
Text(
modifier = Modifier.padding(vertical = 16.dp),
diff --git a/wallet/src/main/java/net/taler/wallet/peer/TransactionPeerPullCredit.kt b/wallet/src/main/java/net/taler/wallet/peer/TransactionPeerPullCredit.kt
index 3b15b6f..59d405c 100644
--- a/wallet/src/main/java/net/taler/wallet/peer/TransactionPeerPullCredit.kt
+++ b/wallet/src/main/java/net/taler/wallet/peer/TransactionPeerPullCredit.kt
@@ -49,15 +49,15 @@ fun ColumnScope.TransactionPeerPullCreditComposable(t: TransactionPeerPullCredit
)
TransactionAmountComposable(
- label = stringResource(id = R.string.receive_peer_amount_invoiced),
+ label = stringResource(id = R.string.amount_invoiced),
amount = t.amountRaw.withSpec(spec),
amountType = AmountType.Neutral,
)
- val fee = t.amountRaw - t.amountEffective
- if (!fee.isZero()) {
+ if (t.amountRaw > t.amountEffective) {
+ val fee = t.amountRaw - t.amountEffective
TransactionAmountComposable(
- label = stringResource(id = R.string.withdraw_fees),
+ label = stringResource(id = R.string.amount_fee),
amount = fee.withSpec(spec),
amountType = AmountType.Negative,
)
diff --git a/wallet/src/main/java/net/taler/wallet/peer/TransactionPeerPullDebit.kt b/wallet/src/main/java/net/taler/wallet/peer/TransactionPeerPullDebit.kt
index dadff4a..b8966d4 100644
--- a/wallet/src/main/java/net/taler/wallet/peer/TransactionPeerPullDebit.kt
+++ b/wallet/src/main/java/net/taler/wallet/peer/TransactionPeerPullDebit.kt
@@ -46,10 +46,10 @@ fun TransactionPeerPullDebitComposable(t: TransactionPeerPullDebit, spec: Curren
amountType = AmountType.Neutral,
)
- val fee = t.amountEffective - t.amountRaw
- if (!fee.isZero()) {
+ if (t.amountEffective > t.amountRaw) {
+ val fee = t.amountEffective - t.amountRaw
TransactionAmountComposable(
- label = stringResource(id = R.string.withdraw_fees),
+ label = stringResource(id = R.string.amount_fee),
amount = fee.withSpec(spec),
amountType = AmountType.Negative,
)
diff --git a/wallet/src/main/java/net/taler/wallet/peer/TransactionPeerPushCredit.kt b/wallet/src/main/java/net/taler/wallet/peer/TransactionPeerPushCredit.kt
index dbf0fb9..d407ff2 100644
--- a/wallet/src/main/java/net/taler/wallet/peer/TransactionPeerPushCredit.kt
+++ b/wallet/src/main/java/net/taler/wallet/peer/TransactionPeerPushCredit.kt
@@ -46,10 +46,10 @@ fun TransactionPeerPushCreditComposable(t: TransactionPeerPushCredit, spec: Curr
amountType = AmountType.Neutral,
)
- val fee = t.amountRaw - t.amountEffective
- if (!fee.isZero()) {
+ if (t.amountRaw > t.amountEffective) {
+ val fee = t.amountRaw - t.amountEffective
TransactionAmountComposable(
- label = stringResource(id = R.string.withdraw_fees),
+ label = stringResource(id = R.string.amount_fee),
amount = fee.withSpec(spec),
amountType = AmountType.Negative,
)
diff --git a/wallet/src/main/java/net/taler/wallet/peer/TransactionPeerPushDebit.kt b/wallet/src/main/java/net/taler/wallet/peer/TransactionPeerPushDebit.kt
index e592c3e..f2edc19 100644
--- a/wallet/src/main/java/net/taler/wallet/peer/TransactionPeerPushDebit.kt
+++ b/wallet/src/main/java/net/taler/wallet/peer/TransactionPeerPushDebit.kt
@@ -65,10 +65,10 @@ fun ColumnScope.TransactionPeerPushDebitComposable(t: TransactionPeerPushDebit,
amountType = AmountType.Neutral,
)
- val fee = t.amountEffective - t.amountRaw
- if (!fee.isZero()) {
+ if (t.amountEffective > t.amountRaw) {
+ val fee = t.amountEffective - t.amountRaw
TransactionAmountComposable(
- label = stringResource(id = R.string.withdraw_fees),
+ label = stringResource(id = R.string.amount_fee),
amount = fee.withSpec(spec),
amountType = AmountType.Negative,
)
diff --git a/wallet/src/main/java/net/taler/wallet/refund/TransactionRefundComposable.kt b/wallet/src/main/java/net/taler/wallet/refund/TransactionRefundComposable.kt
index 637b41a..b17658a 100644
--- a/wallet/src/main/java/net/taler/wallet/refund/TransactionRefundComposable.kt
+++ b/wallet/src/main/java/net/taler/wallet/refund/TransactionRefundComposable.kt
@@ -81,10 +81,10 @@ fun TransactionRefundComposable(
amount = t.amountRaw.withSpec(spec),
amountType = AmountType.Neutral,
)
- val fee = t.amountRaw - t.amountEffective
- if (!fee.isZero()) {
+ if (t.amountRaw > t.amountEffective) {
+ val fee = t.amountRaw - t.amountEffective
TransactionAmountComposable(
- label = stringResource(id = R.string.withdraw_fees),
+ label = stringResource(id = R.string.amount_fee),
amount = fee.withSpec(spec),
amountType = AmountType.Negative,
)
diff --git a/wallet/src/main/java/net/taler/wallet/settings/SettingsFragment.kt b/wallet/src/main/java/net/taler/wallet/settings/SettingsFragment.kt
index 0435665..38eeb9b 100644
--- a/wallet/src/main/java/net/taler/wallet/settings/SettingsFragment.kt
+++ b/wallet/src/main/java/net/taler/wallet/settings/SettingsFragment.kt
@@ -33,6 +33,7 @@ import net.taler.wallet.BuildConfig.VERSION_CODE
import net.taler.wallet.BuildConfig.VERSION_NAME
import net.taler.wallet.MainViewModel
import net.taler.wallet.R
+import net.taler.wallet.showError
import net.taler.wallet.withdraw.WithdrawTestStatus
import java.lang.System.currentTimeMillis
@@ -108,7 +109,9 @@ class SettingsFragment : PreferenceFragmentCompat() {
devPrefs.forEach { it.isVisible = enabled }
}
prefDevMode.setOnPreferenceChangeListener { _, newValue ->
- model.devMode.value = newValue as Boolean
+ model.setDevMode(newValue as Boolean) { error ->
+ showError(error)
+ }
true
}
diff --git a/wallet/src/main/java/net/taler/wallet/transactions/TransactionAdapter.kt b/wallet/src/main/java/net/taler/wallet/transactions/TransactionAdapter.kt
index 22dcc3f..3b686a6 100644
--- a/wallet/src/main/java/net/taler/wallet/transactions/TransactionAdapter.kt
+++ b/wallet/src/main/java/net/taler/wallet/transactions/TransactionAdapter.kt
@@ -36,6 +36,7 @@ import net.taler.common.CurrencySpecification
import net.taler.common.exhaustive
import net.taler.common.toRelativeTime
import net.taler.wallet.R
+import net.taler.wallet.getThemeColor
import net.taler.wallet.transactions.TransactionAdapter.TransactionViewHolder
import net.taler.wallet.transactions.TransactionMajorState.Aborted
import net.taler.wallet.transactions.TransactionMajorState.Failed
@@ -97,7 +98,7 @@ internal class TransactionAdapter(
private val amountColor = amount.currentTextColor
private val extraInfoColor = extraInfoView.currentTextColor
- private val red = getColor(context, R.color.red)
+ private val red = context.getThemeColor(R.attr.colorError)
private val green = getColor(context, R.color.green)
fun bind(transaction: Transaction, selected: Boolean) {
diff --git a/wallet/src/main/java/net/taler/wallet/transactions/TransactionLossFragment.kt b/wallet/src/main/java/net/taler/wallet/transactions/TransactionLossFragment.kt
new file mode 100644
index 0000000..2c95880
--- /dev/null
+++ b/wallet/src/main/java/net/taler/wallet/transactions/TransactionLossFragment.kt
@@ -0,0 +1,163 @@
+/*
+ * This file is part of GNU Taler
+ * (C) 2024 Taler Systems S.A.
+ *
+ * GNU Taler is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 3, or (at your option) any later version.
+ *
+ * GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ */
+
+package net.taler.wallet.transactions
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.rememberScrollState
+import androidx.compose.foundation.verticalScroll
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Surface
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.livedata.observeAsState
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.ComposeView
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import net.taler.common.Amount
+import net.taler.common.CurrencySpecification
+import net.taler.common.Timestamp
+import net.taler.common.toAbsoluteTime
+import net.taler.wallet.R
+import net.taler.wallet.backend.TalerErrorCode
+import net.taler.wallet.backend.TalerErrorInfo
+import net.taler.wallet.compose.TalerSurface
+import net.taler.wallet.transactions.LossEventType.DenomExpired
+import net.taler.wallet.transactions.LossEventType.DenomUnoffered
+import net.taler.wallet.transactions.LossEventType.DenomVanished
+import net.taler.wallet.transactions.TransactionAction.Abort
+import net.taler.wallet.transactions.TransactionAction.Retry
+import net.taler.wallet.transactions.TransactionAction.Suspend
+import net.taler.wallet.transactions.TransactionMajorState.Pending
+
+class TransactionLossFragment: TransactionDetailFragment() {
+ val scope get() = transactionManager.selectedScope
+
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View = ComposeView(requireContext()).apply {
+ setContent {
+ val t = transactionManager.selectedTransaction.observeAsState().value
+ val spec = scope?.let { balanceManager.getSpecForScopeInfo(it) }
+
+ TalerSurface {
+ if (t is TransactionDenomLoss) {
+ TransitionLossComposable(t, devMode, spec) {
+ onTransitionButtonClicked(t, it)
+ }
+ }
+ }
+ }
+ }
+}
+
+@Composable
+fun TransitionLossComposable(
+ t: TransactionDenomLoss,
+ devMode: Boolean,
+ spec: CurrencySpecification?,
+ onTransition: (t: TransactionAction) -> Unit,
+) {
+ val scrollState = rememberScrollState()
+ val context = LocalContext.current
+
+ Column(
+ modifier = Modifier
+ .fillMaxWidth()
+ .verticalScroll(scrollState),
+ horizontalAlignment = Alignment.CenterHorizontally,
+ ) {
+ Text(
+ modifier = Modifier.padding(16.dp),
+ text = t.timestamp.ms.toAbsoluteTime(context).toString(),
+ style = MaterialTheme.typography.bodyLarge,
+ )
+
+ TransactionAmountComposable(
+ label = stringResource(id = R.string.amount_lost),
+ amount = t.amountEffective.withSpec(spec),
+ amountType = AmountType.Negative,
+ )
+
+ TransactionInfoComposable(
+ label = stringResource(id = R.string.loss_reason),
+ info = stringResource(
+ when(t.lossEventType) {
+ DenomExpired -> R.string.loss_reason_expired
+ DenomVanished -> R.string.loss_reason_vanished
+ DenomUnoffered -> R.string.loss_reason_unoffered
+ }
+ )
+ )
+
+ TransitionsComposable(t, devMode, onTransition)
+
+ if (devMode && t.error != null) {
+ ErrorTransactionButton(error = t.error)
+ }
+ }
+}
+
+fun previewLossTransaction(lossEventType: LossEventType) =
+ TransactionDenomLoss(
+ transactionId = "transactionId",
+ timestamp = Timestamp.fromMillis(System.currentTimeMillis() - 360 * 60 * 1000),
+ txState = TransactionState(Pending),
+ txActions = listOf(Retry, Suspend, Abort),
+ amountRaw = Amount.fromString("TESTKUDOS", "0.3"),
+ amountEffective = Amount.fromString("TESTKUDOS", "0.3"),
+ error = TalerErrorInfo(code = TalerErrorCode.WALLET_WITHDRAWAL_KYC_REQUIRED),
+ lossEventType = lossEventType,
+ )
+
+@Composable
+@Preview
+fun TransitionLossComposableExpiredPreview() {
+ val t = previewLossTransaction(DenomExpired)
+ Surface {
+ TransitionLossComposable(t, true, null) {}
+ }
+}
+
+@Composable
+@Preview
+fun TransitionLossComposableVanishedPreview() {
+ val t = previewLossTransaction(DenomVanished)
+ Surface {
+ TransitionLossComposable(t, true, null) {}
+ }
+}
+
+@Composable
+@Preview
+fun TransactionLossComposableUnofferedPreview() {
+ val t = previewLossTransaction(DenomUnoffered)
+ Surface {
+ TransitionLossComposable(t, true, null) {}
+ }
+}
diff --git a/wallet/src/main/java/net/taler/wallet/transactions/TransactionRefreshFragment.kt b/wallet/src/main/java/net/taler/wallet/transactions/TransactionRefreshFragment.kt
index 8f474f9..e55d887 100644
--- a/wallet/src/main/java/net/taler/wallet/transactions/TransactionRefreshFragment.kt
+++ b/wallet/src/main/java/net/taler/wallet/transactions/TransactionRefreshFragment.kt
@@ -91,7 +91,7 @@ private fun TransactionRefreshComposable(
style = MaterialTheme.typography.bodyLarge,
)
TransactionAmountComposable(
- label = stringResource(id = R.string.withdraw_fees),
+ label = stringResource(id = R.string.amount_fee),
amount = t.amountEffective.withSpec(spec),
amountType = AmountType.Negative,
)
diff --git a/wallet/src/main/java/net/taler/wallet/transactions/Transactions.kt b/wallet/src/main/java/net/taler/wallet/transactions/Transactions.kt
index be36a13..2bd204c 100644
--- a/wallet/src/main/java/net/taler/wallet/transactions/Transactions.kt
+++ b/wallet/src/main/java/net/taler/wallet/transactions/Transactions.kt
@@ -17,6 +17,7 @@
package net.taler.wallet.transactions
import android.content.Context
+import android.net.Uri
import android.util.Log
import androidx.annotation.DrawableRes
import androidx.annotation.IdRes
@@ -216,6 +217,16 @@ data class WithdrawalExchangeAccountDetails (
val paytoUri: String,
/**
+ * Status that indicates whether the account can be used
+ * by the user to send funds for a withdrawal.
+ *
+ * ok: account should be shown to the user
+ * error: account should not be shown to the user, UIs might render the error (in conversionError),
+ * especially in dev mode.
+ */
+ val status: Status,
+
+ /**
* Transfer amount. Might be in a different currency than the requested
* amount for withdrawal.
*
@@ -235,7 +246,23 @@ data class WithdrawalExchangeAccountDetails (
* exchange.
*/
val creditRestrictions: List<AccountRestriction>? = null,
-)
+
+ /**
+ * Label given to the account or the account's bank by the exchange.
+ */
+ val bankLabel: String? = null,
+
+ val priority: Int? = null,
+) {
+ @Serializable
+ enum class Status {
+ @SerialName("ok")
+ Ok,
+
+ @SerialName("error")
+ Error;
+ }
+}
@Serializable
sealed class AccountRestriction {
@@ -328,10 +355,7 @@ class TransactionRefund(
@Transient
override val amountType = AmountType.Positive
- override fun getTitle(context: Context): String {
- val merchantName = paymentInfo?.merchant?.name ?: "null"
- return context.getString(R.string.transaction_refund_from, merchantName)
- }
+ override fun getTitle(context: Context) = paymentInfo?.merchant?.name ?: context.getString(R.string.transaction_refund)
override val generalTitleRes = R.string.refund_title
}
@@ -378,7 +402,10 @@ class TransactionDeposit(
@Transient
override val amountType = AmountType.Negative
override fun getTitle(context: Context): String {
- return context.getString(R.string.transaction_deposit)
+ val uri = Uri.parse(targetPaytoUri)
+ return uri.getQueryParameter("receiver-name")?.let { receiverName ->
+ context.getString(R.string.transaction_deposit_to, receiverName)
+ } ?: context.getString(R.string.transaction_deposit)
}
override val generalTitleRes = R.string.transaction_deposit
@@ -506,6 +533,47 @@ class TransactionPeerPushCredit(
}
/**
+ * A transaction to indicate financial loss due to denominations
+ * that became unusable for deposits.
+ */
+@Serializable
+@SerialName("denom-loss")
+class TransactionDenomLoss(
+ override val transactionId: String,
+ override val timestamp: Timestamp,
+ override val txState: TransactionState,
+ override val txActions: List<TransactionAction>,
+ override val error: TalerErrorInfo? = null,
+ override val amountRaw: Amount,
+ override val amountEffective: Amount,
+ val lossEventType: LossEventType,
+): Transaction() {
+ override val icon: Int = R.drawable.transaction_loss
+ override val detailPageNav = R.id.nav_transactions_detail_loss
+
+ @Transient
+ override val amountType: AmountType = AmountType.Negative
+
+ override fun getTitle(context: Context): String {
+ return context.getString(R.string.transaction_denom_loss)
+ }
+
+ override val generalTitleRes: Int = R.string.transaction_denom_loss
+}
+
+@Serializable
+enum class LossEventType {
+ @SerialName("denom-expired")
+ DenomExpired,
+
+ @SerialName("denom-vanished")
+ DenomVanished,
+
+ @SerialName("denom-unoffered")
+ DenomUnoffered
+}
+
+/**
* This represents a transaction that we can not parse for some reason.
*/
class DummyTransaction(
diff --git a/wallet/src/main/java/net/taler/wallet/transactions/TransactionsFragment.kt b/wallet/src/main/java/net/taler/wallet/transactions/TransactionsFragment.kt
index 5243427..d2d0c9c 100644
--- a/wallet/src/main/java/net/taler/wallet/transactions/TransactionsFragment.kt
+++ b/wallet/src/main/java/net/taler/wallet/transactions/TransactionsFragment.kt
@@ -26,6 +26,7 @@ import android.view.MenuItem
import android.view.View
import android.view.View.INVISIBLE
import android.view.ViewGroup
+import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.SearchView
import androidx.appcompat.widget.SearchView.OnQueryTextListener
import androidx.fragment.app.Fragment
@@ -44,6 +45,8 @@ import net.taler.wallet.MainViewModel
import net.taler.wallet.R
import net.taler.wallet.TAG
import net.taler.wallet.balances.BalanceState.Success
+import net.taler.wallet.balances.ScopeInfo
+import net.taler.wallet.cleanExchange
import net.taler.wallet.databinding.FragmentTransactionsBinding
import net.taler.wallet.showError
@@ -115,7 +118,7 @@ class TransactionsFragment : Fragment(), OnTransactionClickListener, ActionMode.
if (balances.size == 1) ui.mainFab.visibility = INVISIBLE
balances.find { it.scopeInfo == scopeInfo }?.let { balance ->
- ui.amount.text = balance.available.toString(showSymbol = false)
+ ui.actionsBar.amount.text = balance.available.toString(showSymbol = false)
transactionAdapter.setCurrencySpec(balance.available.spec)
}
}
@@ -125,10 +128,10 @@ class TransactionsFragment : Fragment(), OnTransactionClickListener, ActionMode.
transactionManager.transactions.observe(viewLifecycleOwner) { result ->
onTransactionsResult(result)
}
- ui.sendButton.setOnClickListener {
+ ui.actionsBar.sendButton.setOnClickListener {
findNavController().navigate(R.id.sendFunds)
}
- ui.receiveButton.setOnClickListener {
+ ui.actionsBar.receiveButton.setOnClickListener {
findNavController().navigate(R.id.action_global_receiveFunds)
}
ui.mainFab.setOnClickListener {
@@ -154,6 +157,8 @@ class TransactionsFragment : Fragment(), OnTransactionClickListener, ActionMode.
override fun onStart() {
super.onStart()
requireActivity().title = getString(R.string.transactions_detail_title_currency, scopeInfo.currency)
+ (requireActivity() as AppCompatActivity).supportActionBar?.subtitle =
+ (scopeInfo as? ScopeInfo.Exchange)?.url?.let { cleanExchange(it) }
}
private fun setupSearch(item: MenuItem) {
@@ -261,6 +266,11 @@ class TransactionsFragment : Fragment(), OnTransactionClickListener, ActionMode.
return true
}
+ override fun onStop() {
+ super.onStop()
+ (requireActivity() as AppCompatActivity).supportActionBar?.subtitle = null
+ }
+
override fun onDestroyActionMode(mode: ActionMode) {
tracker?.clearSelection()
actionMode = null
diff --git a/wallet/src/main/java/net/taler/wallet/withdraw/PromptWithdrawFragment.kt b/wallet/src/main/java/net/taler/wallet/withdraw/PromptWithdrawFragment.kt
index 56f56f7..9983409 100644
--- a/wallet/src/main/java/net/taler/wallet/withdraw/PromptWithdrawFragment.kt
+++ b/wallet/src/main/java/net/taler/wallet/withdraw/PromptWithdrawFragment.kt
@@ -175,8 +175,8 @@ class PromptWithdrawFragment : Fragment() {
ui.chosenAmountView.text = amountRaw.toString()
ui.chosenAmountView.fadeIn()
- val fee = amountRaw - amountEffective
- if (!fee.isZero()) {
+ if (amountRaw > amountEffective) {
+ val fee = amountRaw - amountEffective
ui.feeLabel.fadeIn()
ui.feeView.text = getString(R.string.amount_negative, fee.toString())
ui.feeView.fadeIn()
diff --git a/wallet/src/main/java/net/taler/wallet/withdraw/TransactionWithdrawalComposable.kt b/wallet/src/main/java/net/taler/wallet/withdraw/TransactionWithdrawalComposable.kt
index 5155b5b..9bfeda6 100644
--- a/wallet/src/main/java/net/taler/wallet/withdraw/TransactionWithdrawalComposable.kt
+++ b/wallet/src/main/java/net/taler/wallet/withdraw/TransactionWithdrawalComposable.kt
@@ -81,23 +81,25 @@ fun TransactionWithdrawalComposable(
ActionButton(tx = t, listener = actionListener)
- TransactionAmountComposable(
- label = stringResource(R.string.amount_chosen),
- amount = t.amountRaw.withSpec(spec),
- amountType = AmountType.Neutral,
- )
+ if (t.amountRaw != t.amountEffective) {
+ TransactionAmountComposable(
+ label = stringResource(R.string.amount_chosen),
+ amount = t.amountRaw.withSpec(spec),
+ amountType = AmountType.Neutral,
+ )
+ }
- val fee = t.amountRaw - t.amountEffective
- if (!fee.isZero()) {
+ if (t.amountRaw > t.amountEffective) {
+ val fee = t.amountRaw - t.amountEffective
TransactionAmountComposable(
- label = stringResource(id = R.string.withdraw_fees),
+ label = stringResource(id = R.string.amount_fee),
amount = fee.withSpec(spec),
amountType = AmountType.Negative,
)
}
TransactionAmountComposable(
- label = stringResource(id = R.string.withdraw_total),
+ label = stringResource(id = R.string.amount_total),
amount = t.amountEffective.withSpec(spec),
amountType = AmountType.Positive,
)
@@ -129,6 +131,7 @@ fun TransactionWithdrawalComposablePreview() {
WithdrawalExchangeAccountDetails(
paytoUri = "payto://IBAN/1231231231",
transferAmount = Amount.fromJSONString("NETZBON:42.23"),
+ status = WithdrawalExchangeAccountDetails.Status.Ok,
currencySpecification = CurrencySpecification(
name = "NETZBON",
numFractionalInputDigits = 2,
diff --git a/wallet/src/main/java/net/taler/wallet/withdraw/manual/ScreenTransfer.kt b/wallet/src/main/java/net/taler/wallet/withdraw/manual/ScreenTransfer.kt
index 35ff89c..00495fb 100644
--- a/wallet/src/main/java/net/taler/wallet/withdraw/manual/ScreenTransfer.kt
+++ b/wallet/src/main/java/net/taler/wallet/withdraw/manual/ScreenTransfer.kt
@@ -53,6 +53,7 @@ import net.taler.wallet.compose.copyToClipBoard
import net.taler.wallet.transactions.AmountType
import net.taler.wallet.transactions.TransactionAmountComposable
import net.taler.wallet.transactions.WithdrawalExchangeAccountDetails
+import net.taler.wallet.transactions.WithdrawalExchangeAccountDetails.Status.*
import net.taler.wallet.withdraw.TransferData
import net.taler.wallet.withdraw.WithdrawStatus
@@ -66,13 +67,20 @@ fun ScreenTransfer(
// TODO: show some placeholder
if (status.withdrawalTransfers.isEmpty()) return
- val defaultTransfer = status.withdrawalTransfers[0]
+ val transfers = status.withdrawalTransfers.filter {
+ // TODO: in dev mode, show debug info when status is `Error'
+ it.withdrawalAccount.status == Ok
+ }.sortedByDescending {
+ it.withdrawalAccount.priority
+ }
+
+ val defaultTransfer = transfers[0]
var selectedTransfer by remember { mutableStateOf(defaultTransfer) }
Column {
if (status.withdrawalTransfers.size > 1) {
TransferAccountChooser(
- accounts = status.withdrawalTransfers.map { it.withdrawalAccount },
+ accounts = transfers.map { it.withdrawalAccount },
selectedAccount = selectedTransfer.withdrawalAccount,
onSelectAccount = { account ->
status.withdrawalTransfers.find {
@@ -92,8 +100,8 @@ fun ScreenTransfer(
is TransferData.Taler -> TransferTaler(
transfer = transfer,
exchangeBaseUrl = status.exchangeBaseUrl,
- transactionAmountRaw = status.transactionAmountRaw,
- transactionAmountEffective = status.transactionAmountEffective,
+ transactionAmountRaw = status.transactionAmountRaw.withSpec(spec),
+ transactionAmountEffective = status.transactionAmountEffective.withSpec(spec),
)
is TransferData.IBAN -> TransferIBAN(
@@ -185,33 +193,33 @@ fun WithdrawalAmountTransfer(
horizontalAlignment = Alignment.CenterHorizontally,
) {
TransactionAmountComposable(
- label = stringResource(R.string.withdraw_transfer),
+ label = stringResource(R.string.amount_transfer),
amount = conversionAmountRaw,
amountType = AmountType.Neutral,
)
if (amountRaw.currency != conversionAmountRaw.currency) {
TransactionAmountComposable(
- label = stringResource(R.string.withdraw_conversion),
+ label = stringResource(R.string.amount_conversion),
amount = amountRaw,
amountType = AmountType.Neutral,
)
}
- val fee = amountRaw - amountEffective
- if (!fee.isZero()) {
+ if (amountRaw > amountEffective) {
+ val fee = amountRaw - amountEffective
TransactionAmountComposable(
- label = stringResource(id = R.string.withdraw_fees),
+ label = stringResource(id = R.string.amount_fee),
amount = fee,
amountType = AmountType.Negative,
)
- }
- TransactionAmountComposable(
- label = stringResource(id = R.string.withdraw_total),
- amount = amountEffective,
- amountType = AmountType.Positive,
- )
+ TransactionAmountComposable(
+ label = stringResource(id = R.string.amount_total),
+ amount = amountEffective,
+ amountType = AmountType.Positive,
+ )
+ }
}
}
@@ -236,7 +244,9 @@ fun TransferAccountChooser(
selected = selectedAccount.paytoUri == account.paytoUri,
onClick = { onSelectAccount(account) },
text = {
- if (account.currencySpecification?.name != null) {
+ if (!account.bankLabel.isNullOrEmpty()) {
+ Text(account.bankLabel)
+ } else if (account.currencySpecification?.name != null) {
Text(stringResource(
R.string.withdraw_account_currency,
index + 1,
@@ -274,6 +284,7 @@ fun ScreenTransferPreview() {
withdrawalAccount = WithdrawalExchangeAccountDetails(
paytoUri = "https://taler.net/kudos",
transferAmount = Amount("KUDOS", 10, 0),
+ status = Ok,
currencySpecification = CurrencySpecification(
"KUDOS",
numFractionalInputDigits = 2,
@@ -295,6 +306,7 @@ fun ScreenTransferPreview() {
withdrawalAccount = WithdrawalExchangeAccountDetails(
paytoUri = "https://taler.net/btc",
transferAmount = Amount("BTC", 0, 14000000),
+ status = Ok,
currencySpecification = CurrencySpecification(
"Bitcoin",
numFractionalInputDigits = 2,
diff --git a/wallet/src/main/java/net/taler/wallet/withdraw/manual/TransferIBAN.kt b/wallet/src/main/java/net/taler/wallet/withdraw/manual/TransferIBAN.kt
index 6c1b014..1698530 100644
--- a/wallet/src/main/java/net/taler/wallet/withdraw/manual/TransferIBAN.kt
+++ b/wallet/src/main/java/net/taler/wallet/withdraw/manual/TransferIBAN.kt
@@ -42,6 +42,12 @@ fun TransferIBAN(
transactionAmountRaw: Amount,
transactionAmountEffective: Amount,
) {
+ val transferAmount = transfer
+ .withdrawalAccount
+ .transferAmount
+ ?.withSpec(transfer.withdrawalAccount.currencySpecification)
+ ?: transfer.amountRaw
+
Column(
modifier = Modifier.padding(all = 16.dp),
horizontalAlignment = Alignment.CenterHorizontally,
@@ -49,7 +55,7 @@ fun TransferIBAN(
Text(
text = stringResource(
R.string.withdraw_manual_ready_intro,
- transfer.amountRaw.toString()),
+ transferAmount),
style = MaterialTheme.typography.bodyLarge,
modifier = Modifier
.padding(vertical = 8.dp)
@@ -67,25 +73,21 @@ fun TransferIBAN(
.padding(all = 16.dp)
)
+ DetailRow(stringResource(R.string.withdraw_manual_ready_subject), transfer.subject)
transfer.receiverName?.let {
DetailRow(stringResource(R.string.withdraw_manual_ready_receiver), it)
}
DetailRow(stringResource(R.string.withdraw_manual_ready_iban), transfer.iban)
- DetailRow(stringResource(R.string.withdraw_manual_ready_subject), transfer.subject)
TransactionInfoComposable(
label = stringResource(R.string.withdraw_exchange),
info = cleanExchange(exchangeBaseUrl),
)
- transfer.withdrawalAccount.transferAmount?.let { amount ->
- WithdrawalAmountTransfer(
- amountRaw = transactionAmountRaw,
- amountEffective = transactionAmountEffective,
- conversionAmountRaw = amount.withSpec(
- transfer.withdrawalAccount.currencySpecification,
- ),
- )
- }
+ WithdrawalAmountTransfer(
+ amountRaw = transactionAmountRaw,
+ amountEffective = transactionAmountEffective,
+ conversionAmountRaw = transferAmount,
+ )
}
} \ No newline at end of file
diff --git a/wallet/src/main/java/net/taler/wallet/withdraw/manual/TransferTaler.kt b/wallet/src/main/java/net/taler/wallet/withdraw/manual/TransferTaler.kt
index cc6597e..089d0de 100644
--- a/wallet/src/main/java/net/taler/wallet/withdraw/manual/TransferTaler.kt
+++ b/wallet/src/main/java/net/taler/wallet/withdraw/manual/TransferTaler.kt
@@ -42,6 +42,12 @@ fun TransferTaler(
transactionAmountRaw: Amount,
transactionAmountEffective: Amount,
) {
+ val transferAmount = transfer
+ .withdrawalAccount
+ .transferAmount
+ ?.withSpec(transfer.withdrawalAccount.currencySpecification)
+ ?: transfer.amountRaw
+
Column(
modifier = Modifier.padding(all = 16.dp),
horizontalAlignment = Alignment.CenterHorizontally,
@@ -49,7 +55,7 @@ fun TransferTaler(
Text(
text = stringResource(
R.string.withdraw_manual_ready_intro,
- transfer.amountRaw.toString()),
+ transferAmount),
style = MaterialTheme.typography.bodyLarge,
modifier = Modifier
.padding(vertical = 8.dp)
@@ -67,23 +73,21 @@ fun TransferTaler(
.padding(all = 16.dp)
)
+ DetailRow(stringResource(R.string.withdraw_manual_ready_subject), transfer.subject)
transfer.receiverName?.let {
DetailRow(stringResource(R.string.withdraw_manual_ready_receiver), it)
}
DetailRow(stringResource(R.string.withdraw_manual_ready_account), transfer.account)
- DetailRow(stringResource(R.string.withdraw_manual_ready_subject), transfer.subject)
TransactionInfoComposable(
label = stringResource(R.string.withdraw_exchange),
info = cleanExchange(exchangeBaseUrl),
)
- transfer.withdrawalAccount.transferAmount?.let { amount ->
- WithdrawalAmountTransfer(
- amountRaw = transactionAmountRaw,
- amountEffective = transactionAmountEffective,
- conversionAmountRaw = amount,
- )
- }
+ WithdrawalAmountTransfer(
+ amountRaw = transactionAmountRaw,
+ amountEffective = transactionAmountEffective,
+ conversionAmountRaw = transferAmount,
+ )
}
} \ No newline at end of file
diff --git a/wallet/src/main/res/drawable/badge.xml b/wallet/src/main/res/drawable/badge.xml
deleted file mode 100644
index 0b06ce5..0000000
--- a/wallet/src/main/res/drawable/badge.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<!--
- ~ This file is part of GNU Taler
- ~ (C) 2020 Taler Systems S.A.
- ~
- ~ GNU Taler is free software; you can redistribute it and/or modify it under the
- ~ terms of the GNU General Public License as published by the Free Software
- ~ Foundation; either version 3, or (at your option) any later version.
- ~
- ~ GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- ~ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- ~ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
- ~
- ~ You should have received a copy of the GNU General Public License along with
- ~ GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- -->
-
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="rectangle">
- <solid android:color="?android:textColorSecondary" />
- <corners android:radius="8dp" />
- <padding
- android:bottom="2dp"
- android:left="8dp"
- android:right="8dp"
- android:top="2dp" />
-</shape> \ No newline at end of file
diff --git a/wallet/src/main/res/drawable/ic_funds_receive.xml b/wallet/src/main/res/drawable/ic_funds_receive.xml
new file mode 100644
index 0000000..f540e4e
--- /dev/null
+++ b/wallet/src/main/res/drawable/ic_funds_receive.xml
@@ -0,0 +1,5 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
+
+ <path android:fillColor="@android:color/white" android:pathData="M20,12l-1.41,-1.41L13,16.17V4h-2v12.17l-5.58,-5.59L4,12l8,8 8,-8z"/>
+
+</vector>
diff --git a/wallet/src/main/res/drawable/ic_funds_send.xml b/wallet/src/main/res/drawable/ic_funds_send.xml
new file mode 100644
index 0000000..9696eb6
--- /dev/null
+++ b/wallet/src/main/res/drawable/ic_funds_send.xml
@@ -0,0 +1,5 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
+
+ <path android:fillColor="@android:color/white" android:pathData="M4,12l1.41,1.41L11,7.83V20h2V7.83l5.58,5.59L20,12l-8,-8 -8,8z"/>
+
+</vector>
diff --git a/wallet/src/main/res/drawable/ic_sync.xml b/wallet/src/main/res/drawable/ic_sync.xml
deleted file mode 100644
index 8991613..0000000
--- a/wallet/src/main/res/drawable/ic_sync.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24.0"
- android:viewportHeight="24.0">
- <path
- android:fillColor="#FF000000"
- android:pathData="M12,4L12,1L8,5l4,4L12,6c3.31,0 6,2.69 6,6 0,1.01 -0.25,1.97 -0.7,2.8l1.46,1.46C19.54,15.03 20,13.57 20,12c0,-4.42 -3.58,-8 -8,-8zM12,18c-3.31,0 -6,-2.69 -6,-6 0,-1.01 0.25,-1.97 0.7,-2.8L5.24,7.74C4.46,8.97 4,10.43 4,12c0,4.42 3.58,8 8,8v3l4,-4 -4,-4v3z" />
-</vector>
diff --git a/wallet/src/main/res/drawable/pending_border.xml b/wallet/src/main/res/drawable/pending_border.xml
deleted file mode 100644
index 0e201dc..0000000
--- a/wallet/src/main/res/drawable/pending_border.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?><!--
- ~ This file is part of GNU Taler
- ~ (C) 2020 Taler Systems S.A.
- ~
- ~ GNU Taler is free software; you can redistribute it and/or modify it under the
- ~ terms of the GNU General Public License as published by the Free Software
- ~ Foundation; either version 3, or (at your option) any later version.
- ~
- ~ GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
- ~ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- ~ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
- ~
- ~ You should have received a copy of the GNU General Public License along with
- ~ GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
- -->
-
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="rectangle">
-
- <!-- View background color -->
- <solid android:color="@android:color/transparent"/>
-
- <!-- View border color and width -->
- <stroke
- android:width="1dp"
- android:color="@color/colorPrimary"/>
-
- <!-- The radius makes the corners rounded -->
- <corners android:radius="2dp"/>
-
-</shape> \ No newline at end of file
diff --git a/wallet/src/main/res/drawable/transaction_tip_accepted.xml b/wallet/src/main/res/drawable/transaction_loss.xml
index 27b1ae4..ffc9a2e 100644
--- a/wallet/src/main/res/drawable/transaction_tip_accepted.xml
+++ b/wallet/src/main/res/drawable/transaction_loss.xml
@@ -1,6 +1,6 @@
<!--
~ This file is part of GNU Taler
- ~ (C) 2020 Taler Systems S.A.
+ ~ (C) 2024 Taler Systems S.A.
~
~ GNU Taler is free software; you can redistribute it and/or modify it under the
~ terms of the GNU General Public License as published by the Free Software
@@ -20,7 +20,7 @@
android:tint="?attr/colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
- <path
- android:fillColor="#000"
- android:pathData="M18,21L15,18L18,15V17H22V19H18V21M10,4A4,4 0 0,1 14,8A4,4 0 0,1 10,12A4,4 0 0,1 6,8A4,4 0 0,1 10,4M10,14C11.15,14 12.25,14.12 13.24,14.34C12.46,15.35 12,16.62 12,18C12,18.7 12.12,19.37 12.34,20H2V18C2,15.79 5.58,14 10,14Z" />
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M17.12,9.88C16.56,9.32 15.8,9 15,9S13.44,9.32 12.88,9.88C12.32,10.44 12,11.2 12,12S12.32,13.56 12.88,14.12 14.2,15 15,15 16.56,14.68 17.12,14.12 18,12.8 18,12 17.68,10.44 17.12,9.88M7,6V18H23V6H7M21,14C20.47,14 19.96,14.21 19.59,14.59C19.21,14.96 19,15.47 19,16H11C11,15.47 10.79,14.96 10.41,14.59C10.04,14.21 9.53,14 9,14V10C9.53,10 10.04,9.79 10.41,9.41C10.79,9.04 11,8.53 11,8H19C19,8.53 19.21,9.04 19.59,9.41C19.96,9.79 20.47,10 21,10V14M5,8H3C2.45,8 2,7.55 2,7C2,6.45 2.45,6 3,6H5V8M5,13H2C1.45,13 1,12.55 1,12C1,11.45 1.45,11 2,11H5V13M5,18H1C0.448,18 0,17.55 0,17C0,16.45 0.448,16 1,16H5V18Z"/>
</vector>
diff --git a/wallet/src/main/res/layout-w550dp/payment_bottom_bar.xml b/wallet/src/main/res/layout-w550dp/payment_bottom_bar.xml
index b5eabbe..ebfeabb 100644
--- a/wallet/src/main/res/layout-w550dp/payment_bottom_bar.xml
+++ b/wallet/src/main/res/layout-w550dp/payment_bottom_bar.xml
@@ -31,7 +31,7 @@
android:id="@+id/totalLabelView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="@string/payment_label_amount_total"
+ android:text="@string/amount_total_label"
android:visibility="invisible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/totalView"
diff --git a/wallet/src/main/res/layout/balance_actions.xml b/wallet/src/main/res/layout/balance_actions.xml
new file mode 100644
index 0000000..d071a78
--- /dev/null
+++ b/wallet/src/main/res/layout/balance_actions.xml
@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ This file is part of GNU Taler
+ ~ (C) 2024 Taler Systems S.A.
+ ~
+ ~ GNU Taler is free software; you can redistribute it and/or modify it under the
+ ~ terms of the GNU General Public License as published by the Free Software
+ ~ Foundation; either version 3, or (at your option) any later version.
+ ~
+ ~ GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
+ ~ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ ~ A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ ~
+ ~ You should have received a copy of the GNU General Public License along with
+ ~ GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+ -->
+
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools">
+
+ <com.google.android.material.button.MaterialButton
+ android:id="@+id/sendButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="10dp"
+ android:layout_marginVertical="10dp"
+ android:paddingHorizontal="18dp"
+ android:text="@string/transactions_send_funds"
+ app:icon="@drawable/ic_funds_send"
+ tools:ignore="MissingConstraints" />
+
+ <com.google.android.material.button.MaterialButton
+ android:id="@+id/receiveButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginHorizontal="10dp"
+ android:layout_marginVertical="10dp"
+ android:paddingHorizontal="18dp"
+ android:text="@string/transactions_receive_funds"
+ app:icon="@drawable/ic_funds_receive"
+ tools:ignore="MissingConstraints" />
+
+ <androidx.constraintlayout.helper.widget.Flow
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ app:constraint_referenced_ids="sendButton,receiveButton"
+ android:paddingHorizontal="10dp"
+ app:flow_horizontalGap="10dp"
+ app:flow_horizontalBias="0"
+ app:flow_horizontalAlign="start"
+ app:flow_horizontalStyle="packed"
+ app:flow_wrapMode="chain"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintEnd_toStartOf="@id/amountBarrier"
+ app:layout_constraintBottom_toBottomOf="@id/topBarrier"/>
+
+ <androidx.constraintlayout.widget.Barrier
+ android:id="@+id/amountBarrier"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toTopOf="@id/divider"
+ app:barrierDirection="start"/>
+
+ <LinearLayout
+ android:id="@+id/amountLayout"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="16dp"
+ android:orientation="vertical"
+ android:gravity="end"
+ app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintBottom_toTopOf="@id/divider"
+ app:layout_constraintStart_toEndOf="@id/amountBarrier">
+
+ <TextView
+ android:id="@+id/balanceLabel"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dp"
+ android:layout_marginEnd="16dp"
+ android:text="@string/transactions_balance"
+ android:textSize="14sp" />
+
+ <TextView
+ android:id="@+id/amount"
+ style="@style/TextAppearance.Material3.TitleLarge"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="16dp"
+ android:layout_marginBottom="8dp"
+ android:textStyle="bold"
+ tools:text="23.42"
+ tools:visibility="visible" />
+
+ </LinearLayout>
+
+ <androidx.constraintlayout.widget.Barrier
+ android:id="@+id/topBarrier"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ app:barrierDirection="bottom"
+ app:constraint_referenced_ids="sendButton,receiveButton,amountLayout" />
+
+ <com.google.android.material.divider.MaterialDivider
+ android:id="@+id/divider"
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/topBarrier" />
+
+</androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file
diff --git a/wallet/src/main/res/layout/fragment_prompt_withdraw.xml b/wallet/src/main/res/layout/fragment_prompt_withdraw.xml
index 44d95de..e77a549 100644
--- a/wallet/src/main/res/layout/fragment_prompt_withdraw.xml
+++ b/wallet/src/main/res/layout/fragment_prompt_withdraw.xml
@@ -64,7 +64,7 @@
android:layout_marginTop="32dp"
android:layout_marginEnd="16dp"
android:gravity="center"
- android:text="@string/withdraw_fees"
+ android:text="@string/amount_fee"
android:visibility="gone"
app:layout_constraintBottom_toTopOf="@+id/feeView"
app:layout_constraintEnd_toEndOf="parent"
@@ -100,7 +100,7 @@
android:layout_marginEnd="16dp"
android:layout_marginBottom="8dp"
android:gravity="center"
- android:text="@string/withdraw_total"
+ android:text="@string/amount_total"
android:visibility="invisible"
app:layout_constraintBottom_toTopOf="@+id/effectiveAmountView"
app:layout_constraintEnd_toEndOf="parent"
diff --git a/wallet/src/main/res/layout/fragment_transactions.xml b/wallet/src/main/res/layout/fragment_transactions.xml
index 8fa46f5..c417540 100644
--- a/wallet/src/main/res/layout/fragment_transactions.xml
+++ b/wallet/src/main/res/layout/fragment_transactions.xml
@@ -20,87 +20,40 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
- <com.google.android.material.button.MaterialButton
- android:id="@+id/sendButton"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginStart="10dp"
- android:text="@string/transactions_send_funds"
- app:layout_constraintBottom_toTopOf="@+id/divider"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toTopOf="parent" />
+ <androidx.core.widget.NestedScrollView
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
- <com.google.android.material.button.MaterialButton
- android:id="@+id/receiveButton"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginHorizontal="10dp"
- android:text="@string/transactions_receive_funds"
- app:layout_constraintBottom_toTopOf="@+id/divider"
- app:layout_constraintEnd_toStartOf="@+id/amount"
- app:layout_constraintHorizontal_chainStyle="spread_inside"
- app:layout_constraintStart_toEndOf="@+id/sendButton"
- app:layout_constraintTop_toTopOf="parent" />
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
- <TextView
- android:id="@+id/balanceLabel"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="8dp"
- android:layout_marginEnd="16dp"
- android:text="@string/transactions_balance"
- android:textSize="14sp"
- app:layout_constraintBottom_toTopOf="@+id/amount"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintHorizontal_bias="1.0"
- app:layout_constraintStart_toEndOf="@+id/receiveButton"
- app:layout_constraintTop_toTopOf="parent" />
+ <FrameLayout
+ android:id="@+id/actionsFrame"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent">
+ <include
+ android:id="@+id/actionsBar"
+ layout="@layout/balance_actions"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"/>
+ </FrameLayout>
- <TextView
- android:id="@+id/amount"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginEnd="16dp"
- android:layout_marginBottom="8dp"
- android:textSize="24sp"
- android:textStyle="bold"
- app:layout_constrainedWidth="true"
- app:layout_constraintBottom_toTopOf="@+id/divider"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintHorizontal_bias="0.5"
- app:layout_constraintStart_toEndOf="@+id/receiveButton"
- app:layout_constraintTop_toBottomOf="@+id/balanceLabel"
- tools:text="23.42"
- tools:visibility="visible" />
-
- <androidx.constraintlayout.widget.Barrier
- android:id="@+id/topBarrier"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- app:barrierDirection="bottom"
- app:constraint_referenced_ids="sendButton,receiveButton,amount" />
+ <androidx.recyclerview.widget.RecyclerView
+ android:id="@+id/list"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:nestedScrollingEnabled="false"
+ android:scrollbars="vertical"
+ android:visibility="invisible"
+ app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
+ tools:listitem="@layout/list_item_transaction"
+ tools:visibility="visible" />
- <com.google.android.material.divider.MaterialDivider
- android:id="@+id/divider"
- android:layout_width="match_parent"
- android:layout_height="1dp"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/topBarrier" />
+ </LinearLayout>
- <androidx.recyclerview.widget.RecyclerView
- android:id="@+id/list"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:scrollbars="vertical"
- android:visibility="invisible"
- app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/divider"
- tools:listitem="@layout/list_item_transaction"
- tools:visibility="visible" />
+ </androidx.core.widget.NestedScrollView>
<TextView
android:id="@+id/emptyState"
@@ -115,7 +68,7 @@
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/divider"
+ app:layout_constraintTop_toTopOf="parent"
tools:visibility="visible" />
<ProgressBar
@@ -128,7 +81,7 @@
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/divider"
+ app:layout_constraintTop_toTopOf="parent"
tools:visibility="visible" />
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
diff --git a/wallet/src/main/res/layout/fragment_uri_input.xml b/wallet/src/main/res/layout/fragment_uri_input.xml
index 95c2297..6547625 100644
--- a/wallet/src/main/res/layout/fragment_uri_input.xml
+++ b/wallet/src/main/res/layout/fragment_uri_input.xml
@@ -68,7 +68,7 @@
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:backgroundTint="@color/green"
- android:text="@string/ok"
+ android:text="@string/open"
android:textColor="@android:color/white"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/pasteButton"
diff --git a/wallet/src/main/res/layout/list_item_balance.xml b/wallet/src/main/res/layout/list_item_balance.xml
index 53e3d89..6e5e440 100644
--- a/wallet/src/main/res/layout/list_item_balance.xml
+++ b/wallet/src/main/res/layout/list_item_balance.xml
@@ -14,9 +14,9 @@
~ GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
-->
-<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
+ android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
@@ -26,26 +26,16 @@
android:id="@+id/balanceAmountView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginEnd="8dp"
style="?textAppearanceDisplaySmall"
- app:layout_constraintEnd_toStartOf="@+id/pendingView"
- app:layout_constraintHorizontal_bias="0.0"
- app:layout_constraintHorizontal_chainStyle="packed"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toTopOf="parent"
tools:text="100.50" />
<TextView
android:id="@+id/scopeView"
- android:layout_width="0dp"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
style="?textAppearanceBodyMedium"
android:visibility="gone"
- app:layout_constraintTop_toBottomOf="@id/balanceAmountView"
- app:layout_constraintBottom_toTopOf="@id/balanceInboundAmount"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintEnd_toStartOf="@id/pendingView"
tools:text="@string/balance_scope_exchange"
tools:visibility="visible"/>
@@ -54,40 +44,17 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/green"
- android:textSize="20sp"
style="?textAppearanceBodyLarge"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintEnd_toStartOf="@+id/balanceInboundLabel"
- app:layout_constraintHorizontal_bias="0.0"
- app:layout_constraintHorizontal_chainStyle="packed"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/scopeView"
- tools:text="+10 TESTKUDOS"
+ tools:text="+10 TESTKUDOS inbound"
tools:visibility="visible" />
<TextView
- android:id="@+id/balanceInboundLabel"
+ android:id="@+id/balanceOutboundAmount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginStart="8dp"
- android:text="@string/balances_inbound_label"
- android:textColor="@color/green"
- style="?textAppearanceBodyMedium"
- app:layout_constraintBottom_toBottomOf="@+id/balanceInboundAmount"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toEndOf="@+id/balanceInboundAmount"
- app:layout_constraintTop_toTopOf="@+id/balanceInboundAmount"
+ android:textColor="?colorError"
+ style="?textAppearanceBodyLarge"
+ tools:text="-10 TESTKUDOS outbound"
tools:visibility="visible" />
- <TextView
- android:id="@+id/pendingView"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:background="@drawable/badge"
- android:text="@string/transaction_pending"
- android:textColor="?android:textColorPrimaryInverse"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintTop_toTopOf="parent" />
-
-</androidx.constraintlayout.widget.ConstraintLayout>
+</LinearLayout>
diff --git a/wallet/src/main/res/layout/list_item_transaction.xml b/wallet/src/main/res/layout/list_item_transaction.xml
index 64d9045..ad792ae 100644
--- a/wallet/src/main/res/layout/list_item_transaction.xml
+++ b/wallet/src/main/res/layout/list_item_transaction.xml
@@ -22,9 +22,9 @@
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:paddingStart="16dp"
- android:paddingTop="8dp"
+ android:paddingTop="12dp"
android:paddingEnd="16dp"
- android:paddingBottom="8dp">
+ android:paddingBottom="12dp">
<ImageView
android:id="@+id/icon"
@@ -50,11 +50,11 @@
<TextView
android:id="@+id/extraInfoView"
+ style="@style/TransactionSubtitle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
- android:textSize="14sp"
android:visibility="gone"
app:layout_constraintEnd_toStartOf="@+id/barrier"
app:layout_constraintStart_toStartOf="@+id/title"
@@ -64,11 +64,11 @@
<TextView
android:id="@+id/time"
+ style="@style/TransactionTimestamp"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
- android:textSize="14sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/barrier"
app:layout_constraintStart_toStartOf="@+id/title"
@@ -84,9 +84,9 @@
<TextView
android:id="@+id/amount"
+ style="@style/TransactionAmount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:textSize="24sp"
app:layout_constraintBottom_toTopOf="@+id/pendingView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
diff --git a/wallet/src/main/res/layout/payment_bottom_bar.xml b/wallet/src/main/res/layout/payment_bottom_bar.xml
index 496f2f3..9026127 100644
--- a/wallet/src/main/res/layout/payment_bottom_bar.xml
+++ b/wallet/src/main/res/layout/payment_bottom_bar.xml
@@ -33,7 +33,7 @@
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
- android:text="@string/payment_label_amount_total"
+ android:text="@string/amount_total_label"
android:visibility="invisible"
app:layout_constraintBottom_toTopOf="@+id/confirmButton"
app:layout_constraintEnd_toStartOf="@+id/totalView"
diff --git a/wallet/src/main/res/menu/exchange.xml b/wallet/src/main/res/menu/exchange.xml
index 1d2c2e5..d99ff00 100644
--- a/wallet/src/main/res/menu/exchange.xml
+++ b/wallet/src/main/res/menu/exchange.xml
@@ -22,6 +22,9 @@
android:id="@+id/action_receive_peer"
android:title="@string/receive_peer" />
<item
+ android:id="@+id/action_reload"
+ android:title="@string/exchange_reload" />
+ <item
android:id="@+id/action_delete"
android:title="@string/transactions_delete" />
</menu>
diff --git a/wallet/src/main/res/navigation/nav_graph.xml b/wallet/src/main/res/navigation/nav_graph.xml
index bc2e871..94c13a7 100644
--- a/wallet/src/main/res/navigation/nav_graph.xml
+++ b/wallet/src/main/res/navigation/nav_graph.xml
@@ -36,7 +36,7 @@
<fragment
android:id="@+id/handleUri"
android:name="net.taler.wallet.HandleUriFragment"
- android:label="@string/handle_uri_title">
+ android:label="@string/loading">
<argument
android:name="uri"
app:argType="string"
@@ -324,6 +324,11 @@
android:label="@string/transactions_detail_title" />
<fragment
+ android:id="@+id/nav_transactions_detail_loss"
+ android:name="net.taler.wallet.transactions.TransactionLossFragment"
+ android:label="@string/transactions_detail_title" />
+
+ <fragment
android:id="@+id/nav_transactions_detail_dummy"
android:name="net.taler.wallet.transactions.TransactionDummyFragment"
android:label="@string/transactions_detail_title" />
diff --git a/wallet/src/main/res/values-de/strings.xml b/wallet/src/main/res/values-de/strings.xml
index 5ea98e9..f4e3fed 100644
--- a/wallet/src/main/res/values-de/strings.xml
+++ b/wallet/src/main/res/values-de/strings.xml
@@ -120,7 +120,7 @@
<string name="paste_invalid">Die Zwischenablage enthält einen ungültigen Datentyp</string>
<string name="uri_invalid">Keine gültige Taler-URI</string>
<string name="ok">Bestätigen</string>
- <string name="cancel">Abbrechen</string>
+ <string name="cancel">Zurück</string>
<string name="search">Suche</string>
<string name="menu">Menü</string>
<string name="nav_error">Fehler</string>
@@ -161,7 +161,7 @@
<string name="transactions_delete_dialog_message">Sind Sie sicher, dass Sie diese Transaktion aus Ihrem Wallet entfernen möchten?</string>
<string name="transactions_delete_dialog_title">Transaktion löschen</string>
<string name="receive_peer_payment_intro">Möchten Sie diese Zahlung erhalten?</string>
- <string name="transactions_abort">Abbrechen</string>
+ <string name="transactions_abort">Abbruch ausführen</string>
<string name="payment_pay_template_title">Passen Sie Ihre Bestellung an</string>
<string name="send_intro">Wählen Sie aus, wohin Sie Geld senden möchten:</string>
<string name="send_deposit_title">Einzahlung auf ein Bankkonto</string>
diff --git a/wallet/src/main/res/values-it/strings.xml b/wallet/src/main/res/values-it/strings.xml
index fdc4594..61bb306 100644
--- a/wallet/src/main/res/values-it/strings.xml
+++ b/wallet/src/main/res/values-it/strings.xml
@@ -226,7 +226,7 @@
<string name="settings_db_export_error">Errore nell\'esportazione della banca dati</string>
<string name="transactions_abort">Annulla</string>
<string name="transactions_fail">Arresta</string>
- <string name="transactions_abort_dialog_title">Annulla la Transazione</string>
+ <string name="transactions_abort_dialog_title">Annulla la transazione</string>
<string name="transactions_fail_dialog_title">Annulla la Transazione</string>
<string name="transactions_fail_dialog_message">Sei sicuro di voler annullare questa transazione? I fondi ancora in transito ANDRANNO PERSI.</string>
<string name="transactions_abort_dialog_message">Sei sicuro di voler annullare questa transazione? I fondi ancora in transito potrebbero andare persi.</string>
diff --git a/wallet/src/main/res/values/strings.xml b/wallet/src/main/res/values/strings.xml
index 64a0d7b..b5dcc02 100644
--- a/wallet/src/main/res/values/strings.xml
+++ b/wallet/src/main/res/values/strings.xml
@@ -14,9 +14,13 @@
~ GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
-->
+<!-- NOTE: please organize strings in alphabetic order! -->
+
<resources xmlns:tools="http://schemas.android.com/tools">
<string name="app_name">Taler Wallet</string>
+ <!-- Google Play Store -->
+
<string name="google_play_title" tools:keep="@string/google_play_title">Taler Wallet (experimental)</string>
<string name="google_play_short_desc" tools:keep="@string/google_play_short_desc">GNU Taler makes privacy-friendly online transactions fast and easy.</string>
<string name="google_play_full_desc" tools:keep="@string/google_play_full_desc"><![CDATA[
@@ -33,146 +37,161 @@ When making a payment, customers only need a charged wallet. A merchant can acce
GNU Taler is immune against many types of fraud, such as phishing of credit card information or chargeback fraud. In case of loss or theft, only the limited amount of money left in the wallet might be gone.
]]></string>
- <string name="nav_header_title">GNU Taler</string>
- <string name="nav_header_subtitle">Wallet</string>
+ <!-- Navigation -->
- <string name="nav_prompt_withdraw">Withdraw Digital Cash</string>
- <string name="nav_exchange_tos">Exchange\'s Terms of Service</string>
- <string name="nav_exchange_select">Select Exchange</string>
- <string name="nav_exchange_fees">Exchange Fees</string>
<string name="nav_error">Error</string>
+ <string name="nav_exchange_fees">Provider fees</string>
+ <string name="nav_exchange_tos">PSP\'s Terms of Service</string>
+ <string name="nav_header_subtitle">Wallet</string>
+ <string name="nav_header_title">GNU Taler</string>
+ <string name="nav_prompt_withdraw">Withdraw Digital Cash</string>
+
+ <!-- General -->
<string name="button_back">Go Back</string>
<string name="button_scan_qr_code">Scan Taler QR Code</string>
<string name="button_scan_qr_code_label">Scan QR code</string>
- <string name="enter_uri">Enter Taler URI</string>
- <string name="copy" tools:override="true">Copy</string>
- <string name="copy_uri">Copy Taler URI</string>
- <string name="paste">Paste</string>
- <string name="paste_invalid">Clipboard contains an invalid data type</string>
- <string name="uri_invalid">Not a valid Taler URI</string>
- <string name="ok">OK</string>
<string name="cancel">Cancel</string>
- <string name="search">Search</string>
- <string name="menu">Menu</string>
- <string name="or">or</string>
- <string name="currency">Currency</string>
<!-- The count should be mirrored in RTL languages -->
<string name="char_count">%1$d/%2$d</string>
+ <string name="copy" tools:override="true">Copy</string>
+ <string name="currency">Currency</string>
+ <string name="enter_uri">Enter taler:// URI</string>
<string name="import_db">Import</string>
+ <string name="loading">Loading</string>
+ <string name="menu">Menu</string>
+ <string name="offline">Operation requires internet access. Please ensure your internet connection works and try again.</string>
+ <string name="offline_banner">No internet access</string>
+ <string name="ok">OK</string>
+ <string name="open">Open</string>
+ <string name="or">or</string>
+ <string name="paste">Paste</string>
+ <string name="paste_invalid">Clipboard contains an invalid data type</string>
<string name="reset">Reset</string>
+ <string name="search">Search</string>
<string name="share_payment">Share payment link</string>
+ <string name="uri_invalid">Not a valid Taler URI</string>
+
+ <!-- Errors -->
- <string name="offline">Operation requires internet access. Please ensure your internet connection works and try again.</string>
- <string name="offline_banner">No internet access</string>
<string name="error_unsupported_uri">Error: This Taler URI is not supported.</string>
<string name="error_broken_uri">Error: This Taler URI is (currently) not working.</string>
- <string name="menu_settings">Settings</string>
- <string name="menu_retry_pending_operations">Retry Pending Operations</string>
-
- <string name="host_apdu_service_desc">Taler NFC Payments</string>
-
- <string name="handle_uri_title">Loading action</string>
+ <!-- Amounts -->
- <string name="balances_title">Balances</string>
- <string name="amount_positive">+%s</string>
+ <string name="amount_chosen">Chosen amount</string>
+ <string name="amount_conversion">Conversion</string>
+ <string name="amount_effective">Effective amount</string>
+ <string name="amount_fee">Fee</string>
+ <string name="amount_invalid">Amount invalid</string>
+ <string name="amount_invoiced">Amount invoiced</string>
+ <string name="amount_lost">Amount lost</string>
<string name="amount_negative">-%s</string>
- <string name="amount_chosen">Chosen Amount</string>
- <string name="amount_sent">Amount sent</string>
+ <string name="amount_positive">+%s</string>
+ <string name="amount_receive">Amount to receive</string>
<string name="amount_received">Amount received</string>
- <string name="balances_inbound_label">inbound</string>
- <string name="balances_empty_state">There is no digital cash in your wallet.\n\nYou can get test money from the demo bank:\n\nhttps://bank.demo.taler.net</string>
- <string name="balance_scope_exchange">Exchange: %1$s</string>
+ <string name="amount_send">Amount to send</string>
+ <string name="amount_sent">Amount sent</string>
+ <string name="amount_total">Total amount</string>
+ <string name="amount_total_label">Total:</string>
+ <string name="amount_transfer">Transfer</string>
+
+ <!-- Balances -->
+
<string name="balance_scope_auditor">Auditor: %1$s</string>
+ <string name="balance_scope_exchange">From %1$s</string>
+ <string name="balances_empty_state">There is no digital cash in your wallet.\n\nYou can get test money from the demo bank:\n\nhttps://bank.demo.taler.net</string>
+ <string name="balances_inbound_amount">+%1$s inbound</string>
+ <string name="balances_outbound_amount">-%1$s outbound</string>
+ <string name="balances_title">Balances</string>
- <string name="transactions_title">Transactions</string>
+ <!-- Transactions -->
+
+ <string name="transaction_action_kyc">Complete KYC</string>
+ <string name="transaction_denom_loss">Loss of funds</string>
+ <string name="transaction_deposit">Deposit</string>
+ <string name="transaction_deposit_to">Deposit to %1$s</string>
+ <string name="transaction_dummy_title">Unknown Transaction</string>
+ <string name="transaction_order">Purchase</string>
+ <string name="transaction_order_id">Order #%1$s</string>
+ <string name="transaction_order_total">Total</string>
+ <string name="transaction_paid">Paid</string>
+ <string name="transaction_peer_pull_credit">Invoice</string>
+ <string name="transaction_peer_pull_debit">Invoice paid</string>
+ <string name="transaction_peer_push_credit">Push payment</string>
+ <string name="transaction_peer_push_debit">Push payment</string>
+ <string name="transaction_pending">PENDING</string>
+ <string name="transaction_refresh">Coin expiry change fee</string>
+ <string name="transaction_refund">Refund</string>
+ <string name="transactions_abort">Abort</string>
+ <string name="transactions_abort_dialog_message">Are you sure you want to abort this transaction? Funds still in transit might get lost.</string>
+ <string name="transactions_abort_dialog_title">Abort Transaction</string>
<string name="transactions_balance">Balance</string>
- <string name="transactions_send_funds">Send\nFunds</string>
- <string name="transactions_send_funds_title">Send %1$s</string>
- <string name="transactions_receive_funds">Receive\nFunds</string>
- <string name="transactions_receive_funds_title">Receive %1$s</string>
+ <string name="transactions_delete">Delete</string>
+ <string name="transactions_delete_dialog_message">Are you sure you want to remove this transaction from your wallet?</string>
+ <string name="transactions_delete_dialog_title">Delete Transaction</string>
+ <string name="transactions_delete_selected_dialog_message">Are you sure you want to remove the selected transactions from your wallet?</string>
+ <string name="transactions_detail_title">Transaction</string>
+ <string name="transactions_detail_title_currency">%s transactions</string>
<string name="transactions_empty">You don\'t have any transactions</string>
<string name="transactions_empty_search">No transactions found. Try a different search.</string>
<string name="transactions_error">Could not load transactions\n\n%s</string>
- <string name="transactions_detail_title">Transaction</string>
- <string name="transactions_detail_title_currency">%s Transactions</string>
- <string name="transactions_delete">Delete</string>
- <string name="transactions_retry">Retry</string>
- <string name="transactions_abort">Abort</string>
<string name="transactions_fail">Kill</string>
- <string name="transactions_suspend">Suspend</string>
+ <string name="transactions_fail_dialog_message">Are you sure you want to kill this transaction? Funds still in transit WILL GET LOST.</string>
+ <string name="transactions_fail_dialog_title">Kill Transaction</string>
+ <string name="transactions_receive_funds">Receive</string>
+ <string name="transactions_receive_funds_title">Receive %1$s</string>
<string name="transactions_resume">Resume</string>
+ <string name="transactions_retry">Retry</string>
<string name="transactions_select_all">Select All</string>
- <string name="transactions_delete_dialog_title">Delete Transaction</string>
- <string name="transactions_delete_dialog_message">Are you sure you want to remove this transaction from your wallet?</string>
- <string name="transactions_delete_selected_dialog_message">Are you sure you want to remove the selected transactions from your wallet?</string>
- <string name="transactions_abort_dialog_title">Abort Transaction</string>
- <string name="transactions_abort_dialog_message">Are you sure you want to abort this transaction? Funds still in transit might get lost.</string>
- <string name="transactions_fail_dialog_title">Kill Transaction</string>
- <string name="transactions_fail_dialog_message">Are you sure you want to kill this transaction? Funds still in transit WILL GET LOST.</string>
- <string name="transactions_cancel_dialog_message">Are you sure you want to cancel this withdrawal? Funds still in transit might get lost.</string>
+ <string name="transactions_send_funds">Send</string>
+ <string name="transactions_send_funds_title">Send %1$s</string>
+ <string name="transactions_suspend">Suspend</string>
+ <string name="transactions_title">Transactions</string>
- <!-- Transactions -->
- <string name="transaction_paid">Paid</string>
- <string name="transaction_order_total">Total</string>
- <string name="transaction_order">Purchase</string>
- <string name="transaction_order_id">Receipt #%1$s</string>
- <string name="transaction_refund">Refund</string>
- <string name="transaction_refund_from">Refund from %s</string>
- <string name="transaction_pending">PENDING</string>
- <string name="transaction_refresh">Coin expiry change fee</string>
- <string name="transaction_deposit">Deposit</string>
- <string name="transaction_peer_push_debit">Push payment</string>
- <string name="transaction_peer_pull_credit">Invoice</string>
- <string name="transaction_peer_pull_debit">Invoice paid</string>
- <string name="transaction_peer_push_credit">Push payment</string>
- <string name="transaction_action_kyc">Complete KYC</string>
- <string name="transaction_dummy_title">Unknown Transaction</string>
+ <!-- Payments -->
- <string name="payment_title">Payment</string>
- <string name="payment_prompt_title">Review Payment</string>
- <string name="payment_fee">+%s payment fee</string>
+ <string name="payment_aborted">Aborted</string>
+ <string name="payment_already_paid">You\'ve already paid for this purchase.</string>
+ <string name="payment_balance_insufficient">Balance insufficient!</string>
<string name="payment_button_confirm">Confirm Payment</string>
- <string name="payment_label_amount_total">Total Amount:</string>
- <string name="payment_label_order_summary">Purchase</string>
+ <string name="payment_confirmation_code">Confirmation code</string>
+ <string name="payment_create_order">Create order</string>
<string name="payment_error">Error: %s</string>
- <string name="payment_pending">Payment not completed, it will be retried</string>
- <string name="payment_balance_insufficient">Balance insufficient!</string>
- <string name="payment_aborted">Aborted</string>
<string name="payment_failed">Failed</string>
+ <string name="payment_fee">+%s payment fee</string>
<string name="payment_initiated">Payment initiated</string>
- <string name="payment_already_paid_title">Already paid</string>
- <string name="payment_already_paid">You\'ve already paid for this purchase.</string>
+ <string name="payment_label_order_summary">Purchase</string>
<string name="payment_pay_template_title">Customize your order</string>
- <string name="payment_create_order">Create order</string>
- <string name="payment_confirmation_code">Confirmation code</string>
+ <string name="payment_pending">Payment not completed, it will be retried</string>
+ <string name="payment_prompt_title">Review Payment</string>
<string name="payment_template_error">Error creating order</string>
+ <string name="payment_title">Payment</string>
+
+ <!-- P2P receive -->
- <string name="receive_amount">Amount to receive</string>
- <string name="receive_amount_invalid">Amount invalid</string>
<string name="receive_intro">Choose where to receive money from:</string>
- <string name="receive_withdraw">Withdraw from bank account</string>
<string name="receive_peer">Invoice another wallet</string>
- <string name="receive_peer_title">Request payment</string>
<string name="receive_peer_create_button">Create invoice</string>
- <string name="receive_peer_invoice_instruction">Let the payer scan this QR code to pay:</string>
<string name="receive_peer_invoice_uri">Alternatively, copy and send this URI:</string>
- <string name="receive_peer_amount_invoiced">Amount invoiced</string>
+ <string name="receive_peer_payment_intro">Do you want to receive this payment?</string>
+ <string name="receive_peer_payment_title">Receive payment</string>
+ <string name="receive_peer_title">Request payment</string>
+ <string name="receive_withdraw">Withdraw from bank account</string>
+
+ <!-- P2P send -->
- <string name="send_amount">Amount to send</string>
+ <string name="pay_peer_title">Pay invoice</string>
+ <string name="pay_peer_intro">Do you want to pay this invoice?</string>
<string name="send_intro">Choose where to send money to:</string>
<string name="send_deposit">To a bank account</string>
<string name="send_deposit_bitcoin">To a Bitcoin wallet</string>
<string name="send_deposit_title">Deposit to a bank account</string>
<string name="send_deposit_iban">IBAN</string>
<string name="send_deposit_iban_error">IBAN is invalid</string>
- <string name="send_deposit_bic_error">BIC is invalid</string>
- <string name="send_deposit_bic">BIC/SWIFT</string>
<string name="send_deposit_name">Account holder</string>
<string name="send_deposit_bitcoin_address">Bitcoin address</string>
<string name="send_deposit_check_fees_button">Check fees</string>
- <string name="send_deposit_amount_effective">Effective Amount</string>
<string name="send_deposit_create_button">Make deposit</string>
<string name="send_deposit_bitcoin_create_button">Transfer Bitcoin</string>
<string name="send_peer">To another wallet</string>
@@ -182,141 +201,140 @@ GNU Taler is immune against many types of fraud, such as phishing of credit card
<string name="send_peer_payment_instruction">Let the payee scan this QR code to receive:</string>
<string name="send_peer_expiration_period">Expires in</string>
<string name="send_peer_expiration_1d">1 day</string>
- <string name="send_peer_expiration_7d">7 days</string>
+ <string name="send_peer_expiration_7d">1 week</string>
<string name="send_peer_expiration_30d">30 days</string>
<string name="send_peer_expiration_custom">Custom</string>
<string name="send_peer_expiration_days">Days</string>
<string name="send_peer_expiration_hours">Hours</string>
<string name="send_peer_purpose">Purpose</string>
- <string name="pay_peer_title">Pay invoice</string>
- <string name="pay_peer_intro">Do you want to pay this invoice?</string>
- <string name="receive_peer_payment_title">Receive payment</string>
- <string name="receive_peer_payment_intro">Do you want to receive this payment?</string>
+ <!-- Withdrawals -->
- <string name="withdraw_initiated">Withdrawal initiated</string>
- <string name="withdraw_title">Withdrawal</string>
- <string name="withdraw_subtitle">Select target bank account</string>
- <string name="withdraw_total">Withdraw</string>
- <string name="withdraw_fees">Fee</string>
- <string name="withdraw_restrict_age">Restrict Usage to Age</string>
- <string name="withdraw_restrict_age_unrestricted">Unrestricted</string>
- <string name="withdraw_exchange">Exchange</string>
- <string name="withdraw_bank">Bank</string>
+ <string name="withdraw_account">Account #%1$d</string>
+ <string name="withdraw_account_currency">Account #%1$d (%2$s)</string>
+ <string name="withdraw_amount_error">Enter valid amount</string>
<string name="withdraw_button_confirm">Confirm Withdraw</string>
<string name="withdraw_button_confirm_bank">Confirm with bank</string>
<string name="withdraw_button_tos">Review Terms</string>
- <string name="withdraw_waiting_confirm">Waiting for confirmation</string>
- <string name="withdraw_manual_title">Make a manual transfer to the exchange</string>
- <string name="withdraw_amount">How much to withdraw?</string>
- <string name="withdraw_amount_error">Enter valid amount</string>
- <string name="withdraw_manual_payment_options">Payment options supported by %1$s:\n\n%2$s</string>
+ <string name="withdraw_error_message">Withdrawing is currently not possible. Please try again later!</string>
+ <string name="withdraw_error_test">Error withdrawing TESTKUDOS</string>
+ <string name="withdraw_error_title">Withdrawal Error</string>
+ <string name="withdraw_exchange">Provider</string>
+ <string name="withdraw_initiated">Withdrawal initiated</string>
+ <string name="withdraw_manual_bitcoin_intro">Now make a split transaction with the following three outputs.</string>
<string name="withdraw_manual_check_fees">Check fees</string>
- <string name="withdraw_manual_ready_title">Exchange is ready for withdrawal!</string>
- <string name="withdraw_manual_ready_intro">To complete the process you need to wire %s to the exchange bank account</string>
+ <string name="withdraw_manual_payment_options">Payment options supported by %1$s:\n\n%2$s</string>
+ <string name="withdraw_manual_ready_account">Account</string>
+ <string name="withdraw_manual_ready_bank_button">Open in banking app</string>
<string name="withdraw_manual_ready_details_intro">Bank transfer details</string>
- <string name="withdraw_manual_bitcoin_title">Bitcoin exchange ready for withdrawal</string>
- <string name="withdraw_manual_bitcoin_intro">Now make a split transaction with the following three outputs.</string>
<string name="withdraw_manual_ready_iban">IBAN</string>
- <string name="withdraw_manual_ready_account">Account</string>
+ <string name="withdraw_manual_ready_intro">To complete the process you need to wire %s to the provider\'s bank account</string>
<string name="withdraw_manual_ready_receiver">Receiver name</string>
<string name="withdraw_manual_ready_subject">Subject</string>
- <string name="withdraw_manual_ready_bank_button">Open in banking app</string>
- <string name="withdraw_manual_ready_cancel">Cancel withdrawal</string>
<string name="withdraw_manual_ready_warning">Make sure to use the correct subject, otherwise the money will not arrive in this wallet.</string>
- <string name="withdraw_error_title">Withdrawal Error</string>
- <string name="withdraw_error_message">Withdrawing is currently not possible. Please try again later!</string>
- <string name="withdraw_error_test">Error withdrawing TESTKUDOS</string>
- <string name="withdraw_account">Account #%1$d</string>
- <string name="withdraw_account_currency">Account #%1$d (%2$s)</string>
- <string name="withdraw_transfer">Transfer</string>
- <string name="withdraw_conversion">Conversion</string>
- <string name="withdraw_conversion_support">This exchange supports currency conversion</string>
-
- <string name="exchange_settings_title">Exchanges</string>
- <string name="exchange_settings_summary">Manage list of exchanges known to this wallet</string>
- <string name="exchange_list_title">Exchanges</string>
- <string name="exchange_list_empty">No exchanges known\n\nAdd one manually or withdraw digital cash!</string>
- <string name="exchange_list_currency">Currency: %s</string>
- <string name="exchange_list_add">Add exchange</string>
- <string name="exchange_list_select">Select exchange</string>
- <string name="exchange_delete">Delete exchange</string>
- <string name="exchange_delete_force">Force deletion (purge)</string>
- <string name="exchange_dialog_delete_message">Are you sure you want to delete this exchange? Forcing this operation will result in a loss of funds.</string>
- <string name="exchange_not_contacted">Exchange not contacted</string>
- <string name="exchange_add_url">Enter address of exchange</string>
- <string name="exchange_add_error">Could not add exchange</string>
- <string name="exchange_list_error">Could not list exchanges</string>
- <string name="exchange_list_add_dev">Add development exchanges</string>
- <string name="exchange_menu_manual_withdraw">Withdraw</string>
+ <string name="withdraw_manual_title">Make a manual transfer to the provider</string>
+ <string name="withdraw_restrict_age">Restrict Usage to Age</string>
+ <string name="withdraw_restrict_age_unrestricted">Unrestricted</string>
+ <string name="withdraw_subtitle">Select target bank account</string>
+ <string name="withdraw_title">Withdrawal</string>
+ <string name="withdraw_waiting_confirm">Waiting for confirmation</string>
- <string name="exchange_fee_withdrawal_fee_label">Withdrawal Fee:</string>
- <string name="exchange_fee_overhead_label">Rounding Loss:</string>
- <string name="exchange_fee_coin_expiration_label">Earliest Coin Expiry:</string>
- <string name="exchange_fee_coin_fees_label">Coin Fees</string>
- <string name="exchange_fee_wire_fees_label">Wire Fees</string>
+ <!-- Exchanges -->
+
+ <string name="exchange_add_error">Could not add provider</string>
+ <string name="exchange_add_url">Enter address of provider</string>
+ <string name="exchange_delete">Delete provider</string>
+ <string name="exchange_delete_force">Force deletion (purge)</string>
<plurals name="exchange_fee_coin">
<item quantity="one">Coin: %s (used %d time)</item>
<item quantity="other">Coin: %s (used %d times)</item>
</plurals>
- <string name="exchange_fee_withdraw_fee">Withdraw Fee: %s</string>
+ <string name="exchange_fee_coin_expiration_label">Earliest Coin Expiry:</string>
+ <string name="exchange_fee_coin_fees_label">Coin Fees</string>
<string name="exchange_fee_deposit_fee">Deposit Fee: %s</string>
+ <string name="exchange_fee_overhead_label">Rounding Loss:</string>
<string name="exchange_fee_refresh_fee">Change Fee: %s</string>
<string name="exchange_fee_refund_fee">Refund Fee: %s</string>
+ <string name="exchange_fee_wire_fee_closing_fee">Closing Fee: %s</string>
<string name="exchange_fee_wire_fee_timespan">Timespan: %1$s - %2$s</string>
<string name="exchange_fee_wire_fee_wire_fee">Wire Fee: %s</string>
- <string name="exchange_fee_wire_fee_closing_fee">Closing Fee: %s</string>
+ <string name="exchange_fee_wire_fees_label">Wire Fees</string>
+ <string name="exchange_fee_withdraw_fee">Withdraw Fee: %s</string>
+ <string name="exchange_fee_withdrawal_fee_label">Withdrawal Fee:</string>
+ <string name="exchange_list_add">Add provider</string>
+ <string name="exchange_list_add_dev">Add development providers</string>
+ <string name="exchange_list_currency">Currency: %s</string>
+ <string name="exchange_list_empty">No providers known\n\nAdd one manually or withdraw digital cash!</string>
+ <string name="exchange_list_error">Could not list providers</string>
+ <string name="exchange_list_select">Select provider</string>
+ <string name="exchange_list_title">Providers</string>
+ <string name="exchange_menu_manual_withdraw">Withdraw</string>
+ <string name="exchange_not_contacted">Provider not contacted</string>
+ <string name="exchange_reload">Reload information</string>
+ <string name="exchange_settings_summary">Manage list of providers known to this wallet</string>
+ <string name="exchange_settings_title">Providers</string>
<string name="exchange_tos_accept">Accept Terms of Service</string>
<string name="exchange_tos_error">Error showing Terms of Service: %s</string>
- <string name="pending_operations_title">Pending Operations</string>
- <string name="pending_operations_refuse">Refuse Proposal</string>
- <string name="pending_operations_no_action">(no action)</string>
+ <!-- Losses -->
+
+ <string name="loss_reason">Reason</string>
+ <string name="loss_reason_expired">Funds were not renewed, because the wallet was not opened for a long time</string>
+ <string name="loss_reason_unoffered">The payment provider stopped offering the denomination backing the funds</string>
+ <string name="loss_reason_vanished">The payment provider lost the record of the funds</string>
<!-- Observability -->
- <string name="show_logs">Show logs</string>
- <string name="observability_title">Internal event log</string>
- <string name="observability_show_json">Show JSON</string>
+
<string name="observability_hide_json">Hide JSON</string>
+ <string name="observability_show_json">Show JSON</string>
+ <string name="observability_title">Internal event log</string>
+ <string name="show_logs">Show logs</string>
- <string name="settings_dev_mode">Developer Mode</string>
- <string name="settings_dev_mode_summary">Shows more information intended for debugging</string>
- <string name="settings_withdraw_testkudos">Withdraw TESTKUDOS</string>
- <string name="settings_withdraw_testkudos_summary">Get money for testing</string>
- <string name="settings_logcat">Debug log</string>
- <string name="settings_logcat_summary">Save internal log</string>
- <string name="settings_logcat_error">Error exporting log</string>
- <string name="settings_logcat_success">Log exported to file</string>
+ <!-- Settings -->
+
+ <string name="menu_settings">Settings</string>
+ <string name="settings_alert_import_canceled">Import cancelled</string>
+ <string name="settings_alert_reset_canceled">Reset cancelled</string>
+ <string name="settings_alert_reset_done">Wallet has been reset</string>
+ <string name="settings_db_clear_error">Error cleaning database</string>
<string name="settings_db_export">Export database</string>
+ <string name="settings_db_export_error">Error exporting database</string>
+ <string name="settings_db_export_success">Database exported to file</string>
<string name="settings_db_export_summary">Save internal database</string>
<string name="settings_db_import">Import database</string>
- <string name="settings_db_import_summary">Restore database from file</string>
- <string name="settings_db_export_error">Error exporting database</string>
<string name="settings_db_import_error">Error importing database</string>
- <string name="settings_db_clear_error">Error cleaning database</string>
- <string name="settings_db_export_success">Database exported to file</string>
<string name="settings_db_import_success">Database imported from file</string>
+ <string name="settings_db_import_summary">Restore database from file</string>
+ <string name="settings_dev_mode">Developer Mode</string>
+ <string name="settings_dev_mode_summary">Shows more information intended for debugging</string>
+ <string name="settings_dialog_import_message">This operation will overwrite your existing database. Do you want to continue?</string>
+ <string name="settings_dialog_reset_message">Do you really want to reset the wallet and lose all coins and purchases?</string>
+ <string name="settings_logcat">Debug log</string>
+ <string name="settings_logcat_error">Error exporting log</string>
+ <string name="settings_logcat_success">Log exported to file</string>
+ <string name="settings_logcat_summary">Save internal log</string>
+ <string name="settings_reset">Reset Wallet (dangerous!)</string>
+ <string name="settings_reset_summary">Throws away your money</string>
+ <string name="settings_test">Run integration test</string>
+ <string name="settings_test_summary">Performs test transactions with demo setup</string>
<string name="settings_version_app">App Version</string>
<string name="settings_version_core">Wallet Core Version</string>
<string name="settings_version_protocol_exchange">Supported Exchange Versions</string>
<string name="settings_version_protocol_merchant">Supported Merchant Versions</string>
<string name="settings_version_unknown">Unknown</string>
- <string name="settings_test">Run integration test</string>
- <string name="settings_test_summary">Performs test transactions with demo setup</string>
- <string name="settings_reset">Reset Wallet (dangerous!)</string>
- <string name="settings_reset_summary">Throws away your money</string>
+ <string name="settings_withdraw_testkudos">Withdraw TESTKUDOS</string>
+ <string name="settings_withdraw_testkudos_summary">Get money for testing</string>
- <string name="settings_dialog_reset_message">Do you really want to reset the wallet and lose all coins and purchases?</string>
- <string name="settings_dialog_import_message">This operation will overwrite your existing database. Do you want to continue?</string>
- <string name="settings_alert_reset_done">Wallet has been reset</string>
- <string name="settings_alert_reset_canceled">Reset cancelled</string>
- <string name="settings_alert_import_canceled">Import cancelled</string>
+ <!-- Refunds -->
- <string name="refund_title">Refund</string>
<string name="refund_error">Error processing refund</string>
<string name="refund_success">Refund received!</string>
+ <string name="refund_title">Refund</string>
- <string name="wifi_disabled_error">Turn on Wi-Fi to get free Wi-Fi</string>
+ <!-- Miscellaneous -->
+
+ <string name="host_apdu_service_desc">Taler NFC Payments</string>
<string name="wifi_connect_error">Could not connect to free Wi-Fi: %s</string>
+ <string name="wifi_disabled_error">Turn on Wi-Fi to get free Wi-Fi</string>
</resources>
diff --git a/wallet/src/main/res/values/styles.xml b/wallet/src/main/res/values/styles.xml
index d7d939f..961c8da 100644
--- a/wallet/src/main/res/values/styles.xml
+++ b/wallet/src/main/res/values/styles.xml
@@ -98,7 +98,19 @@
<style name="DialogTheme" parent="Theme.Material3.DayNight.Dialog.Alert" />
<style name="TransactionTitle">
- <item name="android:textSize">16sp</item>
+ <item name="android:textAppearance">@style/TextAppearance.Material3.TitleMedium</item>
+ </style>
+
+ <style name="TransactionSubtitle">
+ <item name="android:textAppearance">@style/TextAppearance.Material3.BodyMedium</item>
+ </style>
+
+ <style name="TransactionTimestamp">
+ <item name="android:textAppearance">@style/TextAppearance.Material3.LabelMedium</item>
+ </style>
+
+ <style name="TransactionAmount">
+ <item name="android:textAppearance">@style/TextAppearance.Material3.TitleLarge</item>
</style>
<style name="TransactionLabel">