Project Cleanup/Refactor

This commit is contained in:
2026-09-06 02:56:32 +02:00
parent c6be8eda6b
commit 8564f64576
3 changed files with 64 additions and 26 deletions
@@ -3,8 +3,8 @@ package net.helcel.cowspent.android.project.edit
import android.content.Intent
import android.os.Bundle
import android.widget.Toast
import androidx.activity.enableEdgeToEdge
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
@@ -13,12 +13,11 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import net.helcel.cowspent.R
import net.helcel.cowspent.android.helper.showToast
import net.helcel.cowspent.android.main.MainConstants
import net.helcel.cowspent.model.DBProject
import net.helcel.cowspent.persistence.CowspentSQLiteOpenHelper
import net.helcel.cowspent.theme.ThemeUtils
import net.helcel.cowspent.util.ICallback
import net.helcel.cowspent.util.SupportUtil
import net.helcel.cowspent.android.main.MainConstants
class EditProjectActivity : AppCompatActivity() {
@@ -56,29 +55,33 @@ class EditProjectActivity : AppCompatActivity() {
}
private fun onSave() {
when (viewModel.validate()) {
EditProjectViewModel.ValidationError.EMPTY_NAME -> {
showToast(this, getString(R.string.error_invalid_project_name), Toast.LENGTH_LONG)
return
}
EditProjectViewModel.ValidationError.INVALID_EMAIL -> {
showToast(this, getString(R.string.error_invalid_email), Toast.LENGTH_LONG)
return
}
null -> Unit
}
val changes = viewModel.changesFrom(project)
if (!changes.any) {
showToast(this, getString(R.string.project_edition_no_change), Toast.LENGTH_LONG)
return
}
val currentPwd = viewModel.password
val newPwd = viewModel.newPassword
val newName = viewModel.name
val newEmail = viewModel.email
if (newName.isEmpty()) {
showToast(this, getString(R.string.error_invalid_project_name), Toast.LENGTH_LONG)
return
}
if (newEmail.isNotEmpty() && !SupportUtil.isValidEmail(newEmail)) {
showToast(this, getString(R.string.error_invalid_email), Toast.LENGTH_LONG)
return
}
val nameChanged = newName != project.name
val emailChanged = newEmail != project.email
val pwdChanged = newPwd != project.password
val currentPwdChanged = currentPwd != project.password
if (!nameChanged && !emailChanged && !pwdChanged && !currentPwdChanged) {
showToast(this, getString(R.string.project_edition_no_change), Toast.LENGTH_LONG)
return
}
val nameChanged = changes.name
val emailChanged = changes.email
val pwdChanged = changes.newPassword
val currentPwdChanged = changes.currentPassword
if (project.isLocal) {
val targetPwd = if (pwdChanged) newPwd else currentPwd
@@ -7,6 +7,7 @@ import androidx.compose.ui.graphics.vector.ImageVector
import androidx.lifecycle.ViewModel
import net.helcel.cowspent.android.helper.DialogState
import net.helcel.cowspent.model.DBProject
import net.helcel.cowspent.util.SupportUtil
class EditProjectViewModel : ViewModel() {
var name by mutableStateOf("")
@@ -17,6 +18,31 @@ class EditProjectViewModel : ViewModel() {
var dialogState by mutableStateOf<DialogState?>(null)
enum class ValidationError { EMPTY_NAME, INVALID_EMAIL }
fun validate(): ValidationError? = when {
name.isBlank() -> ValidationError.EMPTY_NAME
email.isNotEmpty() && !SupportUtil.isValidEmail(email) -> ValidationError.INVALID_EMAIL
else -> null
}
data class Changes(
val name: Boolean,
val email: Boolean,
val newPassword: Boolean,
val currentPassword: Boolean
) {
val any: Boolean get() = name || email || newPassword || currentPassword
}
fun changesFrom(project: DBProject) = Changes(
name = name != project.name,
// initFromProject maps a null or "null" email to "", so treat those as unchanged
email = email != project.email && !(email.isEmpty() && project.email == null),
newPassword = newPassword != project.password,
currentPassword = password != project.password
)
fun showDialog(
title: String? = null,
message: String? = null,
@@ -3,8 +3,8 @@ package net.helcel.cowspent.android.statistics
import android.app.DatePickerDialog
import android.content.Context
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.*
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.*
@@ -285,9 +285,18 @@ fun ProjectStatisticsTable(
Spacer(modifier = Modifier.height(4.dp))
LazyColumn(modifier = Modifier.weight(1f)) {
items(stats.memberStats) { m ->
Row(modifier = Modifier.fillMaxWidth().padding(vertical = 12.dp, horizontal = 8.dp), verticalAlignment = Alignment.CenterVertically) {
Column(
modifier = Modifier
.weight(1f)
.verticalScroll(rememberScrollState())
) {
stats.memberStats.forEach { m ->
Row(
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 12.dp, horizontal = 8.dp),
verticalAlignment = Alignment.CenterVertically
) {
Text(m.name, modifier = Modifier.weight(2f), color = MaterialTheme.colors.onSurface, fontWeight = FontWeight.Medium)
Text(