project creation and currency db

This commit is contained in:
soraefir
2026-06-14 21:34:58 +02:00
parent a9a303478c
commit d617c5c7be
5 changed files with 142 additions and 62 deletions
@@ -430,6 +430,7 @@ fun BillsListScreen(
}
},
drawerContent = {
val selectedProject = viewModel.projects.find { it.id == viewModel.selectedProjectId }
Drawer(
projects = viewModel.projects,
members = viewModel.members,
@@ -437,6 +438,7 @@ fun BillsListScreen(
selectedProjectId = viewModel.selectedProjectId,
selectedMemberId = viewModel.selectedMemberId,
lastSyncText = viewModel.lastSyncText,
mainCurrency = selectedProject?.currencyName,
showArchived = showArchived,
onProjectClick = {
viewModel.selectedMemberId = null
@@ -21,6 +21,7 @@ import net.helcel.cowspent.model.*
import net.helcel.cowspent.persistence.CowspentSQLiteOpenHelper
import net.helcel.cowspent.theme.ThemeUtils
import net.helcel.cowspent.util.*
import java.util.Locale
import androidx.core.net.toUri
import androidx.core.content.edit
import net.helcel.cowspent.model.ProjectType
@@ -60,7 +61,8 @@ class NewProjectActivity : AppCompatActivity() {
chooseFromNextcloud()
},
onOkPressed = { onPressOk() },
onBack = { finish() }
onBack = { finish() },
onFieldsChanged = { updateAuthStatus() }
)
}
}
@@ -86,6 +88,8 @@ class NewProjectActivity : AppCompatActivity() {
}
}
updateAuthStatus()
val defaultProjectId = intent.getStringExtra(PARAM_DEFAULT_PROJECT_ID)
if (defaultProjectId != null) {
viewModel.projectId = defaultProjectId
@@ -139,6 +143,17 @@ class NewProjectActivity : AppCompatActivity() {
}
}
private fun updateAuthStatus() {
val url = getFormattedUrl()
val fakeProj = DBProject(
0, "", "", "", url,
"", 0L, viewModel.projectType, 0L,
null, false, DBProject.ACCESS_LEVEL_UNKNOWN,
""
)
viewModel.isAuthenticatedAccount = db.cowspentServerSyncHelper.canCreateAuthenticatedProject(fakeProj)
}
private fun onPressOk() {
val type = viewModel.projectType
val todoCreate = viewModel.whatTodoIsCreate
@@ -186,7 +201,16 @@ class NewProjectActivity : AppCompatActivity() {
}
private fun createProject() {
val isCospendScheme = isCospendSchemeLink(getFormattedUrl())
val url = getFormattedUrl()
val isCospendScheme = isCospendSchemeLink(url)
if (viewModel.whatTodoIsCreate && viewModel.projectId.isEmpty() && viewModel.projectName.isNotEmpty()) {
viewModel.projectId = viewModel.projectName.lowercase(Locale.ROOT)
.replace("[^a-z0-9]".toRegex(), "-")
.replace("-+".toRegex(), "-")
.trim('-')
}
val rid = viewModel.projectId
if (!isCospendScheme && (rid == "" || rid.contains(",") || rid.contains("/"))) {
showToast(getString(R.string.error_invalid_project_remote_id), Toast.LENGTH_LONG)
@@ -194,7 +218,7 @@ class NewProjectActivity : AppCompatActivity() {
}
if (viewModel.projectType != ProjectType.LOCAL && !isCospendScheme) {
if (!isValidUrl(getFormattedUrl())) {
if (!isValidUrl(url)) {
showToast("Invalid URL", Toast.LENGTH_SHORT)
return
}
@@ -217,7 +241,16 @@ class NewProjectActivity : AppCompatActivity() {
showToast("Invalid project name", Toast.LENGTH_SHORT)
return
}
if (!SupportUtil.isValidEmail(viewModel.projectEmail)) {
val fakeProj = DBProject(
0, rid, "", viewModel.projectName, url,
viewModel.projectEmail, 0L, viewModel.projectType, 0L,
null, false, DBProject.ACCESS_LEVEL_UNKNOWN,
""
)
val isAuthenticated = db.cowspentServerSyncHelper.canCreateAuthenticatedProject(fakeProj)
if (!isAuthenticated && !SupportUtil.isValidEmail(viewModel.projectEmail)) {
showToast("Invalid email", Toast.LENGTH_SHORT)
return
}
@@ -226,7 +259,7 @@ class NewProjectActivity : AppCompatActivity() {
if (!db.cowspentServerSyncHelper.createRemoteProject(
viewModel.projectId, viewModel.projectName,
viewModel.projectEmail, viewModel.projectPassword, getFormattedUrl(), viewModel.projectType, createRemoteCallBack
viewModel.projectEmail, viewModel.projectPassword, url, viewModel.projectType, createRemoteCallBack
)
) {
viewModel.isCreatingRemoteProject = false
@@ -32,8 +32,13 @@ fun NewProjectScreen(
onImportFile: () -> Unit,
onChooseFromNextcloud: () -> Unit,
onOkPressed: () -> Unit,
onBack: () -> Unit
onBack: () -> Unit,
onFieldsChanged: () -> Unit
) {
LaunchedEffect(viewModel.projectUrl, viewModel.projectType) {
onFieldsChanged()
}
Scaffold(
topBar = {
TopAppBar(
@@ -162,6 +167,7 @@ fun NewProjectScreen(
Spacer(modifier = Modifier.height(8.dp))
}
if (!viewModel.whatTodoIsCreate || !viewModel.isAuthenticatedAccount || viewModel.projectType != ProjectType.COSPEND) {
OutlinedTextField(
value = viewModel.projectId,
onValueChange = { viewModel.projectId = it },
@@ -169,9 +175,10 @@ fun NewProjectScreen(
modifier = Modifier.fillMaxWidth(),
leadingIcon = { Icon(Icons.AutoMirrored.Filled.LibraryBooks, contentDescription = null) }
)
Spacer(modifier = Modifier.height(8.dp))
}
if (viewModel.projectType != ProjectType.LOCAL && (!viewModel.whatTodoIsCreate || viewModel.projectType == ProjectType.IHATEMONEY)) {
Spacer(modifier = Modifier.height(8.dp))
OutlinedTextField(
value = viewModel.projectPassword,
onValueChange = { viewModel.projectPassword = it },
@@ -179,10 +186,10 @@ fun NewProjectScreen(
modifier = Modifier.fillMaxWidth(),
leadingIcon = { Icon(Icons.Default.Lock, contentDescription = null) }
)
Spacer(modifier = Modifier.height(8.dp))
}
if (viewModel.whatTodoIsCreate && viewModel.projectType != ProjectType.LOCAL) {
Spacer(modifier = Modifier.height(8.dp))
OutlinedTextField(
value = viewModel.projectName,
onValueChange = { viewModel.projectName = it },
@@ -190,6 +197,8 @@ fun NewProjectScreen(
modifier = Modifier.fillMaxWidth(),
leadingIcon = { Icon(Icons.Default.Title, contentDescription = null) }
)
if (!viewModel.isAuthenticatedAccount || viewModel.projectType == ProjectType.IHATEMONEY) {
Spacer(modifier = Modifier.height(8.dp))
OutlinedTextField(
value = viewModel.projectEmail,
@@ -201,6 +210,7 @@ fun NewProjectScreen(
}
}
}
}
if (viewModel.showAuthWarningDialog) {
AlertDialog(
@@ -334,6 +344,7 @@ fun NewProjectScreenPreview() {
onImportFile = {},
onChooseFromNextcloud = {},
onOkPressed = {},
onBack = {}
onBack = {},
onFieldsChanged = {}
)
}
@@ -30,6 +30,8 @@ class NewProjectViewModel : ViewModel() {
var projectName by mutableStateOf("")
var projectEmail by mutableStateOf("")
var isAuthenticatedAccount by mutableStateOf(false)
var showAuthWarningDialog by mutableStateOf(false)
var showNextcloudProjectDialog by mutableStateOf(false)
var nextcloudProjects by mutableStateOf<List<DBAccountProject>>(emptyList())
@@ -39,12 +41,23 @@ class NewProjectViewModel : ViewModel() {
fun isFormValid(): Boolean {
if (whatTodoIsCreate) {
if (projectId.isEmpty()) return false
if (projectType != ProjectType.LOCAL) {
if (projectType == ProjectType.LOCAL) {
return projectId.isNotEmpty()
} else {
if (projectUrl.isEmpty()) return false
if (projectName.isEmpty()) return false
if (projectType == ProjectType.COSPEND && isAuthenticatedAccount) {
return true
}
if (projectId.isEmpty()) return false
if (projectType == ProjectType.IHATEMONEY) {
if (projectEmail.isEmpty()) return false
if (projectType == ProjectType.IHATEMONEY && projectPassword.isEmpty()) return false
if (projectPassword.isEmpty()) return false
} else {
if (projectEmail.isEmpty()) return false
}
}
} else {
// Join
@@ -320,6 +320,7 @@ class CowspentServerSyncHelper private constructor(private val dbHelper: Cowspen
}
}
if (project.type == ProjectType.COSPEND) {
val currenciesToDelete = dbHelper.getCurrenciesOfProjectWithState(project.id, DBBill.STATE_DELETED)
for (cToDel in currenciesToDelete) {
try {
@@ -337,7 +338,14 @@ class CowspentServerSyncHelper private constructor(private val dbHelper: Cowspen
}
}
}
} else {
val currenciesToDelete = dbHelper.getCurrenciesOfProjectWithState(project.id, DBBill.STATE_DELETED)
for (cToDel in currenciesToDelete) {
dbHelper.deleteCurrency(cToDel.id)
}
}
if (project.type == ProjectType.COSPEND) {
val currenciesToEdit = dbHelper.getCurrenciesOfProjectWithState(project.id, DBBill.STATE_EDITED)
for (cToEdit in currenciesToEdit) {
try {
@@ -356,7 +364,14 @@ class CowspentServerSyncHelper private constructor(private val dbHelper: Cowspen
}
}
}
} else {
val currenciesToEdit = dbHelper.getCurrenciesOfProjectWithState(project.id, DBBill.STATE_EDITED)
for (cToEdit in currenciesToEdit) {
dbHelper.setCurrencyState(cToEdit.id, DBBill.STATE_OK)
}
}
if (project.type == ProjectType.COSPEND) {
val currencyToAdd = dbHelper.getCurrenciesOfProjectWithState(project.id, DBBill.STATE_ADDED)
for (cToAdd in currencyToAdd) {
val createRemoteCurrencyResponse = client!!.createRemoteCurrency(project, cToAdd)
@@ -365,6 +380,12 @@ class CowspentServerSyncHelper private constructor(private val dbHelper: Cowspen
dbHelper.setCurrencyState(cToAdd.id, DBBill.STATE_OK)
}
}
} else {
val currencyToAdd = dbHelper.getCurrenciesOfProjectWithState(project.id, DBBill.STATE_ADDED)
for (cToAdd in currencyToAdd) {
dbHelper.setCurrencyState(cToAdd.id, DBBill.STATE_OK)
}
}
LoginStatus.OK
} catch (_: ServerResponse.NotModifiedException) {