summaryrefslogtreecommitdiff
path: root/cashier
diff options
context:
space:
mode:
Diffstat (limited to 'cashier')
-rw-r--r--cashier/.gitlab-ci.yml9
-rw-r--r--cashier/build.gradle37
-rw-r--r--cashier/proguard-rules.pro2
-rw-r--r--cashier/src/debug/res/xml/network_security_config.xml6
-rw-r--r--cashier/src/main/AndroidManifest.xml10
-rw-r--r--cashier/src/main/java/net/taler/cashier/AboutDialogFragment.kt18
-rw-r--r--cashier/src/main/java/net/taler/cashier/BalanceFragment.kt38
-rw-r--r--cashier/src/main/java/net/taler/cashier/HttpHelper.kt12
-rw-r--r--cashier/src/main/java/net/taler/cashier/MainActivity.kt1
-rw-r--r--cashier/src/main/java/net/taler/cashier/MainViewModel.kt23
-rw-r--r--cashier/src/main/java/net/taler/cashier/Response.kt7
-rw-r--r--cashier/src/main/java/net/taler/cashier/SignedAmount.kt10
-rw-r--r--cashier/src/main/java/net/taler/cashier/config/ConfigFragment.kt30
-rw-r--r--cashier/src/main/java/net/taler/cashier/config/ConfigManager.kt12
-rw-r--r--cashier/src/main/java/net/taler/cashier/withdraw/ErrorFragment.kt11
-rw-r--r--cashier/src/main/java/net/taler/cashier/withdraw/TransactionFragment.kt14
-rw-r--r--cashier/src/main/java/net/taler/cashier/withdraw/WithdrawManager.kt49
-rw-r--r--cashier/src/main/res/mipmap-anydpi-v26/ic_launcher.xml1
-rw-r--r--cashier/src/main/res/values-de/strings.xml27
-rw-r--r--cashier/src/main/res/values-es/strings.xml7
-rw-r--r--cashier/src/main/res/values-fi/strings.xml43
-rw-r--r--cashier/src/main/res/values-fr/strings.xml10
-rw-r--r--cashier/src/main/res/values-ru/strings.xml43
-rw-r--r--cashier/src/main/res/values-sv/strings.xml3
-rw-r--r--cashier/src/main/res/values-tr/strings.xml43
-rw-r--r--cashier/src/main/res/values/strings.xml3
-rw-r--r--cashier/src/main/res/xml/backup_descriptor.xml3
-rw-r--r--cashier/src/main/res/xml/data_extraction_rules.xml6
-rw-r--r--cashier/src/main/res/xml/network_security_config.xml2
29 files changed, 335 insertions, 145 deletions
diff --git a/cashier/.gitlab-ci.yml b/cashier/.gitlab-ci.yml
index 6330c91..f0b75ec 100644
--- a/cashier/.gitlab-ci.yml
+++ b/cashier/.gitlab-ci.yml
@@ -39,8 +39,9 @@ cashier_deploy_nightly:
- ./gradlew :cashier:assembleRelease
# Rename APK, so fdroid nightly accepts it (looks for *-debug.apk)
- mv cashier/build/outputs/apk/release/*.apk cashier-debug.apk
- # START only needed while patch not accepted/released upstream
- - apt update && apt install patch
- - patch /usr/lib/python3/dist-packages/fdroidserver/nightly.py nightly-stats.patch
- # END
+ # install fdroidserver and dependencies for nightly publishing
+ - apt update && apt-get -qy install --no-install-recommends fdroidserver openssh-client
+ # backport fix from https://gitlab.com/fdroid/fdroidserver/-/merge_requests/1078
+ - sed -e '/common.apk_strip_v1_signatures/ s/^#*/#/' -i /usr/lib/python3/dist-packages/fdroidserver/nightly.py
+ - fdroid --version
- CI_PROJECT_URL="https://gitlab.com/gnu-taler/fdroid-repo" CI_PROJECT_PATH="gnu-taler/fdroid-repo" fdroid nightly -v
diff --git a/cashier/build.gradle b/cashier/build.gradle
index 54b2df7..074124f 100644
--- a/cashier/build.gradle
+++ b/cashier/build.gradle
@@ -22,17 +22,18 @@ plugins {
}
android {
- compileSdkVersion 30
- //noinspection GradleDependency
- buildToolsVersion "$build_tools_version"
+ namespace 'net.taler.cashier'
+ compileSdk 34
defaultConfig {
applicationId "net.taler.cashier"
minSdkVersion 23
- targetSdkVersion 30
- versionCode 1
- versionName "0.1"
+ targetSdkVersion 33
+ versionCode 3
+ versionName "0.3"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+
+ buildConfigField("String", "BACKEND_API_VERSION", "\"4:0:0\"")
}
buildTypes {
@@ -47,28 +48,28 @@ android {
}
compileOptions {
- sourceCompatibility = 1.8
- targetCompatibility = 1.8
+ sourceCompatibility = JavaVersion.VERSION_17
+ targetCompatibility = JavaVersion.VERSION_17
}
kotlinOptions {
- jvmTarget = "1.8"
+ jvmTarget = "17"
}
buildFeatures {
+ buildConfig = true
viewBinding = true
}
-
packagingOptions {
- exclude("META-INF/*.kotlin_module")
+ resources {
+ excludes += ['META-INF/*.kotlin_module']
+ }
}
- lintOptions {
+ lint {
abortOnError true
+ warning 'WrongConstant'
ignoreWarnings false
- // TODO remove once com.google.android.material fixed this
- // https://github.com/material-components/material-components-android/issues/504
- ignore "WrongConstant"
}
}
@@ -84,9 +85,9 @@ dependencies {
implementation "io.ktor:ktor-client:$ktor_version"
implementation "io.ktor:ktor-client-okhttp:$ktor_version"
implementation "io.ktor:ktor-client-serialization-jvm:$ktor_version"
+ implementation "io.ktor:ktor-serialization-kotlinx-json:$ktor_version"
+ implementation "io.ktor:ktor-client-content-negotiation:$ktor_version"
+ implementation "io.ktor:ktor-server-call-logging:$ktor_version"
testImplementation "junit:junit:$junit_version"
-
- androidTestImplementation 'androidx.test.ext:junit:1.1.3'
- androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}
diff --git a/cashier/proguard-rules.pro b/cashier/proguard-rules.pro
index ced7b5c..9928f24 100644
--- a/cashier/proguard-rules.pro
+++ b/cashier/proguard-rules.pro
@@ -26,3 +26,5 @@
# androidx.security:security-crypto
# https://github.com/google/tink/issues/361
-keep class * extends com.google.crypto.tink.shaded.protobuf.GeneratedMessageLite { *; }
+
+-dontwarn org.slf4j.impl.StaticLoggerBinder
diff --git a/cashier/src/debug/res/xml/network_security_config.xml b/cashier/src/debug/res/xml/network_security_config.xml
new file mode 100644
index 0000000..a85875e
--- /dev/null
+++ b/cashier/src/debug/res/xml/network_security_config.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<network-security-config>
+ <domain-config cleartextTrafficPermitted="true">
+ <domain includeSubdomains="true">int.taler.net</domain>
+ </domain-config>
+</network-security-config>
diff --git a/cashier/src/main/AndroidManifest.xml b/cashier/src/main/AndroidManifest.xml
index 1d8b810..5230be9 100644
--- a/cashier/src/main/AndroidManifest.xml
+++ b/cashier/src/main/AndroidManifest.xml
@@ -1,13 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- package="net.taler.cashier">
+ xmlns:tools="http://schemas.android.com/tools">
+
+ <uses-permission android:name="android.permission.INTERNET" />
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+ <uses-permission android:name="android.permission.NFC" />
<application
android:allowBackup="true"
+ android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_descriptor"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
+ android:networkSecurityConfig="@xml/network_security_config"
android:roundIcon="@mipmap/ic_launcher"
android:supportsRtl="true"
android:theme="@style/AppTheme"
@@ -15,6 +20,7 @@
<activity
android:name=".MainActivity"
+ android:exported="true"
android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
diff --git a/cashier/src/main/java/net/taler/cashier/AboutDialogFragment.kt b/cashier/src/main/java/net/taler/cashier/AboutDialogFragment.kt
index cdea792..90becbd 100644
--- a/cashier/src/main/java/net/taler/cashier/AboutDialogFragment.kt
+++ b/cashier/src/main/java/net/taler/cashier/AboutDialogFragment.kt
@@ -17,20 +17,14 @@
package net.taler.cashier
import android.os.Bundle
-import android.os.Handler
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
-import android.view.WindowManager
-import android.widget.Button
-import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.DialogFragment
-import androidx.fragment.app.Fragment
import net.taler.cashier.BuildConfig.VERSION_NAME
import net.taler.cashier.config.VERSION_BANK
import net.taler.cashier.databinding.FragmentAboutDialogBinding
-import net.taler.cashier.databinding.FragmentBalanceBinding
-import net.taler.lib.common.Version
+import net.taler.common.Version
class AboutDialogFragment : DialogFragment() {
@@ -39,8 +33,8 @@ class AboutDialogFragment : DialogFragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
- savedInstanceState: Bundle?
- ): View? {
+ savedInstanceState: Bundle?,
+ ): View {
ui = FragmentAboutDialogBinding.inflate(layoutInflater, container, false)
return ui.root
}
@@ -50,8 +44,10 @@ class AboutDialogFragment : DialogFragment() {
ui.versionView.text = getString(R.string.about_version, VERSION_NAME)
ui.bankVersionView.text = getString(R.string.about_supported_bank_api, VERSION_BANK.str())
- ui.licenseView.text = getString(R.string.about_license, getString(R.string.about_license_content))
- ui.copyrightView.text = getString(R.string.about_copyright, getString(R.string.about_copyright_holder))
+ ui.licenseView.text =
+ getString(R.string.about_license, getString(R.string.about_license_content))
+ ui.copyrightView.text =
+ getString(R.string.about_copyright, getString(R.string.about_copyright_holder))
ui.button.setOnClickListener { dismiss() }
}
diff --git a/cashier/src/main/java/net/taler/cashier/BalanceFragment.kt b/cashier/src/main/java/net/taler/cashier/BalanceFragment.kt
index 002301c..4fd3143 100644
--- a/cashier/src/main/java/net/taler/cashier/BalanceFragment.kt
+++ b/cashier/src/main/java/net/taler/cashier/BalanceFragment.kt
@@ -32,10 +32,10 @@ import net.taler.cashier.BalanceFragmentDirections.Companion.actionBalanceFragme
import net.taler.cashier.databinding.FragmentBalanceBinding
import net.taler.cashier.withdraw.LastTransaction
import net.taler.cashier.withdraw.WithdrawStatus
+import net.taler.common.Amount
import net.taler.common.exhaustive
import net.taler.common.fadeIn
import net.taler.common.fadeOut
-import net.taler.lib.common.Amount
sealed class BalanceResult {
class Error(val msg: String) : BalanceResult()
@@ -54,19 +54,19 @@ class BalanceFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?,
- ): View? {
+ ): View {
setHasOptionsMenu(true)
ui = FragmentBalanceBinding.inflate(layoutInflater, container, false)
return ui.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- withdrawManager.lastTransaction.observe(viewLifecycleOwner, { lastTransaction ->
+ withdrawManager.lastTransaction.observe(viewLifecycleOwner) { lastTransaction ->
onLastTransaction(lastTransaction)
- })
- viewModel.balance.observe(viewLifecycleOwner, { result ->
+ }
+ viewModel.balance.observe(viewLifecycleOwner) { result ->
onBalanceUpdated(result)
- })
+ }
ui.button5.setOnClickListener { onAmountButtonPressed(5) }
ui.button10.setOnClickListener { onAmountButtonPressed(10) }
ui.button20.setOnClickListener { onAmountButtonPressed(20) }
@@ -81,9 +81,9 @@ class BalanceFragment : Fragment() {
true
} else false
}
- configManager.currency.observe(viewLifecycleOwner, { currency ->
+ configManager.currency.observe(viewLifecycleOwner) { currency ->
ui.currencyView.text = currency
- })
+ }
ui.confirmWithdrawalButton.setOnClickListener { onAmountConfirmed(getAmountFromView()) }
}
@@ -104,11 +104,13 @@ class BalanceFragment : Fragment() {
}
}
+ @Deprecated("Deprecated in Java")
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.balance, menu)
super.onCreateOptionsMenu(menu, inflater)
}
+ @Deprecated("Deprecated in Java")
override fun onOptionsItemSelected(item: MenuItem) = when (item.itemId) {
R.id.action_reconfigure -> {
findNavController().navigate(configManager.configDestination)
@@ -164,13 +166,19 @@ class BalanceFragment : Fragment() {
private fun onAmountConfirmed(amount: Amount) {
if (amount.isZero()) {
ui.amountView.error = getString(R.string.withdraw_error_zero)
- } else if (!withdrawManager.hasSufficientBalance(amount)) {
- ui.amountView.error = getString(R.string.withdraw_error_insufficient_balance)
- } else {
- ui.amountView.error = null
- withdrawManager.withdraw(amount)
- actionBalanceFragmentToTransactionFragment().let {
- findNavController().navigate(it)
+ } else when (withdrawManager.hasSufficientBalance(amount)) {
+ true -> {
+ ui.amountView.error = null
+ withdrawManager.withdraw(amount)
+ actionBalanceFragmentToTransactionFragment().let {
+ findNavController().navigate(it)
+ }
+ }
+ false -> {
+ ui.amountView.error = getString(R.string.withdraw_error_insufficient_balance)
+ }
+ null -> {
+ ui.amountView.error = getString(R.string.withdraw_error_currency_mismatch)
}
}
}
diff --git a/cashier/src/main/java/net/taler/cashier/HttpHelper.kt b/cashier/src/main/java/net/taler/cashier/HttpHelper.kt
index fd48b2d..69cc46f 100644
--- a/cashier/src/main/java/net/taler/cashier/HttpHelper.kt
+++ b/cashier/src/main/java/net/taler/cashier/HttpHelper.kt
@@ -50,11 +50,13 @@ object HttpHelper {
Log.e(TAG, "Error retrieving $url", e)
return HttpJsonResult.Error(0)
}
- return if (response.code == 200 && response.body != null) {
+ return if (response.code == 204) {
+ HttpJsonResult.Success(JSONObject())
+ } else if (response.code in 200..299 && response.body != null) {
val jsonObject = JSONObject(response.body!!.string())
HttpJsonResult.Success(jsonObject)
} else {
- Log.e(TAG, "Received status ${response.code} from $url expected 200")
+ Log.e(TAG, "Received status ${response.code} from $url expected 2xx")
HttpJsonResult.Error(response.code, getErrorBody(response))
}
}
@@ -76,11 +78,13 @@ object HttpHelper {
Log.e(TAG, "Error retrieving $url", e)
return HttpJsonResult.Error(0)
}
- return if (response.code == 200 && response.body != null) {
+ return if (response.code == 204) {
+ HttpJsonResult.Success(JSONObject())
+ } else if (response.code in 200..299 && response.body != null) {
val jsonObject = JSONObject(response.body!!.string())
HttpJsonResult.Success(jsonObject)
} else {
- Log.e(TAG, "Received status ${response.code} from $url expected 200")
+ Log.e(TAG, "Received status ${response.code} from $url expected 2xx")
HttpJsonResult.Error(response.code, getErrorBody(response))
}
}
diff --git a/cashier/src/main/java/net/taler/cashier/MainActivity.kt b/cashier/src/main/java/net/taler/cashier/MainActivity.kt
index 2f4c4ec..aacc225 100644
--- a/cashier/src/main/java/net/taler/cashier/MainActivity.kt
+++ b/cashier/src/main/java/net/taler/cashier/MainActivity.kt
@@ -52,6 +52,7 @@ class MainActivity : AppCompatActivity() {
}
}
+ @Deprecated("Deprecated in Java")
override fun onBackPressed() {
if (!configManager.hasConfig() && nav.currentDestination?.id == R.id.configFragment) {
// we are in the configuration screen and need a config to continue
diff --git a/cashier/src/main/java/net/taler/cashier/MainViewModel.kt b/cashier/src/main/java/net/taler/cashier/MainViewModel.kt
index 253c7d5..2196e78 100644
--- a/cashier/src/main/java/net/taler/cashier/MainViewModel.kt
+++ b/cashier/src/main/java/net/taler/cashier/MainViewModel.kt
@@ -24,17 +24,17 @@ import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import io.ktor.client.HttpClient
import io.ktor.client.engine.okhttp.OkHttp
-import io.ktor.client.features.json.JsonFeature
-import io.ktor.client.features.json.serializer.KotlinxSerializer
+import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
+import io.ktor.serialization.kotlinx.json.json
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.serialization.json.Json
import net.taler.cashier.HttpHelper.makeJsonGetRequest
import net.taler.cashier.config.ConfigManager
import net.taler.cashier.withdraw.WithdrawManager
+import net.taler.common.Amount
+import net.taler.common.AmountParserException
import net.taler.common.isOnline
-import net.taler.lib.common.Amount
-import net.taler.lib.common.AmountParserException
private val TAG = MainViewModel::class.java.simpleName
@@ -46,12 +46,12 @@ class MainViewModel(private val app: Application) : AndroidViewModel(app) {
retryOnConnectionFailure(true)
}
}
- install(JsonFeature) {
- serializer = KotlinxSerializer(
- Json {
- ignoreUnknownKeys = true
- }
- )
+ expectSuccess = true
+ install(ContentNegotiation) {
+ json(Json {
+ encodeDefaults = false
+ ignoreUnknownKeys = true
+ })
}
}
val configManager = ConfigManager(app, viewModelScope, httpClient)
@@ -77,7 +77,8 @@ class MainViewModel(private val app: Application) : AndroidViewModel(app) {
"debit" -> false
else -> throw AmountParserException("Unexpected credit_debit_indicator: $creditDebitIndicator")
}
- BalanceResult.Success(SignedAmount(positive, Amount.fromJSONString(balanceAmount)))
+ BalanceResult.Success(SignedAmount(positive,
+ Amount.fromJSONString(balanceAmount)))
} catch (e: Exception) {
Log.e(TAG, "Error parsing balance", e)
BalanceResult.Error("Invalid amount:\n${response.json.toString(2)}")
diff --git a/cashier/src/main/java/net/taler/cashier/Response.kt b/cashier/src/main/java/net/taler/cashier/Response.kt
index 6a72604..e9db447 100644
--- a/cashier/src/main/java/net/taler/cashier/Response.kt
+++ b/cashier/src/main/java/net/taler/cashier/Response.kt
@@ -18,8 +18,8 @@ package net.taler.cashier
import android.content.Context
import android.util.Log
-import io.ktor.client.call.receive
-import io.ktor.client.features.ResponseException
+import io.ktor.client.call.body
+import io.ktor.client.plugins.ResponseException
import io.ktor.http.HttpStatusCode
import kotlinx.serialization.Serializable
import net.taler.common.isOnline
@@ -46,8 +46,7 @@ class Response<out T> private constructor(
private suspend fun getExceptionString(e: ResponseException): String {
val response = e.response
return try {
- Log.e("TEST", "TRY RECEIVE $response")
- val error: Error = response.receive()
+ val error: Error = response.body()
"Error ${error.code}: ${error.hint}"
} catch (ex: Exception) {
"Status code: ${response.status.value}"
diff --git a/cashier/src/main/java/net/taler/cashier/SignedAmount.kt b/cashier/src/main/java/net/taler/cashier/SignedAmount.kt
index e79acfd..45bc3af 100644
--- a/cashier/src/main/java/net/taler/cashier/SignedAmount.kt
+++ b/cashier/src/main/java/net/taler/cashier/SignedAmount.kt
@@ -16,15 +16,17 @@
package net.taler.cashier
-import net.taler.lib.common.Amount
+import net.taler.common.Amount
data class SignedAmount(
val positive: Boolean,
val amount: Amount
) {
- override fun toString(): String {
- return if (positive) "$amount" else "-$amount"
- }
+ override fun toString() = toString(showSymbol = true)
+ fun toString(showSymbol: Boolean) = amount.toString(
+ showSymbol = showSymbol,
+ negative = !positive,
+ )
}
diff --git a/cashier/src/main/java/net/taler/cashier/config/ConfigFragment.kt b/cashier/src/main/java/net/taler/cashier/config/ConfigFragment.kt
index e6ac249..3085bef 100644
--- a/cashier/src/main/java/net/taler/cashier/config/ConfigFragment.kt
+++ b/cashier/src/main/java/net/taler/cashier/config/ConfigFragment.kt
@@ -37,22 +37,23 @@ import net.taler.cashier.MainViewModel
import net.taler.cashier.R
import net.taler.cashier.databinding.FragmentConfigBinding
import net.taler.common.exhaustive
+import net.taler.common.showError
-private const val URL_BANK_TEST = "https://bank.test.taler.net"
-private const val URL_BANK_TEST_REGISTER = "$URL_BANK_TEST/accounts/register"
+private const val URL_BANK_TEST = "https://bank.demo.taler.net"
+private const val URL_BANK_TEST_REGISTER = "https://bank.demo.taler.net/webui/#/register"
class ConfigFragment : Fragment() {
private val viewModel: MainViewModel by activityViewModels()
- private val configManager by lazy { viewModel.configManager}
+ private val configManager by lazy { viewModel.configManager }
private lateinit var ui: FragmentConfigBinding
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
- savedInstanceState: Bundle?
- ): View? {
+ savedInstanceState: Bundle?,
+ ): View {
ui = FragmentConfigBinding.inflate(inflater, container, false)
return ui.root
}
@@ -73,9 +74,9 @@ class ConfigFragment : Fragment() {
}
ui.saveButton.setOnClickListener {
val config = Config(
- bankUrl = ui.urlView.editText!!.text.toString(),
- username = ui.usernameView.editText!!.text.toString(),
- password = ui.passwordView.editText!!.text.toString()
+ bankUrl = ui.urlView.editText!!.text.toString().trim(),
+ username = ui.usernameView.editText!!.text.toString().trim(),
+ password = ui.passwordView.editText!!.text.toString().trim()
)
if (checkConfig(config)) {
// show progress
@@ -110,13 +111,15 @@ class ConfigFragment : Fragment() {
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
// for some reason automatic restore isn't working at the moment!?
- outState.putCharSequence("urlView", ui.urlView.editText?.text)
- outState.putCharSequence("usernameView", ui.usernameView.editText?.text)
- outState.putCharSequence("passwordView", ui.passwordView.editText?.text)
+ outState.putCharSequence("urlView", ui.urlView.editText?.text?.trim())
+ outState.putCharSequence("usernameView", ui.usernameView.editText?.text?.trim())
+ outState.putCharSequence("passwordView", ui.passwordView.editText?.text?.trim())
}
private fun checkConfig(config: Config): Boolean {
- if (!config.bankUrl.startsWith("https://")) {
+ if (!config.bankUrl.startsWith("https://") &&
+ !config.bankUrl.startsWith("http://")
+ ) {
ui.urlView.error = getString(R.string.config_bank_url_error)
ui.urlView.requestFocus()
return false
@@ -144,8 +147,7 @@ class ConfigFragment : Fragment() {
if (result.authError) {
Snackbar.make(requireView(), R.string.config_error_auth, LENGTH_LONG).show()
} else {
- val str = getString(R.string.config_error, result.msg)
- Snackbar.make(requireView(), str, LENGTH_LONG).show()
+ requireActivity().showError(getString(R.string.config_error), result.msg)
}
}
}.exhaustive
diff --git a/cashier/src/main/java/net/taler/cashier/config/ConfigManager.kt b/cashier/src/main/java/net/taler/cashier/config/ConfigManager.kt
index 0718963..50b1faf 100644
--- a/cashier/src/main/java/net/taler/cashier/config/ConfigManager.kt
+++ b/cashier/src/main/java/net/taler/cashier/config/ConfigManager.kt
@@ -29,6 +29,7 @@ import androidx.security.crypto.EncryptedSharedPreferences.PrefValueEncryptionSc
import androidx.security.crypto.MasterKeys
import androidx.security.crypto.MasterKeys.AES256_GCM_SPEC
import io.ktor.client.HttpClient
+import io.ktor.client.call.body
import io.ktor.client.request.get
import io.ktor.client.request.header
import io.ktor.http.HttpHeaders.Authorization
@@ -37,12 +38,13 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
+import net.taler.cashier.BuildConfig
import net.taler.cashier.Response
import net.taler.cashier.Response.Companion.response
+import net.taler.common.Version
import net.taler.common.getIncompatibleStringOrNull
-import net.taler.lib.common.Version
-val VERSION_BANK = Version(0, 0, 0)
+val VERSION_BANK = Version.parse(BuildConfig.BACKEND_API_VERSION)!!
private const val PREF_NAME = "net.taler.cashier.prefs"
private const val PREF_KEY_BANK_URL = "bankUrl"
private const val PREF_KEY_USERNAME = "username"
@@ -54,7 +56,7 @@ private val TAG = ConfigManager::class.java.simpleName
class ConfigManager(
private val app: Application,
private val scope: CoroutineScope,
- private val httpClient: HttpClient
+ private val httpClient: HttpClient,
) {
val configDestination = ConfigFragmentDirections.actionGlobalConfigFragment()
@@ -116,7 +118,7 @@ class ConfigManager(
val url = "${config.bankUrl}/config"
Log.d(TAG, "Checking config: $url")
val configResponse = response {
- httpClient.get(url) as ConfigResponse
+ httpClient.get(url).body<ConfigResponse>()
}
if (configResponse.isFailure) {
configResponse
@@ -126,7 +128,7 @@ class ConfigManager(
val balanceResponse = response {
val authUrl = "${config.bankUrl}/accounts/${config.username}"
Log.d(TAG, "Checking auth: $authUrl")
- httpClient.get<Unit>(authUrl) {
+ httpClient.get(authUrl) {
header(Authorization, config.basicAuth)
}
}
diff --git a/cashier/src/main/java/net/taler/cashier/withdraw/ErrorFragment.kt b/cashier/src/main/java/net/taler/cashier/withdraw/ErrorFragment.kt
index 4f98847..c951bb8 100644
--- a/cashier/src/main/java/net/taler/cashier/withdraw/ErrorFragment.kt
+++ b/cashier/src/main/java/net/taler/cashier/withdraw/ErrorFragment.kt
@@ -22,7 +22,6 @@ import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
-import androidx.lifecycle.Observer
import androidx.navigation.fragment.findNavController
import net.taler.cashier.MainViewModel
import net.taler.cashier.R
@@ -37,22 +36,22 @@ class ErrorFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
- savedInstanceState: Bundle?
- ): View? {
+ savedInstanceState: Bundle?,
+ ): View {
ui = FragmentErrorBinding.inflate(inflater, container, false)
return ui.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- withdrawManager.withdrawStatus.observe(viewLifecycleOwner, Observer { status ->
- if (status == null) return@Observer
+ withdrawManager.withdrawStatus.observe(viewLifecycleOwner) { status ->
+ if (status == null) return@observe
if (status is WithdrawStatus.Aborted) {
ui.textView.setText(R.string.transaction_aborted)
} else if (status is WithdrawStatus.Error) {
ui.textView.text = status.msg
}
withdrawManager.completeTransaction()
- })
+ }
ui.backButton.setOnClickListener {
findNavController().popBackStack()
}
diff --git a/cashier/src/main/java/net/taler/cashier/withdraw/TransactionFragment.kt b/cashier/src/main/java/net/taler/cashier/withdraw/TransactionFragment.kt
index ffb1539..0f606b8 100644
--- a/cashier/src/main/java/net/taler/cashier/withdraw/TransactionFragment.kt
+++ b/cashier/src/main/java/net/taler/cashier/withdraw/TransactionFragment.kt
@@ -50,21 +50,21 @@ class TransactionFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
- ): View? {
+ ): View {
ui = FragmentTransactionBinding.inflate(inflater, container, false)
return ui.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- withdrawManager.withdrawAmount.observe(viewLifecycleOwner, { amount ->
+ withdrawManager.withdrawAmount.observe(viewLifecycleOwner) { amount ->
ui.amountView.text = amount?.toString()
- })
- withdrawManager.withdrawResult.observe(viewLifecycleOwner, { result ->
+ }
+ withdrawManager.withdrawResult.observe(viewLifecycleOwner) { result ->
onWithdrawResultReceived(result)
- })
- withdrawManager.withdrawStatus.observe(viewLifecycleOwner, { status ->
+ }
+ withdrawManager.withdrawStatus.observe(viewLifecycleOwner) { status ->
onWithdrawStatusChanged(status)
- })
+ }
// change intro text depending on whether NFC is available or not
val hasNfc = NfcManager.hasNfc(requireContext())
diff --git a/cashier/src/main/java/net/taler/cashier/withdraw/WithdrawManager.kt b/cashier/src/main/java/net/taler/cashier/withdraw/WithdrawManager.kt
index 5d34bba..487475d 100644
--- a/cashier/src/main/java/net/taler/cashier/withdraw/WithdrawManager.kt
+++ b/cashier/src/main/java/net/taler/cashier/withdraw/WithdrawManager.kt
@@ -34,21 +34,19 @@ import net.taler.cashier.HttpJsonResult.Error
import net.taler.cashier.HttpJsonResult.Success
import net.taler.cashier.MainViewModel
import net.taler.cashier.R
+import net.taler.common.Amount
import net.taler.common.QrCodeManager.makeQrCode
import net.taler.common.isOnline
-import net.taler.lib.common.Amount
import org.json.JSONObject
-import java.util.concurrent.TimeUnit.MINUTES
import java.util.concurrent.TimeUnit.SECONDS
private val TAG = WithdrawManager::class.java.simpleName
private val INTERVAL = SECONDS.toMillis(1)
-private val TIMEOUT = MINUTES.toMillis(2)
class WithdrawManager(
private val app: Application,
- private val viewModel: MainViewModel
+ private val viewModel: MainViewModel,
) {
private val scope
get() = viewModel.viewModelScope
@@ -73,11 +71,20 @@ class WithdrawManager(
private val mLastTransaction = MutableLiveData<LastTransaction>()
val lastTransaction: LiveData<LastTransaction> = mLastTransaction
+ /**
+ * Returns null if the given [amount] can't be compared to the balance
+ * e.g. due to mismatching currency.
+ */
@UiThread
- fun hasSufficientBalance(amount: Amount): Boolean {
+ fun hasSufficientBalance(amount: Amount): Boolean? {
val balanceResult = viewModel.balance.value
if (balanceResult !is BalanceResult.Success) return false
- return balanceResult.amount.positive && amount <= balanceResult.amount.amount
+ return try {
+ balanceResult.amount.positive && amount <= balanceResult.amount.amount
+ } catch (e: IllegalStateException) {
+ Log.e(TAG, "Error comparing amounts", e)
+ null
+ }
}
@UiThread
@@ -119,7 +126,7 @@ class WithdrawManager(
}
}
- private val timer: CountDownTimer = object : CountDownTimer(TIMEOUT, INTERVAL) {
+ private val timer: CountDownTimer = object : CountDownTimer(Long.MAX_VALUE, INTERVAL) {
override fun onTick(millisUntilFinished: Long) {
val result = withdrawResult.value
if (result is WithdrawResult.Success) {
@@ -146,31 +153,32 @@ class WithdrawManager(
}
private fun checkWithdrawStatus(withdrawalId: String) = scope.launch(Dispatchers.IO) {
- val url = "${config.bankUrl}/accounts/${config.username}/withdrawals/${withdrawalId}"
+ val url =
+ "${config.bankUrl}/withdrawals/${withdrawalId}"
Log.d(TAG, "Checking withdraw status at $url")
val response = makeJsonGetRequest(url, config)
if (response !is Success) return@launch // ignore errors and continue trying
val oldStatus = mWithdrawStatus.value
try {
- when {
- response.json.getBoolean("aborted") -> {
+ when(response.json.getString("status")) {
+ "selected" -> {
+ // only update status, if there's none, yet
+ // so we don't re-notify or overwrite newer status info
+ if (oldStatus == null) {
+ mWithdrawStatus.postValue(WithdrawStatus.SelectionDone(withdrawalId))
+ }
+ }
+ "aborted" -> {
cancelWithdrawStatusCheck()
mWithdrawStatus.postValue(WithdrawStatus.Aborted)
}
- response.json.getBoolean("confirmation_done") -> {
+ "confirmed" -> {
if (oldStatus !is WithdrawStatus.Success) {
cancelWithdrawStatusCheck()
mWithdrawStatus.postValue(WithdrawStatus.Success)
viewModel.getBalance()
}
}
- response.json.getBoolean("selection_done") -> {
- // only update status, if there's none, yet
- // so we don't re-notify or overwrite newer status info
- if (oldStatus == null) {
- mWithdrawStatus.postValue(WithdrawStatus.SelectionDone(withdrawalId))
- }
- }
}
} catch (e: Exception) {
mWithdrawStatus.postValue(WithdrawStatus.Error(e.toString()))
@@ -197,7 +205,8 @@ class WithdrawManager(
}
private fun abort(withdrawalId: String) = scope.launch(Dispatchers.IO) {
- val url = "${config.bankUrl}/accounts/${config.username}/withdrawals/${withdrawalId}/abort"
+ val url =
+ "${config.bankUrl}/accounts/${config.username}/withdrawals/${withdrawalId}/abort"
Log.d(TAG, "Aborting withdrawal at $url")
makeJsonPostRequest(url, JSONObject(), config)
}
@@ -254,5 +263,5 @@ sealed class WithdrawStatus {
data class LastTransaction(
val withdrawAmount: Amount,
- val withdrawStatus: WithdrawStatus
+ val withdrawStatus: WithdrawStatus,
)
diff --git a/cashier/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/cashier/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
index ac94b34..0648fb4 100644
--- a/cashier/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
+++ b/cashier/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -2,4 +2,5 @@
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
+ <monochrome android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon> \ No newline at end of file
diff --git a/cashier/src/main/res/values-de/strings.xml b/cashier/src/main/res/values-de/strings.xml
index d53e3d4..626d909 100644
--- a/cashier/src/main/res/values-de/strings.xml
+++ b/cashier/src/main/res/values-de/strings.xml
@@ -2,21 +2,21 @@
<resources>
<string name="config_button_save">Speichern</string>
<string name="config_bank_url_error">Die Adresse ist ungültig.</string>
- <string name="config_username_error">Bitte geben Sie Ihren Benutzernamen ein</string>
- <string name="config_error">Fehler beim Abrufen der Konfiguration: %s</string>
- <string name="config_error_auth">Benutzername oder Passwort ungültig</string>
+ <string name="config_username_error">Bitte geben Sie Ihren Benutzernamen ein!</string>
+ <string name="config_error">Fehler beim Abrufen der Konfiguration</string>
+ <string name="config_error_auth">Benutzername oder Passwort ungültig!</string>
<string name="balance_current_label">Aktueller Saldo</string>
<string name="balance_error">FEHLER: %s</string>
<string name="balance_offline">Offline. Bitte Verbindung zum Internet herstellen.</string>
<string name="action_reconfigure">Neukonfiguration</string>
<string name="action_lock">Sperren</string>
<string name="withdraw_input_amount">Betrag</string>
- <string name="withdraw_into">Wie viel E-Cash sollte abgehoben werden\?</string>
+ <string name="withdraw_into">Welcher Betrag soll abgehoben werden\?</string>
<string name="withdraw_error_zero">Geben Sie einen positiven Betrag ein!</string>
<string name="withdraw_error_insufficient_balance">Unzureichendes Guthaben</string>
- <string name="withdraw_error_fetch">Fehler bei der Kommunikation mit der Bank: %s</string>
+ <string name="withdraw_error_fetch">Fehler bei der Verbindung mit der Bank: %s</string>
<string name="withdraw_button_confirm">Abheben</string>
- <string name="transaction_intro_nfc">Scannen Sie mit der Taler Wallet App\nden Code oder benutzen Sie NFC.\nDann erhalten Sie</string>
+ <string name="transaction_intro_nfc">Scannen Sie zum Abheben den Code oder kontaktlos mit NFC:</string>
<string name="config_password">Passwort</string>
<string name="transaction_confirm">Bestätigen</string>
<string name="transaction_abort">Abbrechen</string>
@@ -24,19 +24,20 @@
<string name="transaction_button_back">Zurück</string>
<string name="transaction_last_success">Letzte Transaktion: %s abgehoben</string>
<string name="transaction_last_error">Letzte Transaktion: Fehler</string>
- <string name="app_name">Taler Kassierer</string>
+ <string name="app_name">Taler Cashier</string>
<string name="config_bank_url">Bank API Adresse</string>
<string name="config_demo_hint">Zum Testen können Sie <![CDATA[<a href="%s">ein Testkonto bei der Demobank erstellen</a>]]>.</string>
- <string name="transaction_intro">Scannen Sie den Code\nmit der Taler Wallet.\nDann erhalten Sie</string>
+ <string name="transaction_intro">Scannen Sie zum Abheben den Code mit dem Taler-Wallet:</string>
<string name="transaction_intro_scanned">Bitte bestätigen Sie die Transaktion!</string>
<string name="transaction_last_aborted">Letzte Transaktion: Abgebrochen</string>
<string name="config_username">Benutzername</string>
- <string name="withdraw_error_timeout">Es wurde noch keine Abhebung ausgelöst. Bitte versuchen Sie es erneut.</string>
- <string name="action_about">Über</string>
- <string name="ok">OK</string>
+ <string name="withdraw_error_timeout">Bitte lassen Sie ein Wallet die Abhebung auslösen.</string>
+ <string name="action_about">Info</string>
+ <string name="ok">Bestätigen</string>
<string name="about_title">GNU Taler Kassierer</string>
<string name="about_license">Lizenz: %s</string>
<string name="about_version">Version: %s</string>
<string name="about_copyright">Copyright: %s</string>
- <string name="about_supported_bank_api">Bank API Version: %s</string>
-</resources>
+ <string name="about_supported_bank_api">Bankschnittstellen-Version: %s</string>
+ <string name="withdraw_error_currency_mismatch">Fehler: Die Bank hat eine andere Währung gemeldet</string>
+</resources> \ No newline at end of file
diff --git a/cashier/src/main/res/values-es/strings.xml b/cashier/src/main/res/values-es/strings.xml
index af42d1e..c9ecc6b 100644
--- a/cashier/src/main/res/values-es/strings.xml
+++ b/cashier/src/main/res/values-es/strings.xml
@@ -3,11 +3,11 @@
<string name="config_username">Nombre de usuario</string>
<string name="config_password">Contraseña</string>
<string name="app_name">Cajero Taler</string>
- <string name="config_bank_url">Banco dirección API</string>
+ <string name="config_bank_url">Dirección API del banco</string>
<string name="config_button_save">Guardar</string>
<string name="config_bank_url_error">La dirección es inválida.</string>
<string name="config_username_error">Por favor inserta tu nombre de usuario!</string>
- <string name="config_error">Error recuperando la configuración : %s</string>
+ <string name="config_error">Error recuperando la configuración</string>
<string name="config_error_auth">Usuario o contraseña inválido!</string>
<string name="config_demo_hint">Para realizar pruebas, puedes &lt;a href=%s&gt;crear una cuenta de test en el banco demo&lt;/a&gt;.</string>
<string name="balance_current_label">Balance actual</string>
@@ -26,7 +26,7 @@
<string name="withdraw_button_confirm">Retirar</string>
<string name="transaction_intro">Escanear código con la App de cartera Taler para retirar:</string>
<string name="transaction_intro_nfc">Escanear código o usar NFC con la App de cartera Taler para retirar:</string>
- <string name="transaction_intro_scanned">Por favor confirma la transacción!</string>
+ <string name="transaction_intro_scanned">¡Por favor confirma la transacción!</string>
<string name="transaction_confirm">Confirmar</string>
<string name="transaction_abort">Abortar</string>
<string name="transaction_aborted">Transacción abortada</string>
@@ -39,4 +39,5 @@
<string name="about_license">Licencia: %s</string>
<string name="about_copyright">Copyright: %s</string>
<string name="about_supported_bank_api">Banco Versión API: %s</string>
+ <string name="withdraw_error_currency_mismatch">Error: El banco reportó una divisa diferente</string>
</resources> \ No newline at end of file
diff --git a/cashier/src/main/res/values-fi/strings.xml b/cashier/src/main/res/values-fi/strings.xml
new file mode 100644
index 0000000..030008f
--- /dev/null
+++ b/cashier/src/main/res/values-fi/strings.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="config_bank_url">Pankin API-osoite</string>
+ <string name="config_username">Käyttäjänimi</string>
+ <string name="config_password">Salasana</string>
+ <string name="config_bank_url_error">Osoite on virheellinen.</string>
+ <string name="config_username_error">Anna käyttäjätunnuksesi!</string>
+ <string name="app_name">Taler kassa</string>
+ <string name="config_button_save">Tallenna</string>
+ <string name="config_error">Virhe noudettaessa määritystä</string>
+ <string name="config_error_auth">Virheellinen käyttäjätunnus tai salasana!</string>
+ <string name="balance_current_label">Nykyinen saldo</string>
+ <string name="balance_error">ERROR: %s</string>
+ <string name="balance_offline">Offline-tilassa. Muodosta yhteys Internetiin.</string>
+ <string name="ok">OK</string>
+ <string name="action_reconfigure">Määritä uudelleen</string>
+ <string name="action_lock">Lukitse</string>
+ <string name="action_about">Noin</string>
+ <string name="withdraw_input_amount">Summa</string>
+ <string name="withdraw_into">Kuinka paljon sähköistä käteistä pitäisi nostaa?</string>
+ <string name="withdraw_error_zero">Anna positiivinen summa!</string>
+ <string name="withdraw_error_currency_mismatch">Virhe: Pankki ilmoitti toisen valuutan</string>
+ <string name="withdraw_error_fetch">Virhe kommunikoitaessa pankin kanssa: %s</string>
+ <string name="withdraw_error_timeout">Mikään lompakko ei yrittänyt nostaa. Yritä uudelleen.</string>
+ <string name="withdraw_button_confirm">Nosta</string>
+ <string name="transaction_intro">Skannaa koodi Taler-lompakkosovelluksella nostaaksesi:</string>
+ <string name="transaction_intro_nfc">Skannaa koodi tai käytä NFC:tä Taler-lompakkosovelluksen kanssa nostaaksesi:</string>
+ <string name="transaction_intro_scanned">Vahvista tapahtuma!</string>
+ <string name="transaction_confirm">Vahvista</string>
+ <string name="transaction_abort">Keskeytä</string>
+ <string name="transaction_aborted">Toiminta keskeytetty</string>
+ <string name="transaction_button_back">Takaisin</string>
+ <string name="transaction_last_success">Viimeisin tapahtuma: %s nostettu</string>
+ <string name="transaction_last_aborted">Viimeisin tapahtuma: Keskeytetty</string>
+ <string name="transaction_last_error">Viimeisin tapahtuma: epäonnistui</string>
+ <string name="about_title">GNU Taler Kassa</string>
+ <string name="about_version">Versio: %s</string>
+ <string name="about_license">Lisenssi: %s</string>
+ <string name="about_copyright">Tekijänoikeus: %s</string>
+ <string name="about_supported_bank_api">Pankin API-versio: %s</string>
+ <string name="config_demo_hint">Testausta varten voit &lt;a href=%s&gt;luoda testitilin demopankkiin&lt;/a&gt;.</string>
+ <string name="withdraw_error_insufficient_balance">Riittämätön saldo</string>
+</resources> \ No newline at end of file
diff --git a/cashier/src/main/res/values-fr/strings.xml b/cashier/src/main/res/values-fr/strings.xml
index ab46377..10ba6ea 100644
--- a/cashier/src/main/res/values-fr/strings.xml
+++ b/cashier/src/main/res/values-fr/strings.xml
@@ -7,7 +7,7 @@
<string name="config_button_save">Enregistrer</string>
<string name="config_bank_url_error">L\'adresse est invalide.</string>
<string name="config_username_error">Veuillez saisir votre identifiant !</string>
- <string name="config_error">Erreur lors de la récupération de la configuration : %s</string>
+ <string name="config_error">Erreur lors de la récupération de la configuration</string>
<string name="config_error_auth">Identifiant ou mot de passe invalide !</string>
<string name="config_demo_hint" tools:ignore="StringFormatInvalid">Pour les tests, vous pouvez &lt;a href=%s&gt;créer un compte de test dans la banque de démonstration&lt;/a&gt; .</string>
<string name="balance_current_label">Solde actuel</string>
@@ -32,4 +32,12 @@
<string name="transaction_last_success">Dernière transaction : %s retiré</string>
<string name="transaction_last_aborted">Dernière transaction : Annulée</string>
<string name="transaction_last_error">Dernière transaction : Échec</string>
+ <string name="ok">OK</string>
+ <string name="action_about">À propos</string>
+ <string name="about_version">Version : %s</string>
+ <string name="about_license">Licence : %s</string>
+ <string name="about_copyright">Droits d\'auteur : %s</string>
+ <string name="about_supported_bank_api">Version Bank API : %s</string>
+ <string name="about_title">GNU Taler Cashier</string>
+ <string name="withdraw_error_currency_mismatch">Erreur : La banque a déclaré une devise différente</string>
</resources> \ No newline at end of file
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..377f3f7
--- /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/cashier/src/main/res/values-sv/strings.xml b/cashier/src/main/res/values-sv/strings.xml
index 1794aa2..967cedb 100644
--- a/cashier/src/main/res/values-sv/strings.xml
+++ b/cashier/src/main/res/values-sv/strings.xml
@@ -5,7 +5,7 @@
<string name="config_password">Lösenord</string>
<string name="config_button_save">Spara</string>
<string name="config_username_error">Vänligen ange ditt användarnamn!</string>
- <string name="config_error">Fel vid hämtning av konfiguration: %s</string>
+ <string name="config_error">Fel vid hämtning av konfiguration</string>
<string name="config_error_auth">Ogiltigt användarnamn eller lösenord!</string>
<string name="balance_current_label">Nuvarande saldo</string>
<string name="balance_error">FEL: %s</string>
@@ -39,4 +39,5 @@
<string name="config_bank_url_error">Adressen är ogiltig.</string>
<string name="config_demo_hint">För testning kan du &lt;a href=%s&gt;skapa ett testkonto i demobanken&lt;/a&gt; .</string>
<string name="withdraw_error_fetch">Fel vid kommunikation med bank: %s</string>
+ <string name="withdraw_error_currency_mismatch">Fel: Banken har rapporterat en annan valuta</string>
</resources> \ No newline at end of file
diff --git a/cashier/src/main/res/values-tr/strings.xml b/cashier/src/main/res/values-tr/strings.xml
new file mode 100644
index 0000000..09db26f
--- /dev/null
+++ b/cashier/src/main/res/values-tr/strings.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="config_bank_url">Banka API adresi</string>
+ <string name="config_username">Kullanıcı adı</string>
+ <string name="config_password">Şifre</string>
+ <string name="config_button_save">Kaydet</string>
+ <string name="config_bank_url_error">Bu adres geçersiz.</string>
+ <string name="config_username_error">Lütfen kullanıcı adınızı giriniz!</string>
+ <string name="app_name">Taler Kasiyer</string>
+ <string name="config_error">Konfigürasyon alınırken hata oluştu</string>
+ <string name="config_error_auth">Geçersiz kullanıcı adı yada şifre!</string>
+ <string name="config_demo_hint">Test için &lt;a href=%s&gt;demo bankasında bir test hesabı oluşturabilirsiniz&lt;/a&gt;.</string>
+ <string name="balance_current_label">Mevcut bakiye</string>
+ <string name="balance_error">HATA:%s</string>
+ <string name="balance_offline">Çevrimdışı. Lütfen internete bağlanın.</string>
+ <string name="ok">Tamam</string>
+ <string name="action_reconfigure">Yeniden yapılandırın</string>
+ <string name="action_lock">Kilitle</string>
+ <string name="action_about">Hakkında</string>
+ <string name="withdraw_into">Ne kadar e-nakit çekilmelidir\?</string>
+ <string name="withdraw_error_zero">Pozitif tutarı girin!</string>
+ <string name="withdraw_input_amount">Tutar</string>
+ <string name="withdraw_error_insufficient_balance">Yetersiz bakiye</string>
+ <string name="withdraw_error_fetch">Banka ile iletişimde hata: %s</string>
+ <string name="withdraw_error_timeout">Hiçbir cüzdan para çekmeye çalışmadı. Lütfen tekrar deneyin.</string>
+ <string name="withdraw_button_confirm">Para çek</string>
+ <string name="transaction_intro">Para çekmek için Taler cüzdan uygulamasıyla kodu tarayın:</string>
+ <string name="transaction_intro_nfc">Para çekmek için Taler cüzdan uygulamasıyla kodu tarayın veya NFC\'yi kullanın:</string>
+ <string name="transaction_intro_scanned">Lütfen işlemi onaylayın!</string>
+ <string name="transaction_confirm">Onayla</string>
+ <string name="transaction_abort">Durdur</string>
+ <string name="transaction_aborted">İşlem durduruldu</string>
+ <string name="transaction_button_back">Geri git</string>
+ <string name="transaction_last_success">Son İşlem: %s çekildi</string>
+ <string name="transaction_last_aborted">Son İşlem: Durduruldu</string>
+ <string name="transaction_last_error">Son İşlem: Başarısız</string>
+ <string name="about_title">GNU Taler Kasiyer</string>
+ <string name="about_license">Lisans: %s</string>
+ <string name="about_copyright">Telif Hakkı: %s</string>
+ <string name="about_supported_bank_api">Banka API Sürümü: %s</string>
+ <string name="about_version">Sürüm: %s</string>
+ <string name="withdraw_error_currency_mismatch">Hata: Banka farklı bir para birimi bildirdi</string>
+</resources> \ No newline at end of file
diff --git a/cashier/src/main/res/values/strings.xml b/cashier/src/main/res/values/strings.xml
index 4c000d8..8e28d28 100644
--- a/cashier/src/main/res/values/strings.xml
+++ b/cashier/src/main/res/values/strings.xml
@@ -7,7 +7,7 @@
<string name="config_button_save">Save</string>
<string name="config_bank_url_error">The address is invalid.</string>
<string name="config_username_error">Please enter your username!</string>
- <string name="config_error">Error retrieving configuration: %s</string>
+ <string name="config_error">Error retrieving configuration</string>
<string name="config_error_auth">Invalid username or password!</string>
<string name="config_error_offline" translatable="false">@string/balance_offline</string>
<string name="config_demo_hint">For testing, you can <![CDATA[<a href="%s">create a test account at the demo bank</a>]]>.</string>
@@ -26,6 +26,7 @@
<string name="withdraw_into">How much e-cash should be withdrawn?</string>
<string name="withdraw_error_zero">Enter positive amount!</string>
<string name="withdraw_error_insufficient_balance">Insufficient balance</string>
+ <string name="withdraw_error_currency_mismatch">Error: Bank reported a different currency</string>
<string name="withdraw_error_fetch">Error communicating with bank: %s</string>
<string name="withdraw_error_timeout">No wallet tried to withdraw. Please try again.</string>
<string name="withdraw_error_offline" translatable="false">@string/balance_offline</string>
diff --git a/cashier/src/main/res/xml/backup_descriptor.xml b/cashier/src/main/res/xml/backup_descriptor.xml
index a298494..c5d3bc7 100644
--- a/cashier/src/main/res/xml/backup_descriptor.xml
+++ b/cashier/src/main/res/xml/backup_descriptor.xml
@@ -15,5 +15,6 @@
-->
<full-backup-content>
-
+ <!-- will not be able to decrypt this, causing crash -->
+ <exclude domain="sharedpref" path="secret_settings.xml"/>
</full-backup-content>
diff --git a/cashier/src/main/res/xml/data_extraction_rules.xml b/cashier/src/main/res/xml/data_extraction_rules.xml
new file mode 100644
index 0000000..de53be5
--- /dev/null
+++ b/cashier/src/main/res/xml/data_extraction_rules.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<data-extraction-rules>
+ <cloud-backup>
+ <exclude domain="sharedpref" path="secret_settings.xml"/>
+ </cloud-backup>
+</data-extraction-rules>
diff --git a/cashier/src/main/res/xml/network_security_config.xml b/cashier/src/main/res/xml/network_security_config.xml
new file mode 100644
index 0000000..81cd5ce
--- /dev/null
+++ b/cashier/src/main/res/xml/network_security_config.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8"?>
+<network-security-config />