diff options
Diffstat (limited to 'cashier/src/main/java/net/taler/cashier/MainViewModel.kt')
-rw-r--r-- | cashier/src/main/java/net/taler/cashier/MainViewModel.kt | 132 |
1 files changed, 24 insertions, 108 deletions
diff --git a/cashier/src/main/java/net/taler/cashier/MainViewModel.kt b/cashier/src/main/java/net/taler/cashier/MainViewModel.kt index a25467b..95d94d7 100644 --- a/cashier/src/main/java/net/taler/cashier/MainViewModel.kt +++ b/cashier/src/main/java/net/taler/cashier/MainViewModel.kt @@ -16,126 +16,54 @@ package net.taler.cashier -import android.annotation.SuppressLint import android.app.Application import android.util.Log -import androidx.annotation.UiThread -import androidx.annotation.WorkerThread import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.viewModelScope -import androidx.security.crypto.EncryptedSharedPreferences -import androidx.security.crypto.EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV -import androidx.security.crypto.EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM -import androidx.security.crypto.MasterKeys -import androidx.security.crypto.MasterKeys.AES256_GCM_SPEC +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 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.getIncompatibleStringOrNull import net.taler.common.isOnline import net.taler.lib.common.Amount import net.taler.lib.common.AmountParserException -import net.taler.lib.common.Version private val TAG = MainViewModel::class.java.simpleName -private val VERSION_BANK = Version(0, 0, 0) -private const val PREF_NAME = "net.taler.cashier.prefs" -private const val PREF_KEY_BANK_URL = "bankUrl" -private const val PREF_KEY_USERNAME = "username" -private const val PREF_KEY_PASSWORD = "password" -private const val PREF_KEY_CURRENCY = "currency" - class MainViewModel(private val app: Application) : AndroidViewModel(app) { - val configDestination = ConfigFragmentDirections.actionGlobalConfigFragment() - - private val masterKeyAlias = MasterKeys.getOrCreate(AES256_GCM_SPEC) - private val prefs = EncryptedSharedPreferences.create( - PREF_NAME, masterKeyAlias, app, AES256_SIV, AES256_GCM - ) - - internal var config = Config( - bankUrl = prefs.getString(PREF_KEY_BANK_URL, "")!!, - username = prefs.getString(PREF_KEY_USERNAME, "")!!, - password = prefs.getString(PREF_KEY_PASSWORD, "")!! - ) - - private val mCurrency = MutableLiveData<String>( - prefs.getString(PREF_KEY_CURRENCY, null) - ) - internal val currency: LiveData<String> = mCurrency - - private val mConfigResult = MutableLiveData<ConfigResult>() - val configResult: LiveData<ConfigResult> = mConfigResult + private val httpClient = HttpClient(OkHttp) { + engine { + config { + retryOnConnectionFailure(true) + } + } + install(JsonFeature) { + serializer = KotlinxSerializer( + Json { + ignoreUnknownKeys = true + } + ) + } + } + val configManager = ConfigManager(app, viewModelScope, httpClient) private val mBalance = MutableLiveData<BalanceResult>() val balance: LiveData<BalanceResult> = mBalance internal val withdrawManager = WithdrawManager(app, this) - fun hasConfig() = config.bankUrl.isNotEmpty() - && config.username.isNotEmpty() - && config.password.isNotEmpty() - - /** - * Start observing [configResult] after calling this to get the result async. - * Warning: Ignore null results that are used to reset old results. - */ - @UiThread - fun checkAndSaveConfig(config: Config) { - mConfigResult.value = null - viewModelScope.launch(Dispatchers.IO) { - val url = "${config.bankUrl}/config" - Log.d(TAG, "Checking config: $url") - val result = when (val response = makeJsonGetRequest(url, config)) { - is HttpJsonResult.Success -> { - // check if bank's version is compatible with app - val version = response.json.getString("version") - val versionIncompatible = VERSION_BANK.getIncompatibleStringOrNull(app, version) - if (versionIncompatible != null) { - ConfigResult.Error(false, versionIncompatible) - } else { - val currency = response.json.getString("currency") - try { - mCurrency.postValue(currency) - prefs.edit().putString(PREF_KEY_CURRENCY, currency).apply() - // save config - saveConfig(config) - ConfigResult.Success - } catch (e: Exception) { - ConfigResult.Error(false, "Invalid Config: ${response.json}") - } - } - } - is HttpJsonResult.Error -> { - if (response.statusCode > 0 && app.isOnline()) { - ConfigResult.Error(response.statusCode == 401, response.msg) - } else { - ConfigResult.Offline - } - } - } - mConfigResult.postValue(result) - } - } - - @WorkerThread - @SuppressLint("ApplySharedPref") - private fun saveConfig(config: Config) { - this.config = config - prefs.edit() - .putString(PREF_KEY_BANK_URL, config.bankUrl) - .putString(PREF_KEY_USERNAME, config.username) - .putString(PREF_KEY_PASSWORD, config.password) - .commit() - } - fun getBalance() = viewModelScope.launch(Dispatchers.IO) { - check(hasConfig()) { "No config to get balance" } + check(configManager.hasConfig()) { "No config to get balance" } + val config = configManager.config val url = "${config.bankUrl}/accounts/${config.username}/balance" Log.d(TAG, "Checking balance at $url") val result = when (val response = makeJsonGetRequest(url, config)) { @@ -163,19 +91,7 @@ class MainViewModel(private val app: Application) : AndroidViewModel(app) { } fun lock() { - saveConfig(config.copy(password = "")) + configManager.lock() } } - -data class Config( - val bankUrl: String, - val username: String, - val password: String -) - -sealed class ConfigResult { - class Error(val authError: Boolean, val msg: String) : ConfigResult() - object Offline : ConfigResult() - object Success : ConfigResult() -} |