Manage Currencies
This commit is contained in:
+13
-106
@@ -7,14 +7,8 @@ import androidx.activity.enableEdgeToEdge
|
|||||||
import androidx.activity.compose.setContent
|
import androidx.activity.compose.setContent
|
||||||
import androidx.activity.viewModels
|
import androidx.activity.viewModels
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.lifecycle.lifecycleScope
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import kotlinx.coroutines.withContext
|
|
||||||
import net.helcel.cowspent.R
|
import net.helcel.cowspent.R
|
||||||
import net.helcel.cowspent.android.helper.showToast
|
import net.helcel.cowspent.android.helper.showToast
|
||||||
import net.helcel.cowspent.model.DBBill
|
|
||||||
import net.helcel.cowspent.model.DBCurrency
|
|
||||||
import net.helcel.cowspent.model.ProjectType
|
import net.helcel.cowspent.model.ProjectType
|
||||||
import net.helcel.cowspent.persistence.CowspentSQLiteOpenHelper
|
import net.helcel.cowspent.persistence.CowspentSQLiteOpenHelper
|
||||||
import net.helcel.cowspent.theme.ThemeUtils
|
import net.helcel.cowspent.theme.ThemeUtils
|
||||||
@@ -25,7 +19,6 @@ class ManageCurrenciesActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
internal val viewModel: ManageCurrenciesViewModel by viewModels()
|
internal val viewModel: ManageCurrenciesViewModel by viewModels()
|
||||||
private var db: CowspentSQLiteOpenHelper? = null
|
private var db: CowspentSQLiteOpenHelper? = null
|
||||||
private var selectedProjectID: Long = -1
|
|
||||||
|
|
||||||
private val editMainCurrencyCallBack: ICallback = object : ICallback {
|
private val editMainCurrencyCallBack: ICallback = object : ICallback {
|
||||||
override fun onFinish() {}
|
override fun onFinish() {}
|
||||||
@@ -47,21 +40,17 @@ class ManageCurrenciesActivity : AppCompatActivity() {
|
|||||||
enableEdgeToEdge()
|
enableEdgeToEdge()
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
intent.extras?.let {
|
val selectedProjectID = intent.getLongExtra(EXTRA_PROJECT_ID, -1L)
|
||||||
selectedProjectID = it.getLong(EXTRA_PROJECT_ID)
|
|
||||||
}
|
|
||||||
if (selectedProjectID == -1L) {
|
if (selectedProjectID == -1L) {
|
||||||
Log.e(TAG, "Missing project id")
|
Log.e(TAG, "Missing project id")
|
||||||
finish()
|
finish()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
db = CowspentSQLiteOpenHelper.getInstance(this)
|
viewModel.projectId = selectedProjectID
|
||||||
|
viewModel.loadCurrencies()
|
||||||
|
|
||||||
lifecycleScope.launch {
|
db = CowspentSQLiteOpenHelper.getInstance(this)
|
||||||
val project = withContext(Dispatchers.IO) { db!!.getProject(selectedProjectID) }
|
|
||||||
viewModel.mainCurrencyName = project?.currencyName?.let { if (it == "null") "" else it } ?: ""
|
|
||||||
updateCurrenciesList()
|
|
||||||
|
|
||||||
setContent {
|
setContent {
|
||||||
ThemeUtils.CowspentTheme {
|
ThemeUtils.CowspentTheme {
|
||||||
@@ -69,109 +58,27 @@ class ManageCurrenciesActivity : AppCompatActivity() {
|
|||||||
viewModel = viewModel,
|
viewModel = viewModel,
|
||||||
onBack = { finish() },
|
onBack = { finish() },
|
||||||
onSaveMain = { saveMainCurrency() },
|
onSaveMain = { saveMainCurrency() },
|
||||||
onAdd = { addOrUpdateCurrency() },
|
onAdd = { viewModel.addCurrency() },
|
||||||
onDelete = { deleteCurrency(it) },
|
onDelete = { viewModel.deleteCurrency(it.id) },
|
||||||
onEdit = { startEditing(it) },
|
onEdit = { viewModel.startEditing(it) },
|
||||||
onCancelEdit = { cancelEditing() }
|
onCancelEdit = { viewModel.cancelEditing() }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private fun saveMainCurrency() {
|
private fun saveMainCurrency() {
|
||||||
val newMainCurrencyName = viewModel.mainCurrencyName
|
val project = db?.getProject(viewModel.projectId)
|
||||||
lifecycleScope.launch {
|
|
||||||
withContext(Dispatchers.IO) {
|
|
||||||
db!!.updateProject(
|
|
||||||
projId = selectedProjectID,
|
|
||||||
newCurrencyName = newMainCurrencyName
|
|
||||||
)
|
|
||||||
val project = db!!.getProject(selectedProjectID)
|
|
||||||
if (project != null) {
|
if (project != null) {
|
||||||
db!!.syncIfRemote(project)
|
|
||||||
if (project.type == ProjectType.COSPEND) {
|
if (project.type == ProjectType.COSPEND) {
|
||||||
withContext(Dispatchers.Main) {
|
if (!db!!.cowspentServerSyncHelper.isSyncPossible) {
|
||||||
if (!db!!.cowspentServerSyncHelper
|
showToast(this, getString(R.string.remote_project_operation_no_network), Toast.LENGTH_LONG)
|
||||||
.editRemoteProject(
|
|
||||||
projId = selectedProjectID,
|
|
||||||
newName = project.name,
|
|
||||||
newMainCurrencyName = newMainCurrencyName,
|
|
||||||
callback = editMainCurrencyCallBack
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
showToast(this@ManageCurrenciesActivity, getString(R.string.remote_project_operation_no_network), Toast.LENGTH_LONG)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
withContext(Dispatchers.Main) {
|
showToast(this, getString(R.string.currency_saved_success), Toast.LENGTH_LONG)
|
||||||
showToast(this@ManageCurrenciesActivity, getString(R.string.currency_saved_success), Toast.LENGTH_LONG)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
viewModel.saveMainCurrency(editMainCurrencyCallBack)
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun addOrUpdateCurrency() {
|
|
||||||
val uiRate = try { viewModel.newCurrencyRate.toDouble() } catch (_: Exception) { 0.0 }
|
|
||||||
val exchangeRate = if (uiRate != 0.0) 1.0 / uiRate else 0.0
|
|
||||||
val currencyName = viewModel.newCurrencyName
|
|
||||||
val editingId = viewModel.editingCurrencyId
|
|
||||||
|
|
||||||
lifecycleScope.launch {
|
|
||||||
withContext(Dispatchers.IO) {
|
|
||||||
if (editingId != null) {
|
|
||||||
db!!.updateCurrency(editingId, currencyName, exchangeRate)
|
|
||||||
val currency = db!!.getCurrency(editingId)
|
|
||||||
if (currency != null) {
|
|
||||||
db!!.setCurrencyStateSync(editingId, DBBill.STATE_EDITED)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
val newCurrency = DBCurrency(
|
|
||||||
0, 0, selectedProjectID,
|
|
||||||
currencyName, exchangeRate, DBBill.STATE_ADDED
|
|
||||||
)
|
|
||||||
db!!.addCurrencyAndSync(newCurrency)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cancelEditing()
|
|
||||||
updateCurrenciesList()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun startEditing(currency: DBCurrency) {
|
|
||||||
viewModel.editingCurrencyId = currency.id
|
|
||||||
viewModel.newCurrencyName = currency.name ?: ""
|
|
||||||
val uiRate = if (currency.exchangeRate != 0.0) 1.0 / currency.exchangeRate else 0.0
|
|
||||||
viewModel.newCurrencyRate = uiRate.toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun cancelEditing() {
|
|
||||||
viewModel.editingCurrencyId = null
|
|
||||||
viewModel.newCurrencyName = ""
|
|
||||||
viewModel.newCurrencyRate = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun deleteCurrency(currency: DBCurrency) {
|
|
||||||
lifecycleScope.launch {
|
|
||||||
withContext(Dispatchers.IO) {
|
|
||||||
db!!.setCurrencyStateSync(currency.id, DBBill.STATE_DELETED)
|
|
||||||
}
|
|
||||||
updateCurrenciesList()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private suspend fun updateCurrenciesList() {
|
|
||||||
val currenciesDB = withContext(Dispatchers.IO) {
|
|
||||||
val list = db!!.getCurrenciesOfProjectWithState(selectedProjectID, DBBill.STATE_ADDED).toMutableList()
|
|
||||||
list.addAll(db!!.getCurrenciesOfProjectWithState(selectedProjectID, DBBill.STATE_EDITED))
|
|
||||||
list.addAll(db!!.getCurrenciesOfProjectWithState(selectedProjectID, DBBill.STATE_OK))
|
|
||||||
list
|
|
||||||
}
|
|
||||||
withContext(Dispatchers.Main) {
|
|
||||||
viewModel.currencies = currenciesDB
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSupportNavigateUp(): Boolean {
|
override fun onSupportNavigateUp(): Boolean {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package net.helcel.cowspent.android.currencies
|
package net.helcel.cowspent.android.currencies
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
|
import android.app.Application
|
||||||
import androidx.compose.foundation.BorderStroke
|
import androidx.compose.foundation.BorderStroke
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
@@ -351,9 +352,10 @@ fun CurrencyRowPreview() {
|
|||||||
@Preview(showBackground = true)
|
@Preview(showBackground = true)
|
||||||
@Composable
|
@Composable
|
||||||
fun ManageCurrenciesScreenPreview() {
|
fun ManageCurrenciesScreenPreview() {
|
||||||
|
val application = LocalContext.current.applicationContext as Application
|
||||||
MaterialTheme {
|
MaterialTheme {
|
||||||
ManageCurrenciesScreen(
|
ManageCurrenciesScreen(
|
||||||
viewModel = ManageCurrenciesViewModel().apply {
|
viewModel = ManageCurrenciesViewModel(application).apply {
|
||||||
mainCurrencyName = "EUR"
|
mainCurrencyName = "EUR"
|
||||||
currencies = listOf(
|
currencies = listOf(
|
||||||
DBCurrency(1, 0, 0, "USD", 1.1, 0),
|
DBCurrency(1, 0, 0, "USD", 1.1, 0),
|
||||||
|
|||||||
+111
-2
@@ -1,14 +1,24 @@
|
|||||||
package net.helcel.cowspent.android.currencies
|
package net.helcel.cowspent.android.currencies
|
||||||
|
|
||||||
|
import android.app.Application
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.AndroidViewModel
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
import net.helcel.cowspent.android.helper.DialogState
|
import net.helcel.cowspent.android.helper.DialogState
|
||||||
|
import net.helcel.cowspent.model.DBBill
|
||||||
import net.helcel.cowspent.model.DBCurrency
|
import net.helcel.cowspent.model.DBCurrency
|
||||||
|
import net.helcel.cowspent.model.ProjectType
|
||||||
|
import net.helcel.cowspent.persistence.CowspentSQLiteOpenHelper
|
||||||
|
import net.helcel.cowspent.util.ICallback
|
||||||
|
|
||||||
class ManageCurrenciesViewModel : ViewModel() {
|
class ManageCurrenciesViewModel(application: Application) : AndroidViewModel(application) {
|
||||||
|
var projectId: Long = -1
|
||||||
var mainCurrencyName by mutableStateOf("")
|
var mainCurrencyName by mutableStateOf("")
|
||||||
var newCurrencyName by mutableStateOf("")
|
var newCurrencyName by mutableStateOf("")
|
||||||
var newCurrencyRate by mutableStateOf("")
|
var newCurrencyRate by mutableStateOf("")
|
||||||
@@ -19,6 +29,105 @@ class ManageCurrenciesViewModel : ViewModel() {
|
|||||||
|
|
||||||
var dialogState by mutableStateOf<DialogState?>(null)
|
var dialogState by mutableStateOf<DialogState?>(null)
|
||||||
|
|
||||||
|
private val db = CowspentSQLiteOpenHelper.getInstance(application)
|
||||||
|
|
||||||
|
fun loadCurrencies() {
|
||||||
|
if (projectId == -1L) return
|
||||||
|
viewModelScope.launch {
|
||||||
|
val project = withContext(Dispatchers.IO) { db.getProject(projectId) }
|
||||||
|
mainCurrencyName = project?.currencyName?.let { if (it == "null") "" else it } ?: ""
|
||||||
|
updateCurrenciesList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun updateCurrenciesList() {
|
||||||
|
val currenciesDB = withContext(Dispatchers.IO) {
|
||||||
|
val list = db.getCurrenciesOfProjectWithState(projectId, DBBill.STATE_ADDED).toMutableList()
|
||||||
|
list.addAll(db.getCurrenciesOfProjectWithState(projectId, DBBill.STATE_EDITED))
|
||||||
|
list.addAll(db.getCurrenciesOfProjectWithState(projectId, DBBill.STATE_OK))
|
||||||
|
list
|
||||||
|
}
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
currencies = currenciesDB
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun saveMainCurrency(callback: ICallback) {
|
||||||
|
val newMainCurrencyName = mainCurrencyName
|
||||||
|
viewModelScope.launch {
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
db.updateProject(
|
||||||
|
projId = projectId,
|
||||||
|
newCurrencyName = newMainCurrencyName
|
||||||
|
)
|
||||||
|
val project = db.getProject(projectId)
|
||||||
|
if (project != null) {
|
||||||
|
db.syncIfRemote(project)
|
||||||
|
if (project.type == ProjectType.COSPEND) {
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
if (!db.cowspentServerSyncHelper
|
||||||
|
.editRemoteProject(
|
||||||
|
projId = projectId,
|
||||||
|
newName = project.name,
|
||||||
|
newMainCurrencyName = newMainCurrencyName,
|
||||||
|
callback = callback
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
// Handled by activity showing toast
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addCurrency() {
|
||||||
|
val uiRate = try { newCurrencyRate.toDouble() } catch (_: Exception) { 0.0 }
|
||||||
|
val exchangeRate = if (uiRate != 0.0) 1.0 / uiRate else 0.0
|
||||||
|
val currencyName = newCurrencyName
|
||||||
|
val editingId = editingCurrencyId
|
||||||
|
|
||||||
|
viewModelScope.launch {
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
if (editingId != null) {
|
||||||
|
db.updateCurrency(editingId, currencyName, exchangeRate)
|
||||||
|
db.setCurrencyStateSync(editingId, DBBill.STATE_EDITED)
|
||||||
|
} else {
|
||||||
|
val newCurrency = DBCurrency(
|
||||||
|
0, 0, projectId,
|
||||||
|
currencyName, exchangeRate, DBBill.STATE_ADDED
|
||||||
|
)
|
||||||
|
db.addCurrencyAndSync(newCurrency)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cancelEditing()
|
||||||
|
updateCurrenciesList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun deleteCurrency(currencyId: Long) {
|
||||||
|
viewModelScope.launch {
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
db.setCurrencyStateSync(currencyId, DBBill.STATE_DELETED)
|
||||||
|
}
|
||||||
|
updateCurrenciesList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun startEditing(currency: DBCurrency) {
|
||||||
|
editingCurrencyId = currency.id
|
||||||
|
newCurrencyName = currency.name ?: ""
|
||||||
|
val uiRate = if (currency.exchangeRate != 0.0) 1.0 / currency.exchangeRate else 0.0
|
||||||
|
newCurrencyRate = uiRate.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun cancelEditing() {
|
||||||
|
editingCurrencyId = null
|
||||||
|
newCurrencyName = ""
|
||||||
|
newCurrencyRate = ""
|
||||||
|
}
|
||||||
|
|
||||||
fun showDialog(
|
fun showDialog(
|
||||||
title: String? = null,
|
title: String? = null,
|
||||||
message: String? = null,
|
message: String? = null,
|
||||||
|
|||||||
Reference in New Issue
Block a user