project creation and currency db
This commit is contained in:
@@ -430,6 +430,7 @@ fun BillsListScreen(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
drawerContent = {
|
drawerContent = {
|
||||||
|
val selectedProject = viewModel.projects.find { it.id == viewModel.selectedProjectId }
|
||||||
Drawer(
|
Drawer(
|
||||||
projects = viewModel.projects,
|
projects = viewModel.projects,
|
||||||
members = viewModel.members,
|
members = viewModel.members,
|
||||||
@@ -437,6 +438,7 @@ fun BillsListScreen(
|
|||||||
selectedProjectId = viewModel.selectedProjectId,
|
selectedProjectId = viewModel.selectedProjectId,
|
||||||
selectedMemberId = viewModel.selectedMemberId,
|
selectedMemberId = viewModel.selectedMemberId,
|
||||||
lastSyncText = viewModel.lastSyncText,
|
lastSyncText = viewModel.lastSyncText,
|
||||||
|
mainCurrency = selectedProject?.currencyName,
|
||||||
showArchived = showArchived,
|
showArchived = showArchived,
|
||||||
onProjectClick = {
|
onProjectClick = {
|
||||||
viewModel.selectedMemberId = null
|
viewModel.selectedMemberId = null
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import net.helcel.cowspent.model.*
|
|||||||
import net.helcel.cowspent.persistence.CowspentSQLiteOpenHelper
|
import net.helcel.cowspent.persistence.CowspentSQLiteOpenHelper
|
||||||
import net.helcel.cowspent.theme.ThemeUtils
|
import net.helcel.cowspent.theme.ThemeUtils
|
||||||
import net.helcel.cowspent.util.*
|
import net.helcel.cowspent.util.*
|
||||||
|
import java.util.Locale
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
import androidx.core.content.edit
|
import androidx.core.content.edit
|
||||||
import net.helcel.cowspent.model.ProjectType
|
import net.helcel.cowspent.model.ProjectType
|
||||||
@@ -60,7 +61,8 @@ class NewProjectActivity : AppCompatActivity() {
|
|||||||
chooseFromNextcloud()
|
chooseFromNextcloud()
|
||||||
},
|
},
|
||||||
onOkPressed = { onPressOk() },
|
onOkPressed = { onPressOk() },
|
||||||
onBack = { finish() }
|
onBack = { finish() },
|
||||||
|
onFieldsChanged = { updateAuthStatus() }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -85,6 +87,8 @@ class NewProjectActivity : AppCompatActivity() {
|
|||||||
viewModel.projectUrl = defaultNcUrl
|
viewModel.projectUrl = defaultNcUrl
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateAuthStatus()
|
||||||
|
|
||||||
val defaultProjectId = intent.getStringExtra(PARAM_DEFAULT_PROJECT_ID)
|
val defaultProjectId = intent.getStringExtra(PARAM_DEFAULT_PROJECT_ID)
|
||||||
if (defaultProjectId != null) {
|
if (defaultProjectId != null) {
|
||||||
@@ -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() {
|
private fun onPressOk() {
|
||||||
val type = viewModel.projectType
|
val type = viewModel.projectType
|
||||||
val todoCreate = viewModel.whatTodoIsCreate
|
val todoCreate = viewModel.whatTodoIsCreate
|
||||||
@@ -186,7 +201,16 @@ class NewProjectActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun createProject() {
|
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
|
val rid = viewModel.projectId
|
||||||
if (!isCospendScheme && (rid == "" || rid.contains(",") || rid.contains("/"))) {
|
if (!isCospendScheme && (rid == "" || rid.contains(",") || rid.contains("/"))) {
|
||||||
showToast(getString(R.string.error_invalid_project_remote_id), Toast.LENGTH_LONG)
|
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 (viewModel.projectType != ProjectType.LOCAL && !isCospendScheme) {
|
||||||
if (!isValidUrl(getFormattedUrl())) {
|
if (!isValidUrl(url)) {
|
||||||
showToast("Invalid URL", Toast.LENGTH_SHORT)
|
showToast("Invalid URL", Toast.LENGTH_SHORT)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -217,7 +241,16 @@ class NewProjectActivity : AppCompatActivity() {
|
|||||||
showToast("Invalid project name", Toast.LENGTH_SHORT)
|
showToast("Invalid project name", Toast.LENGTH_SHORT)
|
||||||
return
|
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)
|
showToast("Invalid email", Toast.LENGTH_SHORT)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -226,7 +259,7 @@ class NewProjectActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
if (!db.cowspentServerSyncHelper.createRemoteProject(
|
if (!db.cowspentServerSyncHelper.createRemoteProject(
|
||||||
viewModel.projectId, viewModel.projectName,
|
viewModel.projectId, viewModel.projectName,
|
||||||
viewModel.projectEmail, viewModel.projectPassword, getFormattedUrl(), viewModel.projectType, createRemoteCallBack
|
viewModel.projectEmail, viewModel.projectPassword, url, viewModel.projectType, createRemoteCallBack
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
viewModel.isCreatingRemoteProject = false
|
viewModel.isCreatingRemoteProject = false
|
||||||
|
|||||||
@@ -32,8 +32,13 @@ fun NewProjectScreen(
|
|||||||
onImportFile: () -> Unit,
|
onImportFile: () -> Unit,
|
||||||
onChooseFromNextcloud: () -> Unit,
|
onChooseFromNextcloud: () -> Unit,
|
||||||
onOkPressed: () -> Unit,
|
onOkPressed: () -> Unit,
|
||||||
onBack: () -> Unit
|
onBack: () -> Unit,
|
||||||
|
onFieldsChanged: () -> Unit
|
||||||
) {
|
) {
|
||||||
|
LaunchedEffect(viewModel.projectUrl, viewModel.projectType) {
|
||||||
|
onFieldsChanged()
|
||||||
|
}
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
topBar = {
|
topBar = {
|
||||||
TopAppBar(
|
TopAppBar(
|
||||||
@@ -162,16 +167,18 @@ fun NewProjectScreen(
|
|||||||
Spacer(modifier = Modifier.height(8.dp))
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
}
|
}
|
||||||
|
|
||||||
OutlinedTextField(
|
if (!viewModel.whatTodoIsCreate || !viewModel.isAuthenticatedAccount || viewModel.projectType != ProjectType.COSPEND) {
|
||||||
value = viewModel.projectId,
|
OutlinedTextField(
|
||||||
onValueChange = { viewModel.projectId = it },
|
value = viewModel.projectId,
|
||||||
label = { Text(stringResource(R.string.setting_project_id)) },
|
onValueChange = { viewModel.projectId = it },
|
||||||
modifier = Modifier.fillMaxWidth(),
|
label = { Text(stringResource(R.string.setting_project_id)) },
|
||||||
leadingIcon = { Icon(Icons.AutoMirrored.Filled.LibraryBooks, contentDescription = null) }
|
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)) {
|
if (viewModel.projectType != ProjectType.LOCAL && (!viewModel.whatTodoIsCreate || viewModel.projectType == ProjectType.IHATEMONEY)) {
|
||||||
Spacer(modifier = Modifier.height(8.dp))
|
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
value = viewModel.projectPassword,
|
value = viewModel.projectPassword,
|
||||||
onValueChange = { viewModel.projectPassword = it },
|
onValueChange = { viewModel.projectPassword = it },
|
||||||
@@ -179,10 +186,10 @@ fun NewProjectScreen(
|
|||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
leadingIcon = { Icon(Icons.Default.Lock, contentDescription = null) }
|
leadingIcon = { Icon(Icons.Default.Lock, contentDescription = null) }
|
||||||
)
|
)
|
||||||
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
}
|
}
|
||||||
|
|
||||||
if (viewModel.whatTodoIsCreate && viewModel.projectType != ProjectType.LOCAL) {
|
if (viewModel.whatTodoIsCreate && viewModel.projectType != ProjectType.LOCAL) {
|
||||||
Spacer(modifier = Modifier.height(8.dp))
|
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
value = viewModel.projectName,
|
value = viewModel.projectName,
|
||||||
onValueChange = { viewModel.projectName = it },
|
onValueChange = { viewModel.projectName = it },
|
||||||
@@ -190,14 +197,17 @@ fun NewProjectScreen(
|
|||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
leadingIcon = { Icon(Icons.Default.Title, contentDescription = null) }
|
leadingIcon = { Icon(Icons.Default.Title, contentDescription = null) }
|
||||||
)
|
)
|
||||||
Spacer(modifier = Modifier.height(8.dp))
|
|
||||||
OutlinedTextField(
|
if (!viewModel.isAuthenticatedAccount || viewModel.projectType == ProjectType.IHATEMONEY) {
|
||||||
value = viewModel.projectEmail,
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
onValueChange = { viewModel.projectEmail = it },
|
OutlinedTextField(
|
||||||
label = { Text(stringResource(R.string.setting_new_project_email)) },
|
value = viewModel.projectEmail,
|
||||||
modifier = Modifier.fillMaxWidth(),
|
onValueChange = { viewModel.projectEmail = it },
|
||||||
leadingIcon = { Icon(Icons.Default.Email, contentDescription = null) }
|
label = { Text(stringResource(R.string.setting_new_project_email)) },
|
||||||
)
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
leadingIcon = { Icon(Icons.Default.Email, contentDescription = null) }
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -334,6 +344,7 @@ fun NewProjectScreenPreview() {
|
|||||||
onImportFile = {},
|
onImportFile = {},
|
||||||
onChooseFromNextcloud = {},
|
onChooseFromNextcloud = {},
|
||||||
onOkPressed = {},
|
onOkPressed = {},
|
||||||
onBack = {}
|
onBack = {},
|
||||||
|
onFieldsChanged = {}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
+17
-4
@@ -30,6 +30,8 @@ class NewProjectViewModel : ViewModel() {
|
|||||||
var projectName by mutableStateOf("")
|
var projectName by mutableStateOf("")
|
||||||
var projectEmail by mutableStateOf("")
|
var projectEmail by mutableStateOf("")
|
||||||
|
|
||||||
|
var isAuthenticatedAccount by mutableStateOf(false)
|
||||||
|
|
||||||
var showAuthWarningDialog by mutableStateOf(false)
|
var showAuthWarningDialog by mutableStateOf(false)
|
||||||
var showNextcloudProjectDialog by mutableStateOf(false)
|
var showNextcloudProjectDialog by mutableStateOf(false)
|
||||||
var nextcloudProjects by mutableStateOf<List<DBAccountProject>>(emptyList())
|
var nextcloudProjects by mutableStateOf<List<DBAccountProject>>(emptyList())
|
||||||
@@ -39,12 +41,23 @@ class NewProjectViewModel : ViewModel() {
|
|||||||
|
|
||||||
fun isFormValid(): Boolean {
|
fun isFormValid(): Boolean {
|
||||||
if (whatTodoIsCreate) {
|
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 (projectUrl.isEmpty()) return false
|
||||||
if (projectName.isEmpty()) return false
|
if (projectName.isEmpty()) return false
|
||||||
if (projectEmail.isEmpty()) return false
|
|
||||||
if (projectType == ProjectType.IHATEMONEY && projectPassword.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 (projectPassword.isEmpty()) return false
|
||||||
|
} else {
|
||||||
|
if (projectEmail.isEmpty()) return false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Join
|
// Join
|
||||||
|
|||||||
@@ -320,48 +320,69 @@ class CowspentServerSyncHelper private constructor(private val dbHelper: Cowspen
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val currenciesToDelete = dbHelper.getCurrenciesOfProjectWithState(project.id, DBBill.STATE_DELETED)
|
if (project.type == ProjectType.COSPEND) {
|
||||||
for (cToDel in currenciesToDelete) {
|
val currenciesToDelete = dbHelper.getCurrenciesOfProjectWithState(project.id, DBBill.STATE_DELETED)
|
||||||
try {
|
for (cToDel in currenciesToDelete) {
|
||||||
val deleteRemoteCurrencyResponse = client!!.deleteRemoteCurrency(project, cToDel.remoteId)
|
try {
|
||||||
if (deleteRemoteCurrencyResponse.stringContent == "OK") {
|
val deleteRemoteCurrencyResponse = client!!.deleteRemoteCurrency(project, cToDel.remoteId)
|
||||||
Log.d(TAG, "successfully deleted currency on remote project : delete it locally")
|
if (deleteRemoteCurrencyResponse.stringContent == "OK") {
|
||||||
dbHelper.deleteCurrency(cToDel.id)
|
Log.d(TAG, "successfully deleted currency on remote project : delete it locally")
|
||||||
}
|
dbHelper.deleteCurrency(cToDel.id)
|
||||||
} catch (e: IOException) {
|
}
|
||||||
if (e.message == "\"Not Found\"") {
|
} catch (e: IOException) {
|
||||||
Log.d(TAG, "failed to delete currency on remote project : delete it locally anyway")
|
if (e.message == "\"Not Found\"") {
|
||||||
dbHelper.deleteCurrency(cToDel.id)
|
Log.d(TAG, "failed to delete currency on remote project : delete it locally anyway")
|
||||||
} else {
|
dbHelper.deleteCurrency(cToDel.id)
|
||||||
throw e
|
} else {
|
||||||
|
throw e
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
val currenciesToDelete = dbHelper.getCurrenciesOfProjectWithState(project.id, DBBill.STATE_DELETED)
|
||||||
|
for (cToDel in currenciesToDelete) {
|
||||||
|
dbHelper.deleteCurrency(cToDel.id)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val currenciesToEdit = dbHelper.getCurrenciesOfProjectWithState(project.id, DBBill.STATE_EDITED)
|
if (project.type == ProjectType.COSPEND) {
|
||||||
for (cToEdit in currenciesToEdit) {
|
val currenciesToEdit = dbHelper.getCurrenciesOfProjectWithState(project.id, DBBill.STATE_EDITED)
|
||||||
try {
|
for (cToEdit in currenciesToEdit) {
|
||||||
val editRemoteCurrencyResponse = client!!.editRemoteCurrency(project, cToEdit)
|
try {
|
||||||
if (editRemoteCurrencyResponse.stringContent == cToEdit.remoteId.toString()) {
|
val editRemoteCurrencyResponse = client!!.editRemoteCurrency(project, cToEdit)
|
||||||
dbHelper.setCurrencyState(cToEdit.id, DBBill.STATE_OK)
|
if (editRemoteCurrencyResponse.stringContent == cToEdit.remoteId.toString()) {
|
||||||
Log.d(TAG, "SUCCESSFUL remote currency edition (${editRemoteCurrencyResponse.stringContent})")
|
dbHelper.setCurrencyState(cToEdit.id, DBBill.STATE_OK)
|
||||||
} else {
|
Log.d(TAG, "SUCCESSFUL remote currency edition (${editRemoteCurrencyResponse.stringContent})")
|
||||||
Log.d(TAG, "FAILED to edit remote currency (${editRemoteCurrencyResponse.stringContent})")
|
} else {
|
||||||
}
|
Log.d(TAG, "FAILED to edit remote currency (${editRemoteCurrencyResponse.stringContent})")
|
||||||
} catch (e: IOException) {
|
}
|
||||||
if (e.message == "{\"message\": \"Internal Server Error\"}") {
|
} catch (e: IOException) {
|
||||||
Log.d(TAG, "FAILED to edit remote currency : it does not exist remotely")
|
if (e.message == "{\"message\": \"Internal Server Error\"}") {
|
||||||
} else {
|
Log.d(TAG, "FAILED to edit remote currency : it does not exist remotely")
|
||||||
throw e
|
} else {
|
||||||
|
throw e
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
val currenciesToEdit = dbHelper.getCurrenciesOfProjectWithState(project.id, DBBill.STATE_EDITED)
|
||||||
|
for (cToEdit in currenciesToEdit) {
|
||||||
|
dbHelper.setCurrencyState(cToEdit.id, DBBill.STATE_OK)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val currencyToAdd = dbHelper.getCurrenciesOfProjectWithState(project.id, DBBill.STATE_ADDED)
|
if (project.type == ProjectType.COSPEND) {
|
||||||
for (cToAdd in currencyToAdd) {
|
val currencyToAdd = dbHelper.getCurrenciesOfProjectWithState(project.id, DBBill.STATE_ADDED)
|
||||||
val createRemoteCurrencyResponse = client!!.createRemoteCurrency(project, cToAdd)
|
for (cToAdd in currencyToAdd) {
|
||||||
val newRemoteId = createRemoteCurrencyResponse.stringContent.toLong()
|
val createRemoteCurrencyResponse = client!!.createRemoteCurrency(project, cToAdd)
|
||||||
if (newRemoteId > 0) {
|
val newRemoteId = createRemoteCurrencyResponse.stringContent.toLong()
|
||||||
|
if (newRemoteId > 0) {
|
||||||
|
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)
|
dbHelper.setCurrencyState(cToAdd.id, DBBill.STATE_OK)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user