diff --git a/app/src/main/java/net/helcel/cowspent/android/currencies/ManageCurrenciesActivity.kt b/app/src/main/java/net/helcel/cowspent/android/currencies/ManageCurrenciesActivity.kt index 0602d75..c08eef7 100644 --- a/app/src/main/java/net/helcel/cowspent/android/currencies/ManageCurrenciesActivity.kt +++ b/app/src/main/java/net/helcel/cowspent/android/currencies/ManageCurrenciesActivity.kt @@ -7,14 +7,8 @@ import androidx.activity.enableEdgeToEdge import androidx.activity.compose.setContent import androidx.activity.viewModels 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.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.persistence.CowspentSQLiteOpenHelper import net.helcel.cowspent.theme.ThemeUtils @@ -25,7 +19,6 @@ class ManageCurrenciesActivity : AppCompatActivity() { internal val viewModel: ManageCurrenciesViewModel by viewModels() private var db: CowspentSQLiteOpenHelper? = null - private var selectedProjectID: Long = -1 private val editMainCurrencyCallBack: ICallback = object : ICallback { override fun onFinish() {} @@ -47,131 +40,45 @@ class ManageCurrenciesActivity : AppCompatActivity() { enableEdgeToEdge() super.onCreate(savedInstanceState) - intent.extras?.let { - selectedProjectID = it.getLong(EXTRA_PROJECT_ID) - } + val selectedProjectID = intent.getLongExtra(EXTRA_PROJECT_ID, -1L) if (selectedProjectID == -1L) { Log.e(TAG, "Missing project id") finish() return } - db = CowspentSQLiteOpenHelper.getInstance(this) - - lifecycleScope.launch { - val project = withContext(Dispatchers.IO) { db!!.getProject(selectedProjectID) } - viewModel.mainCurrencyName = project?.currencyName?.let { if (it == "null") "" else it } ?: "" - updateCurrenciesList() + viewModel.projectId = selectedProjectID + viewModel.loadCurrencies() - setContent { - ThemeUtils.CowspentTheme { - ManageCurrenciesScreen( - viewModel = viewModel, - onBack = { finish() }, - onSaveMain = { saveMainCurrency() }, - onAdd = { addOrUpdateCurrency() }, - onDelete = { deleteCurrency(it) }, - onEdit = { startEditing(it) }, - onCancelEdit = { cancelEditing() } - ) - } + db = CowspentSQLiteOpenHelper.getInstance(this) + + setContent { + ThemeUtils.CowspentTheme { + ManageCurrenciesScreen( + viewModel = viewModel, + onBack = { finish() }, + onSaveMain = { saveMainCurrency() }, + onAdd = { viewModel.addCurrency() }, + onDelete = { viewModel.deleteCurrency(it.id) }, + onEdit = { viewModel.startEditing(it) }, + onCancelEdit = { viewModel.cancelEditing() } + ) } } } private fun saveMainCurrency() { - val newMainCurrencyName = viewModel.mainCurrencyName - lifecycleScope.launch { - withContext(Dispatchers.IO) { - db!!.updateProject( - projId = selectedProjectID, - newCurrencyName = newMainCurrencyName - ) - val project = db!!.getProject(selectedProjectID) - if (project != null) { - db!!.syncIfRemote(project) - if (project.type == ProjectType.COSPEND) { - withContext(Dispatchers.Main) { - if (!db!!.cowspentServerSyncHelper - .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 { - withContext(Dispatchers.Main) { - showToast(this@ManageCurrenciesActivity, getString(R.string.currency_saved_success), Toast.LENGTH_LONG) - } - } + val project = db?.getProject(viewModel.projectId) + if (project != null) { + if (project.type == ProjectType.COSPEND) { + if (!db!!.cowspentServerSyncHelper.isSyncPossible) { + showToast(this, getString(R.string.remote_project_operation_no_network), Toast.LENGTH_LONG) } + } else { + showToast(this, getString(R.string.currency_saved_success), Toast.LENGTH_LONG) } } - } - - 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 - } + viewModel.saveMainCurrency(editMainCurrencyCallBack) } override fun onSupportNavigateUp(): Boolean { diff --git a/app/src/main/java/net/helcel/cowspent/android/currencies/ManageCurrenciesScreen.kt b/app/src/main/java/net/helcel/cowspent/android/currencies/ManageCurrenciesScreen.kt index 979789f..617c9a5 100644 --- a/app/src/main/java/net/helcel/cowspent/android/currencies/ManageCurrenciesScreen.kt +++ b/app/src/main/java/net/helcel/cowspent/android/currencies/ManageCurrenciesScreen.kt @@ -1,6 +1,7 @@ package net.helcel.cowspent.android.currencies import android.annotation.SuppressLint +import android.app.Application import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.background import androidx.compose.foundation.clickable @@ -351,9 +352,10 @@ fun CurrencyRowPreview() { @Preview(showBackground = true) @Composable fun ManageCurrenciesScreenPreview() { + val application = LocalContext.current.applicationContext as Application MaterialTheme { ManageCurrenciesScreen( - viewModel = ManageCurrenciesViewModel().apply { + viewModel = ManageCurrenciesViewModel(application).apply { mainCurrencyName = "EUR" currencies = listOf( DBCurrency(1, 0, 0, "USD", 1.1, 0), diff --git a/app/src/main/java/net/helcel/cowspent/android/currencies/ManageCurrenciesViewModel.kt b/app/src/main/java/net/helcel/cowspent/android/currencies/ManageCurrenciesViewModel.kt index 9d80694..536beb6 100644 --- a/app/src/main/java/net/helcel/cowspent/android/currencies/ManageCurrenciesViewModel.kt +++ b/app/src/main/java/net/helcel/cowspent/android/currencies/ManageCurrenciesViewModel.kt @@ -1,14 +1,24 @@ package net.helcel.cowspent.android.currencies +import android.app.Application import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue 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.model.DBBill 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 newCurrencyName by mutableStateOf("") var newCurrencyRate by mutableStateOf("") @@ -19,6 +29,105 @@ class ManageCurrenciesViewModel : ViewModel() { var dialogState by mutableStateOf(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( title: String? = null, message: String? = null,