Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2ee7c14e77
|
||
|
|
8d28ee2d6c
|
||
|
|
aee1bd582b
|
||
|
|
8d398db1cb
|
||
|
|
9da65e0725
|
||
|
|
38128d12a0
|
||
|
|
2d7f1b9c2d
|
||
|
|
34ed687234
|
||
|
|
8564f64576
|
||
|
|
c6be8eda6b
|
||
|
|
7904aabbc3
|
||
|
|
e59680e710
|
||
|
|
fff3490719
|
||
|
|
aedefc9010
|
||
|
|
492230faa2
|
||
|
|
488aa9bba6 | ||
|
|
f321eee4f5 | ||
|
|
78da09a312 | ||
|
|
1c6b246ea0 | ||
|
|
f78dc42f44 | ||
|
|
7e7d7face2 | ||
|
|
7ae20373da | ||
|
|
67359d98e0 | ||
|
|
e91fd05bac | ||
|
|
48fa785681 | ||
|
|
16410b7a7a | ||
|
|
367a13a84b | ||
|
|
0d98576b6b | ||
|
|
54481c8dc2 | ||
|
|
0179fdbee7 | ||
|
|
375830a9bd | ||
|
|
373a56a68a | ||
|
|
c487ca644e | ||
|
|
72867a9b5e | ||
|
|
f84d44770d | ||
|
|
bd6ab50859 | ||
|
|
b9e995f30d | ||
|
|
95bdc28336 | ||
|
|
72ba99f4b6 | ||
|
|
42f67dfbe4 | ||
|
|
54ddf69afb | ||
|
|
90b5c7a6e9 | ||
|
|
805a8d0bc4 | ||
|
|
10bf854a50 | ||
|
|
e7a72bef48 | ||
|
|
e45065e3b8 | ||
|
|
db3e27a215 | ||
|
|
ad0928b719 | ||
|
|
0c700232c9 | ||
|
|
7237aedb02 | ||
|
|
4a10025c4f | ||
|
|
a3709d2f04 | ||
|
|
7f04a41d32 |
@@ -23,7 +23,7 @@ jobs:
|
|||||||
contents: write
|
contents: write
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v6
|
- uses: actions/checkout@v7
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
@@ -41,7 +41,7 @@ jobs:
|
|||||||
run: git checkout -B "$BRANCH"
|
run: git checkout -B "$BRANCH"
|
||||||
|
|
||||||
- name: set up JDK
|
- name: set up JDK
|
||||||
uses: actions/setup-java@v5
|
uses: actions/setup-java@v6
|
||||||
with:
|
with:
|
||||||
java-version: 21
|
java-version: 21
|
||||||
distribution: "temurin"
|
distribution: "temurin"
|
||||||
@@ -49,12 +49,28 @@ jobs:
|
|||||||
- name: Setup Gradle
|
- name: Setup Gradle
|
||||||
uses: gradle/actions/setup-gradle@v6
|
uses: gradle/actions/setup-gradle@v6
|
||||||
|
|
||||||
|
- name: Run unit tests
|
||||||
|
run: ./gradlew testDebugUnitTest
|
||||||
|
|
||||||
- name: Build APK
|
- name: Build APK
|
||||||
run: |
|
run: |
|
||||||
VERSION_CODE=$(git rev-list --count HEAD)
|
VERSION_CODE=$(git rev-list --count HEAD)
|
||||||
VERSION_NAME=$(git describe --tags --always)
|
VERSION_BASE=$(git describe --tags --abbrev=0 | sed 's/^v//')
|
||||||
|
VERSION_DEV=$(git rev-list --count $(git describe --tags --abbrev=0)..HEAD)
|
||||||
|
if [ $VERSION_DEV -gt 0 ]; then
|
||||||
|
VERSION_NAME="${VERSION_BASE}.${VERSION_DEV}"
|
||||||
|
else
|
||||||
|
VERSION_NAME="${VERSION_BASE}"
|
||||||
|
fi
|
||||||
./gradlew assembleSignedRelease -PVERSION_CODE=$VERSION_CODE -PVERSION_NAME=$VERSION_NAME
|
./gradlew assembleSignedRelease -PVERSION_CODE=$VERSION_CODE -PVERSION_NAME=$VERSION_NAME
|
||||||
|
|
||||||
|
- name: Upload APK
|
||||||
|
uses: actions/upload-artifact@v7
|
||||||
|
with:
|
||||||
|
path: app/build/outputs/apk/signedRelease/app-signedRelease.apk
|
||||||
|
compression-level: 0
|
||||||
|
archive: false
|
||||||
|
|
||||||
- name: Release
|
- name: Release
|
||||||
uses: softprops/action-gh-release@v3
|
uses: softprops/action-gh-release@v3
|
||||||
if: startsWith(github.ref, 'refs/tags/')
|
if: startsWith(github.ref, 'refs/tags/')
|
||||||
|
|||||||
+67
-12
@@ -1,7 +1,8 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id 'com.android.application' version '9.2.1'
|
id 'com.android.application' version '9.3.2'
|
||||||
id 'org.jetbrains.kotlin.plugin.serialization' version '2.4.0'
|
id 'org.jetbrains.kotlin.plugin.serialization' version '2.4.10'
|
||||||
id 'org.jetbrains.kotlin.plugin.compose' version '2.4.0'
|
id 'org.jetbrains.kotlin.plugin.compose' version '2.4.10'
|
||||||
|
id 'jacoco'
|
||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
@@ -14,8 +15,10 @@ android {
|
|||||||
applicationId "net.helcel.cowspent"
|
applicationId "net.helcel.cowspent"
|
||||||
minSdk = 26
|
minSdk = 26
|
||||||
targetSdk = 37
|
targetSdk = 37
|
||||||
versionName project.hasProperty('VERSION_NAME') ? project.property('VERSION_NAME') : "1"
|
versionName project.hasProperty('VERSION_NAME') ? project.property('VERSION_NAME') : "1.4"
|
||||||
versionCode project.hasProperty('VERSION_CODE') ? project.property('VERSION_CODE').toInteger() : 1
|
versionCode project.hasProperty('VERSION_CODE') ? project.property('VERSION_CODE').toInteger() : 1
|
||||||
|
|
||||||
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
}
|
}
|
||||||
|
|
||||||
signingConfigs {
|
signingConfigs {
|
||||||
@@ -40,6 +43,7 @@ android {
|
|||||||
debuggable true
|
debuggable true
|
||||||
initWith(buildTypes.release)
|
initWith(buildTypes.release)
|
||||||
signingConfig = signingConfigs.debug
|
signingConfig = signingConfigs.debug
|
||||||
|
enableUnitTestCoverage true
|
||||||
}
|
}
|
||||||
release {
|
release {
|
||||||
minifyEnabled true
|
minifyEnabled true
|
||||||
@@ -69,6 +73,24 @@ android {
|
|||||||
compose = true
|
compose = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
testOptions {
|
||||||
|
unitTests {
|
||||||
|
includeAndroidResources = true
|
||||||
|
all {
|
||||||
|
maxParallelForks = 2
|
||||||
|
forkEvery = 50
|
||||||
|
maxHeapSize = "1024m"
|
||||||
|
// Robolectric loads classes through its own sandbox classloader, which leaves them
|
||||||
|
// without a code-source location. Without this JaCoCo skips them entirely and the
|
||||||
|
// report only sees the handful of plain JVM classes.
|
||||||
|
jacoco {
|
||||||
|
includeNoLocationClasses = true
|
||||||
|
excludes = ["jdk.internal.*"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
kotlin {
|
kotlin {
|
||||||
jvmToolchain(21)
|
jvmToolchain(21)
|
||||||
}
|
}
|
||||||
@@ -96,21 +118,21 @@ android {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation 'androidx.compose.foundation:foundation:1.11.4'
|
implementation 'androidx.compose.foundation:foundation:1.12.0'
|
||||||
implementation 'androidx.compose.runtime:runtime:1.11.4'
|
implementation 'androidx.compose.runtime:runtime:1.12.0'
|
||||||
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.1.5'
|
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.1.5'
|
||||||
|
|
||||||
implementation 'androidx.preference:preference-ktx:1.2.1'
|
implementation 'androidx.preference:preference-ktx:1.2.1'
|
||||||
implementation 'androidx.work:work-runtime-ktx:2.11.2'
|
implementation 'androidx.work:work-runtime-ktx:2.11.2'
|
||||||
|
|
||||||
implementation 'com.google.zxing:core:3.5.4'
|
implementation 'com.google.zxing:core:3.5.4'
|
||||||
implementation 'androidx.camera:camera-camera2:1.6.1'
|
implementation 'androidx.camera:camera-camera2:1.6.2'
|
||||||
implementation 'androidx.camera:camera-lifecycle:1.6.1'
|
implementation 'androidx.camera:camera-lifecycle:1.6.2'
|
||||||
implementation 'androidx.camera:camera-view:1.6.1'
|
implementation 'androidx.camera:camera-view:1.6.2'
|
||||||
implementation 'com.github.nextcloud:Android-SingleSignOn:1.1.0'
|
implementation 'com.github.nextcloud:Android-SingleSignOn:1.3.4'
|
||||||
implementation 'com.opencsv:opencsv:5.12.0'
|
implementation 'com.opencsv:opencsv:5.12.0'
|
||||||
|
|
||||||
implementation platform('androidx.compose:compose-bom:2026.06.01')
|
implementation platform('androidx.compose:compose-bom:2026.08.00')
|
||||||
implementation 'androidx.compose.ui:ui'
|
implementation 'androidx.compose.ui:ui'
|
||||||
implementation 'androidx.compose.material:material'
|
implementation 'androidx.compose.material:material'
|
||||||
implementation 'androidx.compose.material:material-icons-extended'
|
implementation 'androidx.compose.material:material-icons-extended'
|
||||||
@@ -121,5 +143,38 @@ dependencies {
|
|||||||
implementation 'androidx.security:security-crypto:1.1.0'
|
implementation 'androidx.security:security-crypto:1.1.0'
|
||||||
implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.11.0'
|
implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.11.0'
|
||||||
implementation "androidx.datastore:datastore-preferences:1.2.1"
|
implementation "androidx.datastore:datastore-preferences:1.2.1"
|
||||||
implementation "com.google.crypto.tink:tink-android:1.22.0"
|
implementation "com.google.crypto.tink:tink-android:1.23.0"
|
||||||
|
|
||||||
|
testImplementation 'junit:junit:4.13.2'
|
||||||
|
testImplementation 'io.mockk:mockk:1.14.11'
|
||||||
|
testImplementation 'org.robolectric:robolectric:4.16.1'
|
||||||
|
testImplementation 'androidx.test:core:1.7.0'
|
||||||
|
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.11.0'
|
||||||
|
testImplementation 'androidx.compose.ui:ui-test-junit4'
|
||||||
|
|
||||||
|
androidTestImplementation platform('androidx.compose:compose-bom:2026.08.00')
|
||||||
|
androidTestImplementation 'androidx.test.ext:junit:1.3.0'
|
||||||
|
androidTestImplementation 'androidx.test.espresso:espresso-core:3.7.0'
|
||||||
|
androidTestImplementation 'androidx.compose.ui:ui-test-junit4'
|
||||||
|
androidTestImplementation 'io.mockk:mockk-android:1.14.11'
|
||||||
|
debugImplementation 'androidx.compose.ui:ui-test-manifest'
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.register('jacocoTestReport', JacocoReport) {
|
||||||
|
dependsOn 'testDebugUnitTest'
|
||||||
|
|
||||||
|
reports {
|
||||||
|
xml.required = true
|
||||||
|
html.required = true
|
||||||
|
}
|
||||||
|
|
||||||
|
def fileFilter = ['**/R.class', '**/R$*.class', '**/BuildConfig.*', '**/Manifest*.*', '**/*Test*.*']
|
||||||
|
def debugTree = fileTree(dir: "${project.layout.buildDirectory.asFile.get()}/intermediates/built_in_kotlinc/debug/compileDebugKotlin/classes", excludes: fileFilter)
|
||||||
|
def mainSrc = "${project.projectDir}/src/main/java"
|
||||||
|
|
||||||
|
sourceDirectories.from = files([mainSrc])
|
||||||
|
classDirectories.from = files([debugTree])
|
||||||
|
executionData.from = fileTree(dir: project.layout.buildDirectory.asFile.get(), includes: [
|
||||||
|
'jacoco/testDebugUnitTest.exec', 'outputs/unit_test_code_coverage/debugUnitTest/testDebugUnitTest.exec'
|
||||||
|
])
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ fun AboutScreen(
|
|||||||
title = { Text(stringResource(R.string.title_about)) },
|
title = { Text(stringResource(R.string.title_about)) },
|
||||||
navigationIcon = {
|
navigationIcon = {
|
||||||
IconButton(onClick = onBack) {
|
IconButton(onClick = onBack) {
|
||||||
Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null)
|
Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Back")
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
backgroundColor = MaterialTheme.colors.primary,
|
backgroundColor = MaterialTheme.colors.primary,
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ import java.util.Locale
|
|||||||
|
|
||||||
class AccountActivity : AppCompatActivity() {
|
class AccountActivity : AppCompatActivity() {
|
||||||
|
|
||||||
private val viewModel: AccountViewModel by viewModels()
|
internal val viewModel: AccountViewModel by viewModels()
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val TAG = AccountActivity::class.java.simpleName
|
private val TAG = AccountActivity::class.java.simpleName
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import androidx.activity.viewModels
|
|||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import androidx.preference.PreferenceManager
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
@@ -26,7 +27,6 @@ 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
|
||||||
import net.helcel.cowspent.util.BillParser
|
import net.helcel.cowspent.util.BillParser
|
||||||
import net.helcel.cowspent.util.CategoryUtils
|
|
||||||
import net.helcel.cowspent.util.SupportUtil
|
import net.helcel.cowspent.util.SupportUtil
|
||||||
import java.text.ParseException
|
import java.text.ParseException
|
||||||
import java.time.ZoneId
|
import java.time.ZoneId
|
||||||
@@ -34,7 +34,7 @@ import java.util.Calendar
|
|||||||
|
|
||||||
class EditBillActivity : AppCompatActivity() {
|
class EditBillActivity : AppCompatActivity() {
|
||||||
|
|
||||||
private val viewModel: EditBillViewModel by viewModels()
|
internal val viewModel: EditBillViewModel by viewModels()
|
||||||
private lateinit var db: CowspentSQLiteOpenHelper
|
private lateinit var db: CowspentSQLiteOpenHelper
|
||||||
private lateinit var bill: DBBill
|
private lateinit var bill: DBBill
|
||||||
private var projectType: ProjectType = ProjectType.LOCAL
|
private var projectType: ProjectType = ProjectType.LOCAL
|
||||||
@@ -52,23 +52,10 @@ class EditBillActivity : AppCompatActivity() {
|
|||||||
ThemeUtils.CowspentTheme {
|
ThemeUtils.CowspentTheme {
|
||||||
|
|
||||||
val categories = remember {
|
val categories = remember {
|
||||||
val syncedCategories = db.getCategories(bill.projectId)
|
db.getCategories(bill.projectId)
|
||||||
val defaultCategories = CategoryUtils.getDefaultCategories(this@EditBillActivity, bill.projectId)
|
|
||||||
val hardcoded = if (projectType == ProjectType.LOCAL) {
|
|
||||||
defaultCategories
|
|
||||||
} else {
|
|
||||||
listOfNotNull(defaultCategories.find { it.remoteId == DBBill.CATEGORY_REIMBURSEMENT.toLong() })
|
|
||||||
}
|
|
||||||
syncedCategories + hardcoded
|
|
||||||
}
|
}
|
||||||
val paymentModes = remember {
|
val paymentModes = remember {
|
||||||
val syncedPaymentModes = db.getPaymentModes(bill.projectId)
|
db.getPaymentModes(bill.projectId)
|
||||||
val defaultPaymentModes = CategoryUtils.getDefaultPaymentModes(this@EditBillActivity, bill.projectId)
|
|
||||||
if (projectType == ProjectType.LOCAL) {
|
|
||||||
syncedPaymentModes + defaultPaymentModes
|
|
||||||
} else {
|
|
||||||
syncedPaymentModes.ifEmpty { defaultPaymentModes }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
EditBillScreen(
|
EditBillScreen(
|
||||||
@@ -165,11 +152,25 @@ class EditBillActivity : AppCompatActivity() {
|
|||||||
val billIdToDuplicate = intent.getLongExtra(PARAM_BILL_ID_TO_DUPLICATE, 0)
|
val billIdToDuplicate = intent.getLongExtra(PARAM_BILL_ID_TO_DUPLICATE, 0)
|
||||||
val timeNowSeconds = System.currentTimeMillis() / 1000
|
val timeNowSeconds = System.currentTimeMillis() / 1000
|
||||||
if (billIdToDuplicate == 0L) {
|
if (billIdToDuplicate == 0L) {
|
||||||
bill = DBBill(
|
val preferences = PreferenceManager.getDefaultSharedPreferences(applicationContext)
|
||||||
0, 0, projectId, 0, 0.0, timeNowSeconds,
|
val fillFromLast = preferences.getBoolean(getString(R.string.pref_key_fill_new_bill_from_last), false)
|
||||||
"", DBBill.STATE_ADDED, DBBill.NON_REPEATED,
|
val lastBill = if (fillFromLast) db.getLastBillOfProject(projectId) else null
|
||||||
DBBill.PAYMODE_NONE, DBBill.CATEGORY_NONE.toLong(), "", DBBill.PAYMODE_ID_NONE.toLong()
|
|
||||||
)
|
if (lastBill != null) {
|
||||||
|
bill = DBBill(
|
||||||
|
0, 0, projectId, lastBill.payerId, 0.0, timeNowSeconds,
|
||||||
|
"", DBBill.STATE_ADDED, lastBill.repeat ?: DBBill.NON_REPEATED,
|
||||||
|
lastBill.paymentMode, lastBill.categoryId, "", lastBill.paymentModeId
|
||||||
|
)
|
||||||
|
bill.billOwers = lastBill.billOwers.map { DBBillOwer(0, 0, it.memberId) }
|
||||||
|
} else {
|
||||||
|
val project = db.getProject(projectId)
|
||||||
|
bill = DBBill(
|
||||||
|
0, 0, projectId, project?.lastPayerId ?: 0, 0.0, timeNowSeconds,
|
||||||
|
"", DBBill.STATE_ADDED, DBBill.NON_REPEATED,
|
||||||
|
DBBill.PAYMODE_NONE, DBBill.CATEGORY_NONE, "", DBBill.PAYMODE_ID_NONE
|
||||||
|
)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
val btd = db.getBill(billIdToDuplicate)!!
|
val btd = db.getBill(billIdToDuplicate)!!
|
||||||
bill = DBBill(
|
bill = DBBill(
|
||||||
@@ -195,6 +196,11 @@ class EditBillActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
val project = db.getProject(bill.projectId)
|
val project = db.getProject(bill.projectId)
|
||||||
val currencies = db.getCurrencies(bill.projectId)
|
val currencies = db.getCurrencies(bill.projectId)
|
||||||
|
|
||||||
|
if (project != null) {
|
||||||
|
db.ensureDefaultLabels(bill.projectId, project.type)
|
||||||
|
}
|
||||||
|
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
viewModel.currencies = currencies
|
viewModel.currencies = currencies
|
||||||
viewModel.mainCurrencyName = project?.currencyName ?: ""
|
viewModel.mainCurrencyName = project?.currencyName ?: ""
|
||||||
@@ -325,7 +331,7 @@ class EditBillActivity : AppCompatActivity() {
|
|||||||
bill.amount == viewModel.getFinalAmount() &&
|
bill.amount == viewModel.getFinalAmount() &&
|
||||||
bill.payerId == viewModel.payerId &&
|
bill.payerId == viewModel.payerId &&
|
||||||
bill.comment == viewModel.getFinalComment() &&
|
bill.comment == viewModel.getFinalComment() &&
|
||||||
bill.repeat == viewModel.repeat &&
|
(bill.repeat ?: DBBill.NON_REPEATED) == viewModel.repeat &&
|
||||||
bill.categoryId == viewModel.categoryId &&
|
bill.categoryId == viewModel.categoryId &&
|
||||||
bill.paymentModeId == viewModel.paymentModeId &&
|
bill.paymentModeId == viewModel.paymentModeId &&
|
||||||
!owersChanged)
|
!owersChanged)
|
||||||
@@ -333,15 +339,25 @@ class EditBillActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
private suspend fun saveBill(): Long = withContext(Dispatchers.IO) {
|
private suspend fun saveBill(): Long = withContext(Dispatchers.IO) {
|
||||||
val groupedBillIds = intent.getLongArrayExtra(PARAM_GROUPED_BILL_IDS)
|
val groupedBillIds = intent.getLongArrayExtra(PARAM_GROUPED_BILL_IDS)
|
||||||
val isCustomSplit = viewModel.isCustomSplit
|
val splitMode = viewModel.splitMode
|
||||||
|
|
||||||
if (isCustomSplit) {
|
if (splitMode != SplitMode.EVEN) {
|
||||||
val splits: Map<Long, Double> = viewModel.owersCustomSplit.filter { (id, amountStr) ->
|
val splits: Map<Long, Double> = if (splitMode == SplitMode.CUSTOM) {
|
||||||
viewModel.owersSelection[id] == true && (amountStr.replace(',', '.').toDoubleOrNull()
|
viewModel.owersCustomSplit.filter { (id, amountStr) ->
|
||||||
?: 0.0) > 0
|
viewModel.owersSelection[id] == true && viewModel.parseAmountFromUi(amountStr) > 0
|
||||||
}.mapValues {
|
}.mapValues {
|
||||||
val uiAmount = it.value.replace(',', '.').toDoubleOrNull() ?: 0.0
|
val uiAmount = viewModel.parseAmountFromUi(it.value)
|
||||||
SupportUtil.round2(uiAmount / viewModel.selectedCurrencyRate)
|
SupportUtil.round2(uiAmount * viewModel.selectedCurrencyRate)
|
||||||
|
}
|
||||||
|
} else { // PERCENT
|
||||||
|
val totalAmount = viewModel.amountAsDouble
|
||||||
|
viewModel.owersPercentSplit.filter { (id, percentStr) ->
|
||||||
|
viewModel.owersSelection[id] == true && viewModel.parseAmountFromUi(percentStr) > 0
|
||||||
|
}.mapValues {
|
||||||
|
val percent = viewModel.parseAmountFromUi(it.value)
|
||||||
|
val uiAmount = SupportUtil.round2(totalAmount * percent / 100.0)
|
||||||
|
SupportUtil.round2(uiAmount * viewModel.selectedCurrencyRate)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (splits.isEmpty()) return@withContext 0L
|
if (splits.isEmpty()) return@withContext 0L
|
||||||
@@ -399,6 +415,8 @@ class EditBillActivity : AppCompatActivity() {
|
|||||||
bill.paymentMode, viewModel.categoryId, finalComment, viewModel.paymentModeId
|
bill.paymentMode, viewModel.categoryId, finalComment, viewModel.paymentModeId
|
||||||
)
|
)
|
||||||
newBill.billOwers = listOf(DBBillOwer(0, 0, memberId))
|
newBill.billOwers = listOf(DBBillOwer(0, 0, memberId))
|
||||||
|
newBill.categoryId = viewModel.categoryId
|
||||||
|
newBill.paymentModeId = viewModel.paymentModeId
|
||||||
val newId = db.addBill(newBill)
|
val newId = db.addBill(newBill)
|
||||||
if (firstSavedId == 0L) firstSavedId = newId
|
if (firstSavedId == 0L) firstSavedId = newId
|
||||||
}
|
}
|
||||||
@@ -412,16 +430,8 @@ class EditBillActivity : AppCompatActivity() {
|
|||||||
val proj = db.getProject(bill.projectId)
|
val proj = db.getProject(bill.projectId)
|
||||||
if (proj != null) db.syncIfRemote(proj)
|
if (proj != null) db.syncIfRemote(proj)
|
||||||
db.updateProject(
|
db.updateProject(
|
||||||
bill.projectId,
|
projId = bill.projectId,
|
||||||
null,
|
newLastPayerId = viewModel.payerId
|
||||||
null,
|
|
||||||
null,
|
|
||||||
viewModel.payerId,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
null
|
|
||||||
)
|
)
|
||||||
|
|
||||||
return@withContext firstSavedId
|
return@withContext firstSavedId
|
||||||
@@ -465,16 +475,8 @@ class EditBillActivity : AppCompatActivity() {
|
|||||||
newOwersIds.forEach { newBill.billOwers += DBBillOwer(0, 0, it) }
|
newOwersIds.forEach { newBill.billOwers += DBBillOwer(0, 0, it) }
|
||||||
val newBillId = db.addBill(newBill)
|
val newBillId = db.addBill(newBill)
|
||||||
db.updateProject(
|
db.updateProject(
|
||||||
bill.projectId,
|
projId = bill.projectId,
|
||||||
null,
|
newLastPayerId = viewModel.payerId
|
||||||
null,
|
|
||||||
null,
|
|
||||||
viewModel.payerId,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
null
|
|
||||||
)
|
)
|
||||||
val proj = db.getProject(bill.projectId)
|
val proj = db.getProject(bill.projectId)
|
||||||
if (proj != null) db.syncIfRemote(proj)
|
if (proj != null) db.syncIfRemote(proj)
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
package net.helcel.cowspent.android.bill_edit
|
package net.helcel.cowspent.android.bill_edit
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.rememberScrollState
|
import androidx.compose.foundation.rememberScrollState
|
||||||
import androidx.compose.foundation.text.BasicTextField
|
import androidx.compose.foundation.text.BasicTextField
|
||||||
|
import androidx.compose.foundation.text.KeyboardActions
|
||||||
import androidx.compose.foundation.text.KeyboardOptions
|
import androidx.compose.foundation.text.KeyboardOptions
|
||||||
import androidx.compose.foundation.verticalScroll
|
import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material.*
|
import androidx.compose.material.*
|
||||||
@@ -16,12 +18,18 @@ import androidx.compose.material.icons.filled.*
|
|||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.draw.scale
|
import androidx.compose.ui.draw.scale
|
||||||
|
import androidx.compose.ui.focus.FocusDirection
|
||||||
|
import androidx.compose.ui.focus.FocusRequester
|
||||||
|
import androidx.compose.ui.focus.focusRequester
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.SolidColor
|
import androidx.compose.ui.graphics.SolidColor
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.platform.LocalFocusManager
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.text.input.ImeAction
|
||||||
import androidx.compose.ui.text.input.KeyboardType
|
import androidx.compose.ui.text.input.KeyboardType
|
||||||
import androidx.compose.ui.text.input.VisualTransformation
|
import androidx.compose.ui.text.input.VisualTransformation
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
@@ -31,6 +39,7 @@ import androidx.compose.ui.unit.sp
|
|||||||
import net.helcel.cowspent.R
|
import net.helcel.cowspent.R
|
||||||
import net.helcel.cowspent.android.helper.*
|
import net.helcel.cowspent.android.helper.*
|
||||||
import net.helcel.cowspent.model.*
|
import net.helcel.cowspent.model.*
|
||||||
|
import net.helcel.cowspent.util.CategoryUtils
|
||||||
import net.helcel.cowspent.util.SupportUtil
|
import net.helcel.cowspent.util.SupportUtil
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
@@ -52,6 +61,13 @@ fun EditBillScreen(
|
|||||||
) {
|
) {
|
||||||
val canEdit = accessLevel == DBProject.ACCESS_LEVEL_UNKNOWN || accessLevel >= DBProject.ACCESS_LEVEL_PARTICIPANT
|
val canEdit = accessLevel == DBProject.ACCESS_LEVEL_UNKNOWN || accessLevel >= DBProject.ACCESS_LEVEL_PARTICIPANT
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
|
val focusRequester = remember { FocusRequester() }
|
||||||
|
|
||||||
|
LaunchedEffect(Unit) {
|
||||||
|
if (viewModel.isNewBill) {
|
||||||
|
focusRequester.requestFocus()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
StatefulAlertDialog(
|
StatefulAlertDialog(
|
||||||
state = viewModel.dialogState,
|
state = viewModel.dialogState,
|
||||||
@@ -127,7 +143,8 @@ fun EditBillScreen(
|
|||||||
viewModel = viewModel,
|
viewModel = viewModel,
|
||||||
canEdit = canEdit,
|
canEdit = canEdit,
|
||||||
onDateClick = onDateClick,
|
onDateClick = onDateClick,
|
||||||
onTimeClick = onTimeClick
|
onTimeClick = onTimeClick,
|
||||||
|
amountFocusRequester = focusRequester
|
||||||
)
|
)
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(8.dp))
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
@@ -163,7 +180,8 @@ fun BillBasicInfoSection(
|
|||||||
viewModel: EditBillViewModel,
|
viewModel: EditBillViewModel,
|
||||||
canEdit: Boolean,
|
canEdit: Boolean,
|
||||||
onDateClick: () -> Unit,
|
onDateClick: () -> Unit,
|
||||||
onTimeClick: () -> Unit
|
onTimeClick: () -> Unit,
|
||||||
|
amountFocusRequester: FocusRequester
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = "GENERAL",
|
text = "GENERAL",
|
||||||
@@ -174,29 +192,20 @@ fun BillBasicInfoSection(
|
|||||||
)
|
)
|
||||||
|
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
|
val focusManager = LocalFocusManager.current
|
||||||
val currencyDialogTitle =
|
val currencyDialogTitle =
|
||||||
stringResource(R.string.currency_dialog_title, viewModel.mainCurrencyName)
|
stringResource(R.string.currency_dialog_title, viewModel.mainCurrencyName)
|
||||||
|
|
||||||
OutlinedTextField(
|
|
||||||
value = viewModel.what,
|
|
||||||
onValueChange = { viewModel.what = it },
|
|
||||||
enabled = canEdit,
|
|
||||||
placeholder = { Text(stringResource(R.string.label_what)) },
|
|
||||||
modifier = Modifier.fillMaxWidth(),
|
|
||||||
leadingIcon = { Icon(Icons.Default.Title, contentDescription = null) }
|
|
||||||
)
|
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(8.dp))
|
|
||||||
|
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
value = viewModel.amount,
|
value = viewModel.amount,
|
||||||
onValueChange = {
|
onValueChange = { nv->
|
||||||
viewModel.amount = it
|
val filteredValue = nv.filter { it in "0123456789.+-*/" }
|
||||||
|
viewModel.amount = filteredValue
|
||||||
viewModel.updateSplits()
|
viewModel.updateSplits()
|
||||||
},
|
},
|
||||||
enabled = canEdit,
|
enabled = canEdit,
|
||||||
placeholder = { Text("0") },
|
placeholder = { Text("0") },
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth().focusRequester(amountFocusRequester),
|
||||||
leadingIcon = {
|
leadingIcon = {
|
||||||
val currencyToShow = viewModel.selectedCurrencyName.ifEmpty {
|
val currencyToShow = viewModel.selectedCurrencyName.ifEmpty {
|
||||||
viewModel.mainCurrencyName.ifEmpty { "$" }
|
viewModel.mainCurrencyName.ifEmpty { "$" }
|
||||||
@@ -230,7 +239,21 @@ fun BillBasicInfoSection(
|
|||||||
Icon(Icons.Default.SwapHoriz, contentDescription = "Change Currency")
|
Icon(Icons.Default.SwapHoriz, contentDescription = "Change Currency")
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number)
|
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Phone, imeAction = ImeAction.Next),
|
||||||
|
keyboardActions = KeyboardActions(onNext = { focusManager.moveFocus(FocusDirection.Next) })
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
|
|
||||||
|
OutlinedTextField(
|
||||||
|
value = viewModel.what,
|
||||||
|
onValueChange = { viewModel.what = it },
|
||||||
|
enabled = canEdit,
|
||||||
|
placeholder = { Text(stringResource(R.string.label_what)) },
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
leadingIcon = { Icon(Icons.Default.Title, contentDescription = null) },
|
||||||
|
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next),
|
||||||
|
keyboardActions = KeyboardActions(onNext = { focusManager.moveFocus(FocusDirection.Next) })
|
||||||
)
|
)
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(8.dp))
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
@@ -356,34 +379,54 @@ fun OwerSelectionSection(
|
|||||||
)
|
)
|
||||||
Spacer(Modifier.weight(1f))
|
Spacer(Modifier.weight(1f))
|
||||||
|
|
||||||
if (viewModel.isCustomSplit) {
|
if (viewModel.splitMode != SplitMode.EVEN) {
|
||||||
val diff = viewModel.getDiffSplit()
|
val diff = viewModel.getDiffSplit()
|
||||||
if (abs(diff) > 0.01) {
|
if (abs(diff) > 0.01) {
|
||||||
|
val unit = if (viewModel.splitMode == SplitMode.PERCENT) "%" else ""
|
||||||
val diffText =
|
val diffText =
|
||||||
if (diff > 0) "Missing: ${SupportUtil.normalNumberFormat.format(diff)}" else "Excess: ${
|
if (diff > 0) "Missing: ${SupportUtil.normalNumberFormat.format(diff)}$unit" else "Excess: ${
|
||||||
SupportUtil.normalNumberFormat.format(-diff)
|
SupportUtil.normalNumberFormat.format(-diff)
|
||||||
}"
|
}$unit"
|
||||||
Text(
|
Text(
|
||||||
diffText,
|
diffText,
|
||||||
color = MaterialTheme.colors.error,
|
color = MaterialTheme.colors.error,
|
||||||
fontSize = 12.sp,
|
fontSize = 12.sp,
|
||||||
modifier = Modifier.padding(horizontal = 16.dp)
|
modifier = Modifier.padding(horizontal = 4.dp)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
Text("Even Split", fontSize = 12.sp)
|
|
||||||
}
|
}
|
||||||
Switch(
|
|
||||||
checked = !viewModel.isCustomSplit,
|
val splitOptions = listOf(SplitMode.EVEN, SplitMode.CUSTOM, SplitMode.PERCENT)
|
||||||
enabled = canEdit,
|
Row(
|
||||||
onCheckedChange = {
|
modifier = Modifier
|
||||||
viewModel.isCustomSplit = !it
|
.padding(start = 8.dp)
|
||||||
viewModel.updateSplits()
|
.background(MaterialTheme.colors.onSurface.copy(alpha = 0.05f), MaterialTheme.shapes.small)
|
||||||
},
|
) {
|
||||||
colors = SwitchDefaults.colors(
|
splitOptions.forEach { mode ->
|
||||||
uncheckedThumbColor = MaterialTheme.colors.onSurface,
|
val isSelected = viewModel.splitMode == mode
|
||||||
)
|
Box(
|
||||||
)
|
modifier = Modifier
|
||||||
|
.clip(MaterialTheme.shapes.small)
|
||||||
|
.background(if (isSelected) MaterialTheme.colors.primary else Color.Transparent)
|
||||||
|
.clickable(enabled = canEdit) {
|
||||||
|
viewModel.splitMode = mode
|
||||||
|
viewModel.updateSplits()
|
||||||
|
}
|
||||||
|
.padding(horizontal = 8.dp, vertical = 4.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = when (mode) {
|
||||||
|
SplitMode.EVEN -> "="
|
||||||
|
SplitMode.CUSTOM -> "#"
|
||||||
|
SplitMode.PERCENT -> "%"
|
||||||
|
},
|
||||||
|
color = if (isSelected) MaterialTheme.colors.onPrimary else MaterialTheme.colors.onSurface,
|
||||||
|
fontSize = 14.sp,
|
||||||
|
fontWeight = FontWeight.Bold
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
viewModel.members.forEach { member ->
|
viewModel.members.forEach { member ->
|
||||||
@@ -407,23 +450,39 @@ fun OwerSelectionSection(
|
|||||||
size = 32.dp
|
size = 32.dp
|
||||||
)
|
)
|
||||||
Spacer(modifier = Modifier.width(8.dp))
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
Text(member.name, modifier = Modifier.weight(1f))
|
val weightSuffix = if (viewModel.hasDifferentWeights && member.weight != 1.0) {
|
||||||
|
" (x${member.weight.toString().removeSuffix(".0")})"
|
||||||
|
} else ""
|
||||||
|
Text("${member.name}$weightSuffix", modifier = Modifier.weight(1f))
|
||||||
|
|
||||||
if (isSelected || viewModel.isCustomSplit) {
|
if (isSelected || viewModel.splitMode != SplitMode.EVEN) {
|
||||||
|
val focusManager = LocalFocusManager.current
|
||||||
val interactionSource = remember { MutableInteractionSource() }
|
val interactionSource = remember { MutableInteractionSource() }
|
||||||
|
val value = if (viewModel.splitMode == SplitMode.PERCENT) {
|
||||||
|
viewModel.owersPercentSplit[member.id] ?: ""
|
||||||
|
} else {
|
||||||
|
viewModel.owersCustomSplit[member.id] ?: ""
|
||||||
|
}
|
||||||
|
|
||||||
BasicTextField(
|
BasicTextField(
|
||||||
value = viewModel.owersCustomSplit[member.id] ?: "",
|
value = value,
|
||||||
onValueChange = {
|
onValueChange = { nv ->
|
||||||
viewModel.owersCustomSplit[member.id] = it
|
val filteredValue = nv.filter { it in "0123456789.+-*/" }
|
||||||
viewModel.owersSelection[member.id] = (it != "")
|
if (viewModel.splitMode == SplitMode.PERCENT) {
|
||||||
|
viewModel.owersPercentSplit[member.id] = filteredValue
|
||||||
|
} else {
|
||||||
|
viewModel.owersCustomSplit[member.id] = filteredValue
|
||||||
|
}
|
||||||
|
viewModel.owersSelection[member.id] = (filteredValue != "")
|
||||||
},
|
},
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.width(80.dp)
|
.width(80.dp)
|
||||||
.height(46.dp),
|
.height(46.dp),
|
||||||
interactionSource = interactionSource,
|
interactionSource = interactionSource,
|
||||||
singleLine = true,
|
singleLine = true,
|
||||||
enabled = viewModel.isCustomSplit && canEdit,
|
enabled = viewModel.splitMode != SplitMode.EVEN && canEdit,
|
||||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
|
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number, imeAction = ImeAction.Next),
|
||||||
|
keyboardActions = KeyboardActions(onNext = { focusManager.moveFocus(FocusDirection.Next) }),
|
||||||
cursorBrush = SolidColor(MaterialTheme.colors.onSurface),
|
cursorBrush = SolidColor(MaterialTheme.colors.onSurface),
|
||||||
textStyle = LocalTextStyle.current.copy(
|
textStyle = LocalTextStyle.current.copy(
|
||||||
textAlign = TextAlign.Right,
|
textAlign = TextAlign.Right,
|
||||||
@@ -431,13 +490,13 @@ fun OwerSelectionSection(
|
|||||||
),
|
),
|
||||||
) { innerTextField ->
|
) { innerTextField ->
|
||||||
TextFieldDefaults.OutlinedTextFieldDecorationBox(
|
TextFieldDefaults.OutlinedTextFieldDecorationBox(
|
||||||
value = viewModel.owersCustomSplit[member.id] ?: "",
|
value = value,
|
||||||
visualTransformation = VisualTransformation.None,
|
visualTransformation = VisualTransformation.None,
|
||||||
innerTextField = innerTextField,
|
innerTextField = innerTextField,
|
||||||
singleLine = true,
|
singleLine = true,
|
||||||
enabled = viewModel.isCustomSplit && canEdit,
|
enabled = viewModel.splitMode != SplitMode.EVEN && canEdit,
|
||||||
interactionSource = interactionSource,
|
interactionSource = interactionSource,
|
||||||
contentPadding = PaddingValues(horizontal = 12.dp, vertical = 0.dp),
|
contentPadding = PaddingValues(horizontal = 8.dp, vertical = 0.dp),
|
||||||
colors = TextFieldDefaults.textFieldColors(
|
colors = TextFieldDefaults.textFieldColors(
|
||||||
cursorColor = MaterialTheme.colors.onSurface,
|
cursorColor = MaterialTheme.colors.onSurface,
|
||||||
backgroundColor = Color.Transparent,
|
backgroundColor = Color.Transparent,
|
||||||
@@ -466,9 +525,10 @@ fun BillAdditionalDetailsSection(
|
|||||||
modifier = Modifier.padding(bottom = 8.dp, top = 16.dp)
|
modifier = Modifier.padding(bottom = 8.dp, top = 16.dp)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val context = LocalContext.current
|
||||||
var categoryExpanded by remember { mutableStateOf(false) }
|
var categoryExpanded by remember { mutableStateOf(false) }
|
||||||
val selectedCategory =
|
val selectedCategory =
|
||||||
categories.find { (if (it.id > 0) it.id else it.remoteId) == viewModel.categoryId }
|
categories.find { it.id == viewModel.categoryId } ?: CategoryUtils.getCategoryById(context, viewModel.categoryId)
|
||||||
|
|
||||||
EditableExposedDropdownMenu(
|
EditableExposedDropdownMenu(
|
||||||
value = selectedCategory?.name ?: "",
|
value = selectedCategory?.name ?: "",
|
||||||
@@ -495,9 +555,19 @@ fun BillAdditionalDetailsSection(
|
|||||||
Spacer(modifier = Modifier.width(12.dp))
|
Spacer(modifier = Modifier.width(12.dp))
|
||||||
Text(stringResource(R.string.category_none))
|
Text(stringResource(R.string.category_none))
|
||||||
}
|
}
|
||||||
categories.forEach { category ->
|
|
||||||
|
DropdownMenuItem(onClick = {
|
||||||
|
viewModel.categoryId = DBBill.CATEGORY_REIMBURSEMENT
|
||||||
|
categoryExpanded = false
|
||||||
|
}) {
|
||||||
|
Text(text = "\uD83D\uDCB0", fontSize = 20.sp)
|
||||||
|
Spacer(modifier = Modifier.width(12.dp))
|
||||||
|
Text(stringResource(R.string.category_reimbursement))
|
||||||
|
}
|
||||||
|
|
||||||
|
categories.filter { it.remoteId != DBBill.CATEGORY_REIMBURSEMENT }.forEach { category ->
|
||||||
DropdownMenuItem(onClick = {
|
DropdownMenuItem(onClick = {
|
||||||
viewModel.categoryId = if (category.id > 0) category.id else category.remoteId
|
viewModel.categoryId = category.id
|
||||||
categoryExpanded = false
|
categoryExpanded = false
|
||||||
}) {
|
}) {
|
||||||
Text(text = category.icon, fontSize = 20.sp)
|
Text(text = category.icon, fontSize = 20.sp)
|
||||||
@@ -512,7 +582,7 @@ fun BillAdditionalDetailsSection(
|
|||||||
|
|
||||||
var pmExpanded by remember { mutableStateOf(false) }
|
var pmExpanded by remember { mutableStateOf(false) }
|
||||||
val selectedPm =
|
val selectedPm =
|
||||||
paymentModes.find { (if (it.id > 0) it.id else it.remoteId) == viewModel.paymentModeId }
|
paymentModes.find { it.id == viewModel.paymentModeId } ?: CategoryUtils.getPaymentModeById(context, viewModel.paymentModeId)
|
||||||
|
|
||||||
EditableExposedDropdownMenu(
|
EditableExposedDropdownMenu(
|
||||||
value = selectedPm?.name ?: "",
|
value = selectedPm?.name ?: "",
|
||||||
@@ -541,7 +611,7 @@ fun BillAdditionalDetailsSection(
|
|||||||
}
|
}
|
||||||
paymentModes.forEach { pm ->
|
paymentModes.forEach { pm ->
|
||||||
DropdownMenuItem(onClick = {
|
DropdownMenuItem(onClick = {
|
||||||
viewModel.paymentModeId = if (pm.id > 0) pm.id else pm.remoteId
|
viewModel.paymentModeId = pm.id
|
||||||
pmExpanded = false
|
pmExpanded = false
|
||||||
}) {
|
}) {
|
||||||
Text(text = pm.icon, fontSize = 20.sp)
|
Text(text = pm.icon, fontSize = 20.sp)
|
||||||
@@ -604,19 +674,115 @@ fun BillAdditionalDetailsSection(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("ViewModelConstructorInComposable")
|
@SuppressLint("ViewModelConstructorInComposable")
|
||||||
@Preview(showBackground = true)
|
@Preview(showBackground = true, name = "Standard Split")
|
||||||
@Composable
|
@Composable
|
||||||
fun EditBillScreenPreview() {
|
fun EditBillScreenPreview() {
|
||||||
MaterialTheme {
|
MaterialTheme {
|
||||||
EditBillScreen(
|
EditBillScreen(
|
||||||
viewModel = EditBillViewModel().apply {
|
viewModel = EditBillViewModel().apply {
|
||||||
what = "Pizza"
|
what = "Pizza"
|
||||||
amount = "12.50"
|
amount = "12.00"
|
||||||
mainCurrencyName = "EUR"
|
mainCurrencyName = "EUR"
|
||||||
members = listOf(
|
members = listOf(
|
||||||
DBMember(1, 0, 0, "Alice", true, 1.0, 0, null, null, null, null, null),
|
DBMember(1, 0, 0, "Alice", true, 1.0, 0, null, null, null, null, null),
|
||||||
DBMember(2, 0, 0, "Bob", true, 1.0, 0, null, null, null, null, null)
|
DBMember(2, 0, 0, "Bob", true, 1.0, 0, null, null, null, null, null)
|
||||||
)
|
)
|
||||||
|
owersSelection[1] = true
|
||||||
|
owersSelection[2] = true
|
||||||
|
updateSplits()
|
||||||
|
},
|
||||||
|
categories = emptyList(),
|
||||||
|
paymentModes = emptyList(),
|
||||||
|
onSave = {},
|
||||||
|
onBack = {},
|
||||||
|
onDateClick = {},
|
||||||
|
onTimeClick = {},
|
||||||
|
onScan = {}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("ViewModelConstructorInComposable")
|
||||||
|
@Preview(showBackground = true, name = "Weighted Split")
|
||||||
|
@Composable
|
||||||
|
fun EditBillScreenWeightedPreview() {
|
||||||
|
MaterialTheme {
|
||||||
|
EditBillScreen(
|
||||||
|
viewModel = EditBillViewModel().apply {
|
||||||
|
what = "Weighted Pizza"
|
||||||
|
amount = "60.00"
|
||||||
|
mainCurrencyName = "EUR"
|
||||||
|
members = listOf(
|
||||||
|
DBMember(1, 0, 0, "Alice", true, 2.0, 0, null, null, null, null, null),
|
||||||
|
DBMember(2, 0, 0, "Bob", true, 1.0, 0, null, null, null, null, null),
|
||||||
|
DBMember(3, 0, 0, "Charlie", true, 1.0, 0, null, null, null, null, null)
|
||||||
|
)
|
||||||
|
owersSelection[1] = true
|
||||||
|
owersSelection[2] = true
|
||||||
|
owersSelection[3] = true
|
||||||
|
updateSplits()
|
||||||
|
},
|
||||||
|
categories = emptyList(),
|
||||||
|
paymentModes = emptyList(),
|
||||||
|
onSave = {},
|
||||||
|
onBack = {},
|
||||||
|
onDateClick = {},
|
||||||
|
onTimeClick = {},
|
||||||
|
onScan = {}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("ViewModelConstructorInComposable")
|
||||||
|
@Preview(showBackground = true, name = "Custom Split (#)")
|
||||||
|
@Composable
|
||||||
|
fun EditBillScreenCustomPreview() {
|
||||||
|
MaterialTheme {
|
||||||
|
EditBillScreen(
|
||||||
|
viewModel = EditBillViewModel().apply {
|
||||||
|
what = "Custom Split Pizza"
|
||||||
|
amount = "60.00"
|
||||||
|
mainCurrencyName = "EUR"
|
||||||
|
members = listOf(
|
||||||
|
DBMember(1, 0, 0, "Alice", true, 1.0, 0, null, null, null, null, null),
|
||||||
|
DBMember(2, 0, 0, "Bob", true, 1.0, 0, null, null, null, null, null)
|
||||||
|
)
|
||||||
|
splitMode = SplitMode.CUSTOM
|
||||||
|
owersSelection[1] = true
|
||||||
|
owersSelection[2] = true
|
||||||
|
owersCustomSplit[1] = "40.00"
|
||||||
|
owersCustomSplit[2] = "20.00"
|
||||||
|
},
|
||||||
|
categories = emptyList(),
|
||||||
|
paymentModes = emptyList(),
|
||||||
|
onSave = {},
|
||||||
|
onBack = {},
|
||||||
|
onDateClick = {},
|
||||||
|
onTimeClick = {},
|
||||||
|
onScan = {}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("ViewModelConstructorInComposable")
|
||||||
|
@Preview(showBackground = true, name = "Percent Split (%)")
|
||||||
|
@Composable
|
||||||
|
fun EditBillScreenPercentPreview() {
|
||||||
|
MaterialTheme {
|
||||||
|
EditBillScreen(
|
||||||
|
viewModel = EditBillViewModel().apply {
|
||||||
|
what = "Percent Split Pizza"
|
||||||
|
amount = "100.00"
|
||||||
|
mainCurrencyName = "EUR"
|
||||||
|
members = listOf(
|
||||||
|
DBMember(1, 0, 0, "Alice", true, 1.0, 0, null, null, null, null, null),
|
||||||
|
DBMember(2, 0, 0, "Bob", true, 1.0, 0, null, null, null, null, null)
|
||||||
|
)
|
||||||
|
splitMode = SplitMode.PERCENT
|
||||||
|
owersSelection[1] = true
|
||||||
|
owersSelection[2] = true
|
||||||
|
owersPercentSplit[1] = "70"
|
||||||
|
owersPercentSplit[2] = "30"
|
||||||
},
|
},
|
||||||
categories = emptyList(),
|
categories = emptyList(),
|
||||||
paymentModes = emptyList(),
|
paymentModes = emptyList(),
|
||||||
|
|||||||
@@ -2,21 +2,23 @@ package net.helcel.cowspent.android.bill_edit
|
|||||||
|
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableDoubleStateOf
|
import androidx.compose.runtime.mutableDoubleStateOf
|
||||||
import androidx.compose.runtime.mutableIntStateOf
|
|
||||||
import androidx.compose.runtime.mutableLongStateOf
|
import androidx.compose.runtime.mutableLongStateOf
|
||||||
import androidx.compose.runtime.mutableStateMapOf
|
import androidx.compose.runtime.mutableStateMapOf
|
||||||
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.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import net.helcel.cowspent.model.DBBill
|
|
||||||
import net.helcel.cowspent.model.DBMember
|
|
||||||
import net.helcel.cowspent.android.helper.DialogState
|
import net.helcel.cowspent.android.helper.DialogState
|
||||||
import net.helcel.cowspent.android.helper.parseAmount
|
import net.helcel.cowspent.android.helper.parseAmount
|
||||||
|
import net.helcel.cowspent.model.DBBill
|
||||||
|
import net.helcel.cowspent.model.DBCurrency
|
||||||
|
import net.helcel.cowspent.model.DBMember
|
||||||
import net.helcel.cowspent.util.SupportUtil
|
import net.helcel.cowspent.util.SupportUtil
|
||||||
import net.helcel.cowspent.util.evalMath
|
import net.helcel.cowspent.util.evalMath
|
||||||
|
|
||||||
import net.helcel.cowspent.model.DBCurrency
|
enum class SplitMode {
|
||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
EVEN, CUSTOM, PERCENT
|
||||||
|
}
|
||||||
|
|
||||||
class EditBillViewModel : ViewModel() {
|
class EditBillViewModel : ViewModel() {
|
||||||
var what by mutableStateOf("")
|
var what by mutableStateOf("")
|
||||||
@@ -36,48 +38,75 @@ class EditBillViewModel : ViewModel() {
|
|||||||
var members by mutableStateOf<List<DBMember>>(emptyList())
|
var members by mutableStateOf<List<DBMember>>(emptyList())
|
||||||
|
|
||||||
var owersSelection = mutableStateMapOf<Long, Boolean>()
|
var owersSelection = mutableStateMapOf<Long, Boolean>()
|
||||||
var isCustomSplit by mutableStateOf(false)
|
var splitMode by mutableStateOf(SplitMode.EVEN)
|
||||||
var owersCustomSplit = mutableStateMapOf<Long, String>()
|
var owersCustomSplit = mutableStateMapOf<Long, String>()
|
||||||
|
var owersPercentSplit = mutableStateMapOf<Long, String>()
|
||||||
|
|
||||||
var dialogState by mutableStateOf<DialogState?>(null)
|
var dialogState by mutableStateOf<DialogState?>(null)
|
||||||
|
|
||||||
val amountAsDouble: Double
|
fun parseAmountFromUi(input: String): Double {
|
||||||
get() {
|
if (input.isBlank()) return 0.0
|
||||||
return parseAmount(amount) ?: try {
|
val sanitized = input.replace(',', '.')
|
||||||
evalMath(amount.replace(',', '.'))
|
// If it contains any math operator, try evalMath first
|
||||||
} catch (_: Exception) {
|
if (sanitized.any { it in "+-*/" }) {
|
||||||
0.0
|
try {
|
||||||
}
|
val result = evalMath(sanitized)
|
||||||
|
if (result != 0.0) return SupportUtil.round2(result)
|
||||||
|
} catch (_: Exception) {}
|
||||||
}
|
}
|
||||||
|
val parsed = parseAmount(input) ?: 0.0
|
||||||
fun getEvenSplit(): Double {
|
return SupportUtil.round2(parsed)
|
||||||
val selectedOwersCount = owersSelection.count { it.value }
|
|
||||||
return if (selectedOwersCount > 0) amountAsDouble / selectedOwersCount else 0.0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val amountAsDouble: Double
|
||||||
|
get() = parseAmountFromUi(amount)
|
||||||
|
|
||||||
|
val hasDifferentWeights: Boolean
|
||||||
|
get() = members.isNotEmpty() && members.any { it.weight != members[0].weight }
|
||||||
|
|
||||||
fun updateSplits() {
|
fun updateSplits() {
|
||||||
if (!isCustomSplit) {
|
if (splitMode == SplitMode.EVEN) {
|
||||||
val even = getEvenSplit()
|
val selectedMembers = members.filter { owersSelection[it.id] == true }
|
||||||
val evenStr = if (even == 0.0) "" else SupportUtil.round2(even).toString()
|
val totalWeight = selectedMembers.sumOf { it.weight }
|
||||||
|
val uiAmount = amountAsDouble
|
||||||
members.forEach { m ->
|
members.forEach { m ->
|
||||||
if (owersSelection[m.id] == true) {
|
if (owersSelection[m.id] == true) {
|
||||||
owersCustomSplit[m.id] = evenStr
|
val share = if (totalWeight > 0) (uiAmount * m.weight) / totalWeight else 0.0
|
||||||
|
owersCustomSplit[m.id] = if (share == 0.0) "" else SupportUtil.round2(share).toString()
|
||||||
} else {
|
} else {
|
||||||
owersCustomSplit.remove(m.id)
|
owersCustomSplit.remove(m.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (splitMode == SplitMode.PERCENT) {
|
||||||
|
val selectedCount = owersSelection.count { it.value }
|
||||||
|
if (selectedCount > 0) {
|
||||||
|
val evenPercent = 100.0 / selectedCount
|
||||||
|
val evenPercentStr = SupportUtil.round2(evenPercent).toString()
|
||||||
|
members.forEach { m ->
|
||||||
|
if (owersSelection[m.id] == true) {
|
||||||
|
if (owersPercentSplit[m.id].isNullOrEmpty()) {
|
||||||
|
owersPercentSplit[m.id] = evenPercentStr
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
owersPercentSplit.remove(m.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun toggleMember(id: Long, selected: Boolean) {
|
fun toggleMember(id: Long, selected: Boolean) {
|
||||||
owersSelection[id] = selected
|
owersSelection[id] = selected
|
||||||
if (isCustomSplit) {
|
if (splitMode != SplitMode.EVEN) {
|
||||||
if (selected) {
|
if (selected) {
|
||||||
if (owersCustomSplit[id].isNullOrEmpty()) {
|
if (splitMode == SplitMode.CUSTOM && owersCustomSplit[id].isNullOrEmpty()) {
|
||||||
owersCustomSplit[id] = "0"
|
owersCustomSplit[id] = "0"
|
||||||
|
} else if (splitMode == SplitMode.PERCENT && owersPercentSplit[id].isNullOrEmpty()) {
|
||||||
|
owersPercentSplit[id] = "0"
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
owersCustomSplit.remove(id)
|
owersCustomSplit.remove(id)
|
||||||
|
owersPercentSplit.remove(id)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
updateSplits()
|
updateSplits()
|
||||||
@@ -85,10 +114,17 @@ class EditBillViewModel : ViewModel() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun getDiffSplit(): Double {
|
fun getDiffSplit(): Double {
|
||||||
val customTotal = owersCustomSplit.entries
|
return if (splitMode == SplitMode.PERCENT) {
|
||||||
.filter { owersSelection[it.key] == true }
|
val customTotal = owersPercentSplit.entries
|
||||||
.sumOf { it.value.replace(',', '.').toDoubleOrNull() ?: 0.0 }
|
.filter { owersSelection[it.key] == true }
|
||||||
return amountAsDouble - customTotal
|
.sumOf { parseAmountFromUi(it.value) }
|
||||||
|
SupportUtil.round2(100.0 - customTotal)
|
||||||
|
} else {
|
||||||
|
val customTotal = owersCustomSplit.entries
|
||||||
|
.filter { owersSelection[it.key] == true }
|
||||||
|
.sumOf { parseAmountFromUi(it.value) }
|
||||||
|
SupportUtil.round2(amountAsDouble - customTotal)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getOwersIds(): List<Long> {
|
fun getOwersIds(): List<Long> {
|
||||||
@@ -144,7 +180,7 @@ class EditBillViewModel : ViewModel() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun getFinalAmount(): Double {
|
fun getFinalAmount(): Double {
|
||||||
return SupportUtil.round2(amountAsDouble / selectedCurrencyRate)
|
return SupportUtil.round2(amountAsDouble * selectedCurrencyRate)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getFinalComment(): String {
|
fun getFinalComment(): String {
|
||||||
@@ -206,44 +242,45 @@ class EditBillViewModel : ViewModel() {
|
|||||||
|
|
||||||
owersSelection.clear()
|
owersSelection.clear()
|
||||||
owersCustomSplit.clear()
|
owersCustomSplit.clear()
|
||||||
|
owersPercentSplit.clear()
|
||||||
|
|
||||||
if (customSplits != null) {
|
if (customSplits != null) {
|
||||||
isCustomSplit = true
|
splitMode = SplitMode.CUSTOM
|
||||||
for (member in members) {
|
for (member in members) {
|
||||||
val selected = customSplits.containsKey(member.id)
|
val selected = customSplits.containsKey(member.id)
|
||||||
owersSelection[member.id] = selected
|
owersSelection[member.id] = selected
|
||||||
if (selected) {
|
if (selected) {
|
||||||
// If we have metadata, the custom splits from DB are also converted.
|
// If we have metadata, the custom splits from DB are also converted.
|
||||||
// We should show them as "Original" if possible?
|
// We should show them as "Original" if possible?
|
||||||
// Actually, if we use metadata, we should probably store original splits too,
|
// Reverse calculation for display: UI Part = DB Part / Rate
|
||||||
// but for now let's just reverse the rate for display.
|
|
||||||
val dbPart = customSplits[member.id]!!
|
val dbPart = customSplits[member.id]!!
|
||||||
val uiPart = if (selectedCurrencyRate != 1.0) dbPart * selectedCurrencyRate else dbPart
|
val uiPart = if (selectedCurrencyRate != 0.0) dbPart / selectedCurrencyRate else dbPart
|
||||||
owersCustomSplit[member.id] = SupportUtil.round2(uiPart).toString()
|
owersCustomSplit[member.id] = SupportUtil.round2(uiPart).toString()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Even split logic
|
// Even split logic
|
||||||
|
splitMode = SplitMode.EVEN
|
||||||
val billOwerIds = bill.billOwersIds
|
val billOwerIds = bill.billOwersIds
|
||||||
val selectedCount = billOwerIds.size
|
val selectedMembers = members.filter { billOwerIds.contains(it.id) }
|
||||||
|
val totalWeight = selectedMembers.sumOf { it.weight }
|
||||||
|
|
||||||
// Use UI amount for even split calculation
|
// Use UI amount for even split calculation
|
||||||
val uiAmount = amountAsDouble
|
val uiAmount = amountAsDouble
|
||||||
val evenSplit = if (selectedCount > 0) uiAmount / selectedCount else 0.0
|
|
||||||
val evenSplitStr = if (evenSplit == 0.0) "" else SupportUtil.round2(evenSplit).toString()
|
|
||||||
|
|
||||||
for (member in members) {
|
for (member in members) {
|
||||||
val selected = billOwerIds.contains(member.id)
|
val selected = billOwerIds.contains(member.id)
|
||||||
owersSelection[member.id] = selected
|
owersSelection[member.id] = selected
|
||||||
if (selected) {
|
if (selected) {
|
||||||
owersCustomSplit[member.id] = evenSplitStr
|
val share = if (totalWeight > 0) (uiAmount * member.weight) / totalWeight else 0.0
|
||||||
|
owersCustomSplit[member.id] = if (share == 0.0) "" else SupportUtil.round2(share).toString()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isFormValid(): Boolean {
|
fun isFormValid(): Boolean {
|
||||||
return what.isNotEmpty() && !what.contains(",") &&
|
return what.isNotEmpty() &&
|
||||||
timestamp != 0L &&
|
timestamp != 0L &&
|
||||||
payerId != 0L &&
|
payerId != 0L &&
|
||||||
owersSelection.any { it.value }
|
owersSelection.any { it.value }
|
||||||
@@ -257,7 +294,7 @@ class EditBillViewModel : ViewModel() {
|
|||||||
errorInvalidForm: String
|
errorInvalidForm: String
|
||||||
): String? {
|
): String? {
|
||||||
return when {
|
return when {
|
||||||
what.isEmpty() || what.contains(",") -> errorWhat
|
what.isEmpty() -> errorWhat
|
||||||
timestamp == 0L -> errorDate
|
timestamp == 0L -> errorDate
|
||||||
payerId == 0L -> errorPayer
|
payerId == 0L -> errorPayer
|
||||||
owersSelection.none { it.value } -> errorOwers
|
owersSelection.none { it.value } -> errorOwers
|
||||||
|
|||||||
@@ -13,12 +13,11 @@ import kotlinx.coroutines.launch
|
|||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
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.CategoryUtils
|
|
||||||
import net.helcel.cowspent.model.DBBill
|
import net.helcel.cowspent.model.DBBill
|
||||||
import net.helcel.cowspent.model.ProjectType
|
import net.helcel.cowspent.model.ProjectType
|
||||||
|
|
||||||
class LabelBillsActivity : AppCompatActivity() {
|
class LabelBillsActivity : AppCompatActivity() {
|
||||||
private val viewModel: LabelBillsViewModel by viewModels()
|
internal val viewModel: LabelBillsViewModel by viewModels()
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
enableEdgeToEdge()
|
enableEdgeToEdge()
|
||||||
@@ -42,14 +41,10 @@ class LabelBillsActivity : AppCompatActivity() {
|
|||||||
val billsToLabel = allBills.filter { it.categoryId == 0L && it.state != DBBill.STATE_DELETED }
|
val billsToLabel = allBills.filter { it.categoryId == 0L && it.state != DBBill.STATE_DELETED }
|
||||||
val allCategorized = allBills.filter { it.categoryId != 0L && it.state != DBBill.STATE_DELETED }
|
val allCategorized = allBills.filter { it.categoryId != 0L && it.state != DBBill.STATE_DELETED }
|
||||||
|
|
||||||
val syncedCategories = db.getCategories(projectId)
|
db.ensureDefaultLabels(projectId, projectType)
|
||||||
val defaultCategories = CategoryUtils.getDefaultCategories(this@LabelBillsActivity, projectId)
|
|
||||||
val hardcoded = if (projectType == ProjectType.LOCAL) {
|
// Reload from DB to get real IDs
|
||||||
defaultCategories
|
val categories = db.getCategories(projectId)
|
||||||
} else {
|
|
||||||
listOfNotNull(defaultCategories.find { it.remoteId == DBBill.CATEGORY_REIMBURSEMENT.toLong() })
|
|
||||||
}
|
|
||||||
val categories = syncedCategories + hardcoded
|
|
||||||
|
|
||||||
Quadruple(members, billsToLabel, categories, allCategorized)
|
Quadruple(members, billsToLabel, categories, allCategorized)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import androidx.compose.ui.Alignment
|
|||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.platform.testTag
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
@@ -45,7 +46,10 @@ fun LabelBillsScreen(
|
|||||||
title = { Text(stringResource(R.string.title_label_bills)) },
|
title = { Text(stringResource(R.string.title_label_bills)) },
|
||||||
navigationIcon = {
|
navigationIcon = {
|
||||||
IconButton(onClick = onBack) {
|
IconButton(onClick = onBack) {
|
||||||
Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null)
|
Icon(
|
||||||
|
Icons.AutoMirrored.Filled.ArrowBack,
|
||||||
|
contentDescription = stringResource(R.string.simple_back)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
backgroundColor = MaterialTheme.colors.primary,
|
backgroundColor = MaterialTheme.colors.primary,
|
||||||
@@ -223,7 +227,10 @@ fun BillSummaryCard(bill: DBBill, members: List<DBMember>, remainingCount: Int)
|
|||||||
fun CategoryButton(icon: String, name: String, onClick: () -> Unit) {
|
fun CategoryButton(icon: String, name: String, onClick: () -> Unit) {
|
||||||
OutlinedButton(
|
OutlinedButton(
|
||||||
onClick = onClick,
|
onClick = onClick,
|
||||||
modifier = Modifier.fillMaxWidth().height(60.dp),
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.height(60.dp)
|
||||||
|
.testTag("CategoryButton_$name"),
|
||||||
contentPadding = PaddingValues(2.dp)
|
contentPadding = PaddingValues(2.dp)
|
||||||
) {
|
) {
|
||||||
Column(horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center) {
|
Column(horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center) {
|
||||||
@@ -248,10 +255,10 @@ fun LabelBillsScreenPreview() {
|
|||||||
DBBill(1L, 0, 1L, 1L, 120.5, System.currentTimeMillis() / 1000, "Groceries at Aldi", 0, null, null, 0L, null, -1L)
|
DBBill(1L, 0, 1L, 1L, 120.5, System.currentTimeMillis() / 1000, "Groceries at Aldi", 0, null, null, 0L, null, -1L)
|
||||||
)
|
)
|
||||||
val cats = listOf(
|
val cats = listOf(
|
||||||
DBCategory(-1, -1, 1, "Groceries", "🛒", ""),
|
DBCategory(1L, 1L, 1L, "Groceries", "🛒", ""),
|
||||||
DBCategory(-2, -2, 1, "Leisure", "🥳", ""),
|
DBCategory(2L, 2L, 1L, "Leisure", "🥳", ""),
|
||||||
DBCategory(-3, -3, 1, "Rent", "🏠", ""),
|
DBCategory(3L, 3L, 1L, "Rent", "🏠", ""),
|
||||||
DBCategory(-4, -4, 1, "Bills", "💸", "")
|
DBCategory(4L, 4L, 1L, "Bills", "💸", "")
|
||||||
)
|
)
|
||||||
categories = cats
|
categories = cats
|
||||||
categoriesMap = cats.associateBy { it.id }
|
categoriesMap = cats.associateBy { it.id }
|
||||||
|
|||||||
+30
-115
@@ -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
|
||||||
@@ -23,9 +17,8 @@ import net.helcel.cowspent.util.ICallback
|
|||||||
|
|
||||||
class ManageCurrenciesActivity : AppCompatActivity() {
|
class ManageCurrenciesActivity : AppCompatActivity() {
|
||||||
|
|
||||||
private 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() {}
|
||||||
@@ -33,9 +26,11 @@ class ManageCurrenciesActivity : AppCompatActivity() {
|
|||||||
if (message.isEmpty()) {
|
if (message.isEmpty()) {
|
||||||
showToast(this@ManageCurrenciesActivity,getString(R.string.currency_saved_success), Toast.LENGTH_LONG)
|
showToast(this@ManageCurrenciesActivity,getString(R.string.currency_saved_success), Toast.LENGTH_LONG)
|
||||||
} else {
|
} else {
|
||||||
viewModel.showDialog(title=getString(R.string.error_edit_remote_project_helper, message),
|
viewModel.showDialog(
|
||||||
message=getString(R.string.action_currencies),
|
title = getString(R.string.dialog_sync_error_title),
|
||||||
positiveText = getString(android.R.string.ok))
|
message = getString(R.string.error_edit_remote_project_helper, message),
|
||||||
|
positiveText = getString(android.R.string.ok)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
override fun onScheduled() {}
|
override fun onScheduled() {}
|
||||||
@@ -45,125 +40,45 @@ 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 {
|
|
||||||
val project = withContext(Dispatchers.IO) { db!!.getProject(selectedProjectID) }
|
|
||||||
viewModel.mainCurrencyName = project?.currencyName?.let { if (it == "null") "" else it } ?: ""
|
|
||||||
updateCurrenciesList()
|
|
||||||
|
|
||||||
setContent {
|
db = CowspentSQLiteOpenHelper.getInstance(this)
|
||||||
ThemeUtils.CowspentTheme {
|
|
||||||
ManageCurrenciesScreen(
|
setContent {
|
||||||
viewModel = viewModel,
|
ThemeUtils.CowspentTheme {
|
||||||
onBack = { finish() },
|
ManageCurrenciesScreen(
|
||||||
onSaveMain = { saveMainCurrency() },
|
viewModel = viewModel,
|
||||||
onAdd = { addOrUpdateCurrency() },
|
onBack = { finish() },
|
||||||
onDelete = { deleteCurrency(it) },
|
onSaveMain = { saveMainCurrency() },
|
||||||
onEdit = { startEditing(it) },
|
onAdd = { viewModel.addCurrency() },
|
||||||
onCancelEdit = { cancelEditing() }
|
onDelete = { viewModel.deleteCurrency(it.id) },
|
||||||
)
|
onEdit = { viewModel.startEditing(it) },
|
||||||
}
|
onCancelEdit = { viewModel.cancelEditing() }
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun saveMainCurrency() {
|
private fun saveMainCurrency() {
|
||||||
val newMainCurrencyName = viewModel.mainCurrencyName
|
val project = db?.getProject(viewModel.projectId)
|
||||||
lifecycleScope.launch {
|
if (project != null) {
|
||||||
withContext(Dispatchers.IO) {
|
if (project.type == ProjectType.COSPEND) {
|
||||||
db!!.updateProject(
|
if (!db!!.cowspentServerSyncHelper.isSyncPossible) {
|
||||||
selectedProjectID, null, null, null,
|
showToast(this, getString(R.string.remote_project_operation_no_network), Toast.LENGTH_LONG)
|
||||||
null, null, newMainCurrencyName,
|
|
||||||
null, null, null
|
|
||||||
)
|
|
||||||
val project = db!!.getProject(selectedProjectID)
|
|
||||||
if (project != null) {
|
|
||||||
db!!.syncIfRemote(project)
|
|
||||||
if (project.type == ProjectType.COSPEND) {
|
|
||||||
withContext(Dispatchers.Main) {
|
|
||||||
if (!db!!.cowspentServerSyncHelper
|
|
||||||
.editRemoteProject(selectedProjectID, project.name, null, null, newMainCurrencyName, 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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
showToast(this, getString(R.string.currency_saved_success), Toast.LENGTH_LONG)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
viewModel.saveMainCurrency(editMainCurrencyCallBack)
|
||||||
|
|
||||||
private fun addOrUpdateCurrency() {
|
|
||||||
val exchangeRate = try { viewModel.newCurrencyRate.toDouble() } catch (_: Exception) { 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 ?: ""
|
|
||||||
viewModel.newCurrencyRate = currency.exchangeRate.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 {
|
||||||
|
|||||||
+16
-35
@@ -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
|
||||||
@@ -41,6 +42,8 @@ import androidx.compose.runtime.LaunchedEffect
|
|||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.platform.testTag
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
@@ -48,7 +51,7 @@ import androidx.compose.ui.unit.dp
|
|||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import net.helcel.cowspent.R
|
import net.helcel.cowspent.R
|
||||||
import net.helcel.cowspent.android.helper.AlertDialog
|
import net.helcel.cowspent.android.helper.StatefulAlertDialog
|
||||||
import net.helcel.cowspent.android.helper.formatAmount
|
import net.helcel.cowspent.android.helper.formatAmount
|
||||||
import net.helcel.cowspent.model.DBCurrency
|
import net.helcel.cowspent.model.DBCurrency
|
||||||
import kotlin.time.Duration.Companion.milliseconds
|
import kotlin.time.Duration.Companion.milliseconds
|
||||||
@@ -63,35 +66,10 @@ fun ManageCurrenciesScreen(
|
|||||||
onEdit: (DBCurrency) -> Unit,
|
onEdit: (DBCurrency) -> Unit,
|
||||||
onCancelEdit: () -> Unit
|
onCancelEdit: () -> Unit
|
||||||
) {
|
) {
|
||||||
val dialogState = viewModel.dialogState
|
StatefulAlertDialog(
|
||||||
if (dialogState != null) {
|
state = viewModel.dialogState,
|
||||||
AlertDialog(
|
onDismissRequest = { viewModel.dismissDialog() }
|
||||||
showDialog = true,
|
)
|
||||||
onDismissRequest = { viewModel.dismissDialog() },
|
|
||||||
title = dialogState.title,
|
|
||||||
message = dialogState.message,
|
|
||||||
icon = dialogState.icon,
|
|
||||||
items = dialogState.items,
|
|
||||||
positiveText = dialogState.positiveText,
|
|
||||||
negativeText = dialogState.negativeText,
|
|
||||||
neutralText = dialogState.neutralText,
|
|
||||||
onConfirm = {
|
|
||||||
dialogState.onConfirm?.invoke()
|
|
||||||
viewModel.dismissDialog()
|
|
||||||
},
|
|
||||||
onCancel = {
|
|
||||||
dialogState.onCancel?.invoke()
|
|
||||||
viewModel.dismissDialog()
|
|
||||||
},
|
|
||||||
onNeutral = {
|
|
||||||
dialogState.onNeutral?.invoke()
|
|
||||||
viewModel.dismissDialog()
|
|
||||||
}
|
|
||||||
) {
|
|
||||||
dialogState.onItemSelected?.invoke(it)
|
|
||||||
viewModel.dismissDialog()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
topBar = {
|
topBar = {
|
||||||
@@ -216,7 +194,7 @@ fun ManageCurrenciesScreen(
|
|||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = if (isEditing) Icons.Default.Done else Icons.Default.Add,
|
imageVector = if (isEditing) Icons.Default.Done else Icons.Default.Add,
|
||||||
contentDescription = null,
|
contentDescription = if (isEditing) "Done" else "Add",
|
||||||
tint = if (viewModel.isAddEnabled()) {
|
tint = if (viewModel.isAddEnabled()) {
|
||||||
if (isEditing) MaterialTheme.colors.secondary else MaterialTheme.colors.primary
|
if (isEditing) MaterialTheme.colors.secondary else MaterialTheme.colors.primary
|
||||||
} else MaterialTheme.colors.onSurface.copy(alpha = 0.2f)
|
} else MaterialTheme.colors.onSurface.copy(alpha = 0.2f)
|
||||||
@@ -274,7 +252,9 @@ fun CurrencyRow(
|
|||||||
shape = RoundedCornerShape(12.dp),
|
shape = RoundedCornerShape(12.dp),
|
||||||
elevation = if (isEditing) 4.dp else 1.dp,
|
elevation = if (isEditing) 4.dp else 1.dp,
|
||||||
border = if (isEditing) BorderStroke(1.dp, MaterialTheme.colors.secondary.copy(alpha = 0.5f)) else null,
|
border = if (isEditing) BorderStroke(1.dp, MaterialTheme.colors.secondary.copy(alpha = 0.5f)) else null,
|
||||||
modifier = Modifier.fillMaxWidth()
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.testTag("CurrencyRow_${currency.name}")
|
||||||
) {
|
) {
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@@ -304,7 +284,7 @@ fun CurrencyRow(
|
|||||||
modifier = Modifier.padding(horizontal = 8.dp)
|
modifier = Modifier.padding(horizontal = 8.dp)
|
||||||
)
|
)
|
||||||
Text(
|
Text(
|
||||||
text = formatAmount(currency.exchangeRate),
|
text = formatAmount(if (currency.exchangeRate != 0.0) 1.0 / currency.exchangeRate else 0.0),
|
||||||
style = MaterialTheme.typography.body1,
|
style = MaterialTheme.typography.body1,
|
||||||
fontWeight = FontWeight.ExtraBold,
|
fontWeight = FontWeight.ExtraBold,
|
||||||
color = if (isEditing) MaterialTheme.colors.secondary else MaterialTheme.colors.onSurface
|
color = if (isEditing) MaterialTheme.colors.secondary else MaterialTheme.colors.onSurface
|
||||||
@@ -320,7 +300,7 @@ fun CurrencyRow(
|
|||||||
IconButton(onClick = onDelete) {
|
IconButton(onClick = onDelete) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Default.Delete,
|
imageVector = Icons.Default.Delete,
|
||||||
contentDescription = null,
|
contentDescription = "Delete",
|
||||||
tint = MaterialTheme.colors.error.copy(alpha = 0.7f),
|
tint = MaterialTheme.colors.error.copy(alpha = 0.7f),
|
||||||
modifier = Modifier.size(20.dp)
|
modifier = Modifier.size(20.dp)
|
||||||
)
|
)
|
||||||
@@ -347,9 +327,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,
|
||||||
|
|||||||
@@ -61,11 +61,7 @@ fun ColorPicker(
|
|||||||
var chroma by remember { mutableFloatStateOf(initialLch[1]) }
|
var chroma by remember { mutableFloatStateOf(initialLch[1]) }
|
||||||
var hue by remember { mutableFloatStateOf(initialLch[2]) }
|
var hue by remember { mutableFloatStateOf(initialLch[2]) }
|
||||||
|
|
||||||
val currentColorInt = remember(lightness, chroma, hue) {
|
val currentColorInt = remember(lightness, chroma, hue) { mLCHtoRBG(lightness, chroma, hue) }
|
||||||
val color = mLCHtoRBG(lightness,chroma,hue)
|
|
||||||
onColorChanged(color)
|
|
||||||
color
|
|
||||||
}
|
|
||||||
|
|
||||||
val currentColor = Color(currentColorInt)
|
val currentColor = Color(currentColorInt)
|
||||||
|
|
||||||
@@ -74,8 +70,9 @@ fun ColorPicker(
|
|||||||
var isHexValid by remember { mutableStateOf(true) }
|
var isHexValid by remember { mutableStateOf(true) }
|
||||||
val interactionSource = remember { MutableInteractionSource() }
|
val interactionSource = remember { MutableInteractionSource() }
|
||||||
|
|
||||||
// Sync HEX with LCH
|
// Report the colour, and keep the HEX field in step with the LCH sliders.
|
||||||
LaunchedEffect(currentColorInt) {
|
LaunchedEffect(currentColorInt) {
|
||||||
|
onColorChanged(currentColorInt)
|
||||||
val newHex = "%06X".format(0xFFFFFF and currentColorInt)
|
val newHex = "%06X".format(0xFFFFFF and currentColorInt)
|
||||||
if (hexText.uppercase() != newHex) {
|
if (hexText.uppercase() != newHex) {
|
||||||
hexText = newHex
|
hexText = newHex
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package net.helcel.cowspent.android.helper
|
package net.helcel.cowspent.android.helper
|
||||||
|
|
||||||
import android.graphics.*
|
import android.graphics.Color
|
||||||
import android.graphics.drawable.Drawable
|
|
||||||
import java.security.MessageDigest
|
import java.security.MessageDigest
|
||||||
import java.security.NoSuchAlgorithmException
|
import java.security.NoSuchAlgorithmException
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@@ -11,209 +10,143 @@ import kotlin.math.round
|
|||||||
import kotlin.math.sqrt
|
import kotlin.math.sqrt
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A Drawable object that draws text (1 character) on top of a circular/filled background.
|
* The color a member's avatar gets, derived from their name.
|
||||||
*/
|
*/
|
||||||
class TextDrawable private constructor(
|
object TextDrawable {
|
||||||
private val mText: String,
|
private const val INDEX_RED = 0
|
||||||
r: Int,
|
private const val INDEX_GREEN = 1
|
||||||
g: Int,
|
private const val INDEX_BLUE = 2
|
||||||
b: Int,
|
private const val INDEX_HUE = 0
|
||||||
private val mRadius: Float,
|
private const val INDEX_SATURATION = 1
|
||||||
private val mDisabled: Boolean
|
private const val INDEX_LUMINATION = 2
|
||||||
) : Drawable() {
|
|
||||||
private val mTextPaint: Paint = Paint()
|
|
||||||
private val mBackground: Paint = Paint()
|
|
||||||
private val mDisabledCircle: Paint = Paint()
|
|
||||||
|
|
||||||
init {
|
fun getColorFromName(name: String): Int {
|
||||||
mBackground.style = Paint.Style.FILL
|
return try {
|
||||||
mBackground.isAntiAlias = true
|
val hsl = calculateHSL(name)
|
||||||
mBackground.color = Color.rgb(r, g, b)
|
val rgb = hslToRgb(hsl[0].toFloat(), hsl[1].toFloat(), hsl[2].toFloat(), 1f)
|
||||||
|
Color.rgb(rgb[0], rgb[1], rgb[2])
|
||||||
if ((r + g + b) / 3 < 220) {
|
} catch (_: NoSuchAlgorithmException) {
|
||||||
mTextPaint.color = Color.WHITE
|
Color.WHITE
|
||||||
} else {
|
|
||||||
mTextPaint.color = Color.BLACK
|
|
||||||
}
|
}
|
||||||
mTextPaint.textSize = mRadius
|
|
||||||
mTextPaint.isAntiAlias = true
|
|
||||||
mTextPaint.textAlign = Paint.Align.CENTER
|
|
||||||
|
|
||||||
mDisabledCircle.style = Paint.Style.STROKE
|
|
||||||
mDisabledCircle.strokeWidth = mRadius * 0.2f
|
|
||||||
mDisabledCircle.isAntiAlias = true
|
|
||||||
mDisabledCircle.color = Color.DKGRAY
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun draw(canvas: Canvas) {
|
@Throws(NoSuchAlgorithmException::class)
|
||||||
canvas.drawCircle(mRadius, mRadius, mRadius, mBackground)
|
private fun calculateHSL(name: String): IntArray {
|
||||||
canvas.drawText(
|
val result = arrayOf("0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0")
|
||||||
mText,
|
val rgb = doubleArrayOf(0.0, 0.0, 0.0)
|
||||||
mRadius,
|
var sat = 70
|
||||||
mRadius - (mTextPaint.descent() + mTextPaint.ascent()) / 2,
|
val lum = 68
|
||||||
mTextPaint
|
val modulo = 16
|
||||||
|
|
||||||
|
var hash = name.lowercase(Locale.ROOT).replace("[^0-9a-f]".toRegex(), "")
|
||||||
|
if (!hash.matches("^[0-9a-f]{32}$".toRegex())) {
|
||||||
|
hash = md5(hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i in hash.indices) {
|
||||||
|
result[i % modulo] = (result[i % modulo].toInt() + hash.substring(i, i + 1).toInt(16)).toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
for (count in 1 until modulo) {
|
||||||
|
rgb[count % 3] += result[count].toDouble()
|
||||||
|
}
|
||||||
|
|
||||||
|
rgb[INDEX_RED] = rgb[INDEX_RED] % 255
|
||||||
|
rgb[INDEX_GREEN] = rgb[INDEX_GREEN] % 255
|
||||||
|
rgb[INDEX_BLUE] = rgb[INDEX_BLUE] % 255
|
||||||
|
|
||||||
|
val hsl = rgbToHsl(rgb[INDEX_RED], rgb[INDEX_GREEN], rgb[INDEX_BLUE])
|
||||||
|
|
||||||
|
val bright = sqrt(
|
||||||
|
0.299 * rgb[INDEX_RED].pow(2.0) + 0.587 * rgb[INDEX_GREEN].pow(2.0) + 0.114 * rgb[INDEX_BLUE].pow(2.0)
|
||||||
)
|
)
|
||||||
if (mDisabled) {
|
|
||||||
canvas.drawCircle(mRadius, mRadius, mRadius * 0.9f, mDisabledCircle)
|
if (bright >= 200) {
|
||||||
canvas.drawLine(
|
sat = 60
|
||||||
mRadius * 0.4f,
|
|
||||||
mRadius * 1.6f,
|
|
||||||
mRadius * 1.6f,
|
|
||||||
mRadius * 0.4f,
|
|
||||||
mDisabledCircle
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return intArrayOf((hsl[INDEX_HUE] * 360).toInt(), sat, lum)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setAlpha(alpha: Int) {
|
private fun hslToRgb(hParam: Float, sParam: Float, lParam: Float, alpha: Float): IntArray {
|
||||||
mTextPaint.alpha = alpha
|
var h = hParam
|
||||||
|
var s = sParam
|
||||||
|
var l = lParam
|
||||||
|
if (s !in 0.0f..100.0f) {
|
||||||
|
throw IllegalArgumentException("Color parameter outside of expected range - Saturation")
|
||||||
|
}
|
||||||
|
if (l !in 0.0f..100.0f) {
|
||||||
|
throw IllegalArgumentException("Color parameter outside of expected range - Luminance")
|
||||||
|
}
|
||||||
|
if (alpha !in 0.0f..1.0f) {
|
||||||
|
throw IllegalArgumentException("Color parameter outside of expected range - Alpha")
|
||||||
|
}
|
||||||
|
|
||||||
|
h %= 360.0f
|
||||||
|
h /= 360f
|
||||||
|
s /= 100f
|
||||||
|
l /= 100f
|
||||||
|
|
||||||
|
val q = if (l < 0.5) {
|
||||||
|
l * (1 + s)
|
||||||
|
} else {
|
||||||
|
(l + s) - s * l
|
||||||
|
}
|
||||||
|
val p = 2 * l - q
|
||||||
|
val r = round(max(0f, hueToRgb(p, q, h + 1.0f / 3.0f)) * 256).toInt()
|
||||||
|
val g = round(max(0f, hueToRgb(p, q, h)) * 256).toInt()
|
||||||
|
val b = round(max(0f, hueToRgb(p, q, h - 1.0f / 3.0f)) * 256).toInt()
|
||||||
|
return intArrayOf(r, g, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setColorFilter(cf: ColorFilter?) {
|
private fun hueToRgb(p: Float, q: Float, hParam: Float): Float {
|
||||||
mTextPaint.colorFilter = cf
|
var h = hParam
|
||||||
|
if (h < 0) h += 1f
|
||||||
|
if (h > 1) h -= 1f
|
||||||
|
if (6 * h < 1) return p + (q - p) * 6 * h
|
||||||
|
if (2 * h < 1) return q
|
||||||
|
if (3 * h < 2) return p + (q - p) * 6 * (2.0f / 3.0f - h)
|
||||||
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated("Deprecated in Java")
|
private fun rgbToHsl(rUntrimmed: Double, gUntrimmed: Double, bUntrimmed: Double): DoubleArray {
|
||||||
override fun getOpacity(): Int {
|
val r = rUntrimmed / 255
|
||||||
return PixelFormat.TRANSLUCENT
|
val g = gUntrimmed / 255
|
||||||
}
|
val b = bUntrimmed / 255
|
||||||
|
val max = max(r, max(g, b))
|
||||||
companion object {
|
val min = r.coerceAtMost(g.coerceAtMost(b))
|
||||||
private const val INDEX_RED = 0
|
var h = (max + min) / 2
|
||||||
private const val INDEX_GREEN = 1
|
val s: Double
|
||||||
private const val INDEX_BLUE = 2
|
val l = (max + min) / 2
|
||||||
private const val INDEX_HUE = 0
|
if (max == min) {
|
||||||
private const val INDEX_SATURATION = 1
|
s = 0.0
|
||||||
private const val INDEX_LUMINATION = 2
|
h = s // achromatic
|
||||||
|
} else {
|
||||||
fun getColorFromName(name: String): Int {
|
val d = max - min
|
||||||
return try {
|
s = if (l > 0.5) d / (2 - max - min) else d / (max + min)
|
||||||
val hsl = calculateHSL(name)
|
when (max) {
|
||||||
val rgb = hslToRgb(hsl[0].toFloat(), hsl[1].toFloat(), hsl[2].toFloat(), 1f)
|
r -> {
|
||||||
Color.rgb(rgb[0], rgb[1], rgb[2])
|
h = (g - b) / d + (if (g < b) 6 else 0)
|
||||||
} catch (_: NoSuchAlgorithmException) {
|
}
|
||||||
Color.WHITE
|
g -> {
|
||||||
}
|
h = (b - r) / d + 2
|
||||||
}
|
}
|
||||||
|
b -> {
|
||||||
@Throws(NoSuchAlgorithmException::class)
|
h = (r - g) / d + 4
|
||||||
private fun calculateHSL(name: String): IntArray {
|
|
||||||
val result = arrayOf("0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0")
|
|
||||||
val rgb = doubleArrayOf(0.0, 0.0, 0.0)
|
|
||||||
var sat = 70
|
|
||||||
val lum = 68
|
|
||||||
val modulo = 16
|
|
||||||
|
|
||||||
var hash = name.lowercase(Locale.ROOT).replace("[^0-9a-f]".toRegex(), "")
|
|
||||||
if (!hash.matches("^[0-9a-f]{32}$".toRegex())) {
|
|
||||||
hash = md5(hash)
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i in hash.indices) {
|
|
||||||
result[i % modulo] = (result[i % modulo].toInt() + hash.substring(i, i + 1).toInt(16)).toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
for (count in 1 until modulo) {
|
|
||||||
rgb[count % 3] += result[count].toDouble()
|
|
||||||
}
|
|
||||||
|
|
||||||
rgb[INDEX_RED] = rgb[INDEX_RED] % 255
|
|
||||||
rgb[INDEX_GREEN] = rgb[INDEX_GREEN] % 255
|
|
||||||
rgb[INDEX_BLUE] = rgb[INDEX_BLUE] % 255
|
|
||||||
|
|
||||||
val hsl = rgbToHsl(rgb[INDEX_RED], rgb[INDEX_GREEN], rgb[INDEX_BLUE])
|
|
||||||
|
|
||||||
val bright = sqrt(
|
|
||||||
0.299 * rgb[INDEX_RED].pow(2.0) + 0.587 * rgb[INDEX_GREEN].pow(2.0) + 0.114 * rgb[INDEX_BLUE].pow(2.0)
|
|
||||||
)
|
|
||||||
|
|
||||||
if (bright >= 200) {
|
|
||||||
sat = 60
|
|
||||||
}
|
|
||||||
|
|
||||||
return intArrayOf((hsl[INDEX_HUE] * 360).toInt(), sat, lum)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun hslToRgb(hParam: Float, sParam: Float, lParam: Float, alpha: Float): IntArray {
|
|
||||||
var h = hParam
|
|
||||||
var s = sParam
|
|
||||||
var l = lParam
|
|
||||||
if (s !in 0.0f..100.0f) {
|
|
||||||
throw IllegalArgumentException("Color parameter outside of expected range - Saturation")
|
|
||||||
}
|
|
||||||
if (l !in 0.0f..100.0f) {
|
|
||||||
throw IllegalArgumentException("Color parameter outside of expected range - Luminance")
|
|
||||||
}
|
|
||||||
if (alpha !in 0.0f..1.0f) {
|
|
||||||
throw IllegalArgumentException("Color parameter outside of expected range - Alpha")
|
|
||||||
}
|
|
||||||
|
|
||||||
h %= 360.0f
|
|
||||||
h /= 360f
|
|
||||||
s /= 100f
|
|
||||||
l /= 100f
|
|
||||||
|
|
||||||
val q = if (l < 0.5) {
|
|
||||||
l * (1 + s)
|
|
||||||
} else {
|
|
||||||
(l + s) - s * l
|
|
||||||
}
|
|
||||||
val p = 2 * l - q
|
|
||||||
val r = round(max(0f, hueToRgb(p, q, h + 1.0f / 3.0f)) * 256).toInt()
|
|
||||||
val g = round(max(0f, hueToRgb(p, q, h)) * 256).toInt()
|
|
||||||
val b = round(max(0f, hueToRgb(p, q, h - 1.0f / 3.0f)) * 256).toInt()
|
|
||||||
return intArrayOf(r, g, b)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun hueToRgb(p: Float, q: Float, hParam: Float): Float {
|
|
||||||
var h = hParam
|
|
||||||
if (h < 0) h += 1f
|
|
||||||
if (h > 1) h -= 1f
|
|
||||||
if (6 * h < 1) return p + (q - p) * 6 * h
|
|
||||||
if (2 * h < 1) return q
|
|
||||||
if (3 * h < 2) return p + (q - p) * 6 * (2.0f / 3.0f - h)
|
|
||||||
return p
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun rgbToHsl(rUntrimmed: Double, gUntrimmed: Double, bUntrimmed: Double): DoubleArray {
|
|
||||||
val r = rUntrimmed / 255
|
|
||||||
val g = gUntrimmed / 255
|
|
||||||
val b = bUntrimmed / 255
|
|
||||||
val max = max(r, max(g, b))
|
|
||||||
val min = r.coerceAtMost(g.coerceAtMost(b))
|
|
||||||
var h = (max + min) / 2
|
|
||||||
val s: Double
|
|
||||||
val l = (max + min) / 2
|
|
||||||
if (max == min) {
|
|
||||||
s = 0.0
|
|
||||||
h = s // achromatic
|
|
||||||
} else {
|
|
||||||
val d = max - min
|
|
||||||
s = if (l > 0.5) d / (2 - max - min) else d / (max + min)
|
|
||||||
when (max) {
|
|
||||||
r -> {
|
|
||||||
h = (g - b) / d + (if (g < b) 6 else 0)
|
|
||||||
}
|
|
||||||
g -> {
|
|
||||||
h = (b - r) / d + 2
|
|
||||||
}
|
|
||||||
b -> {
|
|
||||||
h = (r - g) / d + 4
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
h /= 6.0
|
|
||||||
}
|
}
|
||||||
val hsl = DoubleArray(3)
|
h /= 6.0
|
||||||
hsl[INDEX_HUE] = h
|
|
||||||
hsl[INDEX_SATURATION] = s
|
|
||||||
hsl[INDEX_LUMINATION] = l
|
|
||||||
return hsl
|
|
||||||
}
|
}
|
||||||
|
val hsl = DoubleArray(3)
|
||||||
|
hsl[INDEX_HUE] = h
|
||||||
|
hsl[INDEX_SATURATION] = s
|
||||||
|
hsl[INDEX_LUMINATION] = l
|
||||||
|
return hsl
|
||||||
|
}
|
||||||
|
|
||||||
@Throws(NoSuchAlgorithmException::class)
|
@Throws(NoSuchAlgorithmException::class)
|
||||||
private fun md5(string: String): String {
|
private fun md5(string: String): String {
|
||||||
val md5 = MessageDigest.getInstance("MD5").digest(string.toByteArray())
|
val md5 = MessageDigest.getInstance("MD5").digest(string.toByteArray())
|
||||||
return md5.joinToString("") { "%02x".format(it) }
|
return md5.joinToString("") { "%02x".format(it) }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import androidx.appcompat.app.AppCompatActivity
|
|||||||
import net.helcel.cowspent.theme.ThemeUtils
|
import net.helcel.cowspent.theme.ThemeUtils
|
||||||
|
|
||||||
class LabelManagementActivity : AppCompatActivity() {
|
class LabelManagementActivity : AppCompatActivity() {
|
||||||
private val viewModel: LabelManagementViewModel by viewModels()
|
internal val viewModel: LabelManagementViewModel by viewModels()
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
enableEdgeToEdge()
|
enableEdgeToEdge()
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package net.helcel.cowspent.android.label
|
|||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.ui.window.Dialog
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
import androidx.compose.foundation.rememberScrollState
|
import androidx.compose.foundation.rememberScrollState
|
||||||
@@ -28,6 +29,7 @@ import androidx.core.graphics.toColorInt
|
|||||||
import net.helcel.cowspent.R
|
import net.helcel.cowspent.R
|
||||||
import net.helcel.cowspent.android.helper.ColorPicker
|
import net.helcel.cowspent.android.helper.ColorPicker
|
||||||
import net.helcel.cowspent.android.helper.StatefulAlertDialog
|
import net.helcel.cowspent.android.helper.StatefulAlertDialog
|
||||||
|
import net.helcel.cowspent.model.DBBill
|
||||||
import net.helcel.cowspent.model.DBCategory
|
import net.helcel.cowspent.model.DBCategory
|
||||||
import net.helcel.cowspent.model.DBPaymentMode
|
import net.helcel.cowspent.model.DBPaymentMode
|
||||||
|
|
||||||
@@ -59,10 +61,10 @@ fun LabelManagementScreenContent(
|
|||||||
dialogState: net.helcel.cowspent.android.helper.DialogState?,
|
dialogState: net.helcel.cowspent.android.helper.DialogState?,
|
||||||
onBack: () -> Unit,
|
onBack: () -> Unit,
|
||||||
onAddCategory: (String, String, String) -> Unit,
|
onAddCategory: (String, String, String) -> Unit,
|
||||||
onUpdateCategory: (Long, String, String, String) -> Unit,
|
onUpdateCategory: (DBCategory, String, String, String) -> Unit,
|
||||||
onDeleteCategory: (Long) -> Unit,
|
onDeleteCategory: (Long) -> Unit,
|
||||||
onAddPaymentMode: (String, String, String) -> Unit,
|
onAddPaymentMode: (String, String, String) -> Unit,
|
||||||
onUpdatePaymentMode: (Long, String, String, String) -> Unit,
|
onUpdatePaymentMode: (DBPaymentMode, String, String, String) -> Unit,
|
||||||
onDeletePaymentMode: (Long) -> Unit,
|
onDeletePaymentMode: (Long) -> Unit,
|
||||||
onDismissDialog: () -> Unit,
|
onDismissDialog: () -> Unit,
|
||||||
onShowDialog: (net.helcel.cowspent.android.helper.DialogState) -> Unit,
|
onShowDialog: (net.helcel.cowspent.android.helper.DialogState) -> Unit,
|
||||||
@@ -89,7 +91,7 @@ fun LabelManagementScreenContent(
|
|||||||
title = { Text(stringResource(R.string.title_labels)) },
|
title = { Text(stringResource(R.string.title_labels)) },
|
||||||
navigationIcon = {
|
navigationIcon = {
|
||||||
IconButton(onClick = onBack) {
|
IconButton(onClick = onBack) {
|
||||||
Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null)
|
Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = stringResource(R.string.simple_back))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
backgroundColor = MaterialTheme.colors.primary,
|
backgroundColor = MaterialTheme.colors.primary,
|
||||||
@@ -106,7 +108,7 @@ fun LabelManagementScreenContent(
|
|||||||
showEditDialog = true
|
showEditDialog = true
|
||||||
}
|
}
|
||||||
}) {
|
}) {
|
||||||
Icon(Icons.Default.Add, contentDescription = null)
|
Icon(Icons.Default.Add, contentDescription = "Add Label")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
) { padding ->
|
) { padding ->
|
||||||
@@ -123,7 +125,7 @@ fun LabelManagementScreenContent(
|
|||||||
|
|
||||||
if (selectedTab == 0) {
|
if (selectedTab == 0) {
|
||||||
CategoryList(
|
CategoryList(
|
||||||
categories = categories,
|
categories = categories.filter { it.remoteId != DBBill.CATEGORY_REIMBURSEMENT },
|
||||||
onEdit = {
|
onEdit = {
|
||||||
editingCategory = it
|
editingCategory = it
|
||||||
showEditDialog = true
|
showEditDialog = true
|
||||||
@@ -162,7 +164,7 @@ fun LabelManagementScreenContent(
|
|||||||
if (showEditDialog) {
|
if (showEditDialog) {
|
||||||
if (selectedTab == 0) {
|
if (selectedTab == 0) {
|
||||||
EditLabelDialog(
|
EditLabelDialog(
|
||||||
title = if (editingCategory == null) stringResource(R.string.action_add_project) else stringResource(R.string.action_edit),
|
title = if (editingCategory == null) stringResource(R.string.title_add_category) else stringResource(R.string.action_edit),
|
||||||
initialName = editingCategory?.name ?: "",
|
initialName = editingCategory?.name ?: "",
|
||||||
initialIcon = editingCategory?.icon ?: "",
|
initialIcon = editingCategory?.icon ?: "",
|
||||||
initialColor = editingCategory?.color ?: "#FF0000",
|
initialColor = editingCategory?.color ?: "#FF0000",
|
||||||
@@ -171,14 +173,14 @@ fun LabelManagementScreenContent(
|
|||||||
if (editingCategory == null) {
|
if (editingCategory == null) {
|
||||||
onAddCategory(name, icon, color)
|
onAddCategory(name, icon, color)
|
||||||
} else {
|
} else {
|
||||||
onUpdateCategory(editingCategory!!.id, name, icon, color)
|
onUpdateCategory(editingCategory!!, name, icon, color)
|
||||||
}
|
}
|
||||||
showEditDialog = false
|
showEditDialog = false
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
EditLabelDialog(
|
EditLabelDialog(
|
||||||
title = if (editingPaymentMode == null) stringResource(R.string.action_add_project) else stringResource(R.string.action_edit),
|
title = if (editingPaymentMode == null) stringResource(R.string.title_add_payment_mode) else stringResource(R.string.action_edit),
|
||||||
initialName = editingPaymentMode?.name ?: "",
|
initialName = editingPaymentMode?.name ?: "",
|
||||||
initialIcon = editingPaymentMode?.icon ?: "",
|
initialIcon = editingPaymentMode?.icon ?: "",
|
||||||
initialColor = editingPaymentMode?.color ?: "#00FF00",
|
initialColor = editingPaymentMode?.color ?: "#00FF00",
|
||||||
@@ -187,7 +189,7 @@ fun LabelManagementScreenContent(
|
|||||||
if (editingPaymentMode == null) {
|
if (editingPaymentMode == null) {
|
||||||
onAddPaymentMode(name, icon, color)
|
onAddPaymentMode(name, icon, color)
|
||||||
} else {
|
} else {
|
||||||
onUpdatePaymentMode(editingPaymentMode!!.id, name, icon, color)
|
onUpdatePaymentMode(editingPaymentMode!!, name, icon, color)
|
||||||
}
|
}
|
||||||
showEditDialog = false
|
showEditDialog = false
|
||||||
}
|
}
|
||||||
@@ -266,14 +268,22 @@ fun LabelItem(
|
|||||||
Spacer(modifier = Modifier.width(32.dp))
|
Spacer(modifier = Modifier.width(32.dp))
|
||||||
Text(text = name, modifier = Modifier.weight(1f), style = MaterialTheme.typography.subtitle1)
|
Text(text = name, modifier = Modifier.weight(1f), style = MaterialTheme.typography.subtitle1)
|
||||||
IconButton(onClick = onEdit) {
|
IconButton(onClick = onEdit) {
|
||||||
Icon(Icons.Default.Edit, contentDescription = null, tint = MaterialTheme.colors.onSurface.copy(alpha = 0.6f))
|
Icon(Icons.Default.Edit, contentDescription = stringResource(R.string.action_edit), tint = MaterialTheme.colors.onSurface.copy(alpha = 0.6f))
|
||||||
}
|
}
|
||||||
IconButton(onClick = onDelete) {
|
IconButton(onClick = onDelete) {
|
||||||
Icon(Icons.Default.Delete, contentDescription = null, tint = MaterialTheme.colors.error.copy(alpha = 0.6f))
|
Icon(Icons.Default.Delete, contentDescription = stringResource(R.string.action_delete), tint = MaterialTheme.colors.error.copy(alpha = 0.6f))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Split into a window and its content, the same way MemberEditDialogContent is.
|
||||||
|
*
|
||||||
|
* A Compose text field inside a Material AlertDialog never reaches idle under Robolectric: the
|
||||||
|
* composition spins in measure/layout until Espresso gives up 60s later, having exhausted the
|
||||||
|
* test heap and taken every later test class in that worker with it. A plain Dialog holding a
|
||||||
|
* Surface behaves, so the dialog body lives there instead - which is also what makes it testable.
|
||||||
|
*/
|
||||||
@Composable
|
@Composable
|
||||||
fun EditLabelDialog(
|
fun EditLabelDialog(
|
||||||
title: String,
|
title: String,
|
||||||
@@ -282,15 +292,33 @@ fun EditLabelDialog(
|
|||||||
initialColor: String,
|
initialColor: String,
|
||||||
onDismiss: () -> Unit,
|
onDismiss: () -> Unit,
|
||||||
onSave: (String, String, String) -> Unit
|
onSave: (String, String, String) -> Unit
|
||||||
|
) {
|
||||||
|
Dialog(onDismissRequest = onDismiss) {
|
||||||
|
EditLabelDialogContent(title, initialName, initialIcon, initialColor, onDismiss, onSave)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun EditLabelDialogContent(
|
||||||
|
title: String,
|
||||||
|
initialName: String,
|
||||||
|
initialIcon: String,
|
||||||
|
initialColor: String,
|
||||||
|
onDismiss: () -> Unit,
|
||||||
|
onSave: (String, String, String) -> Unit
|
||||||
) {
|
) {
|
||||||
var name by remember { mutableStateOf(initialName) }
|
var name by remember { mutableStateOf(initialName) }
|
||||||
var icon by remember { mutableStateOf(initialIcon) }
|
var icon by remember { mutableStateOf(initialIcon) }
|
||||||
var color by remember { mutableStateOf(initialColor) }
|
var color by remember { mutableStateOf(initialColor) }
|
||||||
|
|
||||||
AlertDialog(
|
Surface(
|
||||||
onDismissRequest = onDismiss,
|
shape = MaterialTheme.shapes.medium,
|
||||||
title = { Text(title) },
|
color = MaterialTheme.colors.surface,
|
||||||
text = {
|
contentColor = contentColorFor(MaterialTheme.colors.surface)
|
||||||
|
) {
|
||||||
|
Column(modifier = Modifier.padding(24.dp)) {
|
||||||
|
Text(title, style = MaterialTheme.typography.h6)
|
||||||
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
Column(modifier = Modifier.verticalScroll(rememberScrollState())) {
|
Column(modifier = Modifier.verticalScroll(rememberScrollState())) {
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
value = name,
|
value = name,
|
||||||
@@ -314,21 +342,25 @@ fun EditLabelDialog(
|
|||||||
onColorChanged = { color = String.format("#%06X", 0xFFFFFF and it) }
|
onColorChanged = { color = String.format("#%06X", 0xFFFFFF and it) }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
confirmButton = {
|
Row(
|
||||||
Button(
|
modifier = Modifier.fillMaxWidth(),
|
||||||
onClick = { onSave(name, icon, color) },
|
horizontalArrangement = Arrangement.End,
|
||||||
enabled = name.isNotBlank()
|
verticalAlignment = Alignment.CenterVertically
|
||||||
) {
|
) {
|
||||||
Text(stringResource(R.string.action_save))
|
TextButton(onClick = onDismiss) {
|
||||||
}
|
Text(stringResource(R.string.simple_cancel))
|
||||||
},
|
}
|
||||||
dismissButton = {
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
TextButton(onClick = onDismiss) {
|
Button(
|
||||||
Text(stringResource(R.string.simple_cancel))
|
onClick = { onSave(name, icon, color) },
|
||||||
|
enabled = name.isNotBlank()
|
||||||
|
) {
|
||||||
|
Text(stringResource(R.string.action_save))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun parseColor(colorString: String): Color {
|
fun parseColor(colorString: String): Color {
|
||||||
@@ -353,8 +385,8 @@ fun LabelManagementCategoriesPreview() {
|
|||||||
MaterialTheme {
|
MaterialTheme {
|
||||||
LabelManagementScreenContent(
|
LabelManagementScreenContent(
|
||||||
categories = listOf(
|
categories = listOf(
|
||||||
DBCategory(1, 1, 1, "Groceries", "🛒", "#FF0000"),
|
DBCategory(1L, 1L, 1L, "Groceries", "🛒", "#FF0000"),
|
||||||
DBCategory(2, 2, 1, "Rent", "🏠", "#00FF00")
|
DBCategory(2L, 2L, 1L, "Rent", "🏠", "#00FF00")
|
||||||
),
|
),
|
||||||
paymentModes = emptyList(),
|
paymentModes = emptyList(),
|
||||||
dialogState = null,
|
dialogState = null,
|
||||||
@@ -379,8 +411,8 @@ fun LabelManagementPaymentModesPreview() {
|
|||||||
LabelManagementScreenContent(
|
LabelManagementScreenContent(
|
||||||
categories = emptyList(),
|
categories = emptyList(),
|
||||||
paymentModes = listOf(
|
paymentModes = listOf(
|
||||||
DBPaymentMode(1, 1, 1, "Cash", "💵", "#0000FF"),
|
DBPaymentMode(1L, 1L, 1L, "Cash", "💵", "#0000FF"),
|
||||||
DBPaymentMode(2, 2, 1, "Credit Card", "💳", "#FFFF00")
|
DBPaymentMode(2L, 2L, 1L, "Credit Card", "💳", "#FFFF00")
|
||||||
),
|
),
|
||||||
dialogState = null,
|
dialogState = null,
|
||||||
onBack = {},
|
onBack = {},
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ import kotlinx.coroutines.withContext
|
|||||||
import net.helcel.cowspent.android.helper.DialogState
|
import net.helcel.cowspent.android.helper.DialogState
|
||||||
import net.helcel.cowspent.model.DBCategory
|
import net.helcel.cowspent.model.DBCategory
|
||||||
import net.helcel.cowspent.model.DBPaymentMode
|
import net.helcel.cowspent.model.DBPaymentMode
|
||||||
|
import net.helcel.cowspent.model.DBBill
|
||||||
import net.helcel.cowspent.persistence.CowspentSQLiteOpenHelper
|
import net.helcel.cowspent.persistence.CowspentSQLiteOpenHelper
|
||||||
import net.helcel.cowspent.util.CategoryUtils
|
|
||||||
|
|
||||||
class LabelManagementViewModel(application: Application) : AndroidViewModel(application) {
|
class LabelManagementViewModel(application: Application) : AndroidViewModel(application) {
|
||||||
private val db = CowspentSQLiteOpenHelper.getInstance(application)
|
private val db = CowspentSQLiteOpenHelper.getInstance(application)
|
||||||
@@ -28,44 +28,30 @@ class LabelManagementViewModel(application: Application) : AndroidViewModel(appl
|
|||||||
fun loadLabels(projId: Long) {
|
fun loadLabels(projId: Long) {
|
||||||
projectId = projId
|
projectId = projId
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
val cats = withContext(Dispatchers.IO) { db.getCategories(projId) }
|
val project = withContext(Dispatchers.IO) { db.getProject(projId) }
|
||||||
val pms = withContext(Dispatchers.IO) { db.getPaymentModes(projId) }
|
if (project != null) {
|
||||||
|
|
||||||
if (cats.isEmpty()) {
|
|
||||||
val defaults = CategoryUtils.getDefaultCategories(getApplication(), projId)
|
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
defaults.forEach { db.addCategory(it) }
|
db.ensureDefaultLabels(projId, project.type)
|
||||||
}
|
}
|
||||||
categories = withContext(Dispatchers.IO) { db.getCategories(projId) }
|
|
||||||
} else {
|
|
||||||
categories = cats
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pms.isEmpty()) {
|
|
||||||
val defaults = CategoryUtils.getDefaultPaymentModes(getApplication(), projId)
|
|
||||||
withContext(Dispatchers.IO) {
|
|
||||||
defaults.forEach { db.addPaymentMode(it) }
|
|
||||||
}
|
|
||||||
paymentModes = withContext(Dispatchers.IO) { db.getPaymentModes(projId) }
|
|
||||||
} else {
|
|
||||||
paymentModes = pms
|
|
||||||
}
|
}
|
||||||
|
categories = withContext(Dispatchers.IO) { db.getCategories(projId) }
|
||||||
|
paymentModes = withContext(Dispatchers.IO) { db.getPaymentModes(projId) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addCategory(name: String, icon: String, color: String) {
|
fun addCategory(name: String, icon: String, color: String) {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
db.addCategory(DBCategory(0, 0, projectId, name, icon, color))
|
db.addCategoryAndSync(DBCategory(0, 0, projectId, name, icon, color, DBBill.STATE_ADDED))
|
||||||
}
|
}
|
||||||
loadLabels(projectId)
|
loadLabels(projectId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateCategory(id: Long, name: String, icon: String, color: String) {
|
fun updateCategory(cat: DBCategory, name: String, icon: String, color: String) {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
db.updateCategory(id, name, icon, color)
|
db.updateCategoryAndSync(cat, name, icon, color)
|
||||||
}
|
}
|
||||||
loadLabels(projectId)
|
loadLabels(projectId)
|
||||||
}
|
}
|
||||||
@@ -74,7 +60,7 @@ class LabelManagementViewModel(application: Application) : AndroidViewModel(appl
|
|||||||
fun deleteCategory(id: Long) {
|
fun deleteCategory(id: Long) {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
db.deleteCategory(id)
|
db.deleteCategoryAndSync(id)
|
||||||
}
|
}
|
||||||
loadLabels(projectId)
|
loadLabels(projectId)
|
||||||
}
|
}
|
||||||
@@ -83,16 +69,16 @@ class LabelManagementViewModel(application: Application) : AndroidViewModel(appl
|
|||||||
fun addPaymentMode(name: String, icon: String, color: String) {
|
fun addPaymentMode(name: String, icon: String, color: String) {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
db.addPaymentMode(DBPaymentMode(0, 0, projectId, name, icon, color))
|
db.addPaymentModeAndSync(DBPaymentMode(0, 0, projectId, name, icon, color, DBBill.STATE_ADDED))
|
||||||
}
|
}
|
||||||
loadLabels(projectId)
|
loadLabels(projectId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updatePaymentMode(id: Long, name: String, icon: String, color: String) {
|
fun updatePaymentMode(pm: DBPaymentMode, name: String, icon: String, color: String) {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
db.updatePaymentMode(id, name, icon, color)
|
db.updatePaymentModeAndSync(pm, name, icon, color)
|
||||||
}
|
}
|
||||||
loadLabels(projectId)
|
loadLabels(projectId)
|
||||||
}
|
}
|
||||||
@@ -101,7 +87,7 @@ class LabelManagementViewModel(application: Application) : AndroidViewModel(appl
|
|||||||
fun deletePaymentMode(id: Long) {
|
fun deletePaymentMode(id: Long) {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
db.deletePaymentMode(id)
|
db.deletePaymentModeAndSync(id)
|
||||||
}
|
}
|
||||||
loadLabels(projectId)
|
loadLabels(projectId)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,8 +4,10 @@ import android.annotation.SuppressLint
|
|||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
@@ -103,6 +105,10 @@ fun BillsListScreen(
|
|||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val sharedPreferences = remember { PreferenceManager.getDefaultSharedPreferences(context) }
|
val sharedPreferences = remember { PreferenceManager.getDefaultSharedPreferences(context) }
|
||||||
val showArchived = sharedPreferences.getBoolean(stringResource(R.string.pref_key_show_archived), false)
|
val showArchived = sharedPreferences.getBoolean(stringResource(R.string.pref_key_show_archived), false)
|
||||||
|
val keyBetaFeatures = stringResource(R.string.pref_key_beta_features)
|
||||||
|
var showBetaFeatures by remember(keyBetaFeatures) {
|
||||||
|
mutableStateOf(sharedPreferences.getBoolean(keyBetaFeatures, false))
|
||||||
|
}
|
||||||
|
|
||||||
StatefulAlertDialog(
|
StatefulAlertDialog(
|
||||||
state = viewModel.dialogState,
|
state = viewModel.dialogState,
|
||||||
@@ -158,7 +164,8 @@ fun BillsListScreen(
|
|||||||
isArchived = proj?.isArchived == true,
|
isArchived = proj?.isArchived == true,
|
||||||
projectType = proj?.type ?: ProjectType.LOCAL,
|
projectType = proj?.type ?: ProjectType.LOCAL,
|
||||||
accessLevel = proj?.myAccessLevel ?: DBProject.ACCESS_LEVEL_ADMIN,
|
accessLevel = proj?.myAccessLevel ?: DBProject.ACCESS_LEVEL_ADMIN,
|
||||||
isShareable = proj?.isShareable() ?: true
|
isShareable = proj?.isShareable() ?: true,
|
||||||
|
showBetaFeatures = showBetaFeatures
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -286,7 +293,7 @@ fun BillsListScreen(
|
|||||||
isSearchExpanded = false
|
isSearchExpanded = false
|
||||||
viewModel.searchQuery = ""
|
viewModel.searchQuery = ""
|
||||||
}) {
|
}) {
|
||||||
Icon(Icons.Default.Close, contentDescription = null, tint = MaterialTheme.colors.onPrimary)
|
Icon(Icons.Default.Close, contentDescription = stringResource(R.string.action_clear_search), tint = MaterialTheme.colors.onPrimary)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -315,19 +322,19 @@ fun BillsListScreen(
|
|||||||
isSearchExpanded = false
|
isSearchExpanded = false
|
||||||
viewModel.searchQuery = ""
|
viewModel.searchQuery = ""
|
||||||
}) {
|
}) {
|
||||||
Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null)
|
Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = stringResource(R.string.action_close_search))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
IconButton(onClick = {
|
IconButton(onClick = {
|
||||||
scope.launch { scaffoldState.drawerState.open() }
|
scope.launch { scaffoldState.drawerState.open() }
|
||||||
}) {
|
}) {
|
||||||
Icon(Icons.Default.Menu, contentDescription = null)
|
Icon(Icons.Default.Menu, contentDescription = stringResource(R.string.action_open_menu))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
actions = {
|
actions = {
|
||||||
if (!isSearchExpanded) {
|
if (!isSearchExpanded) {
|
||||||
if (viewModel.hasUnlabeledBills) {
|
if (showBetaFeatures && viewModel.hasUnlabeledBills) {
|
||||||
IconButton(onClick = onLabelBillsClick) {
|
IconButton(onClick = onLabelBillsClick) {
|
||||||
Icon(
|
Icon(
|
||||||
Icons.Default.Category,
|
Icons.Default.Category,
|
||||||
@@ -336,7 +343,10 @@ fun BillsListScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
IconButton(onClick = { isSearchExpanded = true }) {
|
IconButton(onClick = { isSearchExpanded = true }) {
|
||||||
Icon(Icons.Default.Search, contentDescription = null)
|
Icon(
|
||||||
|
Icons.Default.Search,
|
||||||
|
contentDescription = stringResource(R.string.action_search)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -412,6 +422,9 @@ fun BillsListScreen(
|
|||||||
is SectionItem -> SectionHeader(item.title)
|
is SectionItem -> SectionHeader(item.title)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
item {
|
||||||
|
Spacer(modifier = Modifier.height(64.dp).fillMaxWidth())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import android.content.Intent
|
|||||||
import net.helcel.cowspent.R
|
import net.helcel.cowspent.R
|
||||||
import net.helcel.cowspent.model.*
|
import net.helcel.cowspent.model.*
|
||||||
import net.helcel.cowspent.persistence.CowspentSQLiteOpenHelper
|
import net.helcel.cowspent.persistence.CowspentSQLiteOpenHelper
|
||||||
|
import net.helcel.cowspent.util.CategoryUtils
|
||||||
import net.helcel.cowspent.util.IRefreshBillsListCallback
|
import net.helcel.cowspent.util.IRefreshBillsListCallback
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@@ -87,6 +88,7 @@ object BillsListUtils {
|
|||||||
shareIntent,
|
shareIntent,
|
||||||
context.getString(R.string.title_settle)
|
context.getString(R.string.title_settle)
|
||||||
)
|
)
|
||||||
|
chooserIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||||
context.startActivity(chooserIntent)
|
context.startActivity(chooserIntent)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,6 +100,10 @@ object BillsListUtils {
|
|||||||
context: Context
|
context: Context
|
||||||
) {
|
) {
|
||||||
val timestamp = System.currentTimeMillis() / 1000
|
val timestamp = System.currentTimeMillis() / 1000
|
||||||
|
val proj = db.getProject(projectId)
|
||||||
|
val categories = db.getCategories(projectId)
|
||||||
|
val reimbursementCategoryId = CategoryUtils.getReimbursementCategoryId(categories, projectId, proj?.remoteId)
|
||||||
|
|
||||||
for (t in transactions) {
|
for (t in transactions) {
|
||||||
val owerId = t.owerMemberId
|
val owerId = t.owerMemberId
|
||||||
val receiverId = t.receiverMemberId
|
val receiverId = t.receiverMemberId
|
||||||
@@ -106,7 +112,7 @@ object BillsListUtils {
|
|||||||
0, 0, projectId, owerId, amount,
|
0, 0, projectId, owerId, amount,
|
||||||
timestamp, context.getString(R.string.settle_bill_what),
|
timestamp, context.getString(R.string.settle_bill_what),
|
||||||
DBBill.STATE_ADDED, DBBill.NON_REPEATED,
|
DBBill.STATE_ADDED, DBBill.NON_REPEATED,
|
||||||
DBBill.PAYMODE_NONE, DBBill.CATEGORY_NONE,
|
DBBill.PAYMODE_NONE, reimbursementCategoryId,
|
||||||
"", DBBill.PAYMODE_ID_NONE
|
"", DBBill.PAYMODE_ID_NONE
|
||||||
)
|
)
|
||||||
bill.billOwers += DBBillOwer(0, 0, receiverId)
|
bill.billOwers += DBBillOwer(0, 0, receiverId)
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import android.app.SearchManager
|
|||||||
import android.content.BroadcastReceiver
|
import android.content.BroadcastReceiver
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.content.SharedPreferences
|
||||||
import android.content.IntentFilter
|
import android.content.IntentFilter
|
||||||
import android.graphics.BitmapFactory
|
import android.graphics.BitmapFactory
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
@@ -18,12 +19,11 @@ import androidx.activity.compose.setContent
|
|||||||
import androidx.activity.enableEdgeToEdge
|
import androidx.activity.enableEdgeToEdge
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.activity.viewModels
|
import androidx.activity.viewModels
|
||||||
|
import androidx.annotation.VisibleForTesting
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.appcompat.view.ActionMode
|
import androidx.appcompat.view.ActionMode
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.AddCircleOutline
|
|
||||||
import androidx.compose.material.icons.filled.Sync
|
import androidx.compose.material.icons.filled.Sync
|
||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.content.edit
|
import androidx.core.content.edit
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
@@ -50,11 +50,14 @@ import net.helcel.cowspent.persistence.CowspentSQLiteOpenHelper
|
|||||||
import net.helcel.cowspent.persistence.CowspentServerSyncHelper
|
import net.helcel.cowspent.persistence.CowspentServerSyncHelper
|
||||||
import net.helcel.cowspent.theme.ThemeUtils
|
import net.helcel.cowspent.theme.ThemeUtils
|
||||||
import net.helcel.cowspent.util.BillFormatter
|
import net.helcel.cowspent.util.BillFormatter
|
||||||
|
import net.helcel.cowspent.util.CategoryUtils
|
||||||
import net.helcel.cowspent.util.CospendClientUtil
|
import net.helcel.cowspent.util.CospendClientUtil
|
||||||
import net.helcel.cowspent.util.ExportUtil
|
import net.helcel.cowspent.util.ExportUtil
|
||||||
import net.helcel.cowspent.util.ICallback
|
import net.helcel.cowspent.util.ICallback
|
||||||
import net.helcel.cowspent.util.IRefreshBillsListCallback
|
import net.helcel.cowspent.util.IRefreshBillsListCallback
|
||||||
|
import net.helcel.cowspent.util.SyncSettings
|
||||||
import net.helcel.cowspent.util.SupportUtil
|
import net.helcel.cowspent.util.SupportUtil
|
||||||
|
import net.helcel.cowspent.util.VersatileProjectSyncClient
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.Calendar
|
import java.util.Calendar
|
||||||
@@ -64,13 +67,16 @@ class BillsListViewActivity :
|
|||||||
AppCompatActivity(),
|
AppCompatActivity(),
|
||||||
IRefreshBillsListCallback {
|
IRefreshBillsListCallback {
|
||||||
|
|
||||||
private val viewModel: BillsListViewModel by viewModels()
|
internal val viewModel: BillsListViewModel by viewModels()
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
var DEBUG = false
|
var DEBUG = false
|
||||||
|
|
||||||
private val TAG = BillsListViewActivity::class.java.simpleName
|
private val TAG = BillsListViewActivity::class.java.simpleName
|
||||||
|
|
||||||
|
// Opening a project only re-syncs it if it has not synced within this window.
|
||||||
|
private const val SELECTED_PROJECT_SYNC_INTERVAL_MS = 60 * 1000L
|
||||||
|
|
||||||
private const val SAVED_STATE_NAVIGATION_SELECTION = "navigationSelection"
|
private const val SAVED_STATE_NAVIGATION_SELECTION = "navigationSelection"
|
||||||
private const val SAVED_STATE_NAVIGATION_OPEN = "navigationOpen"
|
private const val SAVED_STATE_NAVIGATION_OPEN = "navigationOpen"
|
||||||
|
|
||||||
@@ -277,7 +283,7 @@ class BillsListViewActivity :
|
|||||||
labelBillsLauncher.launch(LabelBillsActivity.createIntent(this, selectedProjectId))
|
labelBillsLauncher.launch(LabelBillsActivity.createIntent(this, selectedProjectId))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onRefresh = { synchronize(true) }
|
onRefresh = { synchronize(SyncTrigger.MANUAL) }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -331,10 +337,7 @@ class BillsListViewActivity :
|
|||||||
}
|
}
|
||||||
viewModel.isRefreshing = false
|
viewModel.isRefreshing = false
|
||||||
|
|
||||||
if (db.cowspentServerSyncHelper.isSyncPossible) {
|
synchronize(SyncTrigger.APP_OPEN)
|
||||||
db.cowspentServerSyncHelper.addCallbackPull(syncCallBack)
|
|
||||||
synchronize()
|
|
||||||
}
|
|
||||||
|
|
||||||
registerBroadcastReceiver()
|
registerBroadcastReceiver()
|
||||||
updateAvatarInDrawer(CowspentServerSyncHelper.isNextcloudAccountConfigured(this))
|
updateAvatarInDrawer(CowspentServerSyncHelper.isNextcloudAccountConfigured(this))
|
||||||
@@ -348,6 +351,9 @@ class BillsListViewActivity :
|
|||||||
} catch (_: RuntimeException) {
|
} catch (_: RuntimeException) {
|
||||||
if (DEBUG) Log.d(TAG, "RECEIVER PROBLEM, let's ignore it...")
|
if (DEBUG) Log.d(TAG, "RECEIVER PROBLEM, let's ignore it...")
|
||||||
}
|
}
|
||||||
|
// The helper outlives the activity, and it only drains its pull callbacks when a task
|
||||||
|
// starts; drop ours so a paused activity is not retained by it.
|
||||||
|
db.cowspentServerSyncHelper.removeCallbackPull(syncCallBack)
|
||||||
isActivityVisible = false
|
isActivityVisible = false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -374,7 +380,7 @@ class BillsListViewActivity :
|
|||||||
navigationSelection = Category(null, null)
|
navigationSelection = Category(null, null)
|
||||||
refreshLists(true)
|
refreshLists(true)
|
||||||
|
|
||||||
synchronize()
|
synchronize(SyncTrigger.PROJECT_OPEN)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onManageProjectClick(projectId: Long) {
|
fun onManageProjectClick(projectId: Long) {
|
||||||
@@ -402,12 +408,14 @@ class BillsListViewActivity :
|
|||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
db.deleteProject(projectId)
|
db.deleteProject(projectId)
|
||||||
|
PreferenceManager.getDefaultSharedPreferences(applicationContext)
|
||||||
|
.edit { remove(lastProjectSyncKey(projectId)) }
|
||||||
val dbProjects = db.projects
|
val dbProjects = db.projects
|
||||||
if (dbProjects.isNotEmpty()) setSelectedProject(dbProjects[0].id) else setSelectedProject(0)
|
if (dbProjects.isNotEmpty()) setSelectedProject(dbProjects[0].id) else setSelectedProject(0)
|
||||||
}
|
}
|
||||||
setupDrawerProjects()
|
setupDrawerProjects()
|
||||||
refreshLists()
|
refreshLists()
|
||||||
synchronize()
|
synchronize(SyncTrigger.PROJECT_OPEN)
|
||||||
val projectNameString = proj.name.ifEmpty { proj.remoteId }
|
val projectNameString = proj.name.ifEmpty { proj.remoteId }
|
||||||
showToast(this@BillsListViewActivity, getString(R.string.remove_project_confirmation, projectNameString))
|
showToast(this@BillsListViewActivity, getString(R.string.remove_project_confirmation, projectNameString))
|
||||||
}
|
}
|
||||||
@@ -422,22 +430,34 @@ class BillsListViewActivity :
|
|||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
val proj = withContext(Dispatchers.IO) { db.getProject(projectId) } ?: return@launch
|
val proj = withContext(Dispatchers.IO) { db.getProject(projectId) } ?: return@launch
|
||||||
val isArchiving = !proj.isArchived
|
val isArchiving = !proj.isArchived
|
||||||
|
|
||||||
val newArchivedTs = if (isArchiving) System.currentTimeMillis() / 1000 else 0L
|
val localArchivedTs = if (isArchiving) System.currentTimeMillis() / 1000 else 0L
|
||||||
|
val remoteArchivedTs = if (isArchiving) {
|
||||||
|
localArchivedTs
|
||||||
|
} else {
|
||||||
|
VersatileProjectSyncClient.REMOTE_ARCHIVED_TS_UNSET
|
||||||
|
}
|
||||||
|
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
db.updateProject(
|
db.updateProject(
|
||||||
projId = projectId,
|
projId = projectId,
|
||||||
newName = null,
|
newArchivedTs = localArchivedTs
|
||||||
newEmail = null,
|
)
|
||||||
newPassword = null,
|
}
|
||||||
newLastPayerId = null,
|
|
||||||
newLastSyncedTimestamp = null,
|
if (!proj.isLocal) {
|
||||||
newCurrencyName = null,
|
db.cowspentServerSyncHelper.editRemoteProject(
|
||||||
newDeletionDisabled = null,
|
projId = projectId,
|
||||||
newMyAccessLevel = null,
|
newArchivedTs = remoteArchivedTs,
|
||||||
newBearerToken = null,
|
callback = object : ICallback {
|
||||||
newArchivedTs = newArchivedTs
|
override fun onFinish() {}
|
||||||
|
override fun onFinish(result: String, message: String) {
|
||||||
|
if (message.isNotEmpty()) {
|
||||||
|
showToast(this@BillsListViewActivity, getString(R.string.error_sync, message))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
override fun onScheduled() {}
|
||||||
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -555,11 +575,13 @@ class BillsListViewActivity :
|
|||||||
|
|
||||||
val members = db.getMembersOfProject(proj.id, null)
|
val members = db.getMembersOfProject(proj.id, null)
|
||||||
val bills = db.getBillsOfProject(proj.id)
|
val bills = db.getBillsOfProject(proj.id)
|
||||||
|
val categories = db.getCategories(proj.id)
|
||||||
|
val reimbursementCategoryId = CategoryUtils.getReimbursementCategoryId(categories, proj.id, proj.remoteId)
|
||||||
val balances = HashMap<Long, Double>()
|
val balances = HashMap<Long, Double>()
|
||||||
SupportUtil.getStats(
|
SupportUtil.getStats(
|
||||||
members, bills,
|
members, bills,
|
||||||
mutableMapOf(), balances, mutableMapOf(), mutableMapOf(),
|
mutableMapOf(), balances, mutableMapOf(), mutableMapOf(),
|
||||||
-1000, -1000, null, null
|
-1000L, -1000L, reimbursementCategoryId, null, null
|
||||||
)
|
)
|
||||||
Triple(proj, members, balances)
|
Triple(proj, members, balances)
|
||||||
}
|
}
|
||||||
@@ -698,15 +720,6 @@ class BillsListViewActivity :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showDialog(msg: String, title: String, icon: ImageVector) {
|
|
||||||
viewModel.showDialog(
|
|
||||||
title = title,
|
|
||||||
message = msg,
|
|
||||||
positiveText = getString(android.R.string.ok),
|
|
||||||
icon = icon
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun updateUsernameInDrawer() {
|
private fun updateUsernameInDrawer() {
|
||||||
if (!CowspentServerSyncHelper.isNextcloudAccountConfigured(this)) {
|
if (!CowspentServerSyncHelper.isNextcloudAccountConfigured(this)) {
|
||||||
val text = getString(R.string.drawer_no_account)
|
val text = getString(R.string.drawer_no_account)
|
||||||
@@ -747,31 +760,73 @@ class BillsListViewActivity :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun synchronize(manual: Boolean = false) {
|
/**
|
||||||
|
* What prompted a sync. Only [APP_OPEN] may refresh the account and every project, and only
|
||||||
|
* then when the SyncOnOpen interval has elapsed; the other triggers touch the selected
|
||||||
|
* project alone.
|
||||||
|
*/
|
||||||
|
@VisibleForTesting
|
||||||
|
internal enum class SyncTrigger { APP_OPEN, PROJECT_OPEN, MANUAL }
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
internal fun synchronize(trigger: SyncTrigger) {
|
||||||
val preferences = PreferenceManager.getDefaultSharedPreferences(applicationContext)
|
val preferences = PreferenceManager.getDefaultSharedPreferences(applicationContext)
|
||||||
val offlineMode = preferences.getBoolean(getString(R.string.pref_key_offline_mode), false)
|
// isSyncPossible is networkConnected && !offlineMode, so offline mode is already covered
|
||||||
if (offlineMode && !manual) {
|
// here - including for a manual refresh, which cannot currently override it.
|
||||||
return
|
if (!db.cowspentServerSyncHelper.isSyncPossible) return
|
||||||
}
|
|
||||||
|
val selectedProjectId = preferences.getLong("selected_project", 0)
|
||||||
|
val now = System.currentTimeMillis()
|
||||||
|
|
||||||
|
// The account and all-projects refresh belongs to opening the app, throttled by the
|
||||||
|
// SyncOnOpen interval so that resuming within the interval does not repeat it.
|
||||||
|
val intervalMinutes = SyncSettings.intervalMinutes(applicationContext)
|
||||||
|
val lastAccountSync = preferences.getLong(getString(R.string.pref_key_last_account_sync_timestamp), 0L)
|
||||||
|
val accountSyncDue = trigger == SyncTrigger.APP_OPEN &&
|
||||||
|
now - lastAccountSync > intervalMinutes * 60 * 1000L
|
||||||
|
|
||||||
|
lifecycleScope.launch {
|
||||||
|
val remoteProjects = withContext(Dispatchers.IO) { db.projects }
|
||||||
|
.filter { !it.isLocal && !it.isArchived }
|
||||||
|
|
||||||
if (db.cowspentServerSyncHelper.isSyncPossible) {
|
|
||||||
viewModel.isRefreshing = true
|
viewModel.isRefreshing = true
|
||||||
val selectedProjectId = PreferenceManager.getDefaultSharedPreferences(applicationContext).getLong("selected_project", 0)
|
db.cowspentServerSyncHelper.addCallbackPull(syncCallBack)
|
||||||
if (selectedProjectId != 0L) {
|
|
||||||
lifecycleScope.launch {
|
val started = if (accountSyncDue) {
|
||||||
val proj = withContext(Dispatchers.IO) { db.getProject(selectedProjectId) }
|
if (CowspentServerSyncHelper.isNextcloudAccountConfigured(applicationContext)) {
|
||||||
if (proj != null && !proj.isLocal) {
|
db.cowspentServerSyncHelper.runAccountProjectsSync()
|
||||||
db.cowspentServerSyncHelper.addCallbackPull(syncCallBack)
|
|
||||||
db.cowspentServerSyncHelper.scheduleSync(false, selectedProjectId)
|
|
||||||
} else viewModel.isRefreshing = false
|
|
||||||
}
|
}
|
||||||
} else viewModel.isRefreshing = false
|
remoteProjects.count {
|
||||||
if (CowspentServerSyncHelper.isNextcloudAccountConfigured(applicationContext)) {
|
val scheduled = db.cowspentServerSyncHelper.scheduleSync(false, it, false) != null
|
||||||
db.cowspentServerSyncHelper.runAccountProjectsSync()
|
if (scheduled) markProjectSynced(preferences, it.id, now)
|
||||||
|
scheduled
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
val selectedProj = remoteProjects.find { it.id == selectedProjectId }
|
||||||
|
val lastSync = preferences.getLong(lastProjectSyncKey(selectedProjectId), 0L)
|
||||||
|
val due = trigger == SyncTrigger.MANUAL ||
|
||||||
|
now - lastSync > SELECTED_PROJECT_SYNC_INTERVAL_MS
|
||||||
|
if (selectedProj != null && due &&
|
||||||
|
db.cowspentServerSyncHelper.scheduleSync(
|
||||||
|
false, selectedProj, trigger == SyncTrigger.MANUAL
|
||||||
|
) != null
|
||||||
|
) {
|
||||||
|
markProjectSynced(preferences, selectedProj.id, now)
|
||||||
|
1
|
||||||
|
} else 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Only a task that actually started reports back through syncCallBack, so clear
|
||||||
|
// the indicator here when none did - nothing else would.
|
||||||
|
if (started == 0) viewModel.isRefreshing = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun lastProjectSyncKey(projectId: Long) = "lastProjectSyncTimestamp_$projectId"
|
||||||
|
private fun markProjectSynced(preferences: SharedPreferences, projectId: Long, at: Long) {
|
||||||
|
preferences.edit { putLong(lastProjectSyncKey(projectId), at) }
|
||||||
|
}
|
||||||
|
|
||||||
private fun registerBroadcastReceiver() {
|
private fun registerBroadcastReceiver() {
|
||||||
val filter = IntentFilter().apply {
|
val filter = IntentFilter().apply {
|
||||||
addAction(MainConstants.BROADCAST_PROJECT_SYNC_FAILED)
|
addAction(MainConstants.BROADCAST_PROJECT_SYNC_FAILED)
|
||||||
@@ -811,7 +866,7 @@ class BillsListViewActivity :
|
|||||||
refreshLists()
|
refreshLists()
|
||||||
}
|
}
|
||||||
MainConstants.BROADCAST_SYNC_PROJECT -> {
|
MainConstants.BROADCAST_SYNC_PROJECT -> {
|
||||||
synchronize()
|
synchronize(SyncTrigger.PROJECT_OPEN)
|
||||||
}
|
}
|
||||||
MainConstants.BROADCAST_NETWORK_AVAILABLE -> {
|
MainConstants.BROADCAST_NETWORK_AVAILABLE -> {
|
||||||
}
|
}
|
||||||
@@ -839,7 +894,7 @@ class BillsListViewActivity :
|
|||||||
refreshLists()
|
refreshLists()
|
||||||
if (db.cowspentServerSyncHelper.isSyncPossible) {
|
if (db.cowspentServerSyncHelper.isSyncPossible) {
|
||||||
db.cowspentServerSyncHelper.addCallbackPull(syncCallBack)
|
db.cowspentServerSyncHelper.addCallbackPull(syncCallBack)
|
||||||
synchronize()
|
synchronize(SyncTrigger.PROJECT_OPEN)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,8 +17,6 @@ object MainConstants {
|
|||||||
const val BROADCAST_AVATAR_UPDATED = "net.helcel.cowspent.broadcast.avatar_updated"
|
const val BROADCAST_AVATAR_UPDATED = "net.helcel.cowspent.broadcast.avatar_updated"
|
||||||
const val BROADCAST_AVATAR_UPDATED_MEMBER = "net.helcel.cowspent.broadcast.avatar_updated_for_member"
|
const val BROADCAST_AVATAR_UPDATED_MEMBER = "net.helcel.cowspent.broadcast.avatar_updated_for_member"
|
||||||
|
|
||||||
const val MAIN_CHANNEL_ID = 1234567890
|
|
||||||
|
|
||||||
const val PARAM_DIALOG_CONTENT = "net.helcel.cowspent.PARAM_DIALOG_CONTENT"
|
const val PARAM_DIALOG_CONTENT = "net.helcel.cowspent.PARAM_DIALOG_CONTENT"
|
||||||
const val PARAM_PROJECT_TO_SELECT = "net.helcel.cowspent.PARAM_PROJECT_TO_SELECT"
|
const val PARAM_PROJECT_TO_SELECT = "net.helcel.cowspent.PARAM_PROJECT_TO_SELECT"
|
||||||
|
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ object ProjectImportHelper {
|
|||||||
}
|
}
|
||||||
else -> 0
|
else -> 0
|
||||||
}
|
}
|
||||||
val payerName = if (columns.containsKey("payer_name")) line[columns["payer_name"]!!] else ""
|
val payerName = if (columns.containsKey("payer_name")) line[columns["payer_name"]!!].trim() else ""
|
||||||
val payerWeight = if (columns.containsKey("payer_weight")) line[columns["payer_weight"]!!].toDouble() else 1.0
|
val payerWeight = if (columns.containsKey("payer_weight")) line[columns["payer_weight"]!!].toDouble() else 1.0
|
||||||
val owersStr = if (columns.containsKey("owers")) line[columns["owers"]!!] else ""
|
val owersStr = if (columns.containsKey("owers")) line[columns["owers"]!!] else ""
|
||||||
val payerActive = columns.containsKey("payer_active") && line[columns["payer_active"]!!] == "1"
|
val payerActive = columns.containsKey("payer_active") && line[columns["payer_active"]!!] == "1"
|
||||||
@@ -122,8 +122,10 @@ object ProjectImportHelper {
|
|||||||
val pmId = if (columns.containsKey("paymentmodeid") && line[columns["paymentmodeid"]!!].isNotEmpty()) line[columns["paymentmodeid"]!!].toLong() else 0L
|
val pmId = if (columns.containsKey("paymentmodeid") && line[columns["paymentmodeid"]!!].isNotEmpty()) line[columns["paymentmodeid"]!!].toLong() else 0L
|
||||||
val pm = if (columns.containsKey("paymentmode")) line[columns["paymentmode"]!!] else null
|
val pm = if (columns.containsKey("paymentmode")) line[columns["paymentmode"]!!] else null
|
||||||
|
|
||||||
membersActive[payerName] = payerActive
|
if (payerName.isNotEmpty()) {
|
||||||
membersWeight[payerName] = payerWeight
|
membersActive[payerName] = payerActive
|
||||||
|
membersWeight[payerName] = payerWeight
|
||||||
|
}
|
||||||
|
|
||||||
if (owersStr.trim().isEmpty()) {
|
if (owersStr.trim().isEmpty()) {
|
||||||
onError(context.getString(R.string.import_error_owers, row))
|
onError(context.getString(R.string.import_error_owers, row))
|
||||||
@@ -132,10 +134,10 @@ object ProjectImportHelper {
|
|||||||
|
|
||||||
if (what != "deleteMeIfYouWant") {
|
if (what != "deleteMeIfYouWant") {
|
||||||
billRemoteIdToOwerStr[row.toLong()] = owersStr
|
billRemoteIdToOwerStr[row.toLong()] = owersStr
|
||||||
val owersArray = owersStr.split(", ").filter { it.isNotEmpty() }
|
val owersArray = owersStr.split(",").map { it.trim() }.filter { it.isNotEmpty() }
|
||||||
for (ower in owersArray) {
|
for (ower in owersArray) {
|
||||||
if (!membersWeight.containsKey(ower.trim())) {
|
if (!membersWeight.containsKey(ower)) {
|
||||||
membersWeight[ower.trim()] = 1.0
|
membersWeight[ower] = 1.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bills.add(DBBill(0, row.toLong(), 0, 0, amount, timestamp, what, DBBill.STATE_OK, "n", pm, catId, comment, pmId))
|
bills.add(DBBill(0, row.toLong(), 0, 0, amount, timestamp, what, DBBill.STATE_OK, "n", pm, catId, comment, pmId))
|
||||||
@@ -149,16 +151,19 @@ object ProjectImportHelper {
|
|||||||
|
|
||||||
val memberNameToId = mutableMapOf<String, Long>()
|
val memberNameToId = mutableMapOf<String, Long>()
|
||||||
val pid = db.addProject(DBProject(0, projectRemoteId, "", projectRemoteId, null, null, null, ProjectType.LOCAL, 0L, mainCurrencyName, false, DBProject.ACCESS_LEVEL_UNKNOWN, null))
|
val pid = db.addProject(DBProject(0, projectRemoteId, "", projectRemoteId, null, null, null, ProjectType.LOCAL, 0L, mainCurrencyName, false, DBProject.ACCESS_LEVEL_UNKNOWN, null))
|
||||||
|
// addProject only inserts a subset of the row, currency not among it, so the main
|
||||||
|
// currency the file declared has to be written separately or it is lost.
|
||||||
|
if (mainCurrencyName != null) db.updateProject(pid, newCurrencyName = mainCurrencyName)
|
||||||
|
|
||||||
val pmRemoteToLocal = mutableMapOf<Long, Long>()
|
val pmRemoteToLocal = mutableMapOf<Long, Long>()
|
||||||
paymentModes.forEach { pm ->
|
paymentModes.forEach {
|
||||||
val localId = db.addPaymentMode(DBPaymentMode(0, pm.remoteId, pid, pm.name, pm.icon, pm.color))
|
val newId = db.addPaymentMode(DBPaymentMode(0, it.remoteId, pid, it.name, it.icon, it.color))
|
||||||
pmRemoteToLocal[pm.remoteId] = localId
|
pmRemoteToLocal[it.remoteId] = newId
|
||||||
}
|
}
|
||||||
val catRemoteToLocal = mutableMapOf<Long, Long>()
|
val catRemoteToLocal = mutableMapOf<Long, Long>()
|
||||||
categories.forEach { cat ->
|
categories.forEach {
|
||||||
val localId = db.addCategory(DBCategory(0, cat.remoteId, pid, cat.name, cat.icon, cat.color))
|
val newId = db.addCategory(DBCategory(0, it.remoteId, pid, it.name, it.icon, it.color))
|
||||||
catRemoteToLocal[cat.remoteId] = localId
|
catRemoteToLocal[it.remoteId] = newId
|
||||||
}
|
}
|
||||||
currencies.forEach { db.addCurrency(DBCurrency(0, 0, pid, it.name, it.exchangeRate, DBBill.STATE_OK)) }
|
currencies.forEach { db.addCurrency(DBCurrency(0, 0, pid, it.name, it.exchangeRate, DBBill.STATE_OK)) }
|
||||||
|
|
||||||
@@ -168,11 +173,11 @@ object ProjectImportHelper {
|
|||||||
|
|
||||||
bills.forEach { b ->
|
bills.forEach { b ->
|
||||||
val payerId = memberNameToId[billRemoteIdToPayerName[b.remoteId]] ?: 0L
|
val payerId = memberNameToId[billRemoteIdToPayerName[b.remoteId]] ?: 0L
|
||||||
val localCatId = catRemoteToLocal[b.categoryId] ?: b.categoryId
|
val localCatId = catRemoteToLocal[b.categoryId] ?: 0L
|
||||||
val localPmId = pmRemoteToLocal[b.paymentModeId] ?: b.paymentModeId
|
val localPmId = pmRemoteToLocal[b.paymentModeId] ?: 0L
|
||||||
val billId = db.addBill(DBBill(0, 0, pid, payerId, b.amount, b.timestamp, b.what, DBBill.STATE_OK, b.repeat, b.paymentMode, localCatId, b.comment, localPmId))
|
val billId = db.addBill(DBBill(0, 0, pid, payerId, b.amount, b.timestamp, b.what, DBBill.STATE_OK, b.repeat, b.paymentMode, localCatId, b.comment, localPmId))
|
||||||
billRemoteIdToOwerStr[b.remoteId]?.split(", ")?.filter { it.isNotEmpty() }?.forEach { ower ->
|
billRemoteIdToOwerStr[b.remoteId]?.split(",")?.map { it.trim() }?.filter { it.isNotEmpty() }?.forEach { ower ->
|
||||||
memberNameToId[ower.trim()]?.let { owerId -> db.addBillower(billId, owerId) }
|
memberNameToId[ower]?.let { owerId -> db.addBillower(billId, owerId) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onSuccess(pid)
|
onSuccess(pid)
|
||||||
|
|||||||
@@ -35,7 +35,8 @@ fun ProjectOptionsDialogContent(
|
|||||||
isArchived: Boolean = false,
|
isArchived: Boolean = false,
|
||||||
projectType: ProjectType = ProjectType.LOCAL,
|
projectType: ProjectType = ProjectType.LOCAL,
|
||||||
accessLevel: Int = DBProject.ACCESS_LEVEL_ADMIN,
|
accessLevel: Int = DBProject.ACCESS_LEVEL_ADMIN,
|
||||||
isShareable: Boolean = true
|
isShareable: Boolean = true,
|
||||||
|
showBetaFeatures: Boolean = false
|
||||||
) {
|
) {
|
||||||
Surface(
|
Surface(
|
||||||
shape = MaterialTheme.shapes.large,
|
shape = MaterialTheme.shapes.large,
|
||||||
@@ -79,7 +80,7 @@ fun ProjectOptionsDialogContent(
|
|||||||
// Row 2: Manage Member, Manage Labels, Manage Currencies
|
// Row 2: Manage Member, Manage Labels, Manage Currencies
|
||||||
if (!isArchived && isMaintainer) {
|
if (!isArchived && isMaintainer) {
|
||||||
row2.add(ProjectOption(stringResource(R.string.action_members), Icons.Default.Group, onManageMembers))
|
row2.add(ProjectOption(stringResource(R.string.action_members), Icons.Default.Group, onManageMembers))
|
||||||
if (false && (projectType == ProjectType.LOCAL || projectType == ProjectType.COSPEND)) {
|
if (showBetaFeatures && (projectType == ProjectType.LOCAL || projectType == ProjectType.COSPEND)) {
|
||||||
row2.add(ProjectOption(stringResource(R.string.action_labels), Icons.AutoMirrored.Filled.Label, onManageLabels))
|
row2.add(ProjectOption(stringResource(R.string.action_labels), Icons.AutoMirrored.Filled.Label, onManageLabels))
|
||||||
}
|
}
|
||||||
row2.add(ProjectOption(stringResource(R.string.action_currencies), Icons.Default.MonetizationOn, onManageCurrencies))
|
row2.add(ProjectOption(stringResource(R.string.action_currencies), Icons.Default.MonetizationOn, onManageCurrencies))
|
||||||
@@ -181,7 +182,8 @@ fun ProjectOptionsDialogPreview() {
|
|||||||
isArchived = false,
|
isArchived = false,
|
||||||
projectType = ProjectType.COSPEND,
|
projectType = ProjectType.COSPEND,
|
||||||
accessLevel = DBProject.ACCESS_LEVEL_ADMIN,
|
accessLevel = DBProject.ACCESS_LEVEL_ADMIN,
|
||||||
isShareable = true
|
isShareable = true,
|
||||||
|
showBetaFeatures = true
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -205,7 +207,8 @@ fun ProjectOptionsDialogPreview2() {
|
|||||||
isArchived = true,
|
isArchived = true,
|
||||||
projectType = ProjectType.COSPEND,
|
projectType = ProjectType.COSPEND,
|
||||||
accessLevel = DBProject.ACCESS_LEVEL_ADMIN,
|
accessLevel = DBProject.ACCESS_LEVEL_ADMIN,
|
||||||
isShareable = true
|
isShareable = true,
|
||||||
|
showBetaFeatures = true
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -228,7 +231,8 @@ fun ProjectOptionsDialogPreview3() {
|
|||||||
isArchived = false,
|
isArchived = false,
|
||||||
projectType = ProjectType.LOCAL,
|
projectType = ProjectType.LOCAL,
|
||||||
accessLevel = DBProject.ACCESS_LEVEL_ADMIN,
|
accessLevel = DBProject.ACCESS_LEVEL_ADMIN,
|
||||||
isShareable = true
|
isShareable = true,
|
||||||
|
showBetaFeatures = true
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,10 +10,8 @@ import androidx.activity.compose.setContent
|
|||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.activity.viewModels
|
import androidx.activity.viewModels
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.lifecycle.lifecycleScope
|
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import net.helcel.cowspent.R
|
import net.helcel.cowspent.R
|
||||||
@@ -31,7 +29,7 @@ import net.helcel.cowspent.android.project.ProjectImportHelper
|
|||||||
|
|
||||||
class NewProjectActivity : AppCompatActivity() {
|
class NewProjectActivity : AppCompatActivity() {
|
||||||
|
|
||||||
private val viewModel: NewProjectViewModel by viewModels()
|
internal val viewModel: NewProjectViewModel by viewModels()
|
||||||
private lateinit var db: CowspentSQLiteOpenHelper
|
private lateinit var db: CowspentSQLiteOpenHelper
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
@@ -57,9 +55,6 @@ class NewProjectActivity : AppCompatActivity() {
|
|||||||
.setAction(Intent.ACTION_GET_CONTENT)
|
.setAction(Intent.ACTION_GET_CONTENT)
|
||||||
importFileLauncher.launch(Intent.createChooser(intent, "Select a file"))
|
importFileLauncher.launch(Intent.createChooser(intent, "Select a file"))
|
||||||
},
|
},
|
||||||
onChooseFromNextcloud = {
|
|
||||||
chooseFromNextcloud()
|
|
||||||
},
|
|
||||||
onOkPressed = { onPressOk() },
|
onOkPressed = { onPressOk() },
|
||||||
onBack = { finish() },
|
onBack = { finish() },
|
||||||
onFieldsChanged = { updateAuthStatus() }
|
onFieldsChanged = { updateAuthStatus() }
|
||||||
@@ -130,19 +125,6 @@ class NewProjectActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun chooseFromNextcloud() {
|
|
||||||
lifecycleScope.launch {
|
|
||||||
val accountProjects = withContext(Dispatchers.IO) { db.accountProjects }
|
|
||||||
if (accountProjects.isEmpty()) {
|
|
||||||
showToast(getString(R.string.choose_account_project_dialog_impossible), Toast.LENGTH_LONG)
|
|
||||||
return@launch
|
|
||||||
}
|
|
||||||
|
|
||||||
viewModel.nextcloudProjects = accountProjects
|
|
||||||
viewModel.showNextcloudProjectDialog = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun updateAuthStatus() {
|
private fun updateAuthStatus() {
|
||||||
val url = getFormattedUrl()
|
val url = getFormattedUrl()
|
||||||
val fakeProj = DBProject(
|
val fakeProj = DBProject(
|
||||||
@@ -154,27 +136,7 @@ class NewProjectActivity : AppCompatActivity() {
|
|||||||
viewModel.isAuthenticatedAccount = db.cowspentServerSyncHelper.canCreateAuthenticatedProject(fakeProj)
|
viewModel.isAuthenticatedAccount = db.cowspentServerSyncHelper.canCreateAuthenticatedProject(fakeProj)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onPressOk() {
|
private fun onPressOk() = createProject()
|
||||||
val type = viewModel.projectType
|
|
||||||
val todoCreate = viewModel.whatTodoIsCreate
|
|
||||||
val url = getFormattedUrl()
|
|
||||||
|
|
||||||
val fakeProj = DBProject(
|
|
||||||
0, "", "", "", url,
|
|
||||||
"", 0L, type, 0L,
|
|
||||||
null, false, DBProject.ACCESS_LEVEL_UNKNOWN,
|
|
||||||
""
|
|
||||||
)
|
|
||||||
|
|
||||||
if (isValidUrl(url) && todoCreate && ProjectType.COSPEND == type &&
|
|
||||||
db.cowspentServerSyncHelper.canCreateAuthenticatedProject(fakeProj) &&
|
|
||||||
!viewModel.showAuthWarningDialog // Avoid infinite loop
|
|
||||||
) {
|
|
||||||
viewModel.showAuthWarningDialog = true
|
|
||||||
} else {
|
|
||||||
createProject()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getFormattedUrl(): String {
|
private fun getFormattedUrl(): String {
|
||||||
var url = viewModel.projectUrl.trim()
|
var url = viewModel.projectUrl.trim()
|
||||||
@@ -320,7 +282,6 @@ class NewProjectActivity : AppCompatActivity() {
|
|||||||
pid
|
pid
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
showToast(getString(R.string.project_added_success), Toast.LENGTH_LONG)
|
|
||||||
return pid
|
return pid
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package net.helcel.cowspent.android.project.create
|
|||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.rememberScrollState
|
import androidx.compose.foundation.rememberScrollState
|
||||||
import androidx.compose.foundation.selection.selectable
|
|
||||||
import androidx.compose.foundation.verticalScroll
|
import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material.*
|
import androidx.compose.material.*
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
@@ -31,7 +30,6 @@ fun NewProjectScreen(
|
|||||||
viewModel: NewProjectViewModel,
|
viewModel: NewProjectViewModel,
|
||||||
onScanQrCode: () -> Unit,
|
onScanQrCode: () -> Unit,
|
||||||
onImportFile: () -> Unit,
|
onImportFile: () -> Unit,
|
||||||
onChooseFromNextcloud: () -> Unit,
|
|
||||||
onOkPressed: () -> Unit,
|
onOkPressed: () -> Unit,
|
||||||
onBack: () -> Unit,
|
onBack: () -> Unit,
|
||||||
onFieldsChanged: () -> Unit
|
onFieldsChanged: () -> Unit
|
||||||
@@ -224,40 +222,6 @@ fun NewProjectScreen(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (viewModel.showNextcloudProjectDialog) {
|
|
||||||
AlertDialog(
|
|
||||||
onDismissRequest = { viewModel.showNextcloudProjectDialog = false },
|
|
||||||
title = { Text(stringResource(R.string.choose_account_project_dialog_title)) },
|
|
||||||
text = {
|
|
||||||
Column {
|
|
||||||
viewModel.nextcloudProjects.forEach { project ->
|
|
||||||
Row(
|
|
||||||
Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.selectable(
|
|
||||||
selected = false,
|
|
||||||
onClick = {
|
|
||||||
viewModel.projectId = project.remoteId
|
|
||||||
viewModel.projectUrl = project.ncUrl
|
|
||||||
viewModel.showNextcloudProjectDialog = false
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.padding(16.dp)
|
|
||||||
) {
|
|
||||||
Text(text = project.name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
confirmButton = {},
|
|
||||||
dismissButton = {
|
|
||||||
TextButton(onClick = { viewModel.showNextcloudProjectDialog = false }) {
|
|
||||||
Text(stringResource(R.string.simple_cancel))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (viewModel.isCreatingRemoteProject) {
|
if (viewModel.isCreatingRemoteProject) {
|
||||||
AlertDialog(
|
AlertDialog(
|
||||||
onDismissRequest = { },
|
onDismissRequest = { },
|
||||||
@@ -337,7 +301,6 @@ fun NewProjectScreenPreview() {
|
|||||||
},
|
},
|
||||||
onScanQrCode = {},
|
onScanQrCode = {},
|
||||||
onImportFile = {},
|
onImportFile = {},
|
||||||
onChooseFromNextcloud = {},
|
|
||||||
onOkPressed = {},
|
onOkPressed = {},
|
||||||
onBack = {},
|
onBack = {},
|
||||||
onFieldsChanged = {}
|
onFieldsChanged = {}
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ 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.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import net.helcel.cowspent.model.DBAccountProject
|
|
||||||
import net.helcel.cowspent.model.ProjectType
|
import net.helcel.cowspent.model.ProjectType
|
||||||
|
|
||||||
class NewProjectViewModel : ViewModel() {
|
class NewProjectViewModel : ViewModel() {
|
||||||
@@ -33,8 +32,6 @@ class NewProjectViewModel : ViewModel() {
|
|||||||
var isAuthenticatedAccount by mutableStateOf(false)
|
var isAuthenticatedAccount by mutableStateOf(false)
|
||||||
|
|
||||||
var showAuthWarningDialog by mutableStateOf(false)
|
var showAuthWarningDialog by mutableStateOf(false)
|
||||||
var showNextcloudProjectDialog by mutableStateOf(false)
|
|
||||||
var nextcloudProjects by mutableStateOf<List<DBAccountProject>>(emptyList())
|
|
||||||
|
|
||||||
var isCreatingRemoteProject by mutableStateOf(false)
|
var isCreatingRemoteProject by mutableStateOf(false)
|
||||||
var errorDialogMessage by mutableStateOf<String?>(null)
|
var errorDialogMessage by mutableStateOf<String?>(null)
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ package net.helcel.cowspent.android.project.edit
|
|||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.activity.enableEdgeToEdge
|
|
||||||
import androidx.activity.compose.setContent
|
import androidx.activity.compose.setContent
|
||||||
|
import androidx.activity.enableEdgeToEdge
|
||||||
import androidx.activity.viewModels
|
import androidx.activity.viewModels
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
@@ -13,17 +13,16 @@ import kotlinx.coroutines.launch
|
|||||||
import kotlinx.coroutines.withContext
|
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.android.main.MainConstants
|
||||||
import net.helcel.cowspent.model.DBProject
|
import net.helcel.cowspent.model.DBProject
|
||||||
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.ICallback
|
import net.helcel.cowspent.util.ICallback
|
||||||
import net.helcel.cowspent.util.SupportUtil
|
|
||||||
import net.helcel.cowspent.android.main.MainConstants
|
|
||||||
|
|
||||||
|
|
||||||
class EditProjectActivity : AppCompatActivity() {
|
class EditProjectActivity : AppCompatActivity() {
|
||||||
|
|
||||||
private val viewModel: EditProjectViewModel by viewModels()
|
internal val viewModel: EditProjectViewModel by viewModels()
|
||||||
private lateinit var db: CowspentSQLiteOpenHelper
|
private lateinit var db: CowspentSQLiteOpenHelper
|
||||||
private lateinit var project: DBProject
|
private lateinit var project: DBProject
|
||||||
|
|
||||||
@@ -56,39 +55,44 @@ class EditProjectActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun onSave() {
|
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 currentPwd = viewModel.password
|
||||||
val newPwd = viewModel.newPassword
|
val newPwd = viewModel.newPassword
|
||||||
val newName = viewModel.name
|
val newName = viewModel.name
|
||||||
val newEmail = viewModel.email
|
val newEmail = viewModel.email
|
||||||
|
|
||||||
if (newName.isEmpty()) {
|
val nameChanged = changes.name
|
||||||
showToast(this, getString(R.string.error_invalid_project_name), Toast.LENGTH_LONG)
|
val emailChanged = changes.email
|
||||||
return
|
val pwdChanged = changes.newPassword
|
||||||
}
|
val currentPwdChanged = changes.currentPassword
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
if (project.isLocal) {
|
if (project.isLocal) {
|
||||||
val targetPwd = if (pwdChanged) newPwd else currentPwd
|
val targetPwd = if (pwdChanged) newPwd else currentPwd
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
db.updateProject(
|
db.updateProject(
|
||||||
project.id, newName, newEmail, targetPwd,
|
projId = project.id,
|
||||||
null, project.type, null,
|
newName = newName,
|
||||||
null, null,
|
newEmail = newEmail,
|
||||||
null, null
|
newPassword = targetPwd,
|
||||||
|
projectType = project.type
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
closeOnEdit(project.id)
|
closeOnEdit(project.id)
|
||||||
@@ -103,18 +107,21 @@ class EditProjectActivity : AppCompatActivity() {
|
|||||||
project.password = currentPwd
|
project.password = currentPwd
|
||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
db.updateProject(project.id, null, null, currentPwd, null, project.type, null, null, null, null, null)
|
db.updateProject(
|
||||||
|
projId = project.id,
|
||||||
|
newPassword = currentPwd,
|
||||||
|
projectType = project.type
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!db.cowspentServerSyncHelper.editRemoteProject(
|
if (!db.cowspentServerSyncHelper.editRemoteProject(
|
||||||
project.id,
|
projId = project.id,
|
||||||
newName,
|
newName = newName,
|
||||||
newEmail,
|
newEmail = newEmail,
|
||||||
if (pwdChanged) newPwd else null,
|
newPassword = if (pwdChanged) newPwd else null,
|
||||||
null,
|
callback = editCallBack
|
||||||
editCallBack
|
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
showToast(this, getString(R.string.remote_project_operation_no_network), Toast.LENGTH_LONG)
|
showToast(this, getString(R.string.remote_project_operation_no_network), Toast.LENGTH_LONG)
|
||||||
@@ -124,10 +131,9 @@ class EditProjectActivity : AppCompatActivity() {
|
|||||||
lifecycleScope.launch {
|
lifecycleScope.launch {
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
db.updateProject(
|
db.updateProject(
|
||||||
project.id, null, null, currentPwd,
|
projId = project.id,
|
||||||
null, project.type, null,
|
newPassword = currentPwd,
|
||||||
null, null,
|
projectType = project.type
|
||||||
null, null
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
closeOnEdit(project.id)
|
closeOnEdit(project.id)
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import androidx.compose.ui.graphics.vector.ImageVector
|
|||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import net.helcel.cowspent.android.helper.DialogState
|
import net.helcel.cowspent.android.helper.DialogState
|
||||||
import net.helcel.cowspent.model.DBProject
|
import net.helcel.cowspent.model.DBProject
|
||||||
|
import net.helcel.cowspent.util.SupportUtil
|
||||||
|
|
||||||
class EditProjectViewModel : ViewModel() {
|
class EditProjectViewModel : ViewModel() {
|
||||||
var name by mutableStateOf("")
|
var name by mutableStateOf("")
|
||||||
@@ -17,6 +18,31 @@ class EditProjectViewModel : ViewModel() {
|
|||||||
|
|
||||||
var dialogState by mutableStateOf<DialogState?>(null)
|
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(
|
fun showDialog(
|
||||||
title: String? = null,
|
title: String? = null,
|
||||||
message: String? = null,
|
message: String? = null,
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import androidx.compose.material.icons.Icons
|
|||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.platform.testTag
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.text.input.KeyboardCapitalization
|
import androidx.compose.ui.text.input.KeyboardCapitalization
|
||||||
@@ -100,6 +101,7 @@ fun MemberEditDialogContent(
|
|||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.clickable { isActivated = !isActivated }
|
.clickable { isActivated = !isActivated }
|
||||||
.padding(vertical = 8.dp)
|
.padding(vertical = 8.dp)
|
||||||
|
.testTag("member_activated_row")
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Default.Block,
|
imageVector = Icons.Default.Block,
|
||||||
|
|||||||
+1
-1
@@ -22,7 +22,7 @@ import net.helcel.cowspent.theme.ThemeUtils
|
|||||||
|
|
||||||
class MemberManagementActivity : AppCompatActivity() {
|
class MemberManagementActivity : AppCompatActivity() {
|
||||||
|
|
||||||
private val viewModel: MemberManagementViewModel by viewModels()
|
internal val viewModel: MemberManagementViewModel by viewModels()
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
enableEdgeToEdge()
|
enableEdgeToEdge()
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import androidx.compose.material.IconButton
|
|||||||
import androidx.compose.material.MaterialTheme
|
import androidx.compose.material.MaterialTheme
|
||||||
import androidx.compose.material.RadioButton
|
import androidx.compose.material.RadioButton
|
||||||
import androidx.compose.material.Scaffold
|
import androidx.compose.material.Scaffold
|
||||||
|
import androidx.compose.material.Slider
|
||||||
import androidx.compose.material.Switch
|
import androidx.compose.material.Switch
|
||||||
import androidx.compose.material.SwitchDefaults
|
import androidx.compose.material.SwitchDefaults
|
||||||
import androidx.compose.material.Text
|
import androidx.compose.material.Text
|
||||||
@@ -30,6 +31,7 @@ import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
|||||||
import androidx.compose.material.icons.filled.AccountCircle
|
import androidx.compose.material.icons.filled.AccountCircle
|
||||||
import androidx.compose.material.icons.filled.Archive
|
import androidx.compose.material.icons.filled.Archive
|
||||||
import androidx.compose.material.icons.filled.Brightness2
|
import androidx.compose.material.icons.filled.Brightness2
|
||||||
|
import androidx.compose.material.icons.filled.Group
|
||||||
import androidx.compose.material.icons.filled.Info
|
import androidx.compose.material.icons.filled.Info
|
||||||
import androidx.compose.material.icons.filled.Palette
|
import androidx.compose.material.icons.filled.Palette
|
||||||
import androidx.compose.material.icons.filled.Sync
|
import androidx.compose.material.icons.filled.Sync
|
||||||
@@ -49,13 +51,16 @@ import androidx.compose.ui.res.stringResource
|
|||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import kotlin.math.roundToInt
|
||||||
import androidx.core.content.edit
|
import androidx.core.content.edit
|
||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
import net.helcel.cowspent.R
|
import net.helcel.cowspent.R
|
||||||
import net.helcel.cowspent.android.helper.ColorPicker
|
import net.helcel.cowspent.android.helper.ColorPicker
|
||||||
import net.helcel.cowspent.persistence.CowspentSQLiteOpenHelper
|
import net.helcel.cowspent.persistence.CowspentSQLiteOpenHelper
|
||||||
|
import net.helcel.cowspent.persistence.CowspentServerSyncHelper
|
||||||
import net.helcel.cowspent.util.ColorUtils
|
import net.helcel.cowspent.util.ColorUtils
|
||||||
import net.helcel.cowspent.util.Cowspent
|
import net.helcel.cowspent.util.Cowspent
|
||||||
|
import net.helcel.cowspent.util.SyncSettings
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun SettingsScreen(
|
fun SettingsScreen(
|
||||||
@@ -79,22 +84,32 @@ fun SettingsScreen(
|
|||||||
val keyColor = stringResource(R.string.pref_key_color)
|
val keyColor = stringResource(R.string.pref_key_color)
|
||||||
val keyOfflineMode = stringResource(R.string.pref_key_offline_mode)
|
val keyOfflineMode = stringResource(R.string.pref_key_offline_mode)
|
||||||
val keyShowArchived = stringResource(R.string.pref_key_show_archived)
|
val keyShowArchived = stringResource(R.string.pref_key_show_archived)
|
||||||
|
val keyBetaFeatures = stringResource(R.string.pref_key_beta_features)
|
||||||
|
val keyStatsIncludeDeactivated = stringResource(R.string.pref_key_stats_include_deactivated)
|
||||||
|
val keyAutoSyncOnOpen = stringResource(R.string.pref_key_auto_sync_on_open)
|
||||||
|
val keyFillNewBillFromLast = stringResource(R.string.pref_key_fill_new_bill_from_last)
|
||||||
|
val keyLastAccountSync = stringResource(R.string.pref_key_last_account_sync_timestamp)
|
||||||
|
|
||||||
|
val isNextcloudConfigured = CowspentServerSyncHelper.isNextcloudAccountConfigured(context)
|
||||||
|
|
||||||
// States for preferences
|
// States for preferences
|
||||||
var nightMode by remember(keyNightMode) {
|
var nightMode by remember(keyNightMode) {
|
||||||
mutableStateOf(sharedPreferences.getString(keyNightMode, "-1") ?: "-1")
|
mutableStateOf(sharedPreferences.getString(keyNightMode, "-1") ?: "-1")
|
||||||
}
|
}
|
||||||
|
|
||||||
var colorMode by remember(keyColorMode, keyUseServerColor, keyUseSystemColor) {
|
var colorMode by remember(keyColorMode, keyUseServerColor, keyUseSystemColor, isNextcloudConfigured) {
|
||||||
mutableStateOf(sharedPreferences.getString(keyColorMode, null) ?: run {
|
val savedMode = sharedPreferences.getString(keyColorMode, null)
|
||||||
val useServer = sharedPreferences.getBoolean(keyUseServerColor, true)
|
val mode = savedMode ?: run {
|
||||||
|
val useServer = sharedPreferences.getBoolean(keyUseServerColor, false)
|
||||||
val useSystem = sharedPreferences.getBoolean(keyUseSystemColor, true)
|
val useSystem = sharedPreferences.getBoolean(keyUseSystemColor, true)
|
||||||
when {
|
when {
|
||||||
useServer -> "server"
|
useServer && isNextcloudConfigured -> "server"
|
||||||
useSystem -> "system"
|
useSystem -> "system"
|
||||||
else -> "manual"
|
else -> "manual"
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
// Fallback to system if server is selected but not configured
|
||||||
|
mutableStateOf(if (mode == "server" && !isNextcloudConfigured) "system" else mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply theme globally only when leaving settings to avoid flickering/restarts during selection
|
// Apply theme globally only when leaving settings to avoid flickering/restarts during selection
|
||||||
@@ -113,6 +128,27 @@ fun SettingsScreen(
|
|||||||
var showArchived by remember(keyShowArchived) {
|
var showArchived by remember(keyShowArchived) {
|
||||||
mutableStateOf(sharedPreferences.getBoolean(keyShowArchived, false))
|
mutableStateOf(sharedPreferences.getBoolean(keyShowArchived, false))
|
||||||
}
|
}
|
||||||
|
var betaFeatures by remember(keyBetaFeatures) {
|
||||||
|
mutableStateOf(sharedPreferences.getBoolean(keyBetaFeatures, false))
|
||||||
|
}
|
||||||
|
var fillNewBillFromLast by remember(keyFillNewBillFromLast) {
|
||||||
|
mutableStateOf(sharedPreferences.getBoolean(keyFillNewBillFromLast, false))
|
||||||
|
}
|
||||||
|
var statsIncludeDeactivated by remember(keyStatsIncludeDeactivated) {
|
||||||
|
mutableStateOf(sharedPreferences.getBoolean(keyStatsIncludeDeactivated, false))
|
||||||
|
}
|
||||||
|
|
||||||
|
val syncIntervals = SyncSettings.INTERVAL_CHOICES_MINUTES
|
||||||
|
val syncIntervalLabels = listOf(
|
||||||
|
stringResource(R.string.pref_value_sync_1m),
|
||||||
|
stringResource(R.string.pref_value_sync_10m),
|
||||||
|
stringResource(R.string.pref_value_sync_1h),
|
||||||
|
stringResource(R.string.pref_value_sync_1d)
|
||||||
|
)
|
||||||
|
|
||||||
|
var syncInterval by remember(keyAutoSyncOnOpen) {
|
||||||
|
mutableIntStateOf(SyncSettings.intervalMinutes(context))
|
||||||
|
}
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
topBar = {
|
topBar = {
|
||||||
@@ -120,7 +156,7 @@ fun SettingsScreen(
|
|||||||
title = { Text(stringResource(R.string.action_settings)) },
|
title = { Text(stringResource(R.string.action_settings)) },
|
||||||
navigationIcon = {
|
navigationIcon = {
|
||||||
IconButton(onClick = onBack) {
|
IconButton(onClick = onBack) {
|
||||||
Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null)
|
Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Back")
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
backgroundColor = MaterialTheme.colors.primary,
|
backgroundColor = MaterialTheme.colors.primary,
|
||||||
@@ -177,15 +213,19 @@ fun SettingsScreen(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val colorModeEntries = buildMap {
|
||||||
|
put("system", stringResource(R.string.pref_value_color_system))
|
||||||
|
if (isNextcloudConfigured) {
|
||||||
|
put("server", stringResource(R.string.pref_value_color_server))
|
||||||
|
}
|
||||||
|
put("manual", stringResource(R.string.pref_value_color_manual))
|
||||||
|
}
|
||||||
|
|
||||||
SettingsListPreference(
|
SettingsListPreference(
|
||||||
title = stringResource(R.string.settings_color_mode),
|
title = stringResource(R.string.settings_color_mode),
|
||||||
icon = Icons.Default.Palette,
|
icon = Icons.Default.Palette,
|
||||||
value = colorMode,
|
value = colorMode,
|
||||||
entries = mapOf(
|
entries = colorModeEntries,
|
||||||
"system" to stringResource(R.string.pref_value_color_system),
|
|
||||||
"server" to stringResource(R.string.pref_value_color_server),
|
|
||||||
"manual" to stringResource(R.string.pref_value_color_manual)
|
|
||||||
),
|
|
||||||
onValueChange = { mode ->
|
onValueChange = { mode ->
|
||||||
colorMode = mode
|
colorMode = mode
|
||||||
sharedPreferences.edit {
|
sharedPreferences.edit {
|
||||||
@@ -242,6 +282,64 @@ fun SettingsScreen(
|
|||||||
// Other
|
// Other
|
||||||
SettingsCategory(stringResource(R.string.settings_other))
|
SettingsCategory(stringResource(R.string.settings_other))
|
||||||
|
|
||||||
|
SettingsSwitchPreference(
|
||||||
|
title = stringResource(R.string.settings_beta_features),
|
||||||
|
summary = stringResource(R.string.settings_beta_features_summary),
|
||||||
|
icon = Icons.Default.Info,
|
||||||
|
checked = betaFeatures,
|
||||||
|
onCheckedChange = {
|
||||||
|
betaFeatures = it
|
||||||
|
sharedPreferences.edit {
|
||||||
|
putBoolean(keyBetaFeatures, it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
if (betaFeatures) {
|
||||||
|
SettingsSwitchPreference(
|
||||||
|
title = stringResource(R.string.settings_fill_new_bill_from_last),
|
||||||
|
summary = stringResource(R.string.settings_fill_new_bill_from_last_summary),
|
||||||
|
icon = Icons.Default.Info,
|
||||||
|
checked = fillNewBillFromLast,
|
||||||
|
onCheckedChange = {
|
||||||
|
fillNewBillFromLast = it
|
||||||
|
sharedPreferences.edit {
|
||||||
|
putBoolean(keyFillNewBillFromLast, it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
SettingsSwitchPreference(
|
||||||
|
title = stringResource(R.string.settings_stats_include_deactivated),
|
||||||
|
icon = Icons.Default.Group,
|
||||||
|
checked = statsIncludeDeactivated,
|
||||||
|
onCheckedChange = {
|
||||||
|
statsIncludeDeactivated = it
|
||||||
|
sharedPreferences.edit {
|
||||||
|
putBoolean(keyStatsIncludeDeactivated, it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
SettingsSliderPreference(
|
||||||
|
title = stringResource(R.string.settings_auto_sync_on_open),
|
||||||
|
summary = stringResource(R.string.settings_auto_sync_on_open_summary),
|
||||||
|
icon = Icons.Default.Sync,
|
||||||
|
value = syncInterval,
|
||||||
|
values = syncIntervals,
|
||||||
|
labels = syncIntervalLabels,
|
||||||
|
onValueChange = { newInterval ->
|
||||||
|
// Slider reports every drag delta, not just the snapped steps.
|
||||||
|
if (newInterval != syncInterval) {
|
||||||
|
syncInterval = newInterval
|
||||||
|
sharedPreferences.edit {
|
||||||
|
putInt(keyAutoSyncOnOpen, newInterval)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
SettingsPreference(
|
SettingsPreference(
|
||||||
title = stringResource(R.string.title_about),
|
title = stringResource(R.string.title_about),
|
||||||
icon = Icons.Default.Info,
|
icon = Icons.Default.Info,
|
||||||
@@ -355,13 +453,7 @@ fun SettingsListPreference(
|
|||||||
),
|
),
|
||||||
verticalAlignment = Alignment.CenterVertically
|
verticalAlignment = Alignment.CenterVertically
|
||||||
) {
|
) {
|
||||||
RadioButton(
|
RadioButton(selected = (key == value), onClick = null)
|
||||||
selected = (key == value),
|
|
||||||
onClick = {
|
|
||||||
onValueChange(key)
|
|
||||||
showDialog = false
|
|
||||||
}
|
|
||||||
)
|
|
||||||
Spacer(Modifier.width(8.dp))
|
Spacer(Modifier.width(8.dp))
|
||||||
Text(text = label)
|
Text(text = label)
|
||||||
}
|
}
|
||||||
@@ -424,6 +516,47 @@ fun SettingsColorPreference(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun SettingsSliderPreference(
|
||||||
|
title: String,
|
||||||
|
summary: String? = null,
|
||||||
|
icon: Any? = null,
|
||||||
|
value: Int,
|
||||||
|
values: List<Int>,
|
||||||
|
labels: List<String>,
|
||||||
|
onValueChange: (Int) -> Unit
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(16.dp, 8.dp)
|
||||||
|
) {
|
||||||
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
|
SettingsIcon(icon)
|
||||||
|
Spacer(modifier = Modifier.width(32.dp))
|
||||||
|
Column(modifier = Modifier.weight(1f)) {
|
||||||
|
Text(text = title, style = MaterialTheme.typography.subtitle1)
|
||||||
|
if (summary != null) {
|
||||||
|
Text(text = summary, style = MaterialTheme.typography.caption)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val currentIndex = values.indexOf(value).coerceAtLeast(0)
|
||||||
|
val steps = (values.size - 2).coerceAtLeast(0)
|
||||||
|
|
||||||
|
Column(modifier = Modifier.padding(start = 56.dp, top = 8.dp)) {
|
||||||
|
Slider(
|
||||||
|
value = currentIndex.toFloat(),
|
||||||
|
onValueChange = { onValueChange(values[it.roundToInt()]) },
|
||||||
|
valueRange = 0f..(values.size - 1).toFloat(),
|
||||||
|
steps = steps
|
||||||
|
)
|
||||||
|
Text(text = labels[currentIndex], style = MaterialTheme.typography.caption, fontWeight = FontWeight.Bold, color = MaterialTheme.colors.primary)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun SettingsIcon(icon: Any?) {
|
fun SettingsIcon(icon: Any?) {
|
||||||
Box(modifier = Modifier.size(24.dp), contentAlignment = Alignment.Center) {
|
Box(modifier = Modifier.size(24.dp), contentAlignment = Alignment.Center) {
|
||||||
|
|||||||
@@ -71,6 +71,7 @@ import net.helcel.cowspent.android.helper.formatShortValue
|
|||||||
import net.helcel.cowspent.model.DBBill
|
import net.helcel.cowspent.model.DBBill
|
||||||
import net.helcel.cowspent.model.DBCategory
|
import net.helcel.cowspent.model.DBCategory
|
||||||
import net.helcel.cowspent.model.DBMember
|
import net.helcel.cowspent.model.DBMember
|
||||||
|
import net.helcel.cowspent.util.CategoryUtils
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
@@ -87,6 +88,8 @@ private object SankeyDimens {
|
|||||||
@Composable
|
@Composable
|
||||||
fun ProjectSankeyDiagram(
|
fun ProjectSankeyDiagram(
|
||||||
projectName: String,
|
projectName: String,
|
||||||
|
projectId: Long,
|
||||||
|
projectRemoteId: String?,
|
||||||
allMembers: List<DBMember>,
|
allMembers: List<DBMember>,
|
||||||
allBills: List<DBBill>,
|
allBills: List<DBBill>,
|
||||||
customCategories: List<DBCategory>,
|
customCategories: List<DBCategory>,
|
||||||
@@ -96,8 +99,11 @@ fun ProjectSankeyDiagram(
|
|||||||
var selectedMemberId by remember { mutableLongStateOf(-1L) }
|
var selectedMemberId by remember { mutableLongStateOf(-1L) }
|
||||||
var expanded by remember { mutableStateOf(false) }
|
var expanded by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
val activeBills = remember(allBills) {
|
val reimbursementCategoryId = remember(customCategories, projectId, projectRemoteId) {
|
||||||
allBills.filter { it.state != DBBill.STATE_DELETED && it.categoryId != DBBill.CATEGORY_REIMBURSEMENT.toLong() }
|
CategoryUtils.getReimbursementCategoryId(customCategories, projectId, projectRemoteId)
|
||||||
|
}
|
||||||
|
val activeBills = remember(allBills, reimbursementCategoryId) {
|
||||||
|
allBills.filter { it.state != DBBill.STATE_DELETED && it.categoryId != reimbursementCategoryId }
|
||||||
}
|
}
|
||||||
|
|
||||||
val membersMap = remember(allMembers) { allMembers.associateBy { it.id } }
|
val membersMap = remember(allMembers) { allMembers.associateBy { it.id } }
|
||||||
@@ -115,17 +121,19 @@ fun ProjectSankeyDiagram(
|
|||||||
val catMap = mutableMapOf<Long, Double>()
|
val catMap = mutableMapOf<Long, Double>()
|
||||||
|
|
||||||
activeBills.forEach { bill ->
|
activeBills.forEach { bill ->
|
||||||
val totalWeight = bill.billOwers.sumOf { membersMap[it.memberId]?.weight ?: 1.0 }
|
val totalWeight = bill.billOwers.sumOf { membersMap[it.memberId]?.weight ?: 0.0 }
|
||||||
if (totalWeight > 0) {
|
if (totalWeight > 0) {
|
||||||
if (selectedMemberId == -1L) {
|
if (selectedMemberId == -1L) {
|
||||||
catMap[bill.categoryId] = (catMap[bill.categoryId] ?: 0.0) + bill.amount
|
catMap[bill.categoryId] = (catMap[bill.categoryId] ?: 0.0) + bill.amount
|
||||||
bill.billOwers.forEach { bo ->
|
bill.billOwers.forEach { bo ->
|
||||||
val weight = membersMap[bo.memberId]?.weight ?: 1.0
|
if (membersMap.containsKey(bo.memberId)) {
|
||||||
spentMap[bo.memberId] = (spentMap[bo.memberId] ?: 0.0) + (bill.amount / totalWeight) * weight
|
val weight = membersMap[bo.memberId]?.weight ?: 0.0
|
||||||
|
spentMap[bo.memberId] = (spentMap[bo.memberId] ?: 0.0) + (bill.amount / totalWeight) * weight
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
bill.billOwers.find { it.memberId == selectedMemberId }?.let { bo ->
|
bill.billOwers.find { it.memberId == selectedMemberId }?.let { bo ->
|
||||||
val weight = membersMap[bo.memberId]?.weight ?: 1.0
|
val weight = membersMap[bo.memberId]?.weight ?: 0.0
|
||||||
catMap[bill.categoryId] = (catMap[bill.categoryId] ?: 0.0) + (bill.amount / totalWeight) * weight
|
catMap[bill.categoryId] = (catMap[bill.categoryId] ?: 0.0) + (bill.amount / totalWeight) * weight
|
||||||
spentMap[selectedMemberId] = (spentMap[selectedMemberId] ?: 0.0) + (bill.amount / totalWeight) * weight
|
spentMap[selectedMemberId] = (spentMap[selectedMemberId] ?: 0.0) + (bill.amount / totalWeight) * weight
|
||||||
}
|
}
|
||||||
@@ -338,7 +346,9 @@ private fun SankeyContent(
|
|||||||
scope.launch { topFocalIndex.animateTo(index.toFloat(), spring(Spring.DampingRatioLowBouncy, Spring.StiffnessLow)) }
|
scope.launch { topFocalIndex.animateTo(index.toFloat(), spring(Spring.DampingRatioLowBouncy, Spring.StiffnessLow)) }
|
||||||
} else Modifier), contentAlignment = Alignment.Center) {
|
} else Modifier), contentAlignment = Alignment.Center) {
|
||||||
Column(modifier = Modifier.fillMaxSize().background(color = member?.let { Color(it.r ?: 128, it.g ?: 128, it.b ?: 128) } ?: Color.Gray, shape = RoundedCornerShape(10.dp)), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center) {
|
Column(modifier = Modifier.fillMaxSize().background(color = member?.let { Color(it.r ?: 128, it.g ?: 128, it.b ?: 128) } ?: Color.Gray, shape = RoundedCornerShape(10.dp)), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center) {
|
||||||
Text(text = member?.name ?: "???", color = Color.White, fontWeight = FontWeight.Bold, maxLines = 1, overflow = TextOverflow.Ellipsis, textAlign = TextAlign.Center, modifier = Modifier.wrapContentWidth(unbounded = true))
|
if (wDp >= 32.dp) {
|
||||||
|
Text(text = member?.name ?: "???", color = Color.White, fontWeight = FontWeight.Bold, maxLines = 1, overflow = TextOverflow.Ellipsis, textAlign = TextAlign.Center, modifier = Modifier.wrapContentWidth(unbounded = true))
|
||||||
|
}
|
||||||
if (wDp >= 40.dp) Text(text = formatShortValue(amount), fontSize = 12.sp, color = Color.White.copy(alpha = 0.9f), textAlign = TextAlign.Center)
|
if (wDp >= 40.dp) Text(text = formatShortValue(amount), fontSize = 12.sp, color = Color.White.copy(alpha = 0.9f), textAlign = TextAlign.Center)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -376,7 +386,9 @@ private fun SankeyContent(
|
|||||||
scope.launch { bottomFocalIndex.animateTo(index.toFloat(), spring(Spring.DampingRatioLowBouncy, Spring.StiffnessLow)) }
|
scope.launch { bottomFocalIndex.animateTo(index.toFloat(), spring(Spring.DampingRatioLowBouncy, Spring.StiffnessLow)) }
|
||||||
} else Modifier), contentAlignment = Alignment.Center) {
|
} else Modifier), contentAlignment = Alignment.Center) {
|
||||||
Column(modifier = Modifier.fillMaxSize().background(color = category?.color?.let { try { Color(it.toColorInt()) } catch (_: Exception) { Color(0xFF999999) } } ?: Color(0xFF999999), shape = RoundedCornerShape(10.dp)), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center) {
|
Column(modifier = Modifier.fillMaxSize().background(color = category?.color?.let { try { Color(it.toColorInt()) } catch (_: Exception) { Color(0xFF999999) } } ?: Color(0xFF999999), shape = RoundedCornerShape(10.dp)), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center) {
|
||||||
Text(text = category?.icon ?: "❔", fontSize = 20.sp, textAlign = TextAlign.Center, modifier = Modifier.wrapContentWidth(unbounded = true))
|
if (wDp >= 24.dp) {
|
||||||
|
Text(text = category?.icon ?: "❔", fontSize = 20.sp, textAlign = TextAlign.Center, modifier = Modifier.wrapContentWidth(unbounded = true))
|
||||||
|
}
|
||||||
if (wDp >= 40.dp) Text(text = formatShortValue(amount), fontSize = 12.sp, color = Color.White.copy(alpha = 0.9f), textAlign = TextAlign.Center)
|
if (wDp >= 40.dp) Text(text = formatShortValue(amount), fontSize = 12.sp, color = Color.White.copy(alpha = 0.9f), textAlign = TextAlign.Center)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -399,4 +411,4 @@ private fun DrawScope.drawSankeyFlow(startX: Float, startY: Float, startWidth: F
|
|||||||
|
|
||||||
@Preview(showBackground = true, widthDp = 360, heightDp = 640)
|
@Preview(showBackground = true, widthDp = 360, heightDp = 640)
|
||||||
@Composable
|
@Composable
|
||||||
fun ProjectSankeyDiagramPreview() = MaterialTheme { ProjectSankeyDiagram("Test Project", StatisticsMockData.members, StatisticsMockData.bills, emptyList()) {} }
|
fun ProjectSankeyDiagramPreview() = MaterialTheme { ProjectSankeyDiagram("Test Project", 1L, "1", StatisticsMockData.members, StatisticsMockData.bills, emptyList()) {} }
|
||||||
|
|||||||
+1
-1
@@ -47,7 +47,7 @@ class ProjectStatisticsActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val EXTRA_PROJECT_ID = "extra_project_id"
|
internal const val EXTRA_PROJECT_ID = "extra_project_id"
|
||||||
|
|
||||||
fun createIntent(context: Context, projectId: Long): Intent {
|
fun createIntent(context: Context, projectId: Long): Intent {
|
||||||
return Intent(context, ProjectStatisticsActivity::class.java).apply {
|
return Intent(context, ProjectStatisticsActivity::class.java).apply {
|
||||||
|
|||||||
+28
-12
@@ -40,6 +40,8 @@ fun ProjectStatisticsScreen(
|
|||||||
"Sankey"
|
"Sankey"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val keyStatsIncludeDeactivated = stringResource(R.string.pref_key_stats_include_deactivated)
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
topBar = {
|
topBar = {
|
||||||
TopAppBar(
|
TopAppBar(
|
||||||
@@ -84,29 +86,41 @@ fun ProjectStatisticsScreen(
|
|||||||
|
|
||||||
val statsData by produceState<StatisticsData?>(null, proj.id) {
|
val statsData by produceState<StatisticsData?>(null, proj.id) {
|
||||||
value = withContext(Dispatchers.IO) {
|
value = withContext(Dispatchers.IO) {
|
||||||
|
val syncedCategories = db.getCategories(proj.id)
|
||||||
|
val defaultCategories = CategoryUtils.getDefaultCategories(context, proj.id)
|
||||||
|
|
||||||
|
val toEnsure = if (proj.type == ProjectType.LOCAL) {
|
||||||
|
defaultCategories
|
||||||
|
} else {
|
||||||
|
listOfNotNull(defaultCategories.find { it.remoteId == DBBill.CATEGORY_REIMBURSEMENT })
|
||||||
|
}
|
||||||
|
|
||||||
|
toEnsure.forEach { def ->
|
||||||
|
if (syncedCategories.none { it.remoteId == def.remoteId }) {
|
||||||
|
db.addCategory(def)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val members = db.getMembersOfProject(proj.id, null)
|
val members = db.getMembersOfProject(proj.id, null)
|
||||||
val bills = db.getBillsOfProject(proj.id)
|
val bills = db.getBillsOfProject(proj.id)
|
||||||
val categories = db.getCategories(proj.id)
|
val categories = db.getCategories(proj.id)
|
||||||
val paymentModes = db.getPaymentModes(proj.id)
|
val paymentModes = db.getPaymentModes(proj.id)
|
||||||
StatisticsData(members, bills, categories, paymentModes)
|
|
||||||
|
val includeDeactivated = prefs.getBoolean(keyStatsIncludeDeactivated, false)
|
||||||
|
val filteredMembers = if (includeDeactivated) members else members.filter { it.isActivated }
|
||||||
|
|
||||||
|
StatisticsData(filteredMembers, bills, categories, paymentModes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (statsData != null) {
|
if (statsData != null) {
|
||||||
val data = statsData!!
|
val data = statsData!!
|
||||||
val defaultCategories = remember(proj.id) { CategoryUtils.getDefaultCategories(context, proj.id) }
|
val categories = data.categories
|
||||||
val categories = remember(proj.type, data.categories, defaultCategories) {
|
|
||||||
val hardcoded = if (proj.type == ProjectType.LOCAL) {
|
|
||||||
defaultCategories
|
|
||||||
} else {
|
|
||||||
listOfNotNull(defaultCategories.find { it.remoteId == DBBill.CATEGORY_REIMBURSEMENT })
|
|
||||||
}
|
|
||||||
(data.categories + hardcoded).distinctBy { it.remoteId }
|
|
||||||
}
|
|
||||||
val categoryNoneLabel = stringResource(R.string.category_none)
|
val categoryNoneLabel = stringResource(R.string.category_none)
|
||||||
val sankeyCategories = remember(proj.id, data.categories, defaultCategories, categoryNoneLabel) {
|
val sankeyCategories = remember(proj.id, data.categories, categoryNoneLabel) {
|
||||||
val noneCategory = DBCategory(0, 0, proj.id, categoryNoneLabel, "❌", "#9E9E9E")
|
val noneCategory = DBCategory(0, 0, proj.id, categoryNoneLabel, "❌", "#9E9E9E")
|
||||||
(data.categories + defaultCategories + noneCategory).distinctBy { it.remoteId }
|
(data.categories + noneCategory).distinctBy { if (it.id == 0L) "none" else it.id.toString() }
|
||||||
}
|
}
|
||||||
|
|
||||||
when (selectedTab) {
|
when (selectedTab) {
|
||||||
@@ -131,6 +145,8 @@ fun ProjectStatisticsScreen(
|
|||||||
2 -> {
|
2 -> {
|
||||||
ProjectSankeyDiagram(
|
ProjectSankeyDiagram(
|
||||||
projectName = proj.name.ifEmpty { proj.remoteId },
|
projectName = proj.name.ifEmpty { proj.remoteId },
|
||||||
|
projectId = proj.id,
|
||||||
|
projectRemoteId = proj.remoteId,
|
||||||
allMembers = data.members,
|
allMembers = data.members,
|
||||||
allBills = data.bills,
|
allBills = data.bills,
|
||||||
customCategories = sankeyCategories,
|
customCategories = sankeyCategories,
|
||||||
|
|||||||
+28
-17
@@ -3,8 +3,8 @@ package net.helcel.cowspent.android.statistics
|
|||||||
import android.app.DatePickerDialog
|
import android.app.DatePickerDialog
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.rememberScrollState
|
||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material.*
|
import androidx.compose.material.*
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.*
|
import androidx.compose.material.icons.filled.*
|
||||||
@@ -44,8 +44,8 @@ fun ProjectStatisticsTable(
|
|||||||
val sdf = remember { SimpleDateFormat("yyyy-MM-dd", Locale.ROOT) }
|
val sdf = remember { SimpleDateFormat("yyyy-MM-dd", Locale.ROOT) }
|
||||||
val dateFormat = remember { android.text.format.DateFormat.getDateFormat(context) }
|
val dateFormat = remember { android.text.format.DateFormat.getDateFormat(context) }
|
||||||
|
|
||||||
var categoryId by remember { mutableIntStateOf(-1000) }
|
var categoryId by remember { mutableLongStateOf(-1000L) }
|
||||||
var paymentModeId by remember { mutableIntStateOf(-1000) }
|
var paymentModeId by remember { mutableLongStateOf(-1000L) }
|
||||||
var dateMin by remember { mutableStateOf<String?>(null) }
|
var dateMin by remember { mutableStateOf<String?>(null) }
|
||||||
var dateMax by remember { mutableStateOf<String?>(null) }
|
var dateMax by remember { mutableStateOf<String?>(null) }
|
||||||
|
|
||||||
@@ -61,10 +61,10 @@ fun ProjectStatisticsTable(
|
|||||||
val shareStatsIntro = stringResource(R.string.msg_stats_intro, proj.name.ifEmpty { proj.remoteId })
|
val shareStatsIntro = stringResource(R.string.msg_stats_intro, proj.name.ifEmpty { proj.remoteId })
|
||||||
|
|
||||||
val categories = remember(proj.id, customCategories, categoryAll, categoryNone, categoryReimbursement, categoryAllExceptReimbursement) {
|
val categories = remember(proj.id, customCategories, categoryAll, categoryNone, categoryReimbursement, categoryAllExceptReimbursement) {
|
||||||
val list = mutableListOf<Triple<Int, String, String>>()
|
val list = mutableListOf<Triple<Long, String, String>>()
|
||||||
list.add(Triple(-1000, "📋", categoryAll))
|
list.add(Triple(-1000L, "📋", categoryAll))
|
||||||
list.add(Triple(-100, "🧾", categoryAllExceptReimbursement))
|
list.add(Triple(-100L, "🧾", categoryAllExceptReimbursement))
|
||||||
list.add(Triple(0, "❌", categoryNone))
|
list.add(Triple(0L, "❌", categoryNone))
|
||||||
|
|
||||||
val catsToUse = if (proj.type == ProjectType.LOCAL) {
|
val catsToUse = if (proj.type == ProjectType.LOCAL) {
|
||||||
CategoryUtils.getDefaultCategories(context, proj.id)
|
CategoryUtils.getDefaultCategories(context, proj.id)
|
||||||
@@ -75,15 +75,15 @@ fun ProjectStatisticsTable(
|
|||||||
}
|
}
|
||||||
|
|
||||||
catsToUse.forEach {
|
catsToUse.forEach {
|
||||||
list.add(Triple(it.remoteId.toInt(), it.icon, it.name ?: ""))
|
list.add(Triple(it.id, it.icon, it.name ?: ""))
|
||||||
}
|
}
|
||||||
list.distinctBy { it.first }
|
list.distinctBy { it.first }
|
||||||
}
|
}
|
||||||
|
|
||||||
val paymentModes = remember(proj.id, customPaymentModes, paymentModeAll, paymentModeNone) {
|
val paymentModes = remember(proj.id, customPaymentModes, paymentModeAll, paymentModeNone) {
|
||||||
val list = mutableListOf<Triple<Int, String, String>>()
|
val list = mutableListOf<Triple<Long, String, String>>()
|
||||||
list.add(Triple(-1000, "💳", paymentModeAll))
|
list.add(Triple(-1000L, "💳", paymentModeAll))
|
||||||
list.add(Triple(0, "❌", paymentModeNone))
|
list.add(Triple(0L, "❌", paymentModeNone))
|
||||||
|
|
||||||
val pmsToUse = if (proj.type == ProjectType.LOCAL) {
|
val pmsToUse = if (proj.type == ProjectType.LOCAL) {
|
||||||
CategoryUtils.getDefaultPaymentModes(context, proj.id)
|
CategoryUtils.getDefaultPaymentModes(context, proj.id)
|
||||||
@@ -94,7 +94,7 @@ fun ProjectStatisticsTable(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pmsToUse.forEach {
|
pmsToUse.forEach {
|
||||||
list.add(Triple(it.remoteId.toInt(), it.icon, it.name ?: ""))
|
list.add(Triple(it.id, it.icon, it.name ?: ""))
|
||||||
}
|
}
|
||||||
list.distinctBy { it.first }
|
list.distinctBy { it.first }
|
||||||
}
|
}
|
||||||
@@ -105,10 +105,12 @@ fun ProjectStatisticsTable(
|
|||||||
val membersPaid = HashMap<Long, Double>()
|
val membersPaid = HashMap<Long, Double>()
|
||||||
val membersSpent = HashMap<Long, Double>()
|
val membersSpent = HashMap<Long, Double>()
|
||||||
|
|
||||||
|
val reimbursementCategoryId = CategoryUtils.getReimbursementCategoryId(customCategories, proj.id, proj.remoteId)
|
||||||
|
|
||||||
SupportUtil.getStats(
|
SupportUtil.getStats(
|
||||||
allMembers, allBills,
|
allMembers, allBills,
|
||||||
membersNbBills, membersBalance, membersPaid, membersSpent,
|
membersNbBills, membersBalance, membersPaid, membersSpent,
|
||||||
categoryId, paymentModeId, dateMin, dateMax
|
categoryId, paymentModeId, reimbursementCategoryId, dateMin, dateMax
|
||||||
)
|
)
|
||||||
|
|
||||||
var statsText = shareStatsIntro + "\n\n"
|
var statsText = shareStatsIntro + "\n\n"
|
||||||
@@ -283,9 +285,18 @@ fun ProjectStatisticsTable(
|
|||||||
|
|
||||||
Spacer(modifier = Modifier.height(4.dp))
|
Spacer(modifier = Modifier.height(4.dp))
|
||||||
|
|
||||||
LazyColumn(modifier = Modifier.weight(1f)) {
|
Column(
|
||||||
items(stats.memberStats) { m ->
|
modifier = Modifier
|
||||||
Row(modifier = Modifier.fillMaxWidth().padding(vertical = 12.dp, horizontal = 8.dp), verticalAlignment = Alignment.CenterVertically) {
|
.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(m.name, modifier = Modifier.weight(2f), color = MaterialTheme.colors.onSurface, fontWeight = FontWeight.Medium)
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package net.helcel.cowspent.model
|
package net.helcel.cowspent.model
|
||||||
|
|
||||||
import android.util.Log
|
|
||||||
import java.io.Serializable
|
import java.io.Serializable
|
||||||
import java.util.Calendar
|
import java.util.Calendar
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ enum class ProjectType(val id: String) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
fun getTypeById(id: String?): ProjectType? {
|
fun getTypeById(id: String?): ProjectType? {
|
||||||
return reverseMap[id]
|
return reverseMap[id]
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -46,4 +46,21 @@ object CategoryUtils {
|
|||||||
DBPaymentMode(DBBill.PAYMODE_ID_ONLINE_SERVICE, DBBill.PAYMODE_ID_ONLINE_SERVICE, projectId, context.getString(R.string.payment_mode_online), "\uD83C\uDF0E", "#9932cc")
|
DBPaymentMode(DBBill.PAYMODE_ID_ONLINE_SERVICE, DBBill.PAYMODE_ID_ONLINE_SERVICE, projectId, context.getString(R.string.payment_mode_online), "\uD83C\uDF0E", "#9932cc")
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getReimbursementCategoryId(categories: List<DBCategory>, projectId: Long, projectRemoteId: String? = null): Long {
|
||||||
|
return categories.find {
|
||||||
|
it.projectId == projectId && (
|
||||||
|
it.remoteId == DBBill.CATEGORY_REIMBURSEMENT ||
|
||||||
|
(projectRemoteId != null && it.remoteId.toString() == projectRemoteId)
|
||||||
|
)
|
||||||
|
}?.id ?: DBBill.CATEGORY_REIMBURSEMENT
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getCategoryById(context: Context, id: Long, projectId: Long = 0): DBCategory? {
|
||||||
|
return getDefaultCategories(context, projectId).find { it.id == id }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getPaymentModeById(context: Context, id: Long, projectId: Long = 0): DBPaymentMode? {
|
||||||
|
return getDefaultPaymentModes(context, projectId).find { it.id == id }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ object ColorUtils {
|
|||||||
val colorMode = if (prefs.contains(modeKey)) {
|
val colorMode = if (prefs.contains(modeKey)) {
|
||||||
prefs.getString(modeKey, "system")
|
prefs.getString(modeKey, "system")
|
||||||
} else {
|
} else {
|
||||||
val useServer = prefs.getBoolean(context.getString(R.string.pref_key_use_server_color), true)
|
val useServer = prefs.getBoolean(context.getString(R.string.pref_key_use_server_color), false)
|
||||||
val useSystem = prefs.getBoolean(context.getString(R.string.pref_key_use_system_color), true)
|
val useSystem = prefs.getBoolean(context.getString(R.string.pref_key_use_system_color), true)
|
||||||
when {
|
when {
|
||||||
useServer -> "server"
|
useServer -> "server"
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ class NextcloudClient(
|
|||||||
|
|
||||||
@Throws(JSONException::class, IOException::class, TokenMismatchException::class, NextcloudHttpRequestFailedException::class)
|
@Throws(JSONException::class, IOException::class, TokenMismatchException::class, NextcloudHttpRequestFailedException::class)
|
||||||
fun getCapabilities(project: DBProject?): ServerResponse.CapabilitiesResponse {
|
fun getCapabilities(project: DBProject?): ServerResponse.CapabilitiesResponse {
|
||||||
val target: String = if (project == null || url != "") {
|
val target: String = if (project == null || url != "" || nextcloudAPI != null) {
|
||||||
"/ocs/v2.php/cloud/capabilities"
|
"/ocs/v2.php/cloud/capabilities"
|
||||||
} else {
|
} else {
|
||||||
val realServerUrl = project.serverUrl!!
|
val realServerUrl = project.serverUrl!!
|
||||||
@@ -86,13 +86,17 @@ class NextcloudClient(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Throws(TokenMismatchException::class, NextcloudHttpRequestFailedException::class)
|
@Throws(TokenMismatchException::class, NextcloudHttpRequestFailedException::class)
|
||||||
private fun requestServerWithSSO(
|
internal fun requestServerWithSSO(
|
||||||
nextcloudAPI: NextcloudAPI,
|
nextcloudAPI: NextcloudAPI,
|
||||||
target: String,
|
target: String,
|
||||||
method: String,
|
method: String,
|
||||||
params: Collection<QueryParam>?,
|
params: Collection<QueryParam>?,
|
||||||
isOCSRequest: Boolean
|
isOCSRequest: Boolean
|
||||||
): VersatileProjectSyncClient.ResponseData {
|
): VersatileProjectSyncClient.ResponseData {
|
||||||
|
var finalTarget = target
|
||||||
|
if (finalTarget.contains("/ocs/v2.php") && !finalTarget.contains("format=json")) {
|
||||||
|
finalTarget += if (finalTarget.contains("?")) "&format=json" else "?format=json"
|
||||||
|
}
|
||||||
val result = StringBuilder()
|
val result = StringBuilder()
|
||||||
val headers: MutableMap<String, List<String>> = HashMap()
|
val headers: MutableMap<String, List<String>> = HashMap()
|
||||||
if (isOCSRequest) {
|
if (isOCSRequest) {
|
||||||
@@ -103,13 +107,13 @@ class NextcloudClient(
|
|||||||
val nextcloudRequest: NextcloudRequest = if (params == null) {
|
val nextcloudRequest: NextcloudRequest = if (params == null) {
|
||||||
NextcloudRequest.Builder()
|
NextcloudRequest.Builder()
|
||||||
.setMethod(method)
|
.setMethod(method)
|
||||||
.setUrl(target)
|
.setUrl(finalTarget)
|
||||||
.setHeader(headers)
|
.setHeader(headers)
|
||||||
.build()
|
.build()
|
||||||
} else {
|
} else {
|
||||||
NextcloudRequest.Builder()
|
NextcloudRequest.Builder()
|
||||||
.setMethod(method)
|
.setMethod(method)
|
||||||
.setUrl(target)
|
.setUrl(finalTarget)
|
||||||
.setParameter(params)
|
.setParameter(params)
|
||||||
.setHeader(headers)
|
.setHeader(headers)
|
||||||
.build()
|
.build()
|
||||||
@@ -137,7 +141,7 @@ class NextcloudClient(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Throws(TokenMismatchException::class, NextcloudHttpRequestFailedException::class)
|
@Throws(TokenMismatchException::class, NextcloudHttpRequestFailedException::class)
|
||||||
private fun imageRequestServerWithSSO(
|
internal fun imageRequestServerWithSSO(
|
||||||
nextcloudAPI: NextcloudAPI,
|
nextcloudAPI: NextcloudAPI,
|
||||||
target: String,
|
target: String,
|
||||||
method: String,
|
method: String,
|
||||||
@@ -178,12 +182,16 @@ class NextcloudClient(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Throws(IOException::class, NextcloudHttpRequestFailedException::class)
|
@Throws(IOException::class, NextcloudHttpRequestFailedException::class)
|
||||||
private fun requestServer(
|
internal fun requestServer(
|
||||||
target: String,
|
target: String,
|
||||||
method: String, params: JSONObject?, lastETag: String?, needLogin: Boolean, isOCSRequest: Boolean
|
method: String, params: JSONObject?, lastETag: String?, needLogin: Boolean, isOCSRequest: Boolean
|
||||||
): VersatileProjectSyncClient.ResponseData {
|
): VersatileProjectSyncClient.ResponseData {
|
||||||
|
var finalTarget = target
|
||||||
|
if (finalTarget.contains("/ocs/v2.php") && !finalTarget.contains("format=json")) {
|
||||||
|
finalTarget += if (finalTarget.contains("?")) "&format=json" else "?format=json"
|
||||||
|
}
|
||||||
val result = StringBuilder()
|
val result = StringBuilder()
|
||||||
val targetURL = url + target.replace("^/".toRegex(), "")
|
val targetURL = url + finalTarget.replace("^/".toRegex(), "")
|
||||||
// Log.d(javaClass.simpleName, "method and target URL: $method $targetURL")
|
// Log.d(javaClass.simpleName, "method and target URL: $method $targetURL")
|
||||||
val httpCon = SupportUtil.getHttpURLConnection(targetURL)
|
val httpCon = SupportUtil.getHttpURLConnection(targetURL)
|
||||||
httpCon.requestMethod = method
|
httpCon.requestMethod = method
|
||||||
@@ -194,7 +202,7 @@ class NextcloudClient(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
httpCon.setRequestProperty("Connection", "Close")
|
httpCon.setRequestProperty("Connection", "Close")
|
||||||
httpCon.setRequestProperty("User-Agent", "cowspent-android/" + SupportUtil.getAppVersionName(context))
|
httpCon.setRequestProperty("User-Agent", "Cowspent-android/" + SupportUtil.getAppVersionName(context))
|
||||||
if (lastETag != null && METHOD_GET == method) {
|
if (lastETag != null && METHOD_GET == method) {
|
||||||
httpCon.setRequestProperty("If-None-Match", lastETag)
|
httpCon.setRequestProperty("If-None-Match", lastETag)
|
||||||
}
|
}
|
||||||
@@ -240,12 +248,16 @@ class NextcloudClient(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Throws(IOException::class, NextcloudHttpRequestFailedException::class)
|
@Throws(IOException::class, NextcloudHttpRequestFailedException::class)
|
||||||
private fun imageRequestServer(
|
internal fun imageRequestServer(
|
||||||
target: String,
|
target: String,
|
||||||
method: String, params: JSONObject?, lastETag: String?, needLogin: Boolean, isOCSRequest: Boolean
|
method: String, params: JSONObject?, lastETag: String?, needLogin: Boolean, isOCSRequest: Boolean
|
||||||
): VersatileProjectSyncClient.ResponseData {
|
): VersatileProjectSyncClient.ResponseData {
|
||||||
|
var finalTarget = target
|
||||||
|
if (finalTarget.contains("/ocs/v2.php") && !finalTarget.contains("format=json")) {
|
||||||
|
finalTarget += if (finalTarget.contains("?")) "&format=json" else "?format=json"
|
||||||
|
}
|
||||||
var strBase64: String
|
var strBase64: String
|
||||||
val targetURL = url + target.replace("^/".toRegex(), "")
|
val targetURL = url + finalTarget.replace("^/".toRegex(), "")
|
||||||
val httpCon = SupportUtil.getHttpURLConnection( targetURL)
|
val httpCon = SupportUtil.getHttpURLConnection( targetURL)
|
||||||
httpCon.requestMethod = method
|
httpCon.requestMethod = method
|
||||||
if (needLogin) {
|
if (needLogin) {
|
||||||
|
|||||||
@@ -12,15 +12,10 @@ import net.helcel.cowspent.model.DBProject
|
|||||||
import org.json.JSONArray
|
import org.json.JSONArray
|
||||||
import org.json.JSONException
|
import org.json.JSONException
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
import org.xml.sax.SAXException
|
|
||||||
import java.io.ByteArrayInputStream
|
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.io.InputStream
|
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
import javax.xml.parsers.DocumentBuilderFactory
|
|
||||||
import javax.xml.parsers.ParserConfigurationException
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -41,6 +36,10 @@ open class ServerResponse(
|
|||||||
val lastModified: Long
|
val lastModified: Long
|
||||||
get() = response.lastModified
|
get() = response.lastModified
|
||||||
|
|
||||||
|
@get:Throws(JSONException::class)
|
||||||
|
val stringContent: String
|
||||||
|
get() = getResponseStringData()
|
||||||
|
|
||||||
@Throws(JSONException::class)
|
@Throws(JSONException::class)
|
||||||
fun getResponseObjectData(): JSONObject {
|
fun getResponseObjectData(): JSONObject {
|
||||||
val rawData = JSONObject(content)
|
val rawData = JSONObject(content)
|
||||||
@@ -125,10 +124,6 @@ open class ServerResponse(
|
|||||||
private val isJsonMember: Boolean
|
private val isJsonMember: Boolean
|
||||||
) : ServerResponse(response, isOcsResponse) {
|
) : ServerResponse(response, isOcsResponse) {
|
||||||
|
|
||||||
@get:Throws(JSONException::class)
|
|
||||||
val stringContent: String
|
|
||||||
get() = getResponseStringData()
|
|
||||||
|
|
||||||
@get:Throws(JSONException::class)
|
@get:Throws(JSONException::class)
|
||||||
val remoteMemberId: Long
|
val remoteMemberId: Long
|
||||||
get() = if (isJsonMember)
|
get() = if (isJsonMember)
|
||||||
@@ -137,45 +132,94 @@ open class ServerResponse(
|
|||||||
getResponseStringData().toLong()
|
getResponseStringData().toLong()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class CreateRemoteCategoryResponse(
|
||||||
|
response: VersatileProjectSyncClient.ResponseData,
|
||||||
|
isOcsResponse: Boolean
|
||||||
|
) : ServerResponse(response, isOcsResponse) {
|
||||||
|
|
||||||
|
@get:Throws(JSONException::class)
|
||||||
|
val remoteCategoryId: Long
|
||||||
|
get() {
|
||||||
|
val dataStr = getResponseStringData()
|
||||||
|
return try {
|
||||||
|
dataStr.toLong()
|
||||||
|
} catch (_: NumberFormatException) {
|
||||||
|
val obj = JSONObject(dataStr)
|
||||||
|
obj.optLong("id", obj.optLong("remoteId", 0L))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class EditRemoteCategoryResponse(
|
||||||
|
response: VersatileProjectSyncClient.ResponseData,
|
||||||
|
isOcsResponse: Boolean
|
||||||
|
) : ServerResponse(response, isOcsResponse)
|
||||||
|
|
||||||
|
class DeleteRemoteCategoryResponse(
|
||||||
|
response: VersatileProjectSyncClient.ResponseData,
|
||||||
|
isOcsResponse: Boolean
|
||||||
|
) : ServerResponse(response, isOcsResponse)
|
||||||
|
|
||||||
|
class CreateRemotePaymentModeResponse(
|
||||||
|
response: VersatileProjectSyncClient.ResponseData,
|
||||||
|
isOcsResponse: Boolean
|
||||||
|
) : ServerResponse(response, isOcsResponse) {
|
||||||
|
|
||||||
|
@get:Throws(JSONException::class)
|
||||||
|
val remotePaymentModeId: Long
|
||||||
|
get() {
|
||||||
|
val dataStr = getResponseStringData()
|
||||||
|
return try {
|
||||||
|
dataStr.toLong()
|
||||||
|
} catch (_: NumberFormatException) {
|
||||||
|
val obj = JSONObject(dataStr)
|
||||||
|
obj.optLong("id", obj.optLong("remoteId", 0L))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class EditRemotePaymentModeResponse(
|
||||||
|
response: VersatileProjectSyncClient.ResponseData,
|
||||||
|
isOcsResponse: Boolean
|
||||||
|
) : ServerResponse(response, isOcsResponse)
|
||||||
|
|
||||||
|
class DeleteRemotePaymentModeResponse(
|
||||||
|
response: VersatileProjectSyncClient.ResponseData,
|
||||||
|
isOcsResponse: Boolean
|
||||||
|
) : ServerResponse(response, isOcsResponse)
|
||||||
|
|
||||||
class CreateRemoteCurrencyResponse(
|
class CreateRemoteCurrencyResponse(
|
||||||
response: VersatileProjectSyncClient.ResponseData,
|
response: VersatileProjectSyncClient.ResponseData,
|
||||||
isOcsResponse: Boolean
|
isOcsResponse: Boolean
|
||||||
) : ServerResponse(response, isOcsResponse) {
|
) : ServerResponse(response, isOcsResponse) {
|
||||||
|
|
||||||
@get:Throws(JSONException::class)
|
@get:Throws(JSONException::class)
|
||||||
val stringContent: String
|
val remoteCurrencyId: Long
|
||||||
get() = getResponseStringData()
|
get() {
|
||||||
|
val dataStr = getResponseStringData()
|
||||||
|
return try {
|
||||||
|
dataStr.toLong()
|
||||||
|
} catch (_: NumberFormatException) {
|
||||||
|
val obj = JSONObject(dataStr)
|
||||||
|
obj.optLong("id", obj.optLong("remoteId", 0L))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class EditRemoteCurrencyResponse(
|
class EditRemoteCurrencyResponse(
|
||||||
response: VersatileProjectSyncClient.ResponseData,
|
response: VersatileProjectSyncClient.ResponseData,
|
||||||
isOcsResponse: Boolean
|
isOcsResponse: Boolean
|
||||||
) : ServerResponse(response, isOcsResponse) {
|
) : ServerResponse(response, isOcsResponse)
|
||||||
|
|
||||||
@get:Throws(JSONException::class)
|
|
||||||
val stringContent: String
|
|
||||||
get() = getResponseStringData()
|
|
||||||
}
|
|
||||||
|
|
||||||
class DeleteRemoteCurrencyResponse(
|
class DeleteRemoteCurrencyResponse(
|
||||||
response: VersatileProjectSyncClient.ResponseData,
|
response: VersatileProjectSyncClient.ResponseData,
|
||||||
isOcsResponse: Boolean
|
isOcsResponse: Boolean
|
||||||
) : ServerResponse(response, isOcsResponse) {
|
) : ServerResponse(response, isOcsResponse)
|
||||||
|
|
||||||
@get:Throws(JSONException::class)
|
|
||||||
val stringContent: String
|
|
||||||
get() = getResponseStringData()
|
|
||||||
}
|
|
||||||
|
|
||||||
class EditRemoteProjectResponse(
|
class EditRemoteProjectResponse(
|
||||||
response: VersatileProjectSyncClient.ResponseData,
|
response: VersatileProjectSyncClient.ResponseData,
|
||||||
isOcsResponse: Boolean
|
isOcsResponse: Boolean
|
||||||
) : ServerResponse(response, isOcsResponse) {
|
) : ServerResponse(response, isOcsResponse)
|
||||||
|
|
||||||
@get:Throws(JSONException::class)
|
|
||||||
val stringContent: String
|
|
||||||
get() = getResponseStringData()
|
|
||||||
}
|
|
||||||
|
|
||||||
class EditRemoteMemberResponse(
|
class EditRemoteMemberResponse(
|
||||||
response: VersatileProjectSyncClient.ResponseData,
|
response: VersatileProjectSyncClient.ResponseData,
|
||||||
@@ -194,8 +238,16 @@ open class ServerResponse(
|
|||||||
) : ServerResponse(response, isOcsResponse) {
|
) : ServerResponse(response, isOcsResponse) {
|
||||||
|
|
||||||
@get:Throws(JSONException::class)
|
@get:Throws(JSONException::class)
|
||||||
val stringContent: String
|
val remoteBillId: Long
|
||||||
get() = getResponseStringData()
|
get() {
|
||||||
|
val dataStr = getResponseStringData()
|
||||||
|
return try {
|
||||||
|
dataStr.toLong()
|
||||||
|
} catch (_: NumberFormatException) {
|
||||||
|
val obj = JSONObject(dataStr)
|
||||||
|
obj.optLong("id", obj.optLong("remoteId", 0L))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class CreateRemoteBillResponse(
|
class CreateRemoteBillResponse(
|
||||||
@@ -204,51 +256,54 @@ open class ServerResponse(
|
|||||||
) : ServerResponse(response, isOcsResponse) {
|
) : ServerResponse(response, isOcsResponse) {
|
||||||
|
|
||||||
@get:Throws(JSONException::class)
|
@get:Throws(JSONException::class)
|
||||||
val stringContent: String
|
val remoteBillId: Long
|
||||||
get() = getResponseStringData()
|
get() {
|
||||||
|
val dataStr = getResponseStringData()
|
||||||
|
return try {
|
||||||
|
dataStr.toLong()
|
||||||
|
} catch (_: NumberFormatException) {
|
||||||
|
val obj = JSONObject(dataStr)
|
||||||
|
obj.optLong("id", obj.optLong("remoteId", 0L))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class DeleteRemoteBillResponse(
|
class DeleteRemoteBillResponse(
|
||||||
response: VersatileProjectSyncClient.ResponseData,
|
response: VersatileProjectSyncClient.ResponseData,
|
||||||
isOcsResponse: Boolean
|
isOcsResponse: Boolean
|
||||||
) : ServerResponse(response, isOcsResponse) {
|
) : ServerResponse(response, isOcsResponse)
|
||||||
|
|
||||||
@get:Throws(JSONException::class)
|
|
||||||
val stringContent: String
|
|
||||||
get() = getResponseStringData()
|
|
||||||
}
|
|
||||||
|
|
||||||
class DeleteRemoteProjectResponse(
|
class DeleteRemoteProjectResponse(
|
||||||
response: VersatileProjectSyncClient.ResponseData,
|
response: VersatileProjectSyncClient.ResponseData,
|
||||||
isOcsResponse: Boolean
|
isOcsResponse: Boolean
|
||||||
) : ServerResponse(response, isOcsResponse) {
|
) : ServerResponse(response, isOcsResponse)
|
||||||
|
|
||||||
@get:Throws(JSONException::class)
|
|
||||||
val stringContent: String
|
|
||||||
get() = getResponseStringData()
|
|
||||||
}
|
|
||||||
|
|
||||||
class CreateRemoteProjectResponse(
|
class CreateRemoteProjectResponse(
|
||||||
response: VersatileProjectSyncClient.ResponseData,
|
response: VersatileProjectSyncClient.ResponseData,
|
||||||
isOcsResponse: Boolean
|
isOcsResponse: Boolean
|
||||||
) : ServerResponse(response, isOcsResponse) {
|
) : ServerResponse(response, isOcsResponse)
|
||||||
|
|
||||||
@get:Throws(JSONException::class)
|
|
||||||
val stringContent: String
|
|
||||||
get() = getResponseStringData()
|
|
||||||
}
|
|
||||||
|
|
||||||
class BillsResponse(response: VersatileProjectSyncClient.ResponseData, isOcsResponse: Boolean) :
|
class BillsResponse(response: VersatileProjectSyncClient.ResponseData, isOcsResponse: Boolean) :
|
||||||
ServerResponse(response, isOcsResponse) {
|
ServerResponse(response, isOcsResponse) {
|
||||||
|
|
||||||
@Throws(JSONException::class)
|
@Throws(JSONException::class)
|
||||||
fun getBillsCospend(projId: Long, memberRemoteIdToId: Map<Long, Long>): List<DBBill> {
|
fun getBillsCospend(
|
||||||
return getBillsFromJSONObject(getResponseObjectData(), projId, memberRemoteIdToId)
|
projId: Long,
|
||||||
|
memberRemoteIdToId: Map<Long, Long>,
|
||||||
|
catRemoteIdToId: Map<Long, Long>,
|
||||||
|
pmRemoteIdToId: Map<Long, Long>
|
||||||
|
): List<DBBill> {
|
||||||
|
return getBillsFromJSONObject(projId, memberRemoteIdToId, catRemoteIdToId, pmRemoteIdToId)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Throws(JSONException::class)
|
@Throws(JSONException::class)
|
||||||
fun getBillsIHM(projId: Long, memberRemoteIdToId: Map<Long, Long>): List<DBBill> {
|
fun getBillsIHM(
|
||||||
return getBillsFromJSONArray(JSONArray(content), projId, memberRemoteIdToId)
|
projId: Long,
|
||||||
|
memberRemoteIdToId: Map<Long, Long>,
|
||||||
|
catRemoteIdToId: Map<Long, Long>,
|
||||||
|
pmRemoteIdToId: Map<Long, Long>
|
||||||
|
): List<DBBill> {
|
||||||
|
return getBillsFromJSONArray(JSONArray(content), projId, memberRemoteIdToId, catRemoteIdToId, pmRemoteIdToId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -270,6 +325,32 @@ open class ServerResponse(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class CategoriesResponse(response: VersatileProjectSyncClient.ResponseData, isOcsResponse: Boolean) :
|
||||||
|
ServerResponse(response, isOcsResponse) {
|
||||||
|
|
||||||
|
@Throws(JSONException::class)
|
||||||
|
fun getCategories(projId: Long): List<DBCategory> {
|
||||||
|
return if (isOcsResponse) {
|
||||||
|
getCategoriesFromJSON(getResponseObjectData(), projId)
|
||||||
|
} else {
|
||||||
|
getCategoriesFromJSONArray(getResponseArrayData(), projId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class PaymentModesResponse(response: VersatileProjectSyncClient.ResponseData, isOcsResponse: Boolean) :
|
||||||
|
ServerResponse(response, isOcsResponse) {
|
||||||
|
|
||||||
|
@Throws(JSONException::class)
|
||||||
|
fun getPaymentModes(projId: Long): List<DBPaymentMode> {
|
||||||
|
return if (isOcsResponse) {
|
||||||
|
getPaymentModesFromJSON(getResponseObjectData(), projId)
|
||||||
|
} else {
|
||||||
|
getPaymentModesFromJSONArray(getResponseArrayData(), projId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class AccountProjectsResponse(
|
class AccountProjectsResponse(
|
||||||
response: VersatileProjectSyncClient.ResponseData,
|
response: VersatileProjectSyncClient.ResponseData,
|
||||||
isOcsResponse: Boolean
|
isOcsResponse: Boolean
|
||||||
@@ -301,17 +382,6 @@ open class ServerResponse(
|
|||||||
get() = content
|
get() = content
|
||||||
}
|
}
|
||||||
|
|
||||||
@Throws(JSONException::class)
|
|
||||||
protected fun getPublicTokenFromJSON(json: JSONObject): String? {
|
|
||||||
if (json.has("code") && json.has("sharetoken")) {
|
|
||||||
val done = json.getInt("code")
|
|
||||||
val publicToken = json.getString("sharetoken")
|
|
||||||
if (done == 1) {
|
|
||||||
return publicToken
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
@Throws(JSONException::class)
|
@Throws(JSONException::class)
|
||||||
protected fun getNameFromJSON(json: JSONObject): String {
|
protected fun getNameFromJSON(json: JSONObject): String {
|
||||||
@@ -366,6 +436,26 @@ open class ServerResponse(
|
|||||||
return members
|
return members
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Throws(JSONException::class)
|
||||||
|
protected fun getCategoriesFromJSONArray(jsonCats: JSONArray, projId: Long): List<DBCategory> {
|
||||||
|
val categories: MutableList<DBCategory> = ArrayList()
|
||||||
|
for (i in 0 until jsonCats.length()) {
|
||||||
|
val jsonCat = jsonCats.getJSONObject(i)
|
||||||
|
categories.add(getCategoryFromJSON(jsonCat, projId))
|
||||||
|
}
|
||||||
|
return categories
|
||||||
|
}
|
||||||
|
|
||||||
|
@Throws(JSONException::class)
|
||||||
|
protected fun getPaymentModesFromJSONArray(jsonPms: JSONArray, projId: Long): List<DBPaymentMode> {
|
||||||
|
val paymentModes: MutableList<DBPaymentMode> = ArrayList()
|
||||||
|
for (i in 0 until jsonPms.length()) {
|
||||||
|
val jsonPm = jsonPms.getJSONObject(i)
|
||||||
|
paymentModes.add(getPaymentModeFromJSON(jsonPm, projId))
|
||||||
|
}
|
||||||
|
return paymentModes
|
||||||
|
}
|
||||||
|
|
||||||
@Throws(JSONException::class)
|
@Throws(JSONException::class)
|
||||||
protected fun getCategoriesFromJSON(json: JSONObject, projId: Long): List<DBCategory> {
|
protected fun getCategoriesFromJSON(json: JSONObject, projId: Long): List<DBCategory> {
|
||||||
val categories: MutableList<DBCategory> = ArrayList()
|
val categories: MutableList<DBCategory> = ArrayList()
|
||||||
@@ -382,6 +472,27 @@ open class ServerResponse(
|
|||||||
return categories
|
return categories
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Throws(JSONException::class)
|
||||||
|
protected fun getCategoryFromJSON(json: JSONObject, projId: Long): DBCategory {
|
||||||
|
var remoteId: Long = 0
|
||||||
|
if (json.has("id") && !json.isNull("id")) {
|
||||||
|
remoteId = json.getLong("id")
|
||||||
|
}
|
||||||
|
var name = ""
|
||||||
|
var color = ""
|
||||||
|
var icon = ""
|
||||||
|
if (json.has("color") && !json.isNull("color")) {
|
||||||
|
color = json.getString("color")
|
||||||
|
}
|
||||||
|
if (json.has("icon") && !json.isNull("icon")) {
|
||||||
|
icon = json.getString("icon")
|
||||||
|
}
|
||||||
|
if (json.has("name") && !json.isNull("name")) {
|
||||||
|
name = json.getString("name")
|
||||||
|
}
|
||||||
|
return DBCategory(0, remoteId, projId, name, icon, color)
|
||||||
|
}
|
||||||
|
|
||||||
@Throws(JSONException::class)
|
@Throws(JSONException::class)
|
||||||
protected fun getCategoryFromJSON(json: JSONObject, remoteIdStr: String, projId: Long): DBCategory {
|
protected fun getCategoryFromJSON(json: JSONObject, remoteIdStr: String, projId: Long): DBCategory {
|
||||||
val remoteId = remoteIdStr.toLong()
|
val remoteId = remoteIdStr.toLong()
|
||||||
@@ -416,6 +527,27 @@ open class ServerResponse(
|
|||||||
return paymentModes
|
return paymentModes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Throws(JSONException::class)
|
||||||
|
protected fun getPaymentModeFromJSON(json: JSONObject, projId: Long): DBPaymentMode {
|
||||||
|
var remoteId: Long = 0
|
||||||
|
if (json.has("id") && !json.isNull("id")) {
|
||||||
|
remoteId = json.getLong("id")
|
||||||
|
}
|
||||||
|
var name = ""
|
||||||
|
var color = ""
|
||||||
|
var icon = ""
|
||||||
|
if (json.has("color") && !json.isNull("color")) {
|
||||||
|
color = json.getString("color")
|
||||||
|
}
|
||||||
|
if (json.has("icon") && !json.isNull("icon")) {
|
||||||
|
icon = json.getString("icon")
|
||||||
|
}
|
||||||
|
if (json.has("name") && !json.isNull("name")) {
|
||||||
|
name = json.getString("name")
|
||||||
|
}
|
||||||
|
return DBPaymentMode(0, remoteId, projId, name, icon, color)
|
||||||
|
}
|
||||||
|
|
||||||
@Throws(JSONException::class)
|
@Throws(JSONException::class)
|
||||||
protected fun getPaymentModeFromJSON(json: JSONObject, remoteIdStr: String, projId: Long): DBPaymentMode {
|
protected fun getPaymentModeFromJSON(json: JSONObject, remoteIdStr: String, projId: Long): DBPaymentMode {
|
||||||
val remoteId = remoteIdStr.toLong()
|
val remoteId = remoteIdStr.toLong()
|
||||||
@@ -556,26 +688,30 @@ open class ServerResponse(
|
|||||||
protected fun getBillsFromJSONArray(
|
protected fun getBillsFromJSONArray(
|
||||||
json: JSONArray,
|
json: JSONArray,
|
||||||
projId: Long,
|
projId: Long,
|
||||||
memberRemoteIdToId: Map<Long, Long>
|
memberRemoteIdToId: Map<Long, Long>,
|
||||||
|
catRemoteIdToId: Map<Long, Long>,
|
||||||
|
pmRemoteIdToId: Map<Long, Long>
|
||||||
): List<DBBill> {
|
): List<DBBill> {
|
||||||
val bills: MutableList<DBBill> = ArrayList()
|
val bills: MutableList<DBBill> = ArrayList()
|
||||||
for (i in 0 until json.length()) {
|
for (i in 0 until json.length()) {
|
||||||
val jsonBill = json.getJSONObject(i)
|
val jsonBill = json.getJSONObject(i)
|
||||||
bills.add(getBillFromJSON(jsonBill, projId, memberRemoteIdToId))
|
bills.add(getBillFromJSON(jsonBill, projId, memberRemoteIdToId, catRemoteIdToId, pmRemoteIdToId))
|
||||||
}
|
}
|
||||||
return bills
|
return bills
|
||||||
}
|
}
|
||||||
|
|
||||||
@Throws(JSONException::class)
|
@Throws(JSONException::class)
|
||||||
protected fun getBillsFromJSONObject(
|
protected fun getBillsFromJSONObject(
|
||||||
json: JSONObject,
|
|
||||||
projId: Long,
|
projId: Long,
|
||||||
memberRemoteIdToId: Map<Long, Long>
|
memberRemoteIdToId: Map<Long, Long>,
|
||||||
|
catRemoteIdToId: Map<Long, Long>,
|
||||||
|
pmRemoteIdToId: Map<Long, Long>
|
||||||
): List<DBBill> {
|
): List<DBBill> {
|
||||||
val bills: List<DBBill>
|
val bills: List<DBBill>
|
||||||
|
val json = getResponseObjectData()
|
||||||
if (json.has("bills") && !json.isNull("bills")) {
|
if (json.has("bills") && !json.isNull("bills")) {
|
||||||
val jsonBills = json.getJSONArray("bills")
|
val jsonBills = json.getJSONArray("bills")
|
||||||
bills = getBillsFromJSONArray(jsonBills, projId, memberRemoteIdToId)
|
bills = getBillsFromJSONArray(jsonBills, projId, memberRemoteIdToId, catRemoteIdToId, pmRemoteIdToId)
|
||||||
} else {
|
} else {
|
||||||
bills = ArrayList()
|
bills = ArrayList()
|
||||||
}
|
}
|
||||||
@@ -586,7 +722,9 @@ open class ServerResponse(
|
|||||||
protected fun getBillFromJSON(
|
protected fun getBillFromJSON(
|
||||||
json: JSONObject,
|
json: JSONObject,
|
||||||
projId: Long,
|
projId: Long,
|
||||||
memberRemoteIdToId: Map<Long, Long>
|
memberRemoteIdToId: Map<Long, Long>,
|
||||||
|
catRemoteIdToId: Map<Long, Long>,
|
||||||
|
pmRemoteIdToId: Map<Long, Long>
|
||||||
): DBBill {
|
): DBBill {
|
||||||
var remoteId: Long = 0
|
var remoteId: Long = 0
|
||||||
var payerRemoteId: Long
|
var payerRemoteId: Long
|
||||||
@@ -599,8 +737,8 @@ open class ServerResponse(
|
|||||||
var comment = ""
|
var comment = ""
|
||||||
var repeat = DBBill.NON_REPEATED
|
var repeat = DBBill.NON_REPEATED
|
||||||
var paymentMode = DBBill.PAYMODE_NONE
|
var paymentMode = DBBill.PAYMODE_NONE
|
||||||
var paymentModeId = DBBill.PAYMODE_ID_NONE.toLong()
|
var paymentModeRemoteId = DBBill.PAYMODE_ID_NONE
|
||||||
var categoryId = DBBill.CATEGORY_NONE.toLong()
|
var categoryRemoteId = DBBill.CATEGORY_NONE
|
||||||
if (!json.isNull("id")) {
|
if (!json.isNull("id")) {
|
||||||
remoteId = json.getLong("id")
|
remoteId = json.getLong("id")
|
||||||
}
|
}
|
||||||
@@ -639,20 +777,26 @@ open class ServerResponse(
|
|||||||
}
|
}
|
||||||
if (json.has("paymentmode") && !json.isNull("paymentmode")) {
|
if (json.has("paymentmode") && !json.isNull("paymentmode")) {
|
||||||
paymentMode = json.getString("paymentmode")
|
paymentMode = json.getString("paymentmode")
|
||||||
|
} else if (json.has("paymentMode") && !json.isNull("paymentMode")) {
|
||||||
|
paymentMode = json.getString("paymentMode")
|
||||||
}
|
}
|
||||||
if (json.has("categoryid") && !json.isNull("categoryid")) {
|
if (json.has("categoryid") && !json.isNull("categoryid")) {
|
||||||
categoryId = json.getLong("categoryid")
|
categoryRemoteId = json.getLong("categoryid")
|
||||||
Log.d("PLOP", "LOADED CATTTTTTTTTTTT $categoryId")
|
} else if (json.has("categoryId") && !json.isNull("categoryId")) {
|
||||||
|
categoryRemoteId = json.getLong("categoryId")
|
||||||
}
|
}
|
||||||
if (json.has("paymentmodeid") && !json.isNull("paymentmodeid")) {
|
if (json.has("paymentmodeid") && !json.isNull("paymentmodeid")) {
|
||||||
paymentModeId = json.getLong("paymentmodeid")
|
paymentModeRemoteId = json.getLong("paymentmodeid")
|
||||||
|
} else if (json.has("paymentModeId") && !json.isNull("paymentModeId")) {
|
||||||
|
paymentModeRemoteId = json.getLong("paymentModeId")
|
||||||
}
|
}
|
||||||
// old MB, new Cospend is ok as Cospend provides the old pm ID
|
if (DBBill.PAYMODE_NONE != paymentMode && "" != paymentMode && paymentModeRemoteId == DBBill.PAYMODE_ID_NONE) {
|
||||||
// new MB, old Cospend => set payment mode ID from old one
|
paymentModeRemoteId = DBBill.oldPmIdToNew[paymentMode] ?: DBBill.PAYMODE_ID_NONE
|
||||||
if (DBBill.PAYMODE_NONE != paymentMode && "" != paymentMode && paymentModeId == DBBill.PAYMODE_ID_NONE.toLong()) {
|
|
||||||
Log.d("PaymentMode", "old: $paymentMode and new: 0")
|
|
||||||
paymentModeId = (DBBill.oldPmIdToNew[paymentMode] ?: DBBill.PAYMODE_ID_NONE).toLong()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val categoryId = catRemoteIdToId[categoryRemoteId] ?: 0L
|
||||||
|
val paymentModeId = pmRemoteIdToId[paymentModeRemoteId] ?: 0L
|
||||||
|
|
||||||
val bill = DBBill(
|
val bill = DBBill(
|
||||||
0, remoteId, projId, payerId, amount, timestamp, what,
|
0, remoteId, projId, payerId, amount, timestamp, what,
|
||||||
DBBill.STATE_OK, repeat, paymentMode, categoryId, comment, paymentModeId
|
DBBill.STATE_OK, repeat, paymentMode, categoryId, comment, paymentModeId
|
||||||
@@ -667,7 +811,9 @@ open class ServerResponse(
|
|||||||
memberRemoteIdToId: Map<Long, Long>
|
memberRemoteIdToId: Map<Long, Long>
|
||||||
): List<DBBillOwer> {
|
): List<DBBillOwer> {
|
||||||
val billOwers: MutableList<DBBillOwer> = ArrayList()
|
val billOwers: MutableList<DBBillOwer> = ArrayList()
|
||||||
if (json.has("owers")) {
|
// As everywhere else here, an explicitly null value is not a value: getJSONArray would
|
||||||
|
// throw on it, and that exception fails the whole project sync over one bill.
|
||||||
|
if (json.has("owers") && !json.isNull("owers")) {
|
||||||
val jsonOs = json.getJSONArray("owers")
|
val jsonOs = json.getJSONArray("owers")
|
||||||
for (i in 0 until jsonOs.length()) {
|
for (i in 0 until jsonOs.length()) {
|
||||||
val obj = jsonOs.get(i)
|
val obj = jsonOs.get(i)
|
||||||
@@ -705,6 +851,8 @@ open class ServerResponse(
|
|||||||
remoteId = json.getString("id")
|
remoteId = json.getString("id")
|
||||||
}
|
}
|
||||||
if (!json.isNull("ncurl")) {
|
if (!json.isNull("ncurl")) {
|
||||||
|
ncUrl = json.getString("ncurl")
|
||||||
|
} else if (!json.isNull("ncUrl")) {
|
||||||
ncUrl = json.getString("ncUrl")
|
ncUrl = json.getString("ncUrl")
|
||||||
}
|
}
|
||||||
val archivedTs: Long? = getArchivedTsFromJSON(json)
|
val archivedTs: Long? = getArchivedTsFromJSON(json)
|
||||||
@@ -714,26 +862,6 @@ open class ServerResponse(
|
|||||||
return DBAccountProject(0, remoteId, null, name, ncUrl, archivedTs)
|
return DBAccountProject(0, remoteId, null, name, ncUrl, archivedTs)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Throws(IOException::class)
|
|
||||||
protected fun getColorFromContent(content: String): String? {
|
|
||||||
var result: String? = null
|
|
||||||
try {
|
|
||||||
val dbf = DocumentBuilderFactory.newInstance()
|
|
||||||
val db = dbf.newDocumentBuilder()
|
|
||||||
val stream: InputStream = ByteArrayInputStream(content.toByteArray())
|
|
||||||
val doc = db.parse(stream)
|
|
||||||
doc.documentElement.normalize()
|
|
||||||
// Locate the Tag Name
|
|
||||||
val nodeList = doc.getElementsByTagName("color")
|
|
||||||
if (nodeList.length > 0) {
|
|
||||||
result = nodeList.item(0).textContent
|
|
||||||
Log.i(TAG, "I GOT THE COLOR from server: $result")
|
|
||||||
}
|
|
||||||
} catch (_: ParserConfigurationException) {
|
|
||||||
} catch (_: SAXException) {
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
protected fun getColorFromJsonContent(json: JSONObject): String? {
|
protected fun getColorFromJsonContent(json: JSONObject): String? {
|
||||||
return try {
|
return try {
|
||||||
|
|||||||
@@ -87,14 +87,17 @@ object SupportUtil {
|
|||||||
membersBalance: MutableMap<Long, Double>,
|
membersBalance: MutableMap<Long, Double>,
|
||||||
membersPaid: MutableMap<Long, Double>,
|
membersPaid: MutableMap<Long, Double>,
|
||||||
membersSpent: MutableMap<Long, Double>,
|
membersSpent: MutableMap<Long, Double>,
|
||||||
catId: Int, paymentModeId: Int,
|
catId: Long, paymentModeId: Long,
|
||||||
dateMin: String?, dateMax: String?
|
dateMin: String?, dateMax: String?
|
||||||
): Int {
|
): Int {
|
||||||
|
val proj = db.getProject(projId)
|
||||||
|
val categories = db.getCategories(projId)
|
||||||
|
val reimbursementCategoryId = CategoryUtils.getReimbursementCategoryId(categories, projId, proj?.remoteId)
|
||||||
return getStats(
|
return getStats(
|
||||||
db.getMembersOfProject(projId, null),
|
db.getMembersOfProject(projId, null),
|
||||||
db.getBillsOfProject(projId),
|
db.getBillsOfProject(projId),
|
||||||
membersNbBills, membersBalance, membersPaid, membersSpent,
|
membersNbBills, membersBalance, membersPaid, membersSpent,
|
||||||
catId, paymentModeId, dateMin, dateMax
|
catId, paymentModeId, reimbursementCategoryId, dateMin, dateMax
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,7 +109,8 @@ object SupportUtil {
|
|||||||
membersBalance: MutableMap<Long, Double>,
|
membersBalance: MutableMap<Long, Double>,
|
||||||
membersPaid: MutableMap<Long, Double>,
|
membersPaid: MutableMap<Long, Double>,
|
||||||
membersSpent: MutableMap<Long, Double>,
|
membersSpent: MutableMap<Long, Double>,
|
||||||
catId: Int, paymentModeId: Int,
|
catId: Long, paymentModeId: Long,
|
||||||
|
reimbursementCategoryId: Long,
|
||||||
dateMin: String?, dateMax: String?
|
dateMin: String?, dateMax: String?
|
||||||
): Int {
|
): Int {
|
||||||
val nbBillsTotal = 0
|
val nbBillsTotal = 0
|
||||||
@@ -124,9 +128,9 @@ object SupportUtil {
|
|||||||
for (b in dbBills) {
|
for (b in dbBills) {
|
||||||
// don't take deleted bills and respect category filter
|
// don't take deleted bills and respect category filter
|
||||||
if (b.state != DBBill.STATE_DELETED &&
|
if (b.state != DBBill.STATE_DELETED &&
|
||||||
((catId == -1000 || catId == -100 || b.categoryId == catId.toLong()) &&
|
((catId == -1000L || catId == -100L || b.categoryId == catId) &&
|
||||||
(catId != -100 || b.categoryId != DBBill.CATEGORY_REIMBURSEMENT.toLong()) &&
|
(catId != -100L || b.categoryId != reimbursementCategoryId) &&
|
||||||
(paymentModeId == -1000 || b.paymentModeId == paymentModeId.toLong())) &&
|
(paymentModeId == -1000L || b.paymentModeId == paymentModeId)) &&
|
||||||
(dateMin == null || b.date >= dateMin) &&
|
(dateMin == null || b.date >= dateMin) &&
|
||||||
(dateMax == null || b.date <= dateMax)
|
(dateMax == null || b.date <= dateMax)
|
||||||
) {
|
) {
|
||||||
@@ -285,18 +289,6 @@ object SupportUtil {
|
|||||||
return reduceBalance(crediters, debiters, results)
|
return reduceBalance(crediters, debiters, results)
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
fun getVersionName(context: Context): String {
|
|
||||||
var versionName = "0.0.0"
|
|
||||||
try {
|
|
||||||
val pInfo = context.packageManager.getPackageInfo(context.packageName, 0)
|
|
||||||
versionName = pInfo.versionName ?: "0.0.0"
|
|
||||||
} catch (e: PackageManager.NameNotFoundException) {
|
|
||||||
e.printStackTrace()
|
|
||||||
}
|
|
||||||
return versionName
|
|
||||||
}
|
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun getJsonObject(text: String?): JSONObject? {
|
fun getJsonObject(text: String?): JSONObject? {
|
||||||
if (text == null) return null
|
if (text == null) return null
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package net.helcel.cowspent.util
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.preference.PreferenceManager
|
||||||
|
import net.helcel.cowspent.R
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The SyncOnOpen preference: how often opening the app refreshes the account and every project.
|
||||||
|
*
|
||||||
|
* The choices and the default live here rather than in the settings screen so that the screen and
|
||||||
|
* the sync trigger cannot disagree about what is in effect.
|
||||||
|
*/
|
||||||
|
object SyncSettings {
|
||||||
|
|
||||||
|
/** Steps offered by the slider, in minutes. */
|
||||||
|
val INTERVAL_CHOICES_MINUTES = listOf(1, 10, 60, 1440)
|
||||||
|
|
||||||
|
const val DEFAULT_INTERVAL_MINUTES = 10
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The configured interval in minutes. A stored value that is not one of the offered steps —
|
||||||
|
* from a restored backup, or a build that changed the steps — falls back to the default
|
||||||
|
* rather than being displayed as the first step while a different value drives the sync.
|
||||||
|
*/
|
||||||
|
fun intervalMinutes(context: Context): Int {
|
||||||
|
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
|
val stored = prefs.getInt(
|
||||||
|
context.getString(R.string.pref_key_auto_sync_on_open),
|
||||||
|
DEFAULT_INTERVAL_MINUTES
|
||||||
|
)
|
||||||
|
return if (stored in INTERVAL_CHOICES_MINUTES) stored else DEFAULT_INTERVAL_MINUTES
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,8 +11,10 @@ import com.nextcloud.android.sso.exceptions.NextcloudHttpRequestFailedException
|
|||||||
import com.nextcloud.android.sso.exceptions.TokenMismatchException
|
import com.nextcloud.android.sso.exceptions.TokenMismatchException
|
||||||
import com.nextcloud.android.sso.model.SingleSignOnAccount
|
import com.nextcloud.android.sso.model.SingleSignOnAccount
|
||||||
import net.helcel.cowspent.model.DBBill
|
import net.helcel.cowspent.model.DBBill
|
||||||
|
import net.helcel.cowspent.model.DBCategory
|
||||||
import net.helcel.cowspent.model.DBCurrency
|
import net.helcel.cowspent.model.DBCurrency
|
||||||
import net.helcel.cowspent.model.DBMember
|
import net.helcel.cowspent.model.DBMember
|
||||||
|
import net.helcel.cowspent.model.DBPaymentMode
|
||||||
import net.helcel.cowspent.model.DBProject
|
import net.helcel.cowspent.model.DBProject
|
||||||
import net.helcel.cowspent.model.ProjectType
|
import net.helcel.cowspent.model.ProjectType
|
||||||
import org.json.JSONException
|
import org.json.JSONException
|
||||||
@@ -45,6 +47,8 @@ class VersatileProjectSyncClient(
|
|||||||
gt
|
gt
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val supportsPagedBills: Boolean get() = cospendVersionGT161
|
||||||
|
|
||||||
fun canAccessProjectWithNCLogin(project: DBProject): Boolean {
|
fun canAccessProjectWithNCLogin(project: DBProject): Boolean {
|
||||||
return (project.password == ""
|
return (project.password == ""
|
||||||
&& url.replace("/+$".toRegex(), "") != ""
|
&& url.replace("/+$".toRegex(), "") != ""
|
||||||
@@ -82,13 +86,11 @@ class VersatileProjectSyncClient(
|
|||||||
project.getRequestBaseUrl(false) + "/api-priv/projects/" + project.remoteId
|
project.getRequestBaseUrl(false) + "/api-priv/projects/" + project.remoteId
|
||||||
useOcsApiRequest = cospendVersionGT161
|
useOcsApiRequest = cospendVersionGT161
|
||||||
} else if (canAccessProjectWithSSO(project)) {
|
} else if (canAccessProjectWithSSO(project)) {
|
||||||
return if (cospendVersionGT161) {
|
target = if (cospendVersionGT161)
|
||||||
target = "/ocs/v2.php/apps/cospend/api/v1/projects/" + project.remoteId
|
"/ocs/v2.php/apps/cospend/api/v1/projects/" + project.remoteId
|
||||||
ServerResponse.ProjectResponse(requestServerWithSSO(nextcloudAPI!!, target, METHOD_GET, null, null, true), true)
|
else
|
||||||
} else {
|
"/index.php/apps/cospend/api-priv/projects/" + project.remoteId
|
||||||
target = "/index.php/apps/cospend/api-priv/projects/" + project.remoteId
|
return ServerResponse.ProjectResponse(requestServerWithSSO(nextcloudAPI!!, target, METHOD_GET, null, null, cospendVersionGT161), cospendVersionGT161)
|
||||||
ServerResponse.ProjectResponse(requestServerWithSSO(nextcloudAPI!!, target, METHOD_GET, null, null, false), false)
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
useOcsApiRequest = cospendVersionGT161
|
useOcsApiRequest = cospendVersionGT161
|
||||||
target = if (cospendVersionGT161)
|
target = if (cospendVersionGT161)
|
||||||
@@ -114,7 +116,7 @@ class VersatileProjectSyncClient(
|
|||||||
@Throws(IOException::class, TokenMismatchException::class, NextcloudHttpRequestFailedException::class)
|
@Throws(IOException::class, TokenMismatchException::class, NextcloudHttpRequestFailedException::class)
|
||||||
fun editRemoteProject(
|
fun editRemoteProject(
|
||||||
project: DBProject, newName: String?, newEmail: String?, newPassword: String?,
|
project: DBProject, newName: String?, newEmail: String?, newPassword: String?,
|
||||||
newMainCurrencyName: String?
|
newMainCurrencyName: String?, newArchivedTs: Long? = null
|
||||||
): ServerResponse.EditRemoteProjectResponse {
|
): ServerResponse.EditRemoteProjectResponse {
|
||||||
val paramKeys: MutableList<String> = ArrayList()
|
val paramKeys: MutableList<String> = ArrayList()
|
||||||
val paramValues: MutableList<String> = ArrayList()
|
val paramValues: MutableList<String> = ArrayList()
|
||||||
@@ -130,6 +132,10 @@ class VersatileProjectSyncClient(
|
|||||||
paramKeys.add("password")
|
paramKeys.add("password")
|
||||||
paramValues.add(newPassword)
|
paramValues.add(newPassword)
|
||||||
}
|
}
|
||||||
|
if (newArchivedTs != null) {
|
||||||
|
paramKeys.add("archived_ts")
|
||||||
|
paramValues.add(newArchivedTs.toString())
|
||||||
|
}
|
||||||
|
|
||||||
var target: String
|
var target: String
|
||||||
var username: String? = null
|
var username: String? = null
|
||||||
@@ -154,10 +160,18 @@ class VersatileProjectSyncClient(
|
|||||||
paramKeys.add("password")
|
paramKeys.add("password")
|
||||||
paramValues.add(newPassword)
|
paramValues.add(newPassword)
|
||||||
}
|
}
|
||||||
|
if (newEmail != null) {
|
||||||
|
paramKeys.add("contact_email")
|
||||||
|
paramValues.add(newEmail)
|
||||||
|
}
|
||||||
if (newMainCurrencyName != null) {
|
if (newMainCurrencyName != null) {
|
||||||
paramKeys.add("currencyName")
|
paramKeys.add("currencyName")
|
||||||
paramValues.add(newMainCurrencyName)
|
paramValues.add(newMainCurrencyName)
|
||||||
}
|
}
|
||||||
|
if (newArchivedTs != null) {
|
||||||
|
paramKeys.add("archivedTs")
|
||||||
|
paramValues.add(newArchivedTs.toString())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (canAccessProjectWithNCLogin(project)) {
|
if (canAccessProjectWithNCLogin(project)) {
|
||||||
username = this.username
|
username = this.username
|
||||||
@@ -313,10 +327,8 @@ class VersatileProjectSyncClient(
|
|||||||
payedFor = payedFor.replace(",$".toRegex(), "")
|
payedFor = payedFor.replace(",$".toRegex(), "")
|
||||||
paramValues.add(payedFor)
|
paramValues.add(payedFor)
|
||||||
paramValues.add(bill.paymentMode ?: "")
|
paramValues.add(bill.paymentMode ?: "")
|
||||||
val remoteCatId = if (bill.categoryId <= 0) bill.categoryId else categoryIdToRemoteId[bill.categoryId] ?: 0
|
paramValues.add((categoryIdToRemoteId[bill.categoryId] ?: 0L).toString())
|
||||||
val remotePmId = if (bill.paymentModeId <= 0) bill.paymentModeId else paymentModeIdToRemoteId[bill.paymentModeId] ?: 0
|
paramValues.add((paymentModeIdToRemoteId[bill.paymentModeId] ?: 0L).toString())
|
||||||
paramValues.add(remoteCatId.toString())
|
|
||||||
paramValues.add(remotePmId.toString())
|
|
||||||
|
|
||||||
if (canAccessProjectWithNCLogin(project)) {
|
if (canAccessProjectWithNCLogin(project)) {
|
||||||
username = this.username
|
username = this.username
|
||||||
@@ -568,10 +580,8 @@ class VersatileProjectSyncClient(
|
|||||||
payedFor = payedFor.replace(",$".toRegex(), "")
|
payedFor = payedFor.replace(",$".toRegex(), "")
|
||||||
paramValues.add(payedFor)
|
paramValues.add(payedFor)
|
||||||
paramValues.add(bill.paymentMode ?: "")
|
paramValues.add(bill.paymentMode ?: "")
|
||||||
val remoteCatId = if (bill.categoryId <= 0) bill.categoryId else categoryIdToRemoteId[bill.categoryId] ?: 0
|
paramValues.add((categoryIdToRemoteId[bill.categoryId] ?: 0L).toString())
|
||||||
val remotePmId = if (bill.paymentModeId <= 0) bill.paymentModeId else paymentModeIdToRemoteId[bill.paymentModeId] ?: 0
|
paramValues.add((paymentModeIdToRemoteId[bill.paymentModeId] ?: 0L).toString())
|
||||||
paramValues.add(remoteCatId.toString())
|
|
||||||
paramValues.add(remotePmId.toString())
|
|
||||||
|
|
||||||
if (canAccessProjectWithNCLogin(project)) {
|
if (canAccessProjectWithNCLogin(project)) {
|
||||||
username = this.username
|
username = this.username
|
||||||
@@ -650,7 +660,6 @@ class VersatileProjectSyncClient(
|
|||||||
} else if (canAccessProjectWithSSO(project)) {
|
} else if (canAccessProjectWithSSO(project)) {
|
||||||
return if (cospendVersionGT161) {
|
return if (cospendVersionGT161) {
|
||||||
target = "/ocs/v2.php/apps/cospend/api/v1/projects/" + project.remoteId + "/members"
|
target = "/ocs/v2.php/apps/cospend/api/v1/projects/" + project.remoteId + "/members"
|
||||||
Log.i(TAG, "using new API for createRemoteBill")
|
|
||||||
ServerResponse.CreateRemoteMemberResponse(requestServerWithSSO(nextcloudAPI!!, target, METHOD_POST, paramKeys, paramValues, true), isOcsResponse=true, isJsonMember=true)
|
ServerResponse.CreateRemoteMemberResponse(requestServerWithSSO(nextcloudAPI!!, target, METHOD_POST, paramKeys, paramValues, true), isOcsResponse=true, isJsonMember=true)
|
||||||
} else {
|
} else {
|
||||||
target = "/index.php/apps/cospend/api-priv/projects/" + project.remoteId + "/members"
|
target = "/index.php/apps/cospend/api-priv/projects/" + project.remoteId + "/members"
|
||||||
@@ -680,22 +689,66 @@ class VersatileProjectSyncClient(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Throws(JSONException::class, IOException::class, TokenMismatchException::class, NextcloudHttpRequestFailedException::class)
|
@Throws(JSONException::class, IOException::class, TokenMismatchException::class, NextcloudHttpRequestFailedException::class)
|
||||||
fun getBills(project: DBProject): ServerResponse.BillsResponse {
|
fun getBills(
|
||||||
|
project: DBProject,
|
||||||
|
offset: Int? = null,
|
||||||
|
limit: Int? = null,
|
||||||
|
reverse: Boolean? = null,
|
||||||
|
deleted: Int? = null
|
||||||
|
): ServerResponse.BillsResponse {
|
||||||
var target: String
|
var target: String
|
||||||
var username: String?
|
var username: String?
|
||||||
var password: String?
|
var password: String?
|
||||||
var bearerToken: String?
|
var bearerToken: String?
|
||||||
var useOcsApiRequest: Boolean
|
var useOcsApiRequest: Boolean
|
||||||
|
|
||||||
|
val paramKeys: MutableList<String> = ArrayList()
|
||||||
|
val paramValues: MutableList<String> = ArrayList()
|
||||||
|
|
||||||
if (ProjectType.COSPEND == project.type) {
|
if (ProjectType.COSPEND == project.type) {
|
||||||
val tsLastSync = project.lastSyncedTimestamp
|
val tsLastSync = project.lastSyncedTimestamp
|
||||||
|
if (offset == null) {
|
||||||
|
if (cospendVersionGT161) {
|
||||||
|
paramKeys.add("lastChanged")
|
||||||
|
} else {
|
||||||
|
paramKeys.add("lastchanged")
|
||||||
|
}
|
||||||
|
paramValues.add(tsLastSync.toString())
|
||||||
|
} else {
|
||||||
|
paramKeys.add("offset")
|
||||||
|
paramValues.add(offset.toString())
|
||||||
|
if (limit != null) {
|
||||||
|
paramKeys.add("limit")
|
||||||
|
paramValues.add(limit.toString())
|
||||||
|
}
|
||||||
|
if (reverse != null) {
|
||||||
|
paramKeys.add("reverse")
|
||||||
|
paramValues.add(reverse.toString())
|
||||||
|
}
|
||||||
|
if (deleted != null) {
|
||||||
|
paramKeys.add("deleted")
|
||||||
|
paramValues.add(deleted.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (canAccessProjectWithNCLogin(project)) {
|
if (canAccessProjectWithNCLogin(project)) {
|
||||||
username = this.username
|
username = this.username
|
||||||
password = this.password
|
password = this.password
|
||||||
target = if (cospendVersionGT161)
|
|
||||||
project.getRequestBaseUrl(true) + "/api/v1/projects/" + project.remoteId + "/bills?lastChanged=" + tsLastSync
|
|
||||||
else
|
|
||||||
project.getRequestBaseUrl(false) + "/api-priv/projects/" + project.remoteId + "/bills?lastchanged=" + tsLastSync
|
|
||||||
useOcsApiRequest = cospendVersionGT161
|
useOcsApiRequest = cospendVersionGT161
|
||||||
|
val baseUrl = project.getRequestBaseUrl(useOcsApiRequest)
|
||||||
|
target = if (useOcsApiRequest)
|
||||||
|
"$baseUrl/api/v1/projects/${project.remoteId}/bills"
|
||||||
|
else
|
||||||
|
"$baseUrl/api-priv/projects/${project.remoteId}/bills"
|
||||||
|
|
||||||
|
if (paramKeys.isNotEmpty()) {
|
||||||
|
target += "?"
|
||||||
|
for (i in paramKeys.indices) {
|
||||||
|
if (i > 0) target += "&"
|
||||||
|
target += "${paramKeys[i]}=${paramValues[i]}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return ServerResponse.BillsResponse(
|
return ServerResponse.BillsResponse(
|
||||||
requestServer(
|
requestServer(
|
||||||
target, METHOD_GET, null, null,
|
target, METHOD_GET, null, null,
|
||||||
@@ -704,17 +757,8 @@ class VersatileProjectSyncClient(
|
|||||||
useOcsApiRequest
|
useOcsApiRequest
|
||||||
)
|
)
|
||||||
} else if (canAccessProjectWithSSO(project)) {
|
} else if (canAccessProjectWithSSO(project)) {
|
||||||
val paramKeys: MutableList<String> = ArrayList()
|
|
||||||
val paramValues: MutableList<String> = ArrayList()
|
|
||||||
if (cospendVersionGT161) {
|
|
||||||
paramKeys.add("lastChanged")
|
|
||||||
} else {
|
|
||||||
paramKeys.add("lastchanged")
|
|
||||||
}
|
|
||||||
paramValues.add(tsLastSync.toString())
|
|
||||||
return if (cospendVersionGT161) {
|
return if (cospendVersionGT161) {
|
||||||
target = "/ocs/v2.php/apps/cospend/api/v1/projects/" + project.remoteId + "/bills"
|
target = "/ocs/v2.php/apps/cospend/api/v1/projects/" + project.remoteId + "/bills"
|
||||||
Log.i(TAG, "using new API for getBills")
|
|
||||||
ServerResponse.BillsResponse(requestServerWithSSO(nextcloudAPI!!, target, METHOD_GET, paramKeys, paramValues, true), true)
|
ServerResponse.BillsResponse(requestServerWithSSO(nextcloudAPI!!, target, METHOD_GET, paramKeys, paramValues, true), true)
|
||||||
} else {
|
} else {
|
||||||
target = "/index.php/apps/cospend/api-priv/projects/" + project.remoteId + "/bills"
|
target = "/index.php/apps/cospend/api-priv/projects/" + project.remoteId + "/bills"
|
||||||
@@ -722,10 +766,20 @@ class VersatileProjectSyncClient(
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
useOcsApiRequest = cospendVersionGT161
|
useOcsApiRequest = cospendVersionGT161
|
||||||
target = if (cospendVersionGT161)
|
val baseUrl = project.getRequestBaseUrl(useOcsApiRequest)
|
||||||
project.getRequestBaseUrl(true) + "/api/v1/public/projects/" + project.remoteId + "/" + getEncodedPassword(project.password) + "/bills?lastChanged=" + tsLastSync
|
target = if (useOcsApiRequest)
|
||||||
|
"$baseUrl/api/v1/public/projects/${project.remoteId}/${getEncodedPassword(project.password)}/bills"
|
||||||
else
|
else
|
||||||
project.getRequestBaseUrl(false) + "/apiv2/projects/" + project.remoteId + "/" + getEncodedPassword(project.password) + "/bills?lastchanged=" + tsLastSync
|
"$baseUrl/apiv2/projects/${project.remoteId}/${getEncodedPassword(project.password)}/bills"
|
||||||
|
|
||||||
|
if (paramKeys.isNotEmpty()) {
|
||||||
|
target += "?"
|
||||||
|
for (i in paramKeys.indices) {
|
||||||
|
if (i > 0) target += "&"
|
||||||
|
target += "${paramKeys[i]}=${paramValues[i]}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return ServerResponse.BillsResponse(
|
return ServerResponse.BillsResponse(
|
||||||
requestServer(
|
requestServer(
|
||||||
target, METHOD_GET, null, null,
|
target, METHOD_GET, null, null,
|
||||||
@@ -749,6 +803,92 @@ class VersatileProjectSyncClient(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Throws(JSONException::class, IOException::class, TokenMismatchException::class, NextcloudHttpRequestFailedException::class)
|
||||||
|
fun getCategories(project: DBProject): ServerResponse.CategoriesResponse {
|
||||||
|
var target: String
|
||||||
|
var username: String? = null
|
||||||
|
var password: String? = null
|
||||||
|
var bearerToken: String? = null
|
||||||
|
var useOcsApiRequest = false
|
||||||
|
if (ProjectType.COSPEND == project.type) {
|
||||||
|
if (canAccessProjectWithNCLogin(project)) {
|
||||||
|
username = this.username
|
||||||
|
password = this.password
|
||||||
|
target = if (cospendVersionGT161)
|
||||||
|
project.getRequestBaseUrl(true) + "/api/v1/projects/" + project.remoteId
|
||||||
|
else
|
||||||
|
project.getRequestBaseUrl(false) + "/api-priv/projects/" + project.remoteId + "/categories"
|
||||||
|
useOcsApiRequest = cospendVersionGT161
|
||||||
|
} else if (canAccessProjectWithSSO(project)) {
|
||||||
|
target = if (cospendVersionGT161)
|
||||||
|
"/ocs/v2.php/apps/cospend/api/v1/projects/" + project.remoteId
|
||||||
|
else
|
||||||
|
"/index.php/apps/cospend/api-priv/projects/" + project.remoteId + "/categories"
|
||||||
|
return ServerResponse.CategoriesResponse(requestServerWithSSO(nextcloudAPI!!, target, METHOD_GET, null, null, cospendVersionGT161), cospendVersionGT161)
|
||||||
|
} else {
|
||||||
|
useOcsApiRequest = cospendVersionGT161
|
||||||
|
target = if (cospendVersionGT161)
|
||||||
|
project.getRequestBaseUrl(true) + "/api/v1/public/projects/" + project.remoteId + "/" + getEncodedPassword(project.password)
|
||||||
|
else
|
||||||
|
project.getRequestBaseUrl(false) + "/api/projects/" + project.remoteId + "/" + getEncodedPassword(project.password) + "/categories"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
target = project.serverUrl!!.replace("/+$".toRegex(), "") + "/api/projects/" + project.remoteId + "/categories"
|
||||||
|
username = project.remoteId
|
||||||
|
password = project.password
|
||||||
|
bearerToken = project.bearerToken
|
||||||
|
}
|
||||||
|
return ServerResponse.CategoriesResponse(
|
||||||
|
requestServer(
|
||||||
|
target, METHOD_GET, null, null,
|
||||||
|
null, username, password, bearerToken, useOcsApiRequest
|
||||||
|
), useOcsApiRequest
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Throws(JSONException::class, IOException::class, TokenMismatchException::class, NextcloudHttpRequestFailedException::class)
|
||||||
|
fun getPaymentModes(project: DBProject): ServerResponse.PaymentModesResponse {
|
||||||
|
var target: String
|
||||||
|
var username: String? = null
|
||||||
|
var password: String? = null
|
||||||
|
var bearerToken: String? = null
|
||||||
|
var useOcsApiRequest = false
|
||||||
|
if (ProjectType.COSPEND == project.type) {
|
||||||
|
if (canAccessProjectWithNCLogin(project)) {
|
||||||
|
username = this.username
|
||||||
|
password = this.password
|
||||||
|
target = if (cospendVersionGT161)
|
||||||
|
project.getRequestBaseUrl(true) + "/api/v1/projects/" + project.remoteId
|
||||||
|
else
|
||||||
|
project.getRequestBaseUrl(false) + "/api-priv/projects/" + project.remoteId + "/paymentmodes"
|
||||||
|
useOcsApiRequest = cospendVersionGT161
|
||||||
|
} else if (canAccessProjectWithSSO(project)) {
|
||||||
|
target = if (cospendVersionGT161)
|
||||||
|
"/ocs/v2.php/apps/cospend/api/v1/projects/" + project.remoteId
|
||||||
|
else
|
||||||
|
"/index.php/apps/cospend/api-priv/projects/" + project.remoteId + "/paymentmodes"
|
||||||
|
return ServerResponse.PaymentModesResponse(requestServerWithSSO(nextcloudAPI!!, target, METHOD_GET, null, null, cospendVersionGT161), cospendVersionGT161)
|
||||||
|
} else {
|
||||||
|
useOcsApiRequest = cospendVersionGT161
|
||||||
|
target = if (cospendVersionGT161)
|
||||||
|
project.getRequestBaseUrl(true) + "/api/v1/public/projects/" + project.remoteId + "/" + getEncodedPassword(project.password)
|
||||||
|
else
|
||||||
|
project.getRequestBaseUrl(false) + "/api/projects/" + project.remoteId + "/" + getEncodedPassword(project.password) + "/paymentmodes"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
target = project.serverUrl!!.replace("/+$".toRegex(), "") + "/api/projects/" + project.remoteId + "/paymentmodes"
|
||||||
|
username = project.remoteId
|
||||||
|
password = project.password
|
||||||
|
bearerToken = project.bearerToken
|
||||||
|
}
|
||||||
|
return ServerResponse.PaymentModesResponse(
|
||||||
|
requestServer(
|
||||||
|
target, METHOD_GET, null, null,
|
||||||
|
null, username, password, bearerToken, useOcsApiRequest
|
||||||
|
), useOcsApiRequest
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@Throws(JSONException::class, IOException::class, TokenMismatchException::class, NextcloudHttpRequestFailedException::class)
|
@Throws(JSONException::class, IOException::class, TokenMismatchException::class, NextcloudHttpRequestFailedException::class)
|
||||||
fun getMembers(project: DBProject): ServerResponse.MembersResponse {
|
fun getMembers(project: DBProject): ServerResponse.MembersResponse {
|
||||||
var target: String
|
var target: String
|
||||||
@@ -795,6 +935,305 @@ class VersatileProjectSyncClient(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Throws(IOException::class, TokenMismatchException::class, NextcloudHttpRequestFailedException::class)
|
||||||
|
fun createRemoteCategory(project: DBProject, category: DBCategory): ServerResponse.CreateRemoteCategoryResponse {
|
||||||
|
val paramKeys: MutableList<String> = ArrayList()
|
||||||
|
val paramValues: MutableList<String> = ArrayList()
|
||||||
|
paramKeys.add("name")
|
||||||
|
paramValues.add(category.name ?: "")
|
||||||
|
paramKeys.add("icon")
|
||||||
|
paramValues.add(category.icon)
|
||||||
|
paramKeys.add("color")
|
||||||
|
paramValues.add(category.color)
|
||||||
|
|
||||||
|
var target: String
|
||||||
|
var username: String? = null
|
||||||
|
var password: String? = null
|
||||||
|
var bearerToken: String? = null
|
||||||
|
var useOcsApiRequest = false
|
||||||
|
if (ProjectType.COSPEND == project.type) {
|
||||||
|
if (canAccessProjectWithNCLogin(project)) {
|
||||||
|
username = this.username
|
||||||
|
password = this.password
|
||||||
|
target = if (cospendVersionGT161)
|
||||||
|
project.getRequestBaseUrl(true) + "/api/v1/projects/" + project.remoteId + "/category"
|
||||||
|
else
|
||||||
|
project.getRequestBaseUrl(false) + "/api-priv/projects/" + project.remoteId + "/categories"
|
||||||
|
useOcsApiRequest = cospendVersionGT161
|
||||||
|
} else if (canAccessProjectWithSSO(project)) {
|
||||||
|
target = if (cospendVersionGT161)
|
||||||
|
"/ocs/v2.php/apps/cospend/api/v1/projects/" + project.remoteId + "/category"
|
||||||
|
else
|
||||||
|
"/index.php/apps/cospend/api-priv/projects/" + project.remoteId + "/categories"
|
||||||
|
return ServerResponse.CreateRemoteCategoryResponse(requestServerWithSSO(nextcloudAPI!!, target, METHOD_POST, paramKeys, paramValues, cospendVersionGT161), cospendVersionGT161)
|
||||||
|
} else {
|
||||||
|
useOcsApiRequest = cospendVersionGT161
|
||||||
|
target = if (cospendVersionGT161)
|
||||||
|
project.getRequestBaseUrl(true) + "/api/v1/public/projects/" + project.remoteId + "/" + getEncodedPassword(project.password) + "/category"
|
||||||
|
else
|
||||||
|
project.getRequestBaseUrl(false) + "/api/projects/" + project.remoteId + "/" + getEncodedPassword(project.password) + "/categories"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
target = project.serverUrl!!.replace("/+$".toRegex(), "") + "/api/projects/" + project.remoteId + "/categories"
|
||||||
|
username = project.remoteId
|
||||||
|
password = project.password
|
||||||
|
bearerToken = project.bearerToken
|
||||||
|
}
|
||||||
|
|
||||||
|
val response = requestServer(
|
||||||
|
target, METHOD_POST, paramKeys, paramValues, null,
|
||||||
|
username, password, bearerToken, useOcsApiRequest
|
||||||
|
)
|
||||||
|
return ServerResponse.CreateRemoteCategoryResponse(response, useOcsApiRequest)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Throws(IOException::class, TokenMismatchException::class, NextcloudHttpRequestFailedException::class)
|
||||||
|
fun editRemoteCategory(project: DBProject, category: DBCategory): ServerResponse.EditRemoteCategoryResponse {
|
||||||
|
val paramKeys: MutableList<String> = ArrayList()
|
||||||
|
val paramValues: MutableList<String> = ArrayList()
|
||||||
|
paramKeys.add("name")
|
||||||
|
paramValues.add(category.name ?: "")
|
||||||
|
paramKeys.add("icon")
|
||||||
|
paramValues.add(category.icon)
|
||||||
|
paramKeys.add("color")
|
||||||
|
paramValues.add(category.color)
|
||||||
|
|
||||||
|
var target: String
|
||||||
|
var username: String? = null
|
||||||
|
var password: String? = null
|
||||||
|
var bearerToken: String? = null
|
||||||
|
var useOcsApiRequest = false
|
||||||
|
if (ProjectType.COSPEND == project.type) {
|
||||||
|
if (canAccessProjectWithNCLogin(project)) {
|
||||||
|
username = this.username
|
||||||
|
password = this.password
|
||||||
|
target = if (cospendVersionGT161)
|
||||||
|
project.getRequestBaseUrl(true) + "/api/v1/projects/" + project.remoteId + "/category/" + category.remoteId
|
||||||
|
else
|
||||||
|
project.getRequestBaseUrl(false) + "/api-priv/projects/" + project.remoteId + "/categories/" + category.remoteId
|
||||||
|
useOcsApiRequest = cospendVersionGT161
|
||||||
|
} else if (canAccessProjectWithSSO(project)) {
|
||||||
|
target = if (cospendVersionGT161)
|
||||||
|
"/ocs/v2.php/apps/cospend/api/v1/projects/" + project.remoteId + "/category/" + category.remoteId
|
||||||
|
else
|
||||||
|
"/index.php/apps/cospend/api-priv/projects/" + project.remoteId + "/categories/" + category.remoteId
|
||||||
|
return ServerResponse.EditRemoteCategoryResponse(requestServerWithSSO(nextcloudAPI!!, target, METHOD_PUT, paramKeys, paramValues, cospendVersionGT161), cospendVersionGT161)
|
||||||
|
} else {
|
||||||
|
useOcsApiRequest = cospendVersionGT161
|
||||||
|
target = if (cospendVersionGT161)
|
||||||
|
project.getRequestBaseUrl(true) + "/api/v1/public/projects/" + project.remoteId + "/" + getEncodedPassword(project.password) + "/category/" + category.remoteId
|
||||||
|
else
|
||||||
|
project.getRequestBaseUrl(false) + "/api/projects/" + project.remoteId + "/" + getEncodedPassword(project.password) + "/categories/" + category.remoteId
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
target = project.serverUrl!!.replace("/+$".toRegex(), "") + "/api/projects/" + project.remoteId + "/categories/" + category.remoteId
|
||||||
|
username = project.remoteId
|
||||||
|
password = project.password
|
||||||
|
bearerToken = project.bearerToken
|
||||||
|
}
|
||||||
|
|
||||||
|
return ServerResponse.EditRemoteCategoryResponse(
|
||||||
|
requestServer(
|
||||||
|
target, METHOD_PUT, paramKeys, paramValues, null,
|
||||||
|
username, password, bearerToken, useOcsApiRequest
|
||||||
|
), useOcsApiRequest
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Throws(IOException::class, TokenMismatchException::class, NextcloudHttpRequestFailedException::class)
|
||||||
|
fun deleteRemoteCategory(project: DBProject, categoryRemoteId: Long): ServerResponse.DeleteRemoteCategoryResponse {
|
||||||
|
var target: String
|
||||||
|
var username: String? = null
|
||||||
|
var password: String? = null
|
||||||
|
var bearerToken: String? = null
|
||||||
|
var useOcsApiRequest = false
|
||||||
|
if (ProjectType.COSPEND == project.type) {
|
||||||
|
if (canAccessProjectWithNCLogin(project)) {
|
||||||
|
username = this.username
|
||||||
|
password = this.password
|
||||||
|
target = if (cospendVersionGT161)
|
||||||
|
project.getRequestBaseUrl(true) + "/api/v1/projects/" + project.remoteId + "/category/" + categoryRemoteId
|
||||||
|
else
|
||||||
|
project.getRequestBaseUrl(false) + "/api-priv/projects/" + project.remoteId + "/categories/" + categoryRemoteId
|
||||||
|
useOcsApiRequest = cospendVersionGT161
|
||||||
|
} else if (canAccessProjectWithSSO(project)) {
|
||||||
|
target = if (cospendVersionGT161)
|
||||||
|
"/ocs/v2.php/apps/cospend/api/v1/projects/" + project.remoteId + "/category/" + categoryRemoteId
|
||||||
|
else
|
||||||
|
"/index.php/apps/cospend/api-priv/projects/" + project.remoteId + "/categories/" + categoryRemoteId
|
||||||
|
return ServerResponse.DeleteRemoteCategoryResponse(requestServerWithSSO(nextcloudAPI!!, target, METHOD_DELETE, null, null, cospendVersionGT161), cospendVersionGT161)
|
||||||
|
} else {
|
||||||
|
useOcsApiRequest = cospendVersionGT161
|
||||||
|
target = if (cospendVersionGT161)
|
||||||
|
project.getRequestBaseUrl(true) + "/api/v1/public/projects/" + project.remoteId + "/" + getEncodedPassword(project.password) + "/category/" + categoryRemoteId
|
||||||
|
else
|
||||||
|
project.getRequestBaseUrl(false) + "/api/projects/" + project.remoteId + "/" + getEncodedPassword(project.password) + "/categories/" + categoryRemoteId
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
target = project.serverUrl!!.replace("/+$".toRegex(), "") + "/api/projects/" + project.remoteId + "/categories/" + categoryRemoteId
|
||||||
|
username = project.remoteId
|
||||||
|
password = project.password
|
||||||
|
bearerToken = project.bearerToken
|
||||||
|
}
|
||||||
|
|
||||||
|
return ServerResponse.DeleteRemoteCategoryResponse(
|
||||||
|
requestServer(
|
||||||
|
target, METHOD_DELETE, null, null,
|
||||||
|
null, username, password, bearerToken, useOcsApiRequest
|
||||||
|
), useOcsApiRequest
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Throws(IOException::class, TokenMismatchException::class, NextcloudHttpRequestFailedException::class)
|
||||||
|
fun createRemotePaymentMode(project: DBProject, paymentMode: DBPaymentMode): ServerResponse.CreateRemotePaymentModeResponse {
|
||||||
|
val paramKeys: MutableList<String> = ArrayList()
|
||||||
|
val paramValues: MutableList<String> = ArrayList()
|
||||||
|
paramKeys.add("name")
|
||||||
|
paramValues.add(paymentMode.name ?: "")
|
||||||
|
paramKeys.add("icon")
|
||||||
|
paramValues.add(paymentMode.icon)
|
||||||
|
paramKeys.add("color")
|
||||||
|
paramValues.add(paymentMode.color)
|
||||||
|
|
||||||
|
var target: String
|
||||||
|
var username: String? = null
|
||||||
|
var password: String? = null
|
||||||
|
var bearerToken: String? = null
|
||||||
|
var useOcsApiRequest = false
|
||||||
|
if (ProjectType.COSPEND == project.type) {
|
||||||
|
if (canAccessProjectWithNCLogin(project)) {
|
||||||
|
username = this.username
|
||||||
|
password = this.password
|
||||||
|
target = if (cospendVersionGT161)
|
||||||
|
project.getRequestBaseUrl(true) + "/api/v1/projects/" + project.remoteId + "/paymentmode"
|
||||||
|
else
|
||||||
|
project.getRequestBaseUrl(false) + "/api-priv/projects/" + project.remoteId + "/paymentmodes"
|
||||||
|
useOcsApiRequest = cospendVersionGT161
|
||||||
|
} else if (canAccessProjectWithSSO(project)) {
|
||||||
|
target = if (cospendVersionGT161)
|
||||||
|
"/ocs/v2.php/apps/cospend/api/v1/projects/" + project.remoteId + "/paymentmode"
|
||||||
|
else
|
||||||
|
"/index.php/apps/cospend/api-priv/projects/" + project.remoteId + "/paymentmodes"
|
||||||
|
return ServerResponse.CreateRemotePaymentModeResponse(requestServerWithSSO(nextcloudAPI!!, target, METHOD_POST, paramKeys, paramValues, cospendVersionGT161), cospendVersionGT161)
|
||||||
|
} else {
|
||||||
|
useOcsApiRequest = cospendVersionGT161
|
||||||
|
target = if (cospendVersionGT161)
|
||||||
|
project.getRequestBaseUrl(true) + "/api/v1/public/projects/" + project.remoteId + "/" + getEncodedPassword(project.password) + "/paymentmode"
|
||||||
|
else
|
||||||
|
project.getRequestBaseUrl(false) + "/api/projects/" + project.remoteId + "/" + getEncodedPassword(project.password) + "/paymentmodes"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
target = project.serverUrl!!.replace("/+$".toRegex(), "") + "/api/projects/" + project.remoteId + "/paymentmodes"
|
||||||
|
username = project.remoteId
|
||||||
|
password = project.password
|
||||||
|
bearerToken = project.bearerToken
|
||||||
|
}
|
||||||
|
|
||||||
|
return ServerResponse.CreateRemotePaymentModeResponse(
|
||||||
|
requestServer(
|
||||||
|
target, METHOD_POST, paramKeys, paramValues, null,
|
||||||
|
username, password, bearerToken, useOcsApiRequest
|
||||||
|
), useOcsApiRequest
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Throws(IOException::class, TokenMismatchException::class, NextcloudHttpRequestFailedException::class)
|
||||||
|
fun editRemotePaymentMode(project: DBProject, paymentMode: DBPaymentMode): ServerResponse.EditRemotePaymentModeResponse {
|
||||||
|
val paramKeys: MutableList<String> = ArrayList()
|
||||||
|
val paramValues: MutableList<String> = ArrayList()
|
||||||
|
paramKeys.add("name")
|
||||||
|
paramValues.add(paymentMode.name ?: "")
|
||||||
|
paramKeys.add("icon")
|
||||||
|
paramValues.add(paymentMode.icon)
|
||||||
|
paramKeys.add("color")
|
||||||
|
paramValues.add(paymentMode.color)
|
||||||
|
|
||||||
|
var target: String
|
||||||
|
var username: String? = null
|
||||||
|
var password: String? = null
|
||||||
|
var bearerToken: String? = null
|
||||||
|
var useOcsApiRequest = false
|
||||||
|
if (ProjectType.COSPEND == project.type) {
|
||||||
|
if (canAccessProjectWithNCLogin(project)) {
|
||||||
|
username = this.username
|
||||||
|
password = this.password
|
||||||
|
target = if (cospendVersionGT161)
|
||||||
|
project.getRequestBaseUrl(true) + "/api/v1/projects/" + project.remoteId + "/paymentmode/" + paymentMode.remoteId
|
||||||
|
else
|
||||||
|
project.getRequestBaseUrl(false) + "/api-priv/projects/" + project.remoteId + "/paymentmodes/" + paymentMode.remoteId
|
||||||
|
useOcsApiRequest = cospendVersionGT161
|
||||||
|
} else if (canAccessProjectWithSSO(project)) {
|
||||||
|
target = if (cospendVersionGT161)
|
||||||
|
"/ocs/v2.php/apps/cospend/api/v1/projects/" + project.remoteId + "/paymentmode/" + paymentMode.remoteId
|
||||||
|
else
|
||||||
|
"/index.php/apps/cospend/api-priv/projects/" + project.remoteId + "/paymentmodes/" + paymentMode.remoteId
|
||||||
|
return ServerResponse.EditRemotePaymentModeResponse(requestServerWithSSO(nextcloudAPI!!, target, METHOD_PUT, paramKeys, paramValues, cospendVersionGT161), cospendVersionGT161)
|
||||||
|
} else {
|
||||||
|
useOcsApiRequest = cospendVersionGT161
|
||||||
|
target = if (cospendVersionGT161)
|
||||||
|
project.getRequestBaseUrl(true) + "/api/v1/public/projects/" + project.remoteId + "/" + getEncodedPassword(project.password) + "/paymentmode/" + paymentMode.remoteId
|
||||||
|
else
|
||||||
|
project.getRequestBaseUrl(false) + "/api/projects/" + project.remoteId + "/" + getEncodedPassword(project.password) + "/paymentmodes/" + paymentMode.remoteId
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
target = project.serverUrl!!.replace("/+$".toRegex(), "") + "/api/projects/" + project.remoteId + "/paymentmodes/" + paymentMode.remoteId
|
||||||
|
username = project.remoteId
|
||||||
|
password = project.password
|
||||||
|
bearerToken = project.bearerToken
|
||||||
|
}
|
||||||
|
|
||||||
|
return ServerResponse.EditRemotePaymentModeResponse(
|
||||||
|
requestServer(
|
||||||
|
target, METHOD_PUT, paramKeys, paramValues, null,
|
||||||
|
username, password, bearerToken, useOcsApiRequest
|
||||||
|
), useOcsApiRequest
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Throws(IOException::class, TokenMismatchException::class, NextcloudHttpRequestFailedException::class)
|
||||||
|
fun deleteRemotePaymentMode(project: DBProject, paymentModeRemoteId: Long): ServerResponse.DeleteRemotePaymentModeResponse {
|
||||||
|
var target: String
|
||||||
|
var username: String? = null
|
||||||
|
var password: String? = null
|
||||||
|
var bearerToken: String? = null
|
||||||
|
var useOcsApiRequest = false
|
||||||
|
if (ProjectType.COSPEND == project.type) {
|
||||||
|
if (canAccessProjectWithNCLogin(project)) {
|
||||||
|
username = this.username
|
||||||
|
password = this.password
|
||||||
|
target = if (cospendVersionGT161)
|
||||||
|
project.getRequestBaseUrl(true) + "/api/v1/projects/" + project.remoteId + "/paymentmode/" + paymentModeRemoteId
|
||||||
|
else
|
||||||
|
project.getRequestBaseUrl(false) + "/api-priv/projects/" + project.remoteId + "/paymentmodes/" + paymentModeRemoteId
|
||||||
|
useOcsApiRequest = cospendVersionGT161
|
||||||
|
} else if (canAccessProjectWithSSO(project)) {
|
||||||
|
target = if (cospendVersionGT161)
|
||||||
|
"/ocs/v2.php/apps/cospend/api/v1/projects/" + project.remoteId + "/paymentmode/" + paymentModeRemoteId
|
||||||
|
else
|
||||||
|
"/index.php/apps/cospend/api-priv/projects/" + project.remoteId + "/paymentmodes/" + paymentModeRemoteId
|
||||||
|
return ServerResponse.DeleteRemotePaymentModeResponse(requestServerWithSSO(nextcloudAPI!!, target, METHOD_DELETE, null, null, cospendVersionGT161), cospendVersionGT161)
|
||||||
|
} else {
|
||||||
|
useOcsApiRequest = cospendVersionGT161
|
||||||
|
target = if (cospendVersionGT161)
|
||||||
|
project.getRequestBaseUrl(true) + "/api/v1/public/projects/" + project.remoteId + "/" + getEncodedPassword(project.password) + "/paymentmode/" + paymentModeRemoteId
|
||||||
|
else
|
||||||
|
project.getRequestBaseUrl(false) + "/api/projects/" + project.remoteId + "/" + getEncodedPassword(project.password) + "/paymentmodes/" + paymentModeRemoteId
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
target = project.serverUrl!!.replace("/+$".toRegex(), "") + "/api/projects/" + project.remoteId + "/paymentmodes/" + paymentModeRemoteId
|
||||||
|
username = project.remoteId
|
||||||
|
password = project.password
|
||||||
|
bearerToken = project.bearerToken
|
||||||
|
}
|
||||||
|
|
||||||
|
return ServerResponse.DeleteRemotePaymentModeResponse(
|
||||||
|
requestServer(
|
||||||
|
target, METHOD_DELETE, null, null,
|
||||||
|
null, username, password, bearerToken, useOcsApiRequest
|
||||||
|
), useOcsApiRequest
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@Throws(IOException::class, TokenMismatchException::class, NextcloudHttpRequestFailedException::class)
|
@Throws(IOException::class, TokenMismatchException::class, NextcloudHttpRequestFailedException::class)
|
||||||
fun createRemoteCurrency(project: DBProject, currency: DBCurrency): ServerResponse.CreateRemoteCurrencyResponse {
|
fun createRemoteCurrency(project: DBProject, currency: DBCurrency): ServerResponse.CreateRemoteCurrencyResponse {
|
||||||
val paramKeys: MutableList<String> = ArrayList()
|
val paramKeys: MutableList<String> = ArrayList()
|
||||||
@@ -952,6 +1391,10 @@ class VersatileProjectSyncClient(
|
|||||||
nextcloudAPI: NextcloudAPI, target: String, method: String,
|
nextcloudAPI: NextcloudAPI, target: String, method: String,
|
||||||
paramKeys: List<String>?, paramValues: List<String>?, isOCSRequest: Boolean
|
paramKeys: List<String>?, paramValues: List<String>?, isOCSRequest: Boolean
|
||||||
): ResponseData {
|
): ResponseData {
|
||||||
|
var finalTarget = target
|
||||||
|
if (finalTarget.contains("/ocs/v2.php") && !finalTarget.contains("format=json")) {
|
||||||
|
finalTarget += if (finalTarget.contains("?")) "&format=json" else "?format=json"
|
||||||
|
}
|
||||||
val result = StringBuilder()
|
val result = StringBuilder()
|
||||||
var params: MutableList<QueryParam>? = null
|
var params: MutableList<QueryParam>? = null
|
||||||
if (paramKeys != null && paramValues != null) {
|
if (paramKeys != null && paramValues != null) {
|
||||||
@@ -969,13 +1412,13 @@ class VersatileProjectSyncClient(
|
|||||||
val nextcloudRequest: NextcloudRequest = if (params == null) {
|
val nextcloudRequest: NextcloudRequest = if (params == null) {
|
||||||
NextcloudRequest.Builder()
|
NextcloudRequest.Builder()
|
||||||
.setMethod(method)
|
.setMethod(method)
|
||||||
.setUrl(target)
|
.setUrl(finalTarget)
|
||||||
.setHeader(headers)
|
.setHeader(headers)
|
||||||
.build()
|
.build()
|
||||||
} else {
|
} else {
|
||||||
NextcloudRequest.Builder()
|
NextcloudRequest.Builder()
|
||||||
.setMethod(method)
|
.setMethod(method)
|
||||||
.setUrl(target)
|
.setUrl(finalTarget)
|
||||||
.setParameter(params)
|
.setParameter(params)
|
||||||
.setHeader(headers)
|
.setHeader(headers)
|
||||||
.build()
|
.build()
|
||||||
@@ -1009,8 +1452,12 @@ class VersatileProjectSyncClient(
|
|||||||
lastETag: String?, username: String?, password: String?,
|
lastETag: String?, username: String?, password: String?,
|
||||||
bearerToken: String?, isOCSRequest: Boolean
|
bearerToken: String?, isOCSRequest: Boolean
|
||||||
): ResponseData {
|
): ResponseData {
|
||||||
|
var finalTarget = target
|
||||||
|
if (finalTarget.contains("/ocs/v2.php") && !finalTarget.contains("format=json")) {
|
||||||
|
finalTarget += if (finalTarget.contains("?")) "&format=json" else "?format=json"
|
||||||
|
}
|
||||||
val result = StringBuilder()
|
val result = StringBuilder()
|
||||||
val httpCon = SupportUtil.getHttpURLConnection(target)
|
val httpCon = SupportUtil.getHttpURLConnection(finalTarget)
|
||||||
httpCon.requestMethod = method
|
httpCon.requestMethod = method
|
||||||
if (bearerToken != null) {
|
if (bearerToken != null) {
|
||||||
httpCon.setRequestProperty("Authorization", "Bearer $bearerToken")
|
httpCon.setRequestProperty("Authorization", "Bearer $bearerToken")
|
||||||
@@ -1021,7 +1468,7 @@ class VersatileProjectSyncClient(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
httpCon.setRequestProperty("Connection", "Close")
|
httpCon.setRequestProperty("Connection", "Close")
|
||||||
httpCon.setRequestProperty("User-Agent", "Cowspent/" + SupportUtil.getAppVersionName(context))
|
httpCon.setRequestProperty("User-Agent", "Cowspent-android/" + SupportUtil.getAppVersionName(context))
|
||||||
if (lastETag != null && METHOD_GET == method) {
|
if (lastETag != null && METHOD_GET == method) {
|
||||||
httpCon.setRequestProperty("If-None-Match", lastETag)
|
httpCon.setRequestProperty("If-None-Match", lastETag)
|
||||||
}
|
}
|
||||||
@@ -1083,5 +1530,8 @@ class VersatileProjectSyncClient(
|
|||||||
const val METHOD_POST = "POST"
|
const val METHOD_POST = "POST"
|
||||||
const val METHOD_PUT = "PUT"
|
const val METHOD_PUT = "PUT"
|
||||||
const val METHOD_DELETE = "DELETE"
|
const val METHOD_DELETE = "DELETE"
|
||||||
|
|
||||||
|
const val REMOTE_ARCHIVED_TS_NOW = 0L
|
||||||
|
const val REMOTE_ARCHIVED_TS_UNSET = -1L
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,9 +5,11 @@ fun evalMath(expression: String): Double {
|
|||||||
var result = 0.0
|
var result = 0.0
|
||||||
var db: SQLiteDatabase? = null
|
var db: SQLiteDatabase? = null
|
||||||
try {
|
try {
|
||||||
|
// Force floating point division by replacing / with * 1.0 /
|
||||||
|
val forcedRealExpr = expression.replace("/", "* 1.0 /")
|
||||||
// Opens a temporary, in-memory system database block
|
// Opens a temporary, in-memory system database block
|
||||||
db = SQLiteDatabase.create(null)
|
db = SQLiteDatabase.create(null)
|
||||||
val cursor = db.rawQuery("SELECT ($expression);", null)
|
val cursor = db.rawQuery("SELECT ($forcedRealExpr);", null)
|
||||||
if (cursor.moveToFirst()) {
|
if (cursor.moveToFirst()) {
|
||||||
result = cursor.getDouble(0)
|
result = cursor.getDouble(0)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,272 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Untranslated: these are the English strings, kept here so a translation can be
|
||||||
|
contributed by simply replacing the values. Strings marked translatable="false" in
|
||||||
|
values/strings.xml (app and product names, preference keys) are deliberately absent
|
||||||
|
and must not be added.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- Actions -->
|
||||||
|
<string name="action_new_bill">New bill</string>
|
||||||
|
<string name="action_add_project">Add project</string>
|
||||||
|
<string name="action_save">Save</string>
|
||||||
|
<string name="action_edit">Edit</string>
|
||||||
|
<string name="action_share">Share</string>
|
||||||
|
<string name="action_search">Search</string>
|
||||||
|
<string name="action_open_menu">Open menu</string>
|
||||||
|
<string name="action_close_search">Close search</string>
|
||||||
|
<string name="action_clear_search">Clear search</string>
|
||||||
|
<string name="action_delete">Delete</string>
|
||||||
|
<string name="simple_back">Back</string>
|
||||||
|
<string name="action_archive">Archive</string>
|
||||||
|
<string name="action_unarchive">Unarchive</string>
|
||||||
|
<string name="action_export">Export</string>
|
||||||
|
<string name="action_stats">Stats</string>
|
||||||
|
<string name="action_settle">Settle</string>
|
||||||
|
<string name="action_scan_qrcode">Scan QR Code</string>
|
||||||
|
<string name="action_settings">Settings</string>
|
||||||
|
<string name="action_label_bills">Label missing categories</string>
|
||||||
|
<string name="action_logout">Logout</string>
|
||||||
|
<string name="action_connect">Connect</string>
|
||||||
|
<string name="action_discard">Discard</string>
|
||||||
|
<string name="action_members">Members</string>
|
||||||
|
<string name="action_labels">Labels</string>
|
||||||
|
<string name="action_currencies">Currencies</string>
|
||||||
|
|
||||||
|
<!-- Titles -->
|
||||||
|
<string name="title_stats">Statistics</string>
|
||||||
|
<string name="title_edit_project">Edit project</string>
|
||||||
|
<string name="title_label_bills">Label Bills</string>
|
||||||
|
<string name="title_labels">Manage Labels</string>
|
||||||
|
<string name="title_about">About</string>
|
||||||
|
<string name="title_settle">Settle Project</string>
|
||||||
|
<string name="title_share">Share Project</string>
|
||||||
|
<string name="title_add_project">Add Project</string>
|
||||||
|
<string name="title_add_category">Add Category</string>
|
||||||
|
<string name="title_add_payment_mode">Add Payment Mode</string>
|
||||||
|
<string name="title_account">Nextcloud Account</string>
|
||||||
|
<string name="title_share_web">Web link</string>
|
||||||
|
<string name="title_share_qr">Cowspent link</string>
|
||||||
|
<string name="title_confirm">Are you sure?</string>
|
||||||
|
|
||||||
|
<!-- Labels and Fields -->
|
||||||
|
<string name="label_all_bills">All bills</string>
|
||||||
|
<string name="label_categories">Categories</string>
|
||||||
|
<string name="label_payment_modes">Payment Modes</string>
|
||||||
|
<string name="label_name">Name</string>
|
||||||
|
<string name="label_icon">Icon / Emoji</string>
|
||||||
|
<string name="label_color">Color</string>
|
||||||
|
<string name="label_weight">Weight</string>
|
||||||
|
<string name="label_activated">Activated</string>
|
||||||
|
<string name="label_password">Password</string>
|
||||||
|
<string name="label_email">E-mail</string>
|
||||||
|
<string name="label_url">Server address</string>
|
||||||
|
<string name="label_username">Username</string>
|
||||||
|
<string name="label_comment">Comment</string>
|
||||||
|
<string name="label_what">What?</string>
|
||||||
|
<string name="label_payer">Who paid?</string>
|
||||||
|
<string name="label_owers">For whom?</string>
|
||||||
|
<string name="label_repeat">Repeat every</string>
|
||||||
|
<string name="label_mode">Mode</string>
|
||||||
|
<string name="label_category">Category</string>
|
||||||
|
<string name="label_project_id">Project ID/name</string>
|
||||||
|
<string name="label_project_title">Project title</string>
|
||||||
|
<string name="label_use_sso">Use Nextcloud App Account</string>
|
||||||
|
|
||||||
|
<!-- Dialogs and Messages -->
|
||||||
|
<string name="dialog_unsaved_changes_title">Unsaved changes</string>
|
||||||
|
<string name="dialog_unsaved_changes_msg">Save changes before leaving?</string>
|
||||||
|
<string name="dialog_confirm_remove_project_msg">The remote project will not be deleted.</string>
|
||||||
|
<string name="dialog_sync_error_title">Sync error</string>
|
||||||
|
<string name="dialog_sync_error_msg">Sync failed for %1$s.\n\n%2$s</string>
|
||||||
|
<string name="dialog_balanced_msg">Expenses are already balanced.</string>
|
||||||
|
<string name="msg_project_added">Project %1$s added</string>
|
||||||
|
<string name="msg_bill_labeled_done">All bills labeled</string>
|
||||||
|
<string name="msg_no_suggestions">No suggestions</string>
|
||||||
|
<string name="msg_auth_warning">Requires Cospend v0.3.4+.</string>
|
||||||
|
<string name="msg_link_copied">Link copied to clipboard</string>
|
||||||
|
<string name="msg_share_qr">Scan QR code or share the link to join.</string>
|
||||||
|
<string name="msg_share_web">Link for web browser access.</string>
|
||||||
|
<string name="msg_share_qr_warn">Share this link with a Cowspent user.</string>
|
||||||
|
<string name="msg_settle_intro">Settlement for %1$s:</string>
|
||||||
|
<string name="msg_settle_sentence">%1$s owes %3$.2f to %2$s</string>
|
||||||
|
<string name="msg_stats_intro">Stats for %1$s:</string>
|
||||||
|
<string name="msg_stats_header">Member (Paid | Spent | Balance)</string>
|
||||||
|
<string name="msg_logged_in_as">Logged in as %1$s</string>
|
||||||
|
|
||||||
|
<!-- Errors -->
|
||||||
|
<string name="error_generic">Error</string>
|
||||||
|
<string name="error_loading">Loading</string>
|
||||||
|
<string name="error_no_projects">No projects found</string>
|
||||||
|
<string name="error_no_members">No members found</string>
|
||||||
|
<string name="error_no_bills">No bills found</string>
|
||||||
|
<string name="error_no_member">At least one member required</string>
|
||||||
|
<string name="error_maintenance_mode">Server is in maintenance mode</string>
|
||||||
|
<string name="error_400">400 Bad request</string>
|
||||||
|
<string name="error_401">401 Unauthorized</string>
|
||||||
|
<string name="error_403">403 Forbidden</string>
|
||||||
|
<string name="error_404">404 Not Found</string>
|
||||||
|
<string name="error_sync">Sync failed: %1$s</string>
|
||||||
|
<string name="error_invalid_login">Invalid login: %1$s</string>
|
||||||
|
<string name="error_auth">Wrong username or password</string>
|
||||||
|
<string name="error_json">Invalid server response</string>
|
||||||
|
<string name="error_req_failed">Request failed</string>
|
||||||
|
<string name="error_invalid_email">Invalid e-mail</string>
|
||||||
|
<string name="error_invalid_project_id">Invalid project ID</string>
|
||||||
|
<string name="error_invalid_project_name">Invalid project title</string>
|
||||||
|
<string name="error_invalid_bill_name">Invalid bill name</string>
|
||||||
|
<string name="error_invalid_bill_date">Invalid bill date</string>
|
||||||
|
<string name="error_invalid_bill_payer">Payer required</string>
|
||||||
|
<string name="error_invalid_bill_owers">Owers required</string>
|
||||||
|
<string name="error_no_network">No network connection</string>
|
||||||
|
<string name="error_server">Server error</string>
|
||||||
|
<string name="error_io">Server connection broken</string>
|
||||||
|
<string name="error_share_impossible">Cannot share this project</string>
|
||||||
|
|
||||||
|
<!-- Drawer / Common UI -->
|
||||||
|
<string name="drawer_no_account">Connect to Nextcloud account</string>
|
||||||
|
<string name="drawer_last_sync">Last sync: %1$02d:%2$02d</string>
|
||||||
|
<string name="simple_cancel">Cancel</string>
|
||||||
|
<string name="simple_ok" tools:ignore="ButtonCase,Typos">Ok</string>
|
||||||
|
<string name="simple_yes">Yes</string>
|
||||||
|
<string name="simple_no">No</string>
|
||||||
|
<string name="simple_close">Close</string>
|
||||||
|
|
||||||
|
<!-- Settings -->
|
||||||
|
<string name="settings_appearance">Appearance</string>
|
||||||
|
<string name="settings_network">Network</string>
|
||||||
|
<string name="settings_other">Other</string>
|
||||||
|
<string name="settings_night_mode">Theme</string>
|
||||||
|
<string name="settings_offline_mode">Offline mode</string>
|
||||||
|
<string name="settings_offline_mode_summary">Only sync manually.</string>
|
||||||
|
<string name="settings_color_custom">Custom color</string>
|
||||||
|
<string name="settings_color_mode">Color Selection</string>
|
||||||
|
<string name="settings_show_archived">Show archived projects</string>
|
||||||
|
<string name="settings_beta_features">Beta Features</string>
|
||||||
|
<string name="settings_beta_features_summary">Enable experimental features. Use at your own risk.</string>
|
||||||
|
<string name="settings_fill_new_bill_from_last">Auto-fill from last bill</string>
|
||||||
|
<string name="settings_fill_new_bill_from_last_summary">Pre-fill payer, category, mode and owers from the last bill created in the project.</string>
|
||||||
|
<string name="settings_auto_sync_on_open">Sync interval</string>
|
||||||
|
<string name="settings_auto_sync_on_open_summary">How often to refresh the account and all projects when opening the app.</string>
|
||||||
|
<string name="pref_value_sync_1m">1 minute</string>
|
||||||
|
<string name="pref_value_sync_10m">10 minutes</string>
|
||||||
|
<string name="pref_value_sync_1h">1 hour</string>
|
||||||
|
<string name="pref_value_sync_1d">1 day</string>
|
||||||
|
<string name="settings_url_warn_http">WARNING: "http" is unsafe. Use "https".</string>
|
||||||
|
<string name="settings_colorpicker_title">Choose Color</string>
|
||||||
|
|
||||||
|
<string name="pref_value_color_system">System</string>
|
||||||
|
<string name="pref_value_color_manual">Manual</string>
|
||||||
|
<string name="pref_value_theme_light">Light</string>
|
||||||
|
<string name="pref_value_theme_dark">Dark</string>
|
||||||
|
<string name="pref_value_theme_system">Follow system</string>
|
||||||
|
|
||||||
|
<!-- Enums and Lists -->
|
||||||
|
<string name="repeat_no">No repeat</string>
|
||||||
|
<string name="repeat_day">Daily</string>
|
||||||
|
<string name="repeat_week">Weekly</string>
|
||||||
|
<string name="repeat_fortnight">Fortnightly</string>
|
||||||
|
<string name="repeat_month">Monthly</string>
|
||||||
|
<string name="repeat_year">Yearly</string>
|
||||||
|
|
||||||
|
<string name="payment_mode_none">None</string>
|
||||||
|
<string name="payment_mode_all">All</string>
|
||||||
|
<string name="payment_mode_credit_card">Credit card</string>
|
||||||
|
<string name="payment_mode_cash">Cash</string>
|
||||||
|
<string name="payment_mode_check">Check</string>
|
||||||
|
<string name="payment_mode_online">Online</string>
|
||||||
|
<string name="payment_mode_transfer">Transfer</string>
|
||||||
|
|
||||||
|
<string name="category_none">None</string>
|
||||||
|
<string name="category_all">All</string>
|
||||||
|
<string name="category_all_except_reimbursement">All except reimbursement</string>
|
||||||
|
<string name="category_groceries">Grocery</string>
|
||||||
|
<string name="category_leisure">Bar/Party</string>
|
||||||
|
<string name="category_rent">Rent</string>
|
||||||
|
<string name="category_bills">Bill</string>
|
||||||
|
<string name="category_excursion">Excursion/Culture</string>
|
||||||
|
<string name="category_health">Health</string>
|
||||||
|
<string name="category_shopping">Shopping</string>
|
||||||
|
<string name="category_reimbursement">Reimbursement</string>
|
||||||
|
<string name="category_restaurant">Restaurant</string>
|
||||||
|
<string name="category_accomodation">Accommodation</string>
|
||||||
|
<string name="category_transport">Transport</string>
|
||||||
|
<string name="category_sport">Sport</string>
|
||||||
|
|
||||||
|
<!-- Project specific -->
|
||||||
|
<string name="new_project_action">What</string>
|
||||||
|
<string name="new_project_where">Where</string>
|
||||||
|
<string name="where_local">Local only</string>
|
||||||
|
<string name="todo_join">Join existing project</string>
|
||||||
|
<string name="todo_create">Create new project</string>
|
||||||
|
<string name="import_tooltip">Import from file</string>
|
||||||
|
<string name="choose_project_management_action">Project</string>
|
||||||
|
<string name="project_added_success">Project added successfully.</string>
|
||||||
|
<string name="no_projects_text">You have no projects yet.</string>
|
||||||
|
<string name="configure_account_choice">Configure Nextcloud account</string>
|
||||||
|
<string name="add_project_choice">Add project manually</string>
|
||||||
|
<string name="no_members_text">No members in this project.</string>
|
||||||
|
<string name="no_bills_text">No bills found.</string>
|
||||||
|
<string name="member_already_exists">Member already exists.</string>
|
||||||
|
<string name="activity_dialog_title">Project: %1$s</string>
|
||||||
|
<string name="remove_project_confirmation">Project %1$s removed.</string>
|
||||||
|
<string name="file_saved_success">File saved: %1$s</string>
|
||||||
|
<string name="import_error_header">Import failed at row %d</string>
|
||||||
|
<string name="import_error_date">Invalid date format at row %d</string>
|
||||||
|
<string name="import_error_owers">Invalid owers at row %d</string>
|
||||||
|
<string name="add_member_dialog_title">Add Member</string>
|
||||||
|
<string name="edit_member_dialog_title">Edit Member</string>
|
||||||
|
<string name="member_edit_delete">Delete</string>
|
||||||
|
<string name="project_edition_no_change">No changes to save.</string>
|
||||||
|
|
||||||
|
<!-- Settlement -->
|
||||||
|
<string name="center_none">None (Optimal)</string>
|
||||||
|
<string name="settle_who">Who pays</string>
|
||||||
|
<string name="settle_to_whom">To whom</string>
|
||||||
|
<string name="settle_how_much">Amount</string>
|
||||||
|
<string name="simple_settle_share">Share</string>
|
||||||
|
<string name="simple_create_bills">Create bills</string>
|
||||||
|
<string name="settle_bill_what">Settlement</string>
|
||||||
|
|
||||||
|
<!-- Currencies -->
|
||||||
|
<string name="currency_dialog_title">Choose Currency (%s)</string>
|
||||||
|
<string name="setting_none">None</string>
|
||||||
|
<string name="setting_all">All</string>
|
||||||
|
<string name="currency_saved_success">Currency settings saved.</string>
|
||||||
|
<string name="main_currency">Main Currency</string>
|
||||||
|
|
||||||
|
<!-- Statistics -->
|
||||||
|
<string name="label_bills_suggested">Suggested Categories</string>
|
||||||
|
<string name="label_bills_skip">Skip</string>
|
||||||
|
<string name="stats_date_min">From</string>
|
||||||
|
<string name="stats_date_max">To</string>
|
||||||
|
<string name="stats_who">Member</string>
|
||||||
|
<string name="stats_paid">Paid</string>
|
||||||
|
<string name="stats_spent">Spent</string>
|
||||||
|
<string name="stats_balance">Balance</string>
|
||||||
|
<string name="total">Total: %1$s</string>
|
||||||
|
|
||||||
|
<!-- Errors Extra -->
|
||||||
|
<string name="error_project_connect_check">Connection failed: %1$s</string>
|
||||||
|
<string name="error_create_remote_project_helper">Creation failed: %1$s</string>
|
||||||
|
<string name="error_edit_remote_project_helper">Error updating remote project: %1$s</string>
|
||||||
|
<string name="remote_project_operation_no_network">Network unavailable for remote operation.</string>
|
||||||
|
<string name="error_scanning_bill_qr_code">Failed to parse QR code.</string>
|
||||||
|
<string name="error_token_mismatch">Authentication token mismatch. Please log in again.</string>
|
||||||
|
<string name="insufficient_access_level">You don\'t have permission to perform this action.</string>
|
||||||
|
<string name="delete_label_confirmation_title">Delete Label</string>
|
||||||
|
<string name="delete_label_confirmation_message">Are you sure you want to delete this label?</string>
|
||||||
|
|
||||||
|
<!-- About -->
|
||||||
|
<string name="about_version">Version %1$s</string>
|
||||||
|
<string name="about_maintainer_title">Maintainer</string>
|
||||||
|
<string name="about_license_title">License</string>
|
||||||
|
<string name="about_source_title">Source code</string>
|
||||||
|
|
||||||
|
<!-- New constants for backward compatibility or shared use -->
|
||||||
|
<string name="share_intent_title">Project %1$s</string>
|
||||||
|
<string name="share_chooser_title">Share %1$s</string>
|
||||||
|
|
||||||
|
</resources>
|
||||||
@@ -0,0 +1,272 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Untranslated: these are the English strings, kept here so a translation can be
|
||||||
|
contributed by simply replacing the values. Strings marked translatable="false" in
|
||||||
|
values/strings.xml (app and product names, preference keys) are deliberately absent
|
||||||
|
and must not be added.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- Actions -->
|
||||||
|
<string name="action_new_bill">New bill</string>
|
||||||
|
<string name="action_add_project">Add project</string>
|
||||||
|
<string name="action_save">Save</string>
|
||||||
|
<string name="action_edit">Edit</string>
|
||||||
|
<string name="action_share">Share</string>
|
||||||
|
<string name="action_search">Search</string>
|
||||||
|
<string name="action_open_menu">Open menu</string>
|
||||||
|
<string name="action_close_search">Close search</string>
|
||||||
|
<string name="action_clear_search">Clear search</string>
|
||||||
|
<string name="action_delete">Delete</string>
|
||||||
|
<string name="simple_back">Back</string>
|
||||||
|
<string name="action_archive">Archive</string>
|
||||||
|
<string name="action_unarchive">Unarchive</string>
|
||||||
|
<string name="action_export">Export</string>
|
||||||
|
<string name="action_stats">Stats</string>
|
||||||
|
<string name="action_settle">Settle</string>
|
||||||
|
<string name="action_scan_qrcode">Scan QR Code</string>
|
||||||
|
<string name="action_settings">Settings</string>
|
||||||
|
<string name="action_label_bills">Label missing categories</string>
|
||||||
|
<string name="action_logout">Logout</string>
|
||||||
|
<string name="action_connect">Connect</string>
|
||||||
|
<string name="action_discard">Discard</string>
|
||||||
|
<string name="action_members">Members</string>
|
||||||
|
<string name="action_labels">Labels</string>
|
||||||
|
<string name="action_currencies">Currencies</string>
|
||||||
|
|
||||||
|
<!-- Titles -->
|
||||||
|
<string name="title_stats">Statistics</string>
|
||||||
|
<string name="title_edit_project">Edit project</string>
|
||||||
|
<string name="title_label_bills">Label Bills</string>
|
||||||
|
<string name="title_labels">Manage Labels</string>
|
||||||
|
<string name="title_about">About</string>
|
||||||
|
<string name="title_settle">Settle Project</string>
|
||||||
|
<string name="title_share">Share Project</string>
|
||||||
|
<string name="title_add_project">Add Project</string>
|
||||||
|
<string name="title_add_category">Add Category</string>
|
||||||
|
<string name="title_add_payment_mode">Add Payment Mode</string>
|
||||||
|
<string name="title_account">Nextcloud Account</string>
|
||||||
|
<string name="title_share_web">Web link</string>
|
||||||
|
<string name="title_share_qr">Cowspent link</string>
|
||||||
|
<string name="title_confirm">Are you sure?</string>
|
||||||
|
|
||||||
|
<!-- Labels and Fields -->
|
||||||
|
<string name="label_all_bills">All bills</string>
|
||||||
|
<string name="label_categories">Categories</string>
|
||||||
|
<string name="label_payment_modes">Payment Modes</string>
|
||||||
|
<string name="label_name">Name</string>
|
||||||
|
<string name="label_icon">Icon / Emoji</string>
|
||||||
|
<string name="label_color">Color</string>
|
||||||
|
<string name="label_weight">Weight</string>
|
||||||
|
<string name="label_activated">Activated</string>
|
||||||
|
<string name="label_password">Password</string>
|
||||||
|
<string name="label_email">E-mail</string>
|
||||||
|
<string name="label_url">Server address</string>
|
||||||
|
<string name="label_username">Username</string>
|
||||||
|
<string name="label_comment">Comment</string>
|
||||||
|
<string name="label_what">What?</string>
|
||||||
|
<string name="label_payer">Who paid?</string>
|
||||||
|
<string name="label_owers">For whom?</string>
|
||||||
|
<string name="label_repeat">Repeat every</string>
|
||||||
|
<string name="label_mode">Mode</string>
|
||||||
|
<string name="label_category">Category</string>
|
||||||
|
<string name="label_project_id">Project ID/name</string>
|
||||||
|
<string name="label_project_title">Project title</string>
|
||||||
|
<string name="label_use_sso">Use Nextcloud App Account</string>
|
||||||
|
|
||||||
|
<!-- Dialogs and Messages -->
|
||||||
|
<string name="dialog_unsaved_changes_title">Unsaved changes</string>
|
||||||
|
<string name="dialog_unsaved_changes_msg">Save changes before leaving?</string>
|
||||||
|
<string name="dialog_confirm_remove_project_msg">The remote project will not be deleted.</string>
|
||||||
|
<string name="dialog_sync_error_title">Sync error</string>
|
||||||
|
<string name="dialog_sync_error_msg">Sync failed for %1$s.\n\n%2$s</string>
|
||||||
|
<string name="dialog_balanced_msg">Expenses are already balanced.</string>
|
||||||
|
<string name="msg_project_added">Project %1$s added</string>
|
||||||
|
<string name="msg_bill_labeled_done">All bills labeled</string>
|
||||||
|
<string name="msg_no_suggestions">No suggestions</string>
|
||||||
|
<string name="msg_auth_warning">Requires Cospend v0.3.4+.</string>
|
||||||
|
<string name="msg_link_copied">Link copied to clipboard</string>
|
||||||
|
<string name="msg_share_qr">Scan QR code or share the link to join.</string>
|
||||||
|
<string name="msg_share_web">Link for web browser access.</string>
|
||||||
|
<string name="msg_share_qr_warn">Share this link with a Cowspent user.</string>
|
||||||
|
<string name="msg_settle_intro">Settlement for %1$s:</string>
|
||||||
|
<string name="msg_settle_sentence">%1$s owes %3$.2f to %2$s</string>
|
||||||
|
<string name="msg_stats_intro">Stats for %1$s:</string>
|
||||||
|
<string name="msg_stats_header">Member (Paid | Spent | Balance)</string>
|
||||||
|
<string name="msg_logged_in_as">Logged in as %1$s</string>
|
||||||
|
|
||||||
|
<!-- Errors -->
|
||||||
|
<string name="error_generic">Error</string>
|
||||||
|
<string name="error_loading">Loading</string>
|
||||||
|
<string name="error_no_projects">No projects found</string>
|
||||||
|
<string name="error_no_members">No members found</string>
|
||||||
|
<string name="error_no_bills">No bills found</string>
|
||||||
|
<string name="error_no_member">At least one member required</string>
|
||||||
|
<string name="error_maintenance_mode">Server is in maintenance mode</string>
|
||||||
|
<string name="error_400">400 Bad request</string>
|
||||||
|
<string name="error_401">401 Unauthorized</string>
|
||||||
|
<string name="error_403">403 Forbidden</string>
|
||||||
|
<string name="error_404">404 Not Found</string>
|
||||||
|
<string name="error_sync">Sync failed: %1$s</string>
|
||||||
|
<string name="error_invalid_login">Invalid login: %1$s</string>
|
||||||
|
<string name="error_auth">Wrong username or password</string>
|
||||||
|
<string name="error_json">Invalid server response</string>
|
||||||
|
<string name="error_req_failed">Request failed</string>
|
||||||
|
<string name="error_invalid_email">Invalid e-mail</string>
|
||||||
|
<string name="error_invalid_project_id">Invalid project ID</string>
|
||||||
|
<string name="error_invalid_project_name">Invalid project title</string>
|
||||||
|
<string name="error_invalid_bill_name">Invalid bill name</string>
|
||||||
|
<string name="error_invalid_bill_date">Invalid bill date</string>
|
||||||
|
<string name="error_invalid_bill_payer">Payer required</string>
|
||||||
|
<string name="error_invalid_bill_owers">Owers required</string>
|
||||||
|
<string name="error_no_network">No network connection</string>
|
||||||
|
<string name="error_server">Server error</string>
|
||||||
|
<string name="error_io">Server connection broken</string>
|
||||||
|
<string name="error_share_impossible">Cannot share this project</string>
|
||||||
|
|
||||||
|
<!-- Drawer / Common UI -->
|
||||||
|
<string name="drawer_no_account">Connect to Nextcloud account</string>
|
||||||
|
<string name="drawer_last_sync">Last sync: %1$02d:%2$02d</string>
|
||||||
|
<string name="simple_cancel">Cancel</string>
|
||||||
|
<string name="simple_ok" tools:ignore="ButtonCase,Typos">Ok</string>
|
||||||
|
<string name="simple_yes">Yes</string>
|
||||||
|
<string name="simple_no">No</string>
|
||||||
|
<string name="simple_close">Close</string>
|
||||||
|
|
||||||
|
<!-- Settings -->
|
||||||
|
<string name="settings_appearance">Appearance</string>
|
||||||
|
<string name="settings_network">Network</string>
|
||||||
|
<string name="settings_other">Other</string>
|
||||||
|
<string name="settings_night_mode">Theme</string>
|
||||||
|
<string name="settings_offline_mode">Offline mode</string>
|
||||||
|
<string name="settings_offline_mode_summary">Only sync manually.</string>
|
||||||
|
<string name="settings_color_custom">Custom color</string>
|
||||||
|
<string name="settings_color_mode">Color Selection</string>
|
||||||
|
<string name="settings_show_archived">Show archived projects</string>
|
||||||
|
<string name="settings_beta_features">Beta Features</string>
|
||||||
|
<string name="settings_beta_features_summary">Enable experimental features. Use at your own risk.</string>
|
||||||
|
<string name="settings_fill_new_bill_from_last">Auto-fill from last bill</string>
|
||||||
|
<string name="settings_fill_new_bill_from_last_summary">Pre-fill payer, category, mode and owers from the last bill created in the project.</string>
|
||||||
|
<string name="settings_auto_sync_on_open">Sync interval</string>
|
||||||
|
<string name="settings_auto_sync_on_open_summary">How often to refresh the account and all projects when opening the app.</string>
|
||||||
|
<string name="pref_value_sync_1m">1 minute</string>
|
||||||
|
<string name="pref_value_sync_10m">10 minutes</string>
|
||||||
|
<string name="pref_value_sync_1h">1 hour</string>
|
||||||
|
<string name="pref_value_sync_1d">1 day</string>
|
||||||
|
<string name="settings_url_warn_http">WARNING: "http" is unsafe. Use "https".</string>
|
||||||
|
<string name="settings_colorpicker_title">Choose Color</string>
|
||||||
|
|
||||||
|
<string name="pref_value_color_system">System</string>
|
||||||
|
<string name="pref_value_color_manual">Manual</string>
|
||||||
|
<string name="pref_value_theme_light">Light</string>
|
||||||
|
<string name="pref_value_theme_dark">Dark</string>
|
||||||
|
<string name="pref_value_theme_system">Follow system</string>
|
||||||
|
|
||||||
|
<!-- Enums and Lists -->
|
||||||
|
<string name="repeat_no">No repeat</string>
|
||||||
|
<string name="repeat_day">Daily</string>
|
||||||
|
<string name="repeat_week">Weekly</string>
|
||||||
|
<string name="repeat_fortnight">Fortnightly</string>
|
||||||
|
<string name="repeat_month">Monthly</string>
|
||||||
|
<string name="repeat_year">Yearly</string>
|
||||||
|
|
||||||
|
<string name="payment_mode_none">None</string>
|
||||||
|
<string name="payment_mode_all">All</string>
|
||||||
|
<string name="payment_mode_credit_card">Credit card</string>
|
||||||
|
<string name="payment_mode_cash">Cash</string>
|
||||||
|
<string name="payment_mode_check">Check</string>
|
||||||
|
<string name="payment_mode_online">Online</string>
|
||||||
|
<string name="payment_mode_transfer">Transfer</string>
|
||||||
|
|
||||||
|
<string name="category_none">None</string>
|
||||||
|
<string name="category_all">All</string>
|
||||||
|
<string name="category_all_except_reimbursement">All except reimbursement</string>
|
||||||
|
<string name="category_groceries">Grocery</string>
|
||||||
|
<string name="category_leisure">Bar/Party</string>
|
||||||
|
<string name="category_rent">Rent</string>
|
||||||
|
<string name="category_bills">Bill</string>
|
||||||
|
<string name="category_excursion">Excursion/Culture</string>
|
||||||
|
<string name="category_health">Health</string>
|
||||||
|
<string name="category_shopping">Shopping</string>
|
||||||
|
<string name="category_reimbursement">Reimbursement</string>
|
||||||
|
<string name="category_restaurant">Restaurant</string>
|
||||||
|
<string name="category_accomodation">Accommodation</string>
|
||||||
|
<string name="category_transport">Transport</string>
|
||||||
|
<string name="category_sport">Sport</string>
|
||||||
|
|
||||||
|
<!-- Project specific -->
|
||||||
|
<string name="new_project_action">What</string>
|
||||||
|
<string name="new_project_where">Where</string>
|
||||||
|
<string name="where_local">Local only</string>
|
||||||
|
<string name="todo_join">Join existing project</string>
|
||||||
|
<string name="todo_create">Create new project</string>
|
||||||
|
<string name="import_tooltip">Import from file</string>
|
||||||
|
<string name="choose_project_management_action">Project</string>
|
||||||
|
<string name="project_added_success">Project added successfully.</string>
|
||||||
|
<string name="no_projects_text">You have no projects yet.</string>
|
||||||
|
<string name="configure_account_choice">Configure Nextcloud account</string>
|
||||||
|
<string name="add_project_choice">Add project manually</string>
|
||||||
|
<string name="no_members_text">No members in this project.</string>
|
||||||
|
<string name="no_bills_text">No bills found.</string>
|
||||||
|
<string name="member_already_exists">Member already exists.</string>
|
||||||
|
<string name="activity_dialog_title">Project: %1$s</string>
|
||||||
|
<string name="remove_project_confirmation">Project %1$s removed.</string>
|
||||||
|
<string name="file_saved_success">File saved: %1$s</string>
|
||||||
|
<string name="import_error_header">Import failed at row %d</string>
|
||||||
|
<string name="import_error_date">Invalid date format at row %d</string>
|
||||||
|
<string name="import_error_owers">Invalid owers at row %d</string>
|
||||||
|
<string name="add_member_dialog_title">Add Member</string>
|
||||||
|
<string name="edit_member_dialog_title">Edit Member</string>
|
||||||
|
<string name="member_edit_delete">Delete</string>
|
||||||
|
<string name="project_edition_no_change">No changes to save.</string>
|
||||||
|
|
||||||
|
<!-- Settlement -->
|
||||||
|
<string name="center_none">None (Optimal)</string>
|
||||||
|
<string name="settle_who">Who pays</string>
|
||||||
|
<string name="settle_to_whom">To whom</string>
|
||||||
|
<string name="settle_how_much">Amount</string>
|
||||||
|
<string name="simple_settle_share">Share</string>
|
||||||
|
<string name="simple_create_bills">Create bills</string>
|
||||||
|
<string name="settle_bill_what">Settlement</string>
|
||||||
|
|
||||||
|
<!-- Currencies -->
|
||||||
|
<string name="currency_dialog_title">Choose Currency (%s)</string>
|
||||||
|
<string name="setting_none">None</string>
|
||||||
|
<string name="setting_all">All</string>
|
||||||
|
<string name="currency_saved_success">Currency settings saved.</string>
|
||||||
|
<string name="main_currency">Main Currency</string>
|
||||||
|
|
||||||
|
<!-- Statistics -->
|
||||||
|
<string name="label_bills_suggested">Suggested Categories</string>
|
||||||
|
<string name="label_bills_skip">Skip</string>
|
||||||
|
<string name="stats_date_min">From</string>
|
||||||
|
<string name="stats_date_max">To</string>
|
||||||
|
<string name="stats_who">Member</string>
|
||||||
|
<string name="stats_paid">Paid</string>
|
||||||
|
<string name="stats_spent">Spent</string>
|
||||||
|
<string name="stats_balance">Balance</string>
|
||||||
|
<string name="total">Total: %1$s</string>
|
||||||
|
|
||||||
|
<!-- Errors Extra -->
|
||||||
|
<string name="error_project_connect_check">Connection failed: %1$s</string>
|
||||||
|
<string name="error_create_remote_project_helper">Creation failed: %1$s</string>
|
||||||
|
<string name="error_edit_remote_project_helper">Error updating remote project: %1$s</string>
|
||||||
|
<string name="remote_project_operation_no_network">Network unavailable for remote operation.</string>
|
||||||
|
<string name="error_scanning_bill_qr_code">Failed to parse QR code.</string>
|
||||||
|
<string name="error_token_mismatch">Authentication token mismatch. Please log in again.</string>
|
||||||
|
<string name="insufficient_access_level">You don\'t have permission to perform this action.</string>
|
||||||
|
<string name="delete_label_confirmation_title">Delete Label</string>
|
||||||
|
<string name="delete_label_confirmation_message">Are you sure you want to delete this label?</string>
|
||||||
|
|
||||||
|
<!-- About -->
|
||||||
|
<string name="about_version">Version %1$s</string>
|
||||||
|
<string name="about_maintainer_title">Maintainer</string>
|
||||||
|
<string name="about_license_title">License</string>
|
||||||
|
<string name="about_source_title">Source code</string>
|
||||||
|
|
||||||
|
<!-- New constants for backward compatibility or shared use -->
|
||||||
|
<string name="share_intent_title">Project %1$s</string>
|
||||||
|
<string name="share_chooser_title">Share %1$s</string>
|
||||||
|
|
||||||
|
</resources>
|
||||||
@@ -0,0 +1,272 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Untranslated: these are the English strings, kept here so a translation can be
|
||||||
|
contributed by simply replacing the values. Strings marked translatable="false" in
|
||||||
|
values/strings.xml (app and product names, preference keys) are deliberately absent
|
||||||
|
and must not be added.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- Actions -->
|
||||||
|
<string name="action_new_bill">New bill</string>
|
||||||
|
<string name="action_add_project">Add project</string>
|
||||||
|
<string name="action_save">Save</string>
|
||||||
|
<string name="action_edit">Edit</string>
|
||||||
|
<string name="action_share">Share</string>
|
||||||
|
<string name="action_search">Search</string>
|
||||||
|
<string name="action_open_menu">Open menu</string>
|
||||||
|
<string name="action_close_search">Close search</string>
|
||||||
|
<string name="action_clear_search">Clear search</string>
|
||||||
|
<string name="action_delete">Delete</string>
|
||||||
|
<string name="simple_back">Back</string>
|
||||||
|
<string name="action_archive">Archive</string>
|
||||||
|
<string name="action_unarchive">Unarchive</string>
|
||||||
|
<string name="action_export">Export</string>
|
||||||
|
<string name="action_stats">Stats</string>
|
||||||
|
<string name="action_settle">Settle</string>
|
||||||
|
<string name="action_scan_qrcode">Scan QR Code</string>
|
||||||
|
<string name="action_settings">Settings</string>
|
||||||
|
<string name="action_label_bills">Label missing categories</string>
|
||||||
|
<string name="action_logout">Logout</string>
|
||||||
|
<string name="action_connect">Connect</string>
|
||||||
|
<string name="action_discard">Discard</string>
|
||||||
|
<string name="action_members">Members</string>
|
||||||
|
<string name="action_labels">Labels</string>
|
||||||
|
<string name="action_currencies">Currencies</string>
|
||||||
|
|
||||||
|
<!-- Titles -->
|
||||||
|
<string name="title_stats">Statistics</string>
|
||||||
|
<string name="title_edit_project">Edit project</string>
|
||||||
|
<string name="title_label_bills">Label Bills</string>
|
||||||
|
<string name="title_labels">Manage Labels</string>
|
||||||
|
<string name="title_about">About</string>
|
||||||
|
<string name="title_settle">Settle Project</string>
|
||||||
|
<string name="title_share">Share Project</string>
|
||||||
|
<string name="title_add_project">Add Project</string>
|
||||||
|
<string name="title_add_category">Add Category</string>
|
||||||
|
<string name="title_add_payment_mode">Add Payment Mode</string>
|
||||||
|
<string name="title_account">Nextcloud Account</string>
|
||||||
|
<string name="title_share_web">Web link</string>
|
||||||
|
<string name="title_share_qr">Cowspent link</string>
|
||||||
|
<string name="title_confirm">Are you sure?</string>
|
||||||
|
|
||||||
|
<!-- Labels and Fields -->
|
||||||
|
<string name="label_all_bills">All bills</string>
|
||||||
|
<string name="label_categories">Categories</string>
|
||||||
|
<string name="label_payment_modes">Payment Modes</string>
|
||||||
|
<string name="label_name">Name</string>
|
||||||
|
<string name="label_icon">Icon / Emoji</string>
|
||||||
|
<string name="label_color">Color</string>
|
||||||
|
<string name="label_weight">Weight</string>
|
||||||
|
<string name="label_activated">Activated</string>
|
||||||
|
<string name="label_password">Password</string>
|
||||||
|
<string name="label_email">E-mail</string>
|
||||||
|
<string name="label_url">Server address</string>
|
||||||
|
<string name="label_username">Username</string>
|
||||||
|
<string name="label_comment">Comment</string>
|
||||||
|
<string name="label_what">What?</string>
|
||||||
|
<string name="label_payer">Who paid?</string>
|
||||||
|
<string name="label_owers">For whom?</string>
|
||||||
|
<string name="label_repeat">Repeat every</string>
|
||||||
|
<string name="label_mode">Mode</string>
|
||||||
|
<string name="label_category">Category</string>
|
||||||
|
<string name="label_project_id">Project ID/name</string>
|
||||||
|
<string name="label_project_title">Project title</string>
|
||||||
|
<string name="label_use_sso">Use Nextcloud App Account</string>
|
||||||
|
|
||||||
|
<!-- Dialogs and Messages -->
|
||||||
|
<string name="dialog_unsaved_changes_title">Unsaved changes</string>
|
||||||
|
<string name="dialog_unsaved_changes_msg">Save changes before leaving?</string>
|
||||||
|
<string name="dialog_confirm_remove_project_msg">The remote project will not be deleted.</string>
|
||||||
|
<string name="dialog_sync_error_title">Sync error</string>
|
||||||
|
<string name="dialog_sync_error_msg">Sync failed for %1$s.\n\n%2$s</string>
|
||||||
|
<string name="dialog_balanced_msg">Expenses are already balanced.</string>
|
||||||
|
<string name="msg_project_added">Project %1$s added</string>
|
||||||
|
<string name="msg_bill_labeled_done">All bills labeled</string>
|
||||||
|
<string name="msg_no_suggestions">No suggestions</string>
|
||||||
|
<string name="msg_auth_warning">Requires Cospend v0.3.4+.</string>
|
||||||
|
<string name="msg_link_copied">Link copied to clipboard</string>
|
||||||
|
<string name="msg_share_qr">Scan QR code or share the link to join.</string>
|
||||||
|
<string name="msg_share_web">Link for web browser access.</string>
|
||||||
|
<string name="msg_share_qr_warn">Share this link with a Cowspent user.</string>
|
||||||
|
<string name="msg_settle_intro">Settlement for %1$s:</string>
|
||||||
|
<string name="msg_settle_sentence">%1$s owes %3$.2f to %2$s</string>
|
||||||
|
<string name="msg_stats_intro">Stats for %1$s:</string>
|
||||||
|
<string name="msg_stats_header">Member (Paid | Spent | Balance)</string>
|
||||||
|
<string name="msg_logged_in_as">Logged in as %1$s</string>
|
||||||
|
|
||||||
|
<!-- Errors -->
|
||||||
|
<string name="error_generic">Error</string>
|
||||||
|
<string name="error_loading">Loading</string>
|
||||||
|
<string name="error_no_projects">No projects found</string>
|
||||||
|
<string name="error_no_members">No members found</string>
|
||||||
|
<string name="error_no_bills">No bills found</string>
|
||||||
|
<string name="error_no_member">At least one member required</string>
|
||||||
|
<string name="error_maintenance_mode">Server is in maintenance mode</string>
|
||||||
|
<string name="error_400">400 Bad request</string>
|
||||||
|
<string name="error_401">401 Unauthorized</string>
|
||||||
|
<string name="error_403">403 Forbidden</string>
|
||||||
|
<string name="error_404">404 Not Found</string>
|
||||||
|
<string name="error_sync">Sync failed: %1$s</string>
|
||||||
|
<string name="error_invalid_login">Invalid login: %1$s</string>
|
||||||
|
<string name="error_auth">Wrong username or password</string>
|
||||||
|
<string name="error_json">Invalid server response</string>
|
||||||
|
<string name="error_req_failed">Request failed</string>
|
||||||
|
<string name="error_invalid_email">Invalid e-mail</string>
|
||||||
|
<string name="error_invalid_project_id">Invalid project ID</string>
|
||||||
|
<string name="error_invalid_project_name">Invalid project title</string>
|
||||||
|
<string name="error_invalid_bill_name">Invalid bill name</string>
|
||||||
|
<string name="error_invalid_bill_date">Invalid bill date</string>
|
||||||
|
<string name="error_invalid_bill_payer">Payer required</string>
|
||||||
|
<string name="error_invalid_bill_owers">Owers required</string>
|
||||||
|
<string name="error_no_network">No network connection</string>
|
||||||
|
<string name="error_server">Server error</string>
|
||||||
|
<string name="error_io">Server connection broken</string>
|
||||||
|
<string name="error_share_impossible">Cannot share this project</string>
|
||||||
|
|
||||||
|
<!-- Drawer / Common UI -->
|
||||||
|
<string name="drawer_no_account">Connect to Nextcloud account</string>
|
||||||
|
<string name="drawer_last_sync">Last sync: %1$02d:%2$02d</string>
|
||||||
|
<string name="simple_cancel">Cancel</string>
|
||||||
|
<string name="simple_ok" tools:ignore="ButtonCase,Typos">Ok</string>
|
||||||
|
<string name="simple_yes">Yes</string>
|
||||||
|
<string name="simple_no">No</string>
|
||||||
|
<string name="simple_close">Close</string>
|
||||||
|
|
||||||
|
<!-- Settings -->
|
||||||
|
<string name="settings_appearance">Appearance</string>
|
||||||
|
<string name="settings_network">Network</string>
|
||||||
|
<string name="settings_other">Other</string>
|
||||||
|
<string name="settings_night_mode">Theme</string>
|
||||||
|
<string name="settings_offline_mode">Offline mode</string>
|
||||||
|
<string name="settings_offline_mode_summary">Only sync manually.</string>
|
||||||
|
<string name="settings_color_custom">Custom color</string>
|
||||||
|
<string name="settings_color_mode">Color Selection</string>
|
||||||
|
<string name="settings_show_archived">Show archived projects</string>
|
||||||
|
<string name="settings_beta_features">Beta Features</string>
|
||||||
|
<string name="settings_beta_features_summary">Enable experimental features. Use at your own risk.</string>
|
||||||
|
<string name="settings_fill_new_bill_from_last">Auto-fill from last bill</string>
|
||||||
|
<string name="settings_fill_new_bill_from_last_summary">Pre-fill payer, category, mode and owers from the last bill created in the project.</string>
|
||||||
|
<string name="settings_auto_sync_on_open">Sync interval</string>
|
||||||
|
<string name="settings_auto_sync_on_open_summary">How often to refresh the account and all projects when opening the app.</string>
|
||||||
|
<string name="pref_value_sync_1m">1 minute</string>
|
||||||
|
<string name="pref_value_sync_10m">10 minutes</string>
|
||||||
|
<string name="pref_value_sync_1h">1 hour</string>
|
||||||
|
<string name="pref_value_sync_1d">1 day</string>
|
||||||
|
<string name="settings_url_warn_http">WARNING: "http" is unsafe. Use "https".</string>
|
||||||
|
<string name="settings_colorpicker_title">Choose Color</string>
|
||||||
|
|
||||||
|
<string name="pref_value_color_system">System</string>
|
||||||
|
<string name="pref_value_color_manual">Manual</string>
|
||||||
|
<string name="pref_value_theme_light">Light</string>
|
||||||
|
<string name="pref_value_theme_dark">Dark</string>
|
||||||
|
<string name="pref_value_theme_system">Follow system</string>
|
||||||
|
|
||||||
|
<!-- Enums and Lists -->
|
||||||
|
<string name="repeat_no">No repeat</string>
|
||||||
|
<string name="repeat_day">Daily</string>
|
||||||
|
<string name="repeat_week">Weekly</string>
|
||||||
|
<string name="repeat_fortnight">Fortnightly</string>
|
||||||
|
<string name="repeat_month">Monthly</string>
|
||||||
|
<string name="repeat_year">Yearly</string>
|
||||||
|
|
||||||
|
<string name="payment_mode_none">None</string>
|
||||||
|
<string name="payment_mode_all">All</string>
|
||||||
|
<string name="payment_mode_credit_card">Credit card</string>
|
||||||
|
<string name="payment_mode_cash">Cash</string>
|
||||||
|
<string name="payment_mode_check">Check</string>
|
||||||
|
<string name="payment_mode_online">Online</string>
|
||||||
|
<string name="payment_mode_transfer">Transfer</string>
|
||||||
|
|
||||||
|
<string name="category_none">None</string>
|
||||||
|
<string name="category_all">All</string>
|
||||||
|
<string name="category_all_except_reimbursement">All except reimbursement</string>
|
||||||
|
<string name="category_groceries">Grocery</string>
|
||||||
|
<string name="category_leisure">Bar/Party</string>
|
||||||
|
<string name="category_rent">Rent</string>
|
||||||
|
<string name="category_bills">Bill</string>
|
||||||
|
<string name="category_excursion">Excursion/Culture</string>
|
||||||
|
<string name="category_health">Health</string>
|
||||||
|
<string name="category_shopping">Shopping</string>
|
||||||
|
<string name="category_reimbursement">Reimbursement</string>
|
||||||
|
<string name="category_restaurant">Restaurant</string>
|
||||||
|
<string name="category_accomodation">Accommodation</string>
|
||||||
|
<string name="category_transport">Transport</string>
|
||||||
|
<string name="category_sport">Sport</string>
|
||||||
|
|
||||||
|
<!-- Project specific -->
|
||||||
|
<string name="new_project_action">What</string>
|
||||||
|
<string name="new_project_where">Where</string>
|
||||||
|
<string name="where_local">Local only</string>
|
||||||
|
<string name="todo_join">Join existing project</string>
|
||||||
|
<string name="todo_create">Create new project</string>
|
||||||
|
<string name="import_tooltip">Import from file</string>
|
||||||
|
<string name="choose_project_management_action">Project</string>
|
||||||
|
<string name="project_added_success">Project added successfully.</string>
|
||||||
|
<string name="no_projects_text">You have no projects yet.</string>
|
||||||
|
<string name="configure_account_choice">Configure Nextcloud account</string>
|
||||||
|
<string name="add_project_choice">Add project manually</string>
|
||||||
|
<string name="no_members_text">No members in this project.</string>
|
||||||
|
<string name="no_bills_text">No bills found.</string>
|
||||||
|
<string name="member_already_exists">Member already exists.</string>
|
||||||
|
<string name="activity_dialog_title">Project: %1$s</string>
|
||||||
|
<string name="remove_project_confirmation">Project %1$s removed.</string>
|
||||||
|
<string name="file_saved_success">File saved: %1$s</string>
|
||||||
|
<string name="import_error_header">Import failed at row %d</string>
|
||||||
|
<string name="import_error_date">Invalid date format at row %d</string>
|
||||||
|
<string name="import_error_owers">Invalid owers at row %d</string>
|
||||||
|
<string name="add_member_dialog_title">Add Member</string>
|
||||||
|
<string name="edit_member_dialog_title">Edit Member</string>
|
||||||
|
<string name="member_edit_delete">Delete</string>
|
||||||
|
<string name="project_edition_no_change">No changes to save.</string>
|
||||||
|
|
||||||
|
<!-- Settlement -->
|
||||||
|
<string name="center_none">None (Optimal)</string>
|
||||||
|
<string name="settle_who">Who pays</string>
|
||||||
|
<string name="settle_to_whom">To whom</string>
|
||||||
|
<string name="settle_how_much">Amount</string>
|
||||||
|
<string name="simple_settle_share">Share</string>
|
||||||
|
<string name="simple_create_bills">Create bills</string>
|
||||||
|
<string name="settle_bill_what">Settlement</string>
|
||||||
|
|
||||||
|
<!-- Currencies -->
|
||||||
|
<string name="currency_dialog_title">Choose Currency (%s)</string>
|
||||||
|
<string name="setting_none">None</string>
|
||||||
|
<string name="setting_all">All</string>
|
||||||
|
<string name="currency_saved_success">Currency settings saved.</string>
|
||||||
|
<string name="main_currency">Main Currency</string>
|
||||||
|
|
||||||
|
<!-- Statistics -->
|
||||||
|
<string name="label_bills_suggested">Suggested Categories</string>
|
||||||
|
<string name="label_bills_skip">Skip</string>
|
||||||
|
<string name="stats_date_min">From</string>
|
||||||
|
<string name="stats_date_max">To</string>
|
||||||
|
<string name="stats_who">Member</string>
|
||||||
|
<string name="stats_paid">Paid</string>
|
||||||
|
<string name="stats_spent">Spent</string>
|
||||||
|
<string name="stats_balance">Balance</string>
|
||||||
|
<string name="total">Total: %1$s</string>
|
||||||
|
|
||||||
|
<!-- Errors Extra -->
|
||||||
|
<string name="error_project_connect_check">Connection failed: %1$s</string>
|
||||||
|
<string name="error_create_remote_project_helper">Creation failed: %1$s</string>
|
||||||
|
<string name="error_edit_remote_project_helper">Error updating remote project: %1$s</string>
|
||||||
|
<string name="remote_project_operation_no_network">Network unavailable for remote operation.</string>
|
||||||
|
<string name="error_scanning_bill_qr_code">Failed to parse QR code.</string>
|
||||||
|
<string name="error_token_mismatch">Authentication token mismatch. Please log in again.</string>
|
||||||
|
<string name="insufficient_access_level">You don\'t have permission to perform this action.</string>
|
||||||
|
<string name="delete_label_confirmation_title">Delete Label</string>
|
||||||
|
<string name="delete_label_confirmation_message">Are you sure you want to delete this label?</string>
|
||||||
|
|
||||||
|
<!-- About -->
|
||||||
|
<string name="about_version">Version %1$s</string>
|
||||||
|
<string name="about_maintainer_title">Maintainer</string>
|
||||||
|
<string name="about_license_title">License</string>
|
||||||
|
<string name="about_source_title">Source code</string>
|
||||||
|
|
||||||
|
<!-- New constants for backward compatibility or shared use -->
|
||||||
|
<string name="share_intent_title">Project %1$s</string>
|
||||||
|
<string name="share_chooser_title">Share %1$s</string>
|
||||||
|
|
||||||
|
</resources>
|
||||||
@@ -0,0 +1,272 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Untranslated: these are the English strings, kept here so a translation can be
|
||||||
|
contributed by simply replacing the values. Strings marked translatable="false" in
|
||||||
|
values/strings.xml (app and product names, preference keys) are deliberately absent
|
||||||
|
and must not be added.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- Actions -->
|
||||||
|
<string name="action_new_bill">New bill</string>
|
||||||
|
<string name="action_add_project">Add project</string>
|
||||||
|
<string name="action_save">Save</string>
|
||||||
|
<string name="action_edit">Edit</string>
|
||||||
|
<string name="action_share">Share</string>
|
||||||
|
<string name="action_search">Search</string>
|
||||||
|
<string name="action_open_menu">Open menu</string>
|
||||||
|
<string name="action_close_search">Close search</string>
|
||||||
|
<string name="action_clear_search">Clear search</string>
|
||||||
|
<string name="action_delete">Delete</string>
|
||||||
|
<string name="simple_back">Back</string>
|
||||||
|
<string name="action_archive">Archive</string>
|
||||||
|
<string name="action_unarchive">Unarchive</string>
|
||||||
|
<string name="action_export">Export</string>
|
||||||
|
<string name="action_stats">Stats</string>
|
||||||
|
<string name="action_settle">Settle</string>
|
||||||
|
<string name="action_scan_qrcode">Scan QR Code</string>
|
||||||
|
<string name="action_settings">Settings</string>
|
||||||
|
<string name="action_label_bills">Label missing categories</string>
|
||||||
|
<string name="action_logout">Logout</string>
|
||||||
|
<string name="action_connect">Connect</string>
|
||||||
|
<string name="action_discard">Discard</string>
|
||||||
|
<string name="action_members">Members</string>
|
||||||
|
<string name="action_labels">Labels</string>
|
||||||
|
<string name="action_currencies">Currencies</string>
|
||||||
|
|
||||||
|
<!-- Titles -->
|
||||||
|
<string name="title_stats">Statistics</string>
|
||||||
|
<string name="title_edit_project">Edit project</string>
|
||||||
|
<string name="title_label_bills">Label Bills</string>
|
||||||
|
<string name="title_labels">Manage Labels</string>
|
||||||
|
<string name="title_about">About</string>
|
||||||
|
<string name="title_settle">Settle Project</string>
|
||||||
|
<string name="title_share">Share Project</string>
|
||||||
|
<string name="title_add_project">Add Project</string>
|
||||||
|
<string name="title_add_category">Add Category</string>
|
||||||
|
<string name="title_add_payment_mode">Add Payment Mode</string>
|
||||||
|
<string name="title_account">Nextcloud Account</string>
|
||||||
|
<string name="title_share_web">Web link</string>
|
||||||
|
<string name="title_share_qr">Cowspent link</string>
|
||||||
|
<string name="title_confirm">Are you sure?</string>
|
||||||
|
|
||||||
|
<!-- Labels and Fields -->
|
||||||
|
<string name="label_all_bills">All bills</string>
|
||||||
|
<string name="label_categories">Categories</string>
|
||||||
|
<string name="label_payment_modes">Payment Modes</string>
|
||||||
|
<string name="label_name">Name</string>
|
||||||
|
<string name="label_icon">Icon / Emoji</string>
|
||||||
|
<string name="label_color">Color</string>
|
||||||
|
<string name="label_weight">Weight</string>
|
||||||
|
<string name="label_activated">Activated</string>
|
||||||
|
<string name="label_password">Password</string>
|
||||||
|
<string name="label_email">E-mail</string>
|
||||||
|
<string name="label_url">Server address</string>
|
||||||
|
<string name="label_username">Username</string>
|
||||||
|
<string name="label_comment">Comment</string>
|
||||||
|
<string name="label_what">What?</string>
|
||||||
|
<string name="label_payer">Who paid?</string>
|
||||||
|
<string name="label_owers">For whom?</string>
|
||||||
|
<string name="label_repeat">Repeat every</string>
|
||||||
|
<string name="label_mode">Mode</string>
|
||||||
|
<string name="label_category">Category</string>
|
||||||
|
<string name="label_project_id">Project ID/name</string>
|
||||||
|
<string name="label_project_title">Project title</string>
|
||||||
|
<string name="label_use_sso">Use Nextcloud App Account</string>
|
||||||
|
|
||||||
|
<!-- Dialogs and Messages -->
|
||||||
|
<string name="dialog_unsaved_changes_title">Unsaved changes</string>
|
||||||
|
<string name="dialog_unsaved_changes_msg">Save changes before leaving?</string>
|
||||||
|
<string name="dialog_confirm_remove_project_msg">The remote project will not be deleted.</string>
|
||||||
|
<string name="dialog_sync_error_title">Sync error</string>
|
||||||
|
<string name="dialog_sync_error_msg">Sync failed for %1$s.\n\n%2$s</string>
|
||||||
|
<string name="dialog_balanced_msg">Expenses are already balanced.</string>
|
||||||
|
<string name="msg_project_added">Project %1$s added</string>
|
||||||
|
<string name="msg_bill_labeled_done">All bills labeled</string>
|
||||||
|
<string name="msg_no_suggestions">No suggestions</string>
|
||||||
|
<string name="msg_auth_warning">Requires Cospend v0.3.4+.</string>
|
||||||
|
<string name="msg_link_copied">Link copied to clipboard</string>
|
||||||
|
<string name="msg_share_qr">Scan QR code or share the link to join.</string>
|
||||||
|
<string name="msg_share_web">Link for web browser access.</string>
|
||||||
|
<string name="msg_share_qr_warn">Share this link with a Cowspent user.</string>
|
||||||
|
<string name="msg_settle_intro">Settlement for %1$s:</string>
|
||||||
|
<string name="msg_settle_sentence">%1$s owes %3$.2f to %2$s</string>
|
||||||
|
<string name="msg_stats_intro">Stats for %1$s:</string>
|
||||||
|
<string name="msg_stats_header">Member (Paid | Spent | Balance)</string>
|
||||||
|
<string name="msg_logged_in_as">Logged in as %1$s</string>
|
||||||
|
|
||||||
|
<!-- Errors -->
|
||||||
|
<string name="error_generic">Error</string>
|
||||||
|
<string name="error_loading">Loading</string>
|
||||||
|
<string name="error_no_projects">No projects found</string>
|
||||||
|
<string name="error_no_members">No members found</string>
|
||||||
|
<string name="error_no_bills">No bills found</string>
|
||||||
|
<string name="error_no_member">At least one member required</string>
|
||||||
|
<string name="error_maintenance_mode">Server is in maintenance mode</string>
|
||||||
|
<string name="error_400">400 Bad request</string>
|
||||||
|
<string name="error_401">401 Unauthorized</string>
|
||||||
|
<string name="error_403">403 Forbidden</string>
|
||||||
|
<string name="error_404">404 Not Found</string>
|
||||||
|
<string name="error_sync">Sync failed: %1$s</string>
|
||||||
|
<string name="error_invalid_login">Invalid login: %1$s</string>
|
||||||
|
<string name="error_auth">Wrong username or password</string>
|
||||||
|
<string name="error_json">Invalid server response</string>
|
||||||
|
<string name="error_req_failed">Request failed</string>
|
||||||
|
<string name="error_invalid_email">Invalid e-mail</string>
|
||||||
|
<string name="error_invalid_project_id">Invalid project ID</string>
|
||||||
|
<string name="error_invalid_project_name">Invalid project title</string>
|
||||||
|
<string name="error_invalid_bill_name">Invalid bill name</string>
|
||||||
|
<string name="error_invalid_bill_date">Invalid bill date</string>
|
||||||
|
<string name="error_invalid_bill_payer">Payer required</string>
|
||||||
|
<string name="error_invalid_bill_owers">Owers required</string>
|
||||||
|
<string name="error_no_network">No network connection</string>
|
||||||
|
<string name="error_server">Server error</string>
|
||||||
|
<string name="error_io">Server connection broken</string>
|
||||||
|
<string name="error_share_impossible">Cannot share this project</string>
|
||||||
|
|
||||||
|
<!-- Drawer / Common UI -->
|
||||||
|
<string name="drawer_no_account">Connect to Nextcloud account</string>
|
||||||
|
<string name="drawer_last_sync">Last sync: %1$02d:%2$02d</string>
|
||||||
|
<string name="simple_cancel">Cancel</string>
|
||||||
|
<string name="simple_ok" tools:ignore="ButtonCase,Typos">Ok</string>
|
||||||
|
<string name="simple_yes">Yes</string>
|
||||||
|
<string name="simple_no">No</string>
|
||||||
|
<string name="simple_close">Close</string>
|
||||||
|
|
||||||
|
<!-- Settings -->
|
||||||
|
<string name="settings_appearance">Appearance</string>
|
||||||
|
<string name="settings_network">Network</string>
|
||||||
|
<string name="settings_other">Other</string>
|
||||||
|
<string name="settings_night_mode">Theme</string>
|
||||||
|
<string name="settings_offline_mode">Offline mode</string>
|
||||||
|
<string name="settings_offline_mode_summary">Only sync manually.</string>
|
||||||
|
<string name="settings_color_custom">Custom color</string>
|
||||||
|
<string name="settings_color_mode">Color Selection</string>
|
||||||
|
<string name="settings_show_archived">Show archived projects</string>
|
||||||
|
<string name="settings_beta_features">Beta Features</string>
|
||||||
|
<string name="settings_beta_features_summary">Enable experimental features. Use at your own risk.</string>
|
||||||
|
<string name="settings_fill_new_bill_from_last">Auto-fill from last bill</string>
|
||||||
|
<string name="settings_fill_new_bill_from_last_summary">Pre-fill payer, category, mode and owers from the last bill created in the project.</string>
|
||||||
|
<string name="settings_auto_sync_on_open">Sync interval</string>
|
||||||
|
<string name="settings_auto_sync_on_open_summary">How often to refresh the account and all projects when opening the app.</string>
|
||||||
|
<string name="pref_value_sync_1m">1 minute</string>
|
||||||
|
<string name="pref_value_sync_10m">10 minutes</string>
|
||||||
|
<string name="pref_value_sync_1h">1 hour</string>
|
||||||
|
<string name="pref_value_sync_1d">1 day</string>
|
||||||
|
<string name="settings_url_warn_http">WARNING: "http" is unsafe. Use "https".</string>
|
||||||
|
<string name="settings_colorpicker_title">Choose Color</string>
|
||||||
|
|
||||||
|
<string name="pref_value_color_system">System</string>
|
||||||
|
<string name="pref_value_color_manual">Manual</string>
|
||||||
|
<string name="pref_value_theme_light">Light</string>
|
||||||
|
<string name="pref_value_theme_dark">Dark</string>
|
||||||
|
<string name="pref_value_theme_system">Follow system</string>
|
||||||
|
|
||||||
|
<!-- Enums and Lists -->
|
||||||
|
<string name="repeat_no">No repeat</string>
|
||||||
|
<string name="repeat_day">Daily</string>
|
||||||
|
<string name="repeat_week">Weekly</string>
|
||||||
|
<string name="repeat_fortnight">Fortnightly</string>
|
||||||
|
<string name="repeat_month">Monthly</string>
|
||||||
|
<string name="repeat_year">Yearly</string>
|
||||||
|
|
||||||
|
<string name="payment_mode_none">None</string>
|
||||||
|
<string name="payment_mode_all">All</string>
|
||||||
|
<string name="payment_mode_credit_card">Credit card</string>
|
||||||
|
<string name="payment_mode_cash">Cash</string>
|
||||||
|
<string name="payment_mode_check">Check</string>
|
||||||
|
<string name="payment_mode_online">Online</string>
|
||||||
|
<string name="payment_mode_transfer">Transfer</string>
|
||||||
|
|
||||||
|
<string name="category_none">None</string>
|
||||||
|
<string name="category_all">All</string>
|
||||||
|
<string name="category_all_except_reimbursement">All except reimbursement</string>
|
||||||
|
<string name="category_groceries">Grocery</string>
|
||||||
|
<string name="category_leisure">Bar/Party</string>
|
||||||
|
<string name="category_rent">Rent</string>
|
||||||
|
<string name="category_bills">Bill</string>
|
||||||
|
<string name="category_excursion">Excursion/Culture</string>
|
||||||
|
<string name="category_health">Health</string>
|
||||||
|
<string name="category_shopping">Shopping</string>
|
||||||
|
<string name="category_reimbursement">Reimbursement</string>
|
||||||
|
<string name="category_restaurant">Restaurant</string>
|
||||||
|
<string name="category_accomodation">Accommodation</string>
|
||||||
|
<string name="category_transport">Transport</string>
|
||||||
|
<string name="category_sport">Sport</string>
|
||||||
|
|
||||||
|
<!-- Project specific -->
|
||||||
|
<string name="new_project_action">What</string>
|
||||||
|
<string name="new_project_where">Where</string>
|
||||||
|
<string name="where_local">Local only</string>
|
||||||
|
<string name="todo_join">Join existing project</string>
|
||||||
|
<string name="todo_create">Create new project</string>
|
||||||
|
<string name="import_tooltip">Import from file</string>
|
||||||
|
<string name="choose_project_management_action">Project</string>
|
||||||
|
<string name="project_added_success">Project added successfully.</string>
|
||||||
|
<string name="no_projects_text">You have no projects yet.</string>
|
||||||
|
<string name="configure_account_choice">Configure Nextcloud account</string>
|
||||||
|
<string name="add_project_choice">Add project manually</string>
|
||||||
|
<string name="no_members_text">No members in this project.</string>
|
||||||
|
<string name="no_bills_text">No bills found.</string>
|
||||||
|
<string name="member_already_exists">Member already exists.</string>
|
||||||
|
<string name="activity_dialog_title">Project: %1$s</string>
|
||||||
|
<string name="remove_project_confirmation">Project %1$s removed.</string>
|
||||||
|
<string name="file_saved_success">File saved: %1$s</string>
|
||||||
|
<string name="import_error_header">Import failed at row %d</string>
|
||||||
|
<string name="import_error_date">Invalid date format at row %d</string>
|
||||||
|
<string name="import_error_owers">Invalid owers at row %d</string>
|
||||||
|
<string name="add_member_dialog_title">Add Member</string>
|
||||||
|
<string name="edit_member_dialog_title">Edit Member</string>
|
||||||
|
<string name="member_edit_delete">Delete</string>
|
||||||
|
<string name="project_edition_no_change">No changes to save.</string>
|
||||||
|
|
||||||
|
<!-- Settlement -->
|
||||||
|
<string name="center_none">None (Optimal)</string>
|
||||||
|
<string name="settle_who">Who pays</string>
|
||||||
|
<string name="settle_to_whom">To whom</string>
|
||||||
|
<string name="settle_how_much">Amount</string>
|
||||||
|
<string name="simple_settle_share">Share</string>
|
||||||
|
<string name="simple_create_bills">Create bills</string>
|
||||||
|
<string name="settle_bill_what">Settlement</string>
|
||||||
|
|
||||||
|
<!-- Currencies -->
|
||||||
|
<string name="currency_dialog_title">Choose Currency (%s)</string>
|
||||||
|
<string name="setting_none">None</string>
|
||||||
|
<string name="setting_all">All</string>
|
||||||
|
<string name="currency_saved_success">Currency settings saved.</string>
|
||||||
|
<string name="main_currency">Main Currency</string>
|
||||||
|
|
||||||
|
<!-- Statistics -->
|
||||||
|
<string name="label_bills_suggested">Suggested Categories</string>
|
||||||
|
<string name="label_bills_skip">Skip</string>
|
||||||
|
<string name="stats_date_min">From</string>
|
||||||
|
<string name="stats_date_max">To</string>
|
||||||
|
<string name="stats_who">Member</string>
|
||||||
|
<string name="stats_paid">Paid</string>
|
||||||
|
<string name="stats_spent">Spent</string>
|
||||||
|
<string name="stats_balance">Balance</string>
|
||||||
|
<string name="total">Total: %1$s</string>
|
||||||
|
|
||||||
|
<!-- Errors Extra -->
|
||||||
|
<string name="error_project_connect_check">Connection failed: %1$s</string>
|
||||||
|
<string name="error_create_remote_project_helper">Creation failed: %1$s</string>
|
||||||
|
<string name="error_edit_remote_project_helper">Error updating remote project: %1$s</string>
|
||||||
|
<string name="remote_project_operation_no_network">Network unavailable for remote operation.</string>
|
||||||
|
<string name="error_scanning_bill_qr_code">Failed to parse QR code.</string>
|
||||||
|
<string name="error_token_mismatch">Authentication token mismatch. Please log in again.</string>
|
||||||
|
<string name="insufficient_access_level">You don\'t have permission to perform this action.</string>
|
||||||
|
<string name="delete_label_confirmation_title">Delete Label</string>
|
||||||
|
<string name="delete_label_confirmation_message">Are you sure you want to delete this label?</string>
|
||||||
|
|
||||||
|
<!-- About -->
|
||||||
|
<string name="about_version">Version %1$s</string>
|
||||||
|
<string name="about_maintainer_title">Maintainer</string>
|
||||||
|
<string name="about_license_title">License</string>
|
||||||
|
<string name="about_source_title">Source code</string>
|
||||||
|
|
||||||
|
<!-- New constants for backward compatibility or shared use -->
|
||||||
|
<string name="share_intent_title">Project %1$s</string>
|
||||||
|
<string name="share_chooser_title">Share %1$s</string>
|
||||||
|
|
||||||
|
</resources>
|
||||||
@@ -0,0 +1,272 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Untranslated: these are the English strings, kept here so a translation can be
|
||||||
|
contributed by simply replacing the values. Strings marked translatable="false" in
|
||||||
|
values/strings.xml (app and product names, preference keys) are deliberately absent
|
||||||
|
and must not be added.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- Actions -->
|
||||||
|
<string name="action_new_bill">New bill</string>
|
||||||
|
<string name="action_add_project">Add project</string>
|
||||||
|
<string name="action_save">Save</string>
|
||||||
|
<string name="action_edit">Edit</string>
|
||||||
|
<string name="action_share">Share</string>
|
||||||
|
<string name="action_search">Search</string>
|
||||||
|
<string name="action_open_menu">Open menu</string>
|
||||||
|
<string name="action_close_search">Close search</string>
|
||||||
|
<string name="action_clear_search">Clear search</string>
|
||||||
|
<string name="action_delete">Delete</string>
|
||||||
|
<string name="simple_back">Back</string>
|
||||||
|
<string name="action_archive">Archive</string>
|
||||||
|
<string name="action_unarchive">Unarchive</string>
|
||||||
|
<string name="action_export">Export</string>
|
||||||
|
<string name="action_stats">Stats</string>
|
||||||
|
<string name="action_settle">Settle</string>
|
||||||
|
<string name="action_scan_qrcode">Scan QR Code</string>
|
||||||
|
<string name="action_settings">Settings</string>
|
||||||
|
<string name="action_label_bills">Label missing categories</string>
|
||||||
|
<string name="action_logout">Logout</string>
|
||||||
|
<string name="action_connect">Connect</string>
|
||||||
|
<string name="action_discard">Discard</string>
|
||||||
|
<string name="action_members">Members</string>
|
||||||
|
<string name="action_labels">Labels</string>
|
||||||
|
<string name="action_currencies">Currencies</string>
|
||||||
|
|
||||||
|
<!-- Titles -->
|
||||||
|
<string name="title_stats">Statistics</string>
|
||||||
|
<string name="title_edit_project">Edit project</string>
|
||||||
|
<string name="title_label_bills">Label Bills</string>
|
||||||
|
<string name="title_labels">Manage Labels</string>
|
||||||
|
<string name="title_about">About</string>
|
||||||
|
<string name="title_settle">Settle Project</string>
|
||||||
|
<string name="title_share">Share Project</string>
|
||||||
|
<string name="title_add_project">Add Project</string>
|
||||||
|
<string name="title_add_category">Add Category</string>
|
||||||
|
<string name="title_add_payment_mode">Add Payment Mode</string>
|
||||||
|
<string name="title_account">Nextcloud Account</string>
|
||||||
|
<string name="title_share_web">Web link</string>
|
||||||
|
<string name="title_share_qr">Cowspent link</string>
|
||||||
|
<string name="title_confirm">Are you sure?</string>
|
||||||
|
|
||||||
|
<!-- Labels and Fields -->
|
||||||
|
<string name="label_all_bills">All bills</string>
|
||||||
|
<string name="label_categories">Categories</string>
|
||||||
|
<string name="label_payment_modes">Payment Modes</string>
|
||||||
|
<string name="label_name">Name</string>
|
||||||
|
<string name="label_icon">Icon / Emoji</string>
|
||||||
|
<string name="label_color">Color</string>
|
||||||
|
<string name="label_weight">Weight</string>
|
||||||
|
<string name="label_activated">Activated</string>
|
||||||
|
<string name="label_password">Password</string>
|
||||||
|
<string name="label_email">E-mail</string>
|
||||||
|
<string name="label_url">Server address</string>
|
||||||
|
<string name="label_username">Username</string>
|
||||||
|
<string name="label_comment">Comment</string>
|
||||||
|
<string name="label_what">What?</string>
|
||||||
|
<string name="label_payer">Who paid?</string>
|
||||||
|
<string name="label_owers">For whom?</string>
|
||||||
|
<string name="label_repeat">Repeat every</string>
|
||||||
|
<string name="label_mode">Mode</string>
|
||||||
|
<string name="label_category">Category</string>
|
||||||
|
<string name="label_project_id">Project ID/name</string>
|
||||||
|
<string name="label_project_title">Project title</string>
|
||||||
|
<string name="label_use_sso">Use Nextcloud App Account</string>
|
||||||
|
|
||||||
|
<!-- Dialogs and Messages -->
|
||||||
|
<string name="dialog_unsaved_changes_title">Unsaved changes</string>
|
||||||
|
<string name="dialog_unsaved_changes_msg">Save changes before leaving?</string>
|
||||||
|
<string name="dialog_confirm_remove_project_msg">The remote project will not be deleted.</string>
|
||||||
|
<string name="dialog_sync_error_title">Sync error</string>
|
||||||
|
<string name="dialog_sync_error_msg">Sync failed for %1$s.\n\n%2$s</string>
|
||||||
|
<string name="dialog_balanced_msg">Expenses are already balanced.</string>
|
||||||
|
<string name="msg_project_added">Project %1$s added</string>
|
||||||
|
<string name="msg_bill_labeled_done">All bills labeled</string>
|
||||||
|
<string name="msg_no_suggestions">No suggestions</string>
|
||||||
|
<string name="msg_auth_warning">Requires Cospend v0.3.4+.</string>
|
||||||
|
<string name="msg_link_copied">Link copied to clipboard</string>
|
||||||
|
<string name="msg_share_qr">Scan QR code or share the link to join.</string>
|
||||||
|
<string name="msg_share_web">Link for web browser access.</string>
|
||||||
|
<string name="msg_share_qr_warn">Share this link with a Cowspent user.</string>
|
||||||
|
<string name="msg_settle_intro">Settlement for %1$s:</string>
|
||||||
|
<string name="msg_settle_sentence">%1$s owes %3$.2f to %2$s</string>
|
||||||
|
<string name="msg_stats_intro">Stats for %1$s:</string>
|
||||||
|
<string name="msg_stats_header">Member (Paid | Spent | Balance)</string>
|
||||||
|
<string name="msg_logged_in_as">Logged in as %1$s</string>
|
||||||
|
|
||||||
|
<!-- Errors -->
|
||||||
|
<string name="error_generic">Error</string>
|
||||||
|
<string name="error_loading">Loading</string>
|
||||||
|
<string name="error_no_projects">No projects found</string>
|
||||||
|
<string name="error_no_members">No members found</string>
|
||||||
|
<string name="error_no_bills">No bills found</string>
|
||||||
|
<string name="error_no_member">At least one member required</string>
|
||||||
|
<string name="error_maintenance_mode">Server is in maintenance mode</string>
|
||||||
|
<string name="error_400">400 Bad request</string>
|
||||||
|
<string name="error_401">401 Unauthorized</string>
|
||||||
|
<string name="error_403">403 Forbidden</string>
|
||||||
|
<string name="error_404">404 Not Found</string>
|
||||||
|
<string name="error_sync">Sync failed: %1$s</string>
|
||||||
|
<string name="error_invalid_login">Invalid login: %1$s</string>
|
||||||
|
<string name="error_auth">Wrong username or password</string>
|
||||||
|
<string name="error_json">Invalid server response</string>
|
||||||
|
<string name="error_req_failed">Request failed</string>
|
||||||
|
<string name="error_invalid_email">Invalid e-mail</string>
|
||||||
|
<string name="error_invalid_project_id">Invalid project ID</string>
|
||||||
|
<string name="error_invalid_project_name">Invalid project title</string>
|
||||||
|
<string name="error_invalid_bill_name">Invalid bill name</string>
|
||||||
|
<string name="error_invalid_bill_date">Invalid bill date</string>
|
||||||
|
<string name="error_invalid_bill_payer">Payer required</string>
|
||||||
|
<string name="error_invalid_bill_owers">Owers required</string>
|
||||||
|
<string name="error_no_network">No network connection</string>
|
||||||
|
<string name="error_server">Server error</string>
|
||||||
|
<string name="error_io">Server connection broken</string>
|
||||||
|
<string name="error_share_impossible">Cannot share this project</string>
|
||||||
|
|
||||||
|
<!-- Drawer / Common UI -->
|
||||||
|
<string name="drawer_no_account">Connect to Nextcloud account</string>
|
||||||
|
<string name="drawer_last_sync">Last sync: %1$02d:%2$02d</string>
|
||||||
|
<string name="simple_cancel">Cancel</string>
|
||||||
|
<string name="simple_ok" tools:ignore="ButtonCase,Typos">Ok</string>
|
||||||
|
<string name="simple_yes">Yes</string>
|
||||||
|
<string name="simple_no">No</string>
|
||||||
|
<string name="simple_close">Close</string>
|
||||||
|
|
||||||
|
<!-- Settings -->
|
||||||
|
<string name="settings_appearance">Appearance</string>
|
||||||
|
<string name="settings_network">Network</string>
|
||||||
|
<string name="settings_other">Other</string>
|
||||||
|
<string name="settings_night_mode">Theme</string>
|
||||||
|
<string name="settings_offline_mode">Offline mode</string>
|
||||||
|
<string name="settings_offline_mode_summary">Only sync manually.</string>
|
||||||
|
<string name="settings_color_custom">Custom color</string>
|
||||||
|
<string name="settings_color_mode">Color Selection</string>
|
||||||
|
<string name="settings_show_archived">Show archived projects</string>
|
||||||
|
<string name="settings_beta_features">Beta Features</string>
|
||||||
|
<string name="settings_beta_features_summary">Enable experimental features. Use at your own risk.</string>
|
||||||
|
<string name="settings_fill_new_bill_from_last">Auto-fill from last bill</string>
|
||||||
|
<string name="settings_fill_new_bill_from_last_summary">Pre-fill payer, category, mode and owers from the last bill created in the project.</string>
|
||||||
|
<string name="settings_auto_sync_on_open">Sync interval</string>
|
||||||
|
<string name="settings_auto_sync_on_open_summary">How often to refresh the account and all projects when opening the app.</string>
|
||||||
|
<string name="pref_value_sync_1m">1 minute</string>
|
||||||
|
<string name="pref_value_sync_10m">10 minutes</string>
|
||||||
|
<string name="pref_value_sync_1h">1 hour</string>
|
||||||
|
<string name="pref_value_sync_1d">1 day</string>
|
||||||
|
<string name="settings_url_warn_http">WARNING: "http" is unsafe. Use "https".</string>
|
||||||
|
<string name="settings_colorpicker_title">Choose Color</string>
|
||||||
|
|
||||||
|
<string name="pref_value_color_system">System</string>
|
||||||
|
<string name="pref_value_color_manual">Manual</string>
|
||||||
|
<string name="pref_value_theme_light">Light</string>
|
||||||
|
<string name="pref_value_theme_dark">Dark</string>
|
||||||
|
<string name="pref_value_theme_system">Follow system</string>
|
||||||
|
|
||||||
|
<!-- Enums and Lists -->
|
||||||
|
<string name="repeat_no">No repeat</string>
|
||||||
|
<string name="repeat_day">Daily</string>
|
||||||
|
<string name="repeat_week">Weekly</string>
|
||||||
|
<string name="repeat_fortnight">Fortnightly</string>
|
||||||
|
<string name="repeat_month">Monthly</string>
|
||||||
|
<string name="repeat_year">Yearly</string>
|
||||||
|
|
||||||
|
<string name="payment_mode_none">None</string>
|
||||||
|
<string name="payment_mode_all">All</string>
|
||||||
|
<string name="payment_mode_credit_card">Credit card</string>
|
||||||
|
<string name="payment_mode_cash">Cash</string>
|
||||||
|
<string name="payment_mode_check">Check</string>
|
||||||
|
<string name="payment_mode_online">Online</string>
|
||||||
|
<string name="payment_mode_transfer">Transfer</string>
|
||||||
|
|
||||||
|
<string name="category_none">None</string>
|
||||||
|
<string name="category_all">All</string>
|
||||||
|
<string name="category_all_except_reimbursement">All except reimbursement</string>
|
||||||
|
<string name="category_groceries">Grocery</string>
|
||||||
|
<string name="category_leisure">Bar/Party</string>
|
||||||
|
<string name="category_rent">Rent</string>
|
||||||
|
<string name="category_bills">Bill</string>
|
||||||
|
<string name="category_excursion">Excursion/Culture</string>
|
||||||
|
<string name="category_health">Health</string>
|
||||||
|
<string name="category_shopping">Shopping</string>
|
||||||
|
<string name="category_reimbursement">Reimbursement</string>
|
||||||
|
<string name="category_restaurant">Restaurant</string>
|
||||||
|
<string name="category_accomodation">Accommodation</string>
|
||||||
|
<string name="category_transport">Transport</string>
|
||||||
|
<string name="category_sport">Sport</string>
|
||||||
|
|
||||||
|
<!-- Project specific -->
|
||||||
|
<string name="new_project_action">What</string>
|
||||||
|
<string name="new_project_where">Where</string>
|
||||||
|
<string name="where_local">Local only</string>
|
||||||
|
<string name="todo_join">Join existing project</string>
|
||||||
|
<string name="todo_create">Create new project</string>
|
||||||
|
<string name="import_tooltip">Import from file</string>
|
||||||
|
<string name="choose_project_management_action">Project</string>
|
||||||
|
<string name="project_added_success">Project added successfully.</string>
|
||||||
|
<string name="no_projects_text">You have no projects yet.</string>
|
||||||
|
<string name="configure_account_choice">Configure Nextcloud account</string>
|
||||||
|
<string name="add_project_choice">Add project manually</string>
|
||||||
|
<string name="no_members_text">No members in this project.</string>
|
||||||
|
<string name="no_bills_text">No bills found.</string>
|
||||||
|
<string name="member_already_exists">Member already exists.</string>
|
||||||
|
<string name="activity_dialog_title">Project: %1$s</string>
|
||||||
|
<string name="remove_project_confirmation">Project %1$s removed.</string>
|
||||||
|
<string name="file_saved_success">File saved: %1$s</string>
|
||||||
|
<string name="import_error_header">Import failed at row %d</string>
|
||||||
|
<string name="import_error_date">Invalid date format at row %d</string>
|
||||||
|
<string name="import_error_owers">Invalid owers at row %d</string>
|
||||||
|
<string name="add_member_dialog_title">Add Member</string>
|
||||||
|
<string name="edit_member_dialog_title">Edit Member</string>
|
||||||
|
<string name="member_edit_delete">Delete</string>
|
||||||
|
<string name="project_edition_no_change">No changes to save.</string>
|
||||||
|
|
||||||
|
<!-- Settlement -->
|
||||||
|
<string name="center_none">None (Optimal)</string>
|
||||||
|
<string name="settle_who">Who pays</string>
|
||||||
|
<string name="settle_to_whom">To whom</string>
|
||||||
|
<string name="settle_how_much">Amount</string>
|
||||||
|
<string name="simple_settle_share">Share</string>
|
||||||
|
<string name="simple_create_bills">Create bills</string>
|
||||||
|
<string name="settle_bill_what">Settlement</string>
|
||||||
|
|
||||||
|
<!-- Currencies -->
|
||||||
|
<string name="currency_dialog_title">Choose Currency (%s)</string>
|
||||||
|
<string name="setting_none">None</string>
|
||||||
|
<string name="setting_all">All</string>
|
||||||
|
<string name="currency_saved_success">Currency settings saved.</string>
|
||||||
|
<string name="main_currency">Main Currency</string>
|
||||||
|
|
||||||
|
<!-- Statistics -->
|
||||||
|
<string name="label_bills_suggested">Suggested Categories</string>
|
||||||
|
<string name="label_bills_skip">Skip</string>
|
||||||
|
<string name="stats_date_min">From</string>
|
||||||
|
<string name="stats_date_max">To</string>
|
||||||
|
<string name="stats_who">Member</string>
|
||||||
|
<string name="stats_paid">Paid</string>
|
||||||
|
<string name="stats_spent">Spent</string>
|
||||||
|
<string name="stats_balance">Balance</string>
|
||||||
|
<string name="total">Total: %1$s</string>
|
||||||
|
|
||||||
|
<!-- Errors Extra -->
|
||||||
|
<string name="error_project_connect_check">Connection failed: %1$s</string>
|
||||||
|
<string name="error_create_remote_project_helper">Creation failed: %1$s</string>
|
||||||
|
<string name="error_edit_remote_project_helper">Error updating remote project: %1$s</string>
|
||||||
|
<string name="remote_project_operation_no_network">Network unavailable for remote operation.</string>
|
||||||
|
<string name="error_scanning_bill_qr_code">Failed to parse QR code.</string>
|
||||||
|
<string name="error_token_mismatch">Authentication token mismatch. Please log in again.</string>
|
||||||
|
<string name="insufficient_access_level">You don\'t have permission to perform this action.</string>
|
||||||
|
<string name="delete_label_confirmation_title">Delete Label</string>
|
||||||
|
<string name="delete_label_confirmation_message">Are you sure you want to delete this label?</string>
|
||||||
|
|
||||||
|
<!-- About -->
|
||||||
|
<string name="about_version">Version %1$s</string>
|
||||||
|
<string name="about_maintainer_title">Maintainer</string>
|
||||||
|
<string name="about_license_title">License</string>
|
||||||
|
<string name="about_source_title">Source code</string>
|
||||||
|
|
||||||
|
<!-- New constants for backward compatibility or shared use -->
|
||||||
|
<string name="share_intent_title">Project %1$s</string>
|
||||||
|
<string name="share_chooser_title">Share %1$s</string>
|
||||||
|
|
||||||
|
</resources>
|
||||||
@@ -0,0 +1,263 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Actions -->
|
||||||
|
<string name="action_new_bill">Neue Rechnung</string>
|
||||||
|
<string name="action_add_project">Projekt hinzufügen</string>
|
||||||
|
<string name="action_save">Speichern</string>
|
||||||
|
<string name="action_edit">Bearbeiten</string>
|
||||||
|
<string name="action_share">Teilen</string>
|
||||||
|
<string name="action_search">Suchen</string>
|
||||||
|
<string name="action_open_menu">Menü öffnen</string>
|
||||||
|
<string name="action_close_search">Suche schließen</string>
|
||||||
|
<string name="action_clear_search">Suche leeren</string>
|
||||||
|
<string name="action_delete">Löschen</string>
|
||||||
|
<string name="simple_back">Zurück</string>
|
||||||
|
<string name="action_archive">Archivieren</string>
|
||||||
|
<string name="action_unarchive">Reaktivieren</string>
|
||||||
|
<string name="action_export">Exportieren</string>
|
||||||
|
<string name="action_stats">Statistik</string>
|
||||||
|
<string name="action_settle">Abrechnen</string>
|
||||||
|
<string name="action_scan_qrcode">QR Code einscannen</string>
|
||||||
|
<string name="action_settings">Einstellungen</string>
|
||||||
|
<string name="action_label_bills">Fehlende Kategorien</string>
|
||||||
|
<string name="action_logout">Abmelden</string>
|
||||||
|
<string name="action_connect">Verbinden</string>
|
||||||
|
<string name="action_discard">Verwerfen</string>
|
||||||
|
<string name="action_members">Mitglieder</string>
|
||||||
|
<string name="action_labels">Labels</string>
|
||||||
|
<string name="action_currencies">Währungen</string>
|
||||||
|
|
||||||
|
<!-- Titles -->
|
||||||
|
<string name="title_stats">Statistiken</string>
|
||||||
|
<string name="title_edit_project">Projekt bearbeiten</string>
|
||||||
|
<string name="title_label_bills">Rechnungen kennzeichnen</string>
|
||||||
|
<string name="title_labels">Labels verwalten</string>
|
||||||
|
<string name="title_about">Über</string>
|
||||||
|
<string name="title_settle">Projekt abrechnen</string>
|
||||||
|
<string name="title_share">Projekt teilen</string>
|
||||||
|
<string name="title_add_project">Projekt hinzufügen</string>
|
||||||
|
<string name="title_add_category">Neue Kategorie</string>
|
||||||
|
<string name="title_add_payment_mode">Zahlungsmethode hinzufügen</string>
|
||||||
|
<string name="title_account">Nextcloud-Konto</string>
|
||||||
|
<string name="title_share_web">Weblink</string>
|
||||||
|
<string name="title_share_qr">Cowspent link</string>
|
||||||
|
<string name="title_confirm">Bist du sicher?</string>
|
||||||
|
|
||||||
|
<!-- Labels and Fields -->
|
||||||
|
<string name="label_all_bills">Alle Rechnungen</string>
|
||||||
|
<string name="label_categories">Kategorien</string>
|
||||||
|
<string name="label_payment_modes">Zahlungsmethoden</string>
|
||||||
|
<string name="label_name">Name</string>
|
||||||
|
<string name="label_icon">Icon / Emoji</string>
|
||||||
|
<string name="label_color">Farbe</string>
|
||||||
|
<string name="label_weight">Gewicht</string>
|
||||||
|
<string name="label_activated">Aktiviert</string>
|
||||||
|
<string name="label_password">Passwort</string>
|
||||||
|
<string name="label_email">E-Mail</string>
|
||||||
|
<string name="label_url">Serveradresse</string>
|
||||||
|
<string name="label_username">Benutzername</string>
|
||||||
|
<string name="label_comment">Kommentar</string>
|
||||||
|
<string name="label_what">Was?</string>
|
||||||
|
<string name="label_payer">Wer hat bezahlt?</string>
|
||||||
|
<string name="label_owers">Für wen?</string>
|
||||||
|
<string name="label_repeat">Wiederholen alle</string>
|
||||||
|
<string name="label_mode">Modus</string>
|
||||||
|
<string name="label_category">Kategorie</string>
|
||||||
|
<string name="label_project_id">Projekt-ID/Name</string>
|
||||||
|
<string name="label_project_title">Projekttitel</string>
|
||||||
|
<string name="label_use_sso">Nextcloud App-Konto verwenden</string>
|
||||||
|
|
||||||
|
<!-- Dialogs and Messages -->
|
||||||
|
<string name="dialog_unsaved_changes_title">Ungespeicherte Änderungen</string>
|
||||||
|
<string name="dialog_unsaved_changes_msg">Änderungen vor dem Verlassen speichern?</string>
|
||||||
|
<string name="dialog_confirm_remove_project_msg">Das Remote-Projekt wird nicht gelöscht.</string>
|
||||||
|
<string name="dialog_sync_error_title">Sync-Fehler</string>
|
||||||
|
<string name="dialog_sync_error_msg">Synchronisation fehlgeschlagen für %1$s.\n\n%2$s</string>
|
||||||
|
<string name="dialog_balanced_msg">Die Ausgaben sind bereits ausgeglichen.</string>
|
||||||
|
<string name="msg_project_added">Projekt %1$s hinzugefügt</string>
|
||||||
|
<string name="msg_bill_labeled_done">Alle Rechnungen kategorisiert</string>
|
||||||
|
<string name="msg_no_suggestions">Keine Vorschläge</string>
|
||||||
|
<string name="msg_auth_warning">Benötigt Cospend v0.3.4+.</string>
|
||||||
|
<string name="msg_link_copied">Link in Zwischenablage kopiert</string>
|
||||||
|
<string name="msg_share_qr">Scanne den QR-Code oder teile den Link, um beizutreten.</string>
|
||||||
|
<string name="msg_share_web">Link für den Zugriff per Web-Browser.</string>
|
||||||
|
<string name="msg_share_qr_warn">Teile diesen Link mit einem Cowspent Benutzer.</string>
|
||||||
|
<string name="msg_settle_intro">Abrechnung für %1$s:</string>
|
||||||
|
<string name="msg_settle_sentence">%1$s schuldet %3$.2f an %2$s</string>
|
||||||
|
<string name="msg_stats_intro">Statistiken für %1$s:</string>
|
||||||
|
<string name="msg_stats_header">Mitglied (Gezahlt | Ausgegeben | Saldo)</string>
|
||||||
|
<string name="msg_logged_in_as">Angemeldet als %1$s</string>
|
||||||
|
|
||||||
|
<!-- Errors -->
|
||||||
|
<string name="error_generic">Fehler</string>
|
||||||
|
<string name="error_loading">Lädt</string>
|
||||||
|
<string name="error_no_projects">Keine Projekte gefunden</string>
|
||||||
|
<string name="error_no_members">Keine Mitglieder gefunden</string>
|
||||||
|
<string name="error_no_bills">Keine Rechnungen gefunden</string>
|
||||||
|
<string name="error_no_member">Mindestens ein Mitglied erforderlich</string>
|
||||||
|
<string name="error_maintenance_mode">Server ist im Wartungsmodus</string>
|
||||||
|
<string name="error_400">400 Falsche Anfrage</string>
|
||||||
|
<string name="error_401">401 Unautorisiert</string>
|
||||||
|
<string name="error_403">403 Verboten</string>
|
||||||
|
<string name="error_404">404 Nicht gefunden</string>
|
||||||
|
<string name="error_sync">Sync fehlgeschlagen: %1$s</string>
|
||||||
|
<string name="error_invalid_login">Ungültiger Login: %1$s</string>
|
||||||
|
<string name="error_auth">Benutzername oder Passwort falsch</string>
|
||||||
|
<string name="error_json">Ungültige Server-Antwort</string>
|
||||||
|
<string name="error_req_failed">Anfrage fehlgeschlagen</string>
|
||||||
|
<string name="error_invalid_email">Ungültige E-Mail</string>
|
||||||
|
<string name="error_invalid_project_id">Ungültige Projekt-ID</string>
|
||||||
|
<string name="error_invalid_project_name">Ungültiger Projekttitel</string>
|
||||||
|
<string name="error_invalid_bill_name">Ungültiger Rechnungsname</string>
|
||||||
|
<string name="error_invalid_bill_date">Ungültiges Rechnungsdatum</string>
|
||||||
|
<string name="error_invalid_bill_payer">Zahler erforderlich</string>
|
||||||
|
<string name="error_invalid_bill_owers">Schuldner erforderlich</string>
|
||||||
|
<string name="error_no_network">Keine Netzwerkverbindung</string>
|
||||||
|
<string name="error_server">Serverfehler</string>
|
||||||
|
<string name="error_io">Serververbindung getrennt</string>
|
||||||
|
<string name="error_share_impossible">Dieses Projekt kann nicht geteilt werden</string>
|
||||||
|
|
||||||
|
<!-- Drawer / Common UI -->
|
||||||
|
<string name="drawer_no_account">Mit Nextcloud Konto verbinden</string>
|
||||||
|
<string name="drawer_last_sync">Letzter Sync: %1$02d:%2$02d</string>
|
||||||
|
<string name="simple_cancel">Abbrechen</string>
|
||||||
|
<string name="simple_ok" tools:ignore="ButtonCase,Typos">Ok</string>
|
||||||
|
<string name="simple_yes">Ja</string>
|
||||||
|
<string name="simple_no">Nein</string>
|
||||||
|
<string name="simple_close">Schließen</string>
|
||||||
|
|
||||||
|
<!-- Settings -->
|
||||||
|
<string name="settings_appearance">Erscheinung</string>
|
||||||
|
<string name="settings_network">Netzwerk</string>
|
||||||
|
<string name="settings_other">Andere</string>
|
||||||
|
<string name="settings_night_mode">Thema</string>
|
||||||
|
<string name="settings_offline_mode">Offline-Modus</string>
|
||||||
|
<string name="settings_offline_mode_summary">Nur manuell synchronisieren.</string>
|
||||||
|
<string name="settings_color_custom">Eigene Farbe</string>
|
||||||
|
<string name="settings_color_mode">Farbauswahl</string>
|
||||||
|
<string name="settings_show_archived">Archivierte Projekte anzeigen</string>
|
||||||
|
<string name="settings_beta_features">Beta-Funktionen</string>
|
||||||
|
<string name="settings_beta_features_summary">Experimentelle Funktionen aktivieren. Benutzung auf eigene Gefahr.</string>
|
||||||
|
<string name="settings_fill_new_bill_from_last">Aus letzter Rechnung vorausfüllen</string>
|
||||||
|
<string name="settings_fill_new_bill_from_last_summary">Zahler, Kategorie, Zahlungsart und Beteiligte aus der zuletzt erstellten Rechnung des Projekts übernehmen.</string>
|
||||||
|
<string name="settings_auto_sync_on_open">Synchronisierungsintervall</string>
|
||||||
|
<string name="settings_auto_sync_on_open_summary">Wie oft Konto und alle Projekte beim Öffnen der App aktualisiert werden.</string>
|
||||||
|
<string name="pref_value_sync_1m">1 Minute</string>
|
||||||
|
<string name="pref_value_sync_10m">10 Minuten</string>
|
||||||
|
<string name="pref_value_sync_1h">1 Stunde</string>
|
||||||
|
<string name="pref_value_sync_1d">1 Tag</string>
|
||||||
|
<string name="settings_url_warn_http">WARNUNG: \"http\" ist unsicher. Verwende \"https\".</string>
|
||||||
|
<string name="settings_colorpicker_title">Farbe wählen</string>
|
||||||
|
<string name="pref_value_color_system">System</string>
|
||||||
|
<string name="pref_value_color_manual">Manuell</string>
|
||||||
|
<string name="pref_value_theme_light">Hell</string>
|
||||||
|
<string name="pref_value_theme_dark">Dunkel</string>
|
||||||
|
<string name="pref_value_theme_system">System folgen</string>
|
||||||
|
|
||||||
|
<!-- Constants (Do not translate) -->
|
||||||
|
<!-- Enums and Lists -->
|
||||||
|
<string name="repeat_no">Keine Wiederholung</string>
|
||||||
|
<string name="repeat_day">Täglich</string>
|
||||||
|
<string name="repeat_week">Wöchentlich</string>
|
||||||
|
<string name="repeat_fortnight">Vierzehntägig</string>
|
||||||
|
<string name="repeat_month">Monatlich</string>
|
||||||
|
<string name="repeat_year">Jährlich</string>
|
||||||
|
<string name="payment_mode_none">Keine</string>
|
||||||
|
<string name="payment_mode_all">Alle</string>
|
||||||
|
<string name="payment_mode_credit_card">Kreditkarte</string>
|
||||||
|
<string name="payment_mode_cash">Bargeld</string>
|
||||||
|
<string name="payment_mode_check">Scheck</string>
|
||||||
|
<string name="payment_mode_online">Online</string>
|
||||||
|
<string name="payment_mode_transfer">Überweisung</string>
|
||||||
|
<string name="category_none">Keine</string>
|
||||||
|
<string name="category_all">Alle</string>
|
||||||
|
<string name="category_all_except_reimbursement">Alle außer Erstattung</string>
|
||||||
|
<string name="category_groceries">Lebensmittel</string>
|
||||||
|
<string name="category_leisure">Bar/Party</string>
|
||||||
|
<string name="category_rent">Miete</string>
|
||||||
|
<string name="category_bills">Abrechnung</string>
|
||||||
|
<string name="category_excursion">Ausflug/Kultur</string>
|
||||||
|
<string name="category_health">Gesundheit</string>
|
||||||
|
<string name="category_shopping">Einkaufen</string>
|
||||||
|
<string name="category_reimbursement">Erstattung</string>
|
||||||
|
<string name="category_restaurant">Restaurant</string>
|
||||||
|
<string name="category_accomodation">Unterkunft</string>
|
||||||
|
<string name="category_transport">Transport</string>
|
||||||
|
<string name="category_sport">Sport</string>
|
||||||
|
|
||||||
|
<!-- Project specific -->
|
||||||
|
<string name="new_project_action">Was</string>
|
||||||
|
<string name="new_project_where">Wo</string>
|
||||||
|
<string name="where_local">Nur lokal</string>
|
||||||
|
<string name="todo_join">Bestehendem Projekt beitreten</string>
|
||||||
|
<string name="todo_create">Neues Projekt erstellen</string>
|
||||||
|
<string name="import_tooltip">Aus Datei importieren</string>
|
||||||
|
<string name="choose_project_management_action">Projekt</string>
|
||||||
|
<string name="project_added_success">Projekt erfolgreich hinzugefügt.</string>
|
||||||
|
<string name="no_projects_text">Du hast noch keine Projekte.</string>
|
||||||
|
<string name="configure_account_choice">Nextcloud-Konto konfigurieren</string>
|
||||||
|
<string name="add_project_choice">Projekt manuell hinzufügen</string>
|
||||||
|
<string name="no_members_text">Keine Mitglieder in diesem Projekt.</string>
|
||||||
|
<string name="no_bills_text">Keine Rechnungen gefunden.</string>
|
||||||
|
<string name="member_already_exists">Mitglied existiert bereits.</string>
|
||||||
|
<string name="activity_dialog_title">Projekt: %1$s</string>
|
||||||
|
<string name="remove_project_confirmation">Projekt %1$s entfernt.</string>
|
||||||
|
<string name="file_saved_success">Datei gespeichert: %1$s</string>
|
||||||
|
<string name="import_error_header">Import fehlgeschlagen in Zeile %d</string>
|
||||||
|
<string name="import_error_date">Ungültiges Datumsformat in Zeile %d</string>
|
||||||
|
<string name="import_error_owers">Ungültige Schuldner in Zeile %d</string>
|
||||||
|
<string name="add_member_dialog_title">Mitglied hinzufügen</string>
|
||||||
|
<string name="edit_member_dialog_title">Mitglied bearbeiten</string>
|
||||||
|
<string name="member_edit_delete">Löschen</string>
|
||||||
|
<string name="project_edition_no_change">Keine zu speichernden Änderungen.</string>
|
||||||
|
|
||||||
|
<!-- Settlement -->
|
||||||
|
<string name="center_none">Keine (optimal)</string>
|
||||||
|
<string name="settle_who">Wer zahlt</string>
|
||||||
|
<string name="settle_to_whom">An wen</string>
|
||||||
|
<string name="settle_how_much">Betrag</string>
|
||||||
|
<string name="simple_settle_share">Teilen</string>
|
||||||
|
<string name="simple_create_bills">Rechnungen erstellen</string>
|
||||||
|
<string name="settle_bill_what">Abrechnung</string>
|
||||||
|
|
||||||
|
<!-- Currencies -->
|
||||||
|
<string name="currency_dialog_title">Währung wählen (%s)</string>
|
||||||
|
<string name="setting_none">Keine</string>
|
||||||
|
<string name="setting_all">Alle</string>
|
||||||
|
<string name="currency_saved_success">Währungseinstellungen gespeichert.</string>
|
||||||
|
<string name="main_currency">Hauptwährung</string>
|
||||||
|
|
||||||
|
<!-- Statistics -->
|
||||||
|
<string name="label_bills_suggested">Empfohlene Kategorien</string>
|
||||||
|
<string name="label_bills_skip">Überspringen</string>
|
||||||
|
<string name="stats_date_min">Von</string>
|
||||||
|
<string name="stats_date_max">An</string>
|
||||||
|
<string name="stats_who">Mitglied</string>
|
||||||
|
<string name="stats_paid">Bezahlt</string>
|
||||||
|
<string name="stats_spent">Ausgegeben</string>
|
||||||
|
<string name="stats_balance">Saldo</string>
|
||||||
|
<string name="total">Gesamt: %1$s</string>
|
||||||
|
|
||||||
|
<!-- Errors Extra -->
|
||||||
|
<string name="error_project_connect_check">Verbindung fehlgeschlagen: %1$s</string>
|
||||||
|
<string name="error_create_remote_project_helper">Erstellung fehlgeschlagen: %1$s</string>
|
||||||
|
<string name="error_edit_remote_project_helper">Fehler beim Aktualisieren des Remote-Projekts: %1$s</string>
|
||||||
|
<string name="remote_project_operation_no_network">Netzwerk nicht verfügbar für Remote Operation.</string>
|
||||||
|
<string name="error_scanning_bill_qr_code">Fehler beim Analysieren des QR-Codes.</string>
|
||||||
|
<string name="error_token_mismatch">Authentifizierungstoken stimmen nicht überein. Bitte melde dich erneut an.</string>
|
||||||
|
<string name="insufficient_access_level">Du hast keine Berechtigung, um diese Aktion durchzuführen.</string>
|
||||||
|
<string name="delete_label_confirmation_title">Kategorie löschen</string>
|
||||||
|
<string name="delete_label_confirmation_message">Bist du sicher, dass du diese Kategorie löschen möchtest?</string>
|
||||||
|
|
||||||
|
<!-- About -->
|
||||||
|
<string name="about_version">Version %1$s</string>
|
||||||
|
<string name="about_maintainer_title">Betreuer</string>
|
||||||
|
<string name="about_license_title">Lizenz</string>
|
||||||
|
<string name="about_source_title">Quellcode</string>
|
||||||
|
|
||||||
|
<!-- New constants for backward compatibility or shared use -->
|
||||||
|
<string name="share_intent_title">Projekt %1$s</string>
|
||||||
|
<string name="share_chooser_title">Teilen %1$s</string>
|
||||||
|
</resources>
|
||||||
@@ -0,0 +1,272 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Untranslated: these are the English strings, kept here so a translation can be
|
||||||
|
contributed by simply replacing the values. Strings marked translatable="false" in
|
||||||
|
values/strings.xml (app and product names, preference keys) are deliberately absent
|
||||||
|
and must not be added.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- Actions -->
|
||||||
|
<string name="action_new_bill">New bill</string>
|
||||||
|
<string name="action_add_project">Add project</string>
|
||||||
|
<string name="action_save">Save</string>
|
||||||
|
<string name="action_edit">Edit</string>
|
||||||
|
<string name="action_share">Share</string>
|
||||||
|
<string name="action_search">Search</string>
|
||||||
|
<string name="action_open_menu">Open menu</string>
|
||||||
|
<string name="action_close_search">Close search</string>
|
||||||
|
<string name="action_clear_search">Clear search</string>
|
||||||
|
<string name="action_delete">Delete</string>
|
||||||
|
<string name="simple_back">Back</string>
|
||||||
|
<string name="action_archive">Archive</string>
|
||||||
|
<string name="action_unarchive">Unarchive</string>
|
||||||
|
<string name="action_export">Export</string>
|
||||||
|
<string name="action_stats">Stats</string>
|
||||||
|
<string name="action_settle">Settle</string>
|
||||||
|
<string name="action_scan_qrcode">Scan QR Code</string>
|
||||||
|
<string name="action_settings">Settings</string>
|
||||||
|
<string name="action_label_bills">Label missing categories</string>
|
||||||
|
<string name="action_logout">Logout</string>
|
||||||
|
<string name="action_connect">Connect</string>
|
||||||
|
<string name="action_discard">Discard</string>
|
||||||
|
<string name="action_members">Members</string>
|
||||||
|
<string name="action_labels">Labels</string>
|
||||||
|
<string name="action_currencies">Currencies</string>
|
||||||
|
|
||||||
|
<!-- Titles -->
|
||||||
|
<string name="title_stats">Statistics</string>
|
||||||
|
<string name="title_edit_project">Edit project</string>
|
||||||
|
<string name="title_label_bills">Label Bills</string>
|
||||||
|
<string name="title_labels">Manage Labels</string>
|
||||||
|
<string name="title_about">About</string>
|
||||||
|
<string name="title_settle">Settle Project</string>
|
||||||
|
<string name="title_share">Share Project</string>
|
||||||
|
<string name="title_add_project">Add Project</string>
|
||||||
|
<string name="title_add_category">Add Category</string>
|
||||||
|
<string name="title_add_payment_mode">Add Payment Mode</string>
|
||||||
|
<string name="title_account">Nextcloud Account</string>
|
||||||
|
<string name="title_share_web">Web link</string>
|
||||||
|
<string name="title_share_qr">Cowspent link</string>
|
||||||
|
<string name="title_confirm">Are you sure?</string>
|
||||||
|
|
||||||
|
<!-- Labels and Fields -->
|
||||||
|
<string name="label_all_bills">All bills</string>
|
||||||
|
<string name="label_categories">Categories</string>
|
||||||
|
<string name="label_payment_modes">Payment Modes</string>
|
||||||
|
<string name="label_name">Name</string>
|
||||||
|
<string name="label_icon">Icon / Emoji</string>
|
||||||
|
<string name="label_color">Color</string>
|
||||||
|
<string name="label_weight">Weight</string>
|
||||||
|
<string name="label_activated">Activated</string>
|
||||||
|
<string name="label_password">Password</string>
|
||||||
|
<string name="label_email">E-mail</string>
|
||||||
|
<string name="label_url">Server address</string>
|
||||||
|
<string name="label_username">Username</string>
|
||||||
|
<string name="label_comment">Comment</string>
|
||||||
|
<string name="label_what">What?</string>
|
||||||
|
<string name="label_payer">Who paid?</string>
|
||||||
|
<string name="label_owers">For whom?</string>
|
||||||
|
<string name="label_repeat">Repeat every</string>
|
||||||
|
<string name="label_mode">Mode</string>
|
||||||
|
<string name="label_category">Category</string>
|
||||||
|
<string name="label_project_id">Project ID/name</string>
|
||||||
|
<string name="label_project_title">Project title</string>
|
||||||
|
<string name="label_use_sso">Use Nextcloud App Account</string>
|
||||||
|
|
||||||
|
<!-- Dialogs and Messages -->
|
||||||
|
<string name="dialog_unsaved_changes_title">Unsaved changes</string>
|
||||||
|
<string name="dialog_unsaved_changes_msg">Save changes before leaving?</string>
|
||||||
|
<string name="dialog_confirm_remove_project_msg">The remote project will not be deleted.</string>
|
||||||
|
<string name="dialog_sync_error_title">Sync error</string>
|
||||||
|
<string name="dialog_sync_error_msg">Sync failed for %1$s.\n\n%2$s</string>
|
||||||
|
<string name="dialog_balanced_msg">Expenses are already balanced.</string>
|
||||||
|
<string name="msg_project_added">Project %1$s added</string>
|
||||||
|
<string name="msg_bill_labeled_done">All bills labeled</string>
|
||||||
|
<string name="msg_no_suggestions">No suggestions</string>
|
||||||
|
<string name="msg_auth_warning">Requires Cospend v0.3.4+.</string>
|
||||||
|
<string name="msg_link_copied">Link copied to clipboard</string>
|
||||||
|
<string name="msg_share_qr">Scan QR code or share the link to join.</string>
|
||||||
|
<string name="msg_share_web">Link for web browser access.</string>
|
||||||
|
<string name="msg_share_qr_warn">Share this link with a Cowspent user.</string>
|
||||||
|
<string name="msg_settle_intro">Settlement for %1$s:</string>
|
||||||
|
<string name="msg_settle_sentence">%1$s owes %3$.2f to %2$s</string>
|
||||||
|
<string name="msg_stats_intro">Stats for %1$s:</string>
|
||||||
|
<string name="msg_stats_header">Member (Paid | Spent | Balance)</string>
|
||||||
|
<string name="msg_logged_in_as">Logged in as %1$s</string>
|
||||||
|
|
||||||
|
<!-- Errors -->
|
||||||
|
<string name="error_generic">Error</string>
|
||||||
|
<string name="error_loading">Loading</string>
|
||||||
|
<string name="error_no_projects">No projects found</string>
|
||||||
|
<string name="error_no_members">No members found</string>
|
||||||
|
<string name="error_no_bills">No bills found</string>
|
||||||
|
<string name="error_no_member">At least one member required</string>
|
||||||
|
<string name="error_maintenance_mode">Server is in maintenance mode</string>
|
||||||
|
<string name="error_400">400 Bad request</string>
|
||||||
|
<string name="error_401">401 Unauthorized</string>
|
||||||
|
<string name="error_403">403 Forbidden</string>
|
||||||
|
<string name="error_404">404 Not Found</string>
|
||||||
|
<string name="error_sync">Sync failed: %1$s</string>
|
||||||
|
<string name="error_invalid_login">Invalid login: %1$s</string>
|
||||||
|
<string name="error_auth">Wrong username or password</string>
|
||||||
|
<string name="error_json">Invalid server response</string>
|
||||||
|
<string name="error_req_failed">Request failed</string>
|
||||||
|
<string name="error_invalid_email">Invalid e-mail</string>
|
||||||
|
<string name="error_invalid_project_id">Invalid project ID</string>
|
||||||
|
<string name="error_invalid_project_name">Invalid project title</string>
|
||||||
|
<string name="error_invalid_bill_name">Invalid bill name</string>
|
||||||
|
<string name="error_invalid_bill_date">Invalid bill date</string>
|
||||||
|
<string name="error_invalid_bill_payer">Payer required</string>
|
||||||
|
<string name="error_invalid_bill_owers">Owers required</string>
|
||||||
|
<string name="error_no_network">No network connection</string>
|
||||||
|
<string name="error_server">Server error</string>
|
||||||
|
<string name="error_io">Server connection broken</string>
|
||||||
|
<string name="error_share_impossible">Cannot share this project</string>
|
||||||
|
|
||||||
|
<!-- Drawer / Common UI -->
|
||||||
|
<string name="drawer_no_account">Connect to Nextcloud account</string>
|
||||||
|
<string name="drawer_last_sync">Last sync: %1$02d:%2$02d</string>
|
||||||
|
<string name="simple_cancel">Cancel</string>
|
||||||
|
<string name="simple_ok" tools:ignore="ButtonCase,Typos">Ok</string>
|
||||||
|
<string name="simple_yes">Yes</string>
|
||||||
|
<string name="simple_no">No</string>
|
||||||
|
<string name="simple_close">Close</string>
|
||||||
|
|
||||||
|
<!-- Settings -->
|
||||||
|
<string name="settings_appearance">Appearance</string>
|
||||||
|
<string name="settings_network">Network</string>
|
||||||
|
<string name="settings_other">Other</string>
|
||||||
|
<string name="settings_night_mode">Theme</string>
|
||||||
|
<string name="settings_offline_mode">Offline mode</string>
|
||||||
|
<string name="settings_offline_mode_summary">Only sync manually.</string>
|
||||||
|
<string name="settings_color_custom">Custom color</string>
|
||||||
|
<string name="settings_color_mode">Color Selection</string>
|
||||||
|
<string name="settings_show_archived">Show archived projects</string>
|
||||||
|
<string name="settings_beta_features">Beta Features</string>
|
||||||
|
<string name="settings_beta_features_summary">Enable experimental features. Use at your own risk.</string>
|
||||||
|
<string name="settings_fill_new_bill_from_last">Auto-fill from last bill</string>
|
||||||
|
<string name="settings_fill_new_bill_from_last_summary">Pre-fill payer, category, mode and owers from the last bill created in the project.</string>
|
||||||
|
<string name="settings_auto_sync_on_open">Sync interval</string>
|
||||||
|
<string name="settings_auto_sync_on_open_summary">How often to refresh the account and all projects when opening the app.</string>
|
||||||
|
<string name="pref_value_sync_1m">1 minute</string>
|
||||||
|
<string name="pref_value_sync_10m">10 minutes</string>
|
||||||
|
<string name="pref_value_sync_1h">1 hour</string>
|
||||||
|
<string name="pref_value_sync_1d">1 day</string>
|
||||||
|
<string name="settings_url_warn_http">WARNING: "http" is unsafe. Use "https".</string>
|
||||||
|
<string name="settings_colorpicker_title">Choose Color</string>
|
||||||
|
|
||||||
|
<string name="pref_value_color_system">System</string>
|
||||||
|
<string name="pref_value_color_manual">Manual</string>
|
||||||
|
<string name="pref_value_theme_light">Light</string>
|
||||||
|
<string name="pref_value_theme_dark">Dark</string>
|
||||||
|
<string name="pref_value_theme_system">Follow system</string>
|
||||||
|
|
||||||
|
<!-- Enums and Lists -->
|
||||||
|
<string name="repeat_no">No repeat</string>
|
||||||
|
<string name="repeat_day">Daily</string>
|
||||||
|
<string name="repeat_week">Weekly</string>
|
||||||
|
<string name="repeat_fortnight">Fortnightly</string>
|
||||||
|
<string name="repeat_month">Monthly</string>
|
||||||
|
<string name="repeat_year">Yearly</string>
|
||||||
|
|
||||||
|
<string name="payment_mode_none">None</string>
|
||||||
|
<string name="payment_mode_all">All</string>
|
||||||
|
<string name="payment_mode_credit_card">Credit card</string>
|
||||||
|
<string name="payment_mode_cash">Cash</string>
|
||||||
|
<string name="payment_mode_check">Check</string>
|
||||||
|
<string name="payment_mode_online">Online</string>
|
||||||
|
<string name="payment_mode_transfer">Transfer</string>
|
||||||
|
|
||||||
|
<string name="category_none">None</string>
|
||||||
|
<string name="category_all">All</string>
|
||||||
|
<string name="category_all_except_reimbursement">All except reimbursement</string>
|
||||||
|
<string name="category_groceries">Grocery</string>
|
||||||
|
<string name="category_leisure">Bar/Party</string>
|
||||||
|
<string name="category_rent">Rent</string>
|
||||||
|
<string name="category_bills">Bill</string>
|
||||||
|
<string name="category_excursion">Excursion/Culture</string>
|
||||||
|
<string name="category_health">Health</string>
|
||||||
|
<string name="category_shopping">Shopping</string>
|
||||||
|
<string name="category_reimbursement">Reimbursement</string>
|
||||||
|
<string name="category_restaurant">Restaurant</string>
|
||||||
|
<string name="category_accomodation">Accommodation</string>
|
||||||
|
<string name="category_transport">Transport</string>
|
||||||
|
<string name="category_sport">Sport</string>
|
||||||
|
|
||||||
|
<!-- Project specific -->
|
||||||
|
<string name="new_project_action">What</string>
|
||||||
|
<string name="new_project_where">Where</string>
|
||||||
|
<string name="where_local">Local only</string>
|
||||||
|
<string name="todo_join">Join existing project</string>
|
||||||
|
<string name="todo_create">Create new project</string>
|
||||||
|
<string name="import_tooltip">Import from file</string>
|
||||||
|
<string name="choose_project_management_action">Project</string>
|
||||||
|
<string name="project_added_success">Project added successfully.</string>
|
||||||
|
<string name="no_projects_text">You have no projects yet.</string>
|
||||||
|
<string name="configure_account_choice">Configure Nextcloud account</string>
|
||||||
|
<string name="add_project_choice">Add project manually</string>
|
||||||
|
<string name="no_members_text">No members in this project.</string>
|
||||||
|
<string name="no_bills_text">No bills found.</string>
|
||||||
|
<string name="member_already_exists">Member already exists.</string>
|
||||||
|
<string name="activity_dialog_title">Project: %1$s</string>
|
||||||
|
<string name="remove_project_confirmation">Project %1$s removed.</string>
|
||||||
|
<string name="file_saved_success">File saved: %1$s</string>
|
||||||
|
<string name="import_error_header">Import failed at row %d</string>
|
||||||
|
<string name="import_error_date">Invalid date format at row %d</string>
|
||||||
|
<string name="import_error_owers">Invalid owers at row %d</string>
|
||||||
|
<string name="add_member_dialog_title">Add Member</string>
|
||||||
|
<string name="edit_member_dialog_title">Edit Member</string>
|
||||||
|
<string name="member_edit_delete">Delete</string>
|
||||||
|
<string name="project_edition_no_change">No changes to save.</string>
|
||||||
|
|
||||||
|
<!-- Settlement -->
|
||||||
|
<string name="center_none">None (Optimal)</string>
|
||||||
|
<string name="settle_who">Who pays</string>
|
||||||
|
<string name="settle_to_whom">To whom</string>
|
||||||
|
<string name="settle_how_much">Amount</string>
|
||||||
|
<string name="simple_settle_share">Share</string>
|
||||||
|
<string name="simple_create_bills">Create bills</string>
|
||||||
|
<string name="settle_bill_what">Settlement</string>
|
||||||
|
|
||||||
|
<!-- Currencies -->
|
||||||
|
<string name="currency_dialog_title">Choose Currency (%s)</string>
|
||||||
|
<string name="setting_none">None</string>
|
||||||
|
<string name="setting_all">All</string>
|
||||||
|
<string name="currency_saved_success">Currency settings saved.</string>
|
||||||
|
<string name="main_currency">Main Currency</string>
|
||||||
|
|
||||||
|
<!-- Statistics -->
|
||||||
|
<string name="label_bills_suggested">Suggested Categories</string>
|
||||||
|
<string name="label_bills_skip">Skip</string>
|
||||||
|
<string name="stats_date_min">From</string>
|
||||||
|
<string name="stats_date_max">To</string>
|
||||||
|
<string name="stats_who">Member</string>
|
||||||
|
<string name="stats_paid">Paid</string>
|
||||||
|
<string name="stats_spent">Spent</string>
|
||||||
|
<string name="stats_balance">Balance</string>
|
||||||
|
<string name="total">Total: %1$s</string>
|
||||||
|
|
||||||
|
<!-- Errors Extra -->
|
||||||
|
<string name="error_project_connect_check">Connection failed: %1$s</string>
|
||||||
|
<string name="error_create_remote_project_helper">Creation failed: %1$s</string>
|
||||||
|
<string name="error_edit_remote_project_helper">Error updating remote project: %1$s</string>
|
||||||
|
<string name="remote_project_operation_no_network">Network unavailable for remote operation.</string>
|
||||||
|
<string name="error_scanning_bill_qr_code">Failed to parse QR code.</string>
|
||||||
|
<string name="error_token_mismatch">Authentication token mismatch. Please log in again.</string>
|
||||||
|
<string name="insufficient_access_level">You don\'t have permission to perform this action.</string>
|
||||||
|
<string name="delete_label_confirmation_title">Delete Label</string>
|
||||||
|
<string name="delete_label_confirmation_message">Are you sure you want to delete this label?</string>
|
||||||
|
|
||||||
|
<!-- About -->
|
||||||
|
<string name="about_version">Version %1$s</string>
|
||||||
|
<string name="about_maintainer_title">Maintainer</string>
|
||||||
|
<string name="about_license_title">License</string>
|
||||||
|
<string name="about_source_title">Source code</string>
|
||||||
|
|
||||||
|
<!-- New constants for backward compatibility or shared use -->
|
||||||
|
<string name="share_intent_title">Project %1$s</string>
|
||||||
|
<string name="share_chooser_title">Share %1$s</string>
|
||||||
|
|
||||||
|
</resources>
|
||||||
@@ -0,0 +1,265 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<!-- Actions -->
|
||||||
|
<string name="action_new_bill">Nueva factura</string>
|
||||||
|
<string name="action_add_project">Añadir proyecto</string>
|
||||||
|
<string name="action_save">Guardar</string>
|
||||||
|
<string name="action_edit">Editar</string>
|
||||||
|
<string name="action_share">Compartir</string>
|
||||||
|
<string name="action_search">Buscar</string>
|
||||||
|
<string name="action_open_menu">Abrir el menú</string>
|
||||||
|
<string name="action_close_search">Cerrar la búsqueda</string>
|
||||||
|
<string name="action_clear_search">Borrar la búsqueda</string>
|
||||||
|
<string name="action_delete">Eliminar</string>
|
||||||
|
<string name="simple_back">Atrás</string>
|
||||||
|
<string name="action_archive">Archivar</string>
|
||||||
|
<string name="action_unarchive">Desarchivar</string>
|
||||||
|
<string name="action_export">Exportar</string>
|
||||||
|
<string name="action_stats">Estadísticas</string>
|
||||||
|
<string name="action_settle">Liquidar</string>
|
||||||
|
<string name="action_scan_qrcode">Escanear código QR</string>
|
||||||
|
<string name="action_settings">Ajustes</string>
|
||||||
|
<string name="action_label_bills">Categorizar facturas</string>
|
||||||
|
<string name="action_logout">Cerrar sesión</string>
|
||||||
|
<string name="action_connect">Conectar</string>
|
||||||
|
<string name="action_discard">Descartar</string>
|
||||||
|
<string name="action_members">Miembros</string>
|
||||||
|
<string name="action_labels">Etiquetas</string>
|
||||||
|
<string name="action_currencies">Monedas</string>
|
||||||
|
|
||||||
|
<!-- Titles -->
|
||||||
|
<string name="title_stats">Estadísticas</string>
|
||||||
|
<string name="title_edit_project">Editar proyecto</string>
|
||||||
|
<string name="title_label_bills">Categorizar facturas</string>
|
||||||
|
<string name="title_labels">Gestionar etiquetas</string>
|
||||||
|
<string name="title_about">Acerca de</string>
|
||||||
|
<string name="title_settle">Liquidar proyecto</string>
|
||||||
|
<string name="title_share">Compartir proyecto</string>
|
||||||
|
<string name="title_add_project">Añadir proyecto</string>
|
||||||
|
<string name="title_add_category">Añadir categoría</string>
|
||||||
|
<string name="title_add_payment_mode">Añadir modo de pago</string>
|
||||||
|
<string name="title_account">Cuenta de Nextcloud</string>
|
||||||
|
<string name="title_share_web">Enlace web</string>
|
||||||
|
<string name="title_share_qr">Enlace de Cowspent</string>
|
||||||
|
<string name="title_confirm">¿Estás seguro?</string>
|
||||||
|
|
||||||
|
<!-- Labels and Fields -->
|
||||||
|
<string name="label_all_bills">Todas las facturas</string>
|
||||||
|
<string name="label_categories">Categorías</string>
|
||||||
|
<string name="label_payment_modes">Modos de pago</string>
|
||||||
|
<string name="label_name">Nombre</string>
|
||||||
|
<string name="label_icon">Icono / Emoji</string>
|
||||||
|
<string name="label_color">Color</string>
|
||||||
|
<string name="label_weight">Peso</string>
|
||||||
|
<string name="label_activated">Activado</string>
|
||||||
|
<string name="label_password">Contraseña</string>
|
||||||
|
<string name="label_email">Correo electrónico</string>
|
||||||
|
<string name="label_url">Dirección del servidor</string>
|
||||||
|
<string name="label_username">Nombre de usuario</string>
|
||||||
|
<string name="label_comment">Comentario</string>
|
||||||
|
<string name="label_what">¿Qué?</string>
|
||||||
|
<string name="label_payer">¿Quién pagó?</string>
|
||||||
|
<string name="label_owers">¿Para quién?</string>
|
||||||
|
<string name="label_repeat">Repetición</string>
|
||||||
|
<string name="label_mode">Modo</string>
|
||||||
|
<string name="label_category">Categoría</string>
|
||||||
|
<string name="label_project_id">ID/nombre del proyecto</string>
|
||||||
|
<string name="label_project_title">Título del proyecto</string>
|
||||||
|
<string name="label_use_sso">Usar la cuenta de la aplicación Nextcloud</string>
|
||||||
|
|
||||||
|
<!-- Dialogs and Messages -->
|
||||||
|
<string name="dialog_unsaved_changes_title">Cambios sin guardar</string>
|
||||||
|
<string name="dialog_unsaved_changes_msg">¿Guardar los cambios antes de salir?</string>
|
||||||
|
<string name="dialog_confirm_remove_project_msg">El proyecto remoto no se eliminará.</string>
|
||||||
|
<string name="dialog_sync_error_title">Error de sincronización</string>
|
||||||
|
<string name="dialog_sync_error_msg">Error al sincronizar %1$s.\n\n%2$s</string>
|
||||||
|
<string name="dialog_balanced_msg">Los gastos ya están equilibrados.</string>
|
||||||
|
<string name="msg_project_added">Proyecto %1$s añadido</string>
|
||||||
|
<string name="msg_bill_labeled_done">Todas las facturas están categorizadas</string>
|
||||||
|
<string name="msg_no_suggestions">No hay sugerencias</string>
|
||||||
|
<string name="msg_auth_warning">Requiere Cospend v0.3.4+.</string>
|
||||||
|
<string name="msg_link_copied">Enlace copiado al portapapeles</string>
|
||||||
|
<string name="msg_share_qr">Escanea el código QR o comparte el enlace para unirte al proyecto.</string>
|
||||||
|
<string name="msg_share_web">Enlace de acceso desde un navegador web.</string>
|
||||||
|
<string name="msg_share_qr_warn">Comparte este enlace con un usuario de Cowspent.</string>
|
||||||
|
<string name="msg_settle_intro">Liquidación de %1$s:</string>
|
||||||
|
<string name="msg_settle_sentence">%1$s debe %3$.2f a %2$s</string>
|
||||||
|
<string name="msg_stats_intro">Estadísticas de %1$s:</string>
|
||||||
|
<string name="msg_stats_header">Miembro (Pagado | Gastado | Saldo)</string>
|
||||||
|
<string name="msg_logged_in_as">Sesión iniciada como %1$s</string>
|
||||||
|
|
||||||
|
<!-- Errors -->
|
||||||
|
<string name="error_generic">Error</string>
|
||||||
|
<string name="error_loading">Cargando</string>
|
||||||
|
<string name="error_no_projects">No se encontraron proyectos</string>
|
||||||
|
<string name="error_no_members">No se encontraron miembros</string>
|
||||||
|
<string name="error_no_bills">No se encontraron facturas</string>
|
||||||
|
<string name="error_no_member">Se requiere al menos un miembro</string>
|
||||||
|
<string name="error_maintenance_mode">El servidor está en modo de mantenimiento</string>
|
||||||
|
<string name="error_400">400 Solicitud incorrecta</string>
|
||||||
|
<string name="error_401">401 No autorizado</string>
|
||||||
|
<string name="error_403">403 Prohibido</string>
|
||||||
|
<string name="error_404">404 No encontrado</string>
|
||||||
|
<string name="error_sync">Error de sincronización: %1$s</string>
|
||||||
|
<string name="error_invalid_login">Inicio de sesión no válido: %1$s</string>
|
||||||
|
<string name="error_auth">Nombre de usuario o contraseña incorrectos</string>
|
||||||
|
<string name="error_json">Respuesta del servidor no válida</string>
|
||||||
|
<string name="error_req_failed">La petición ha fallado</string>
|
||||||
|
<string name="error_invalid_email">Correo electrónico no válido</string>
|
||||||
|
<string name="error_invalid_project_id">ID de proyecto no válido</string>
|
||||||
|
<string name="error_invalid_project_name">Título de proyecto no válido</string>
|
||||||
|
<string name="error_invalid_bill_name">Nombre de factura no válido</string>
|
||||||
|
<string name="error_invalid_bill_date">Fecha de factura no válida</string>
|
||||||
|
<string name="error_invalid_bill_payer">Pagador requerido</string>
|
||||||
|
<string name="error_invalid_bill_owers">Participantes requeridos</string>
|
||||||
|
<string name="error_no_network">No hay conexión de red</string>
|
||||||
|
<string name="error_server">Error del servidor</string>
|
||||||
|
<string name="error_io">Se ha perdido la conexión con el servidor</string>
|
||||||
|
<string name="error_share_impossible">No se puede compartir este proyecto</string>
|
||||||
|
|
||||||
|
<!-- Drawer / Common UI -->
|
||||||
|
<string name="drawer_no_account">Conectar a una cuenta de Nextcloud</string>
|
||||||
|
<string name="drawer_last_sync">Última sincronización: %1$02d:%2$02d</string>
|
||||||
|
<string name="simple_cancel">Cancelar</string>
|
||||||
|
<string name="simple_ok" tools:ignore="ButtonCase,Typos">Ok</string>
|
||||||
|
<string name="simple_yes">Sí</string>
|
||||||
|
<string name="simple_no">No</string>
|
||||||
|
<string name="simple_close">Cerrar</string>
|
||||||
|
|
||||||
|
<!-- Settings -->
|
||||||
|
<string name="settings_appearance">Apariencia</string>
|
||||||
|
<string name="settings_network">Red</string>
|
||||||
|
<string name="settings_other">Otros</string>
|
||||||
|
<string name="settings_night_mode">Tema</string>
|
||||||
|
<string name="settings_offline_mode">Modo sin conexión</string>
|
||||||
|
<string name="settings_offline_mode_summary">Sincronizar solo manualmente.</string>
|
||||||
|
<string name="settings_color_custom">Color personalizado</string>
|
||||||
|
<string name="settings_color_mode">Selección de color</string>
|
||||||
|
<string name="settings_show_archived">Mostrar los proyectos archivados</string>
|
||||||
|
<string name="settings_beta_features">Funciones beta</string>
|
||||||
|
<string name="settings_beta_features_summary">Activar las funciones experimentales. Úsalas bajo tu propia responsabilidad.</string>
|
||||||
|
<string name="settings_fill_new_bill_from_last">Rellenar desde la última factura</string>
|
||||||
|
<string name="settings_fill_new_bill_from_last_summary">Reutilizar el pagador, la categoría, el modo y los participantes de la última factura creada en el proyecto.</string>
|
||||||
|
<string name="settings_auto_sync_on_open">Intervalo de sincronización</string>
|
||||||
|
<string name="settings_auto_sync_on_open_summary">Con qué frecuencia se actualizan la cuenta y todos los proyectos al abrir la aplicación.</string>
|
||||||
|
<string name="pref_value_sync_1m">1 minuto</string>
|
||||||
|
<string name="pref_value_sync_10m">10 minutos</string>
|
||||||
|
<string name="pref_value_sync_1h">1 hora</string>
|
||||||
|
<string name="pref_value_sync_1d">1 día</string>
|
||||||
|
<string name="settings_url_warn_http">ADVERTENCIA: \"http\" no es seguro. Usa \"https\".</string>
|
||||||
|
<string name="settings_colorpicker_title">Elegir un color</string>
|
||||||
|
|
||||||
|
<string name="pref_value_color_system">Sistema</string>
|
||||||
|
<string name="pref_value_color_manual">Manual</string>
|
||||||
|
<string name="pref_value_theme_light">Claro</string>
|
||||||
|
<string name="pref_value_theme_dark">Oscuro</string>
|
||||||
|
<string name="pref_value_theme_system">Seguir el sistema</string>
|
||||||
|
|
||||||
|
<!-- Enums and Lists -->
|
||||||
|
<string name="repeat_no">Sin repetición</string>
|
||||||
|
<string name="repeat_day">Diaria</string>
|
||||||
|
<string name="repeat_week">Semanal</string>
|
||||||
|
<string name="repeat_fortnight">Quincenal</string>
|
||||||
|
<string name="repeat_month">Mensual</string>
|
||||||
|
<string name="repeat_year">Anual</string>
|
||||||
|
|
||||||
|
<string name="payment_mode_none">Ninguno</string>
|
||||||
|
<string name="payment_mode_all">Todos</string>
|
||||||
|
<string name="payment_mode_credit_card">Tarjeta de crédito</string>
|
||||||
|
<string name="payment_mode_cash">Efectivo</string>
|
||||||
|
<string name="payment_mode_check">Cheque</string>
|
||||||
|
<string name="payment_mode_online">En línea</string>
|
||||||
|
<string name="payment_mode_transfer">Transferencia</string>
|
||||||
|
|
||||||
|
<string name="category_none">Ninguna</string>
|
||||||
|
<string name="category_all">Todas</string>
|
||||||
|
<string name="category_all_except_reimbursement">Todas excepto reembolso</string>
|
||||||
|
<string name="category_groceries">Supermercado</string>
|
||||||
|
<string name="category_leisure">Bar/Fiesta</string>
|
||||||
|
<string name="category_rent">Alquiler</string>
|
||||||
|
<string name="category_bills">Factura</string>
|
||||||
|
<string name="category_excursion">Excursión/Cultura</string>
|
||||||
|
<string name="category_health">Salud</string>
|
||||||
|
<string name="category_shopping">Compras</string>
|
||||||
|
<string name="category_reimbursement">Reembolso</string>
|
||||||
|
<string name="category_restaurant">Restaurante</string>
|
||||||
|
<string name="category_accomodation">Alojamiento</string>
|
||||||
|
<string name="category_transport">Transporte</string>
|
||||||
|
<string name="category_sport">Deporte</string>
|
||||||
|
|
||||||
|
<!-- Project specific -->
|
||||||
|
<string name="new_project_action">Qué</string>
|
||||||
|
<string name="new_project_where">Dónde</string>
|
||||||
|
<string name="where_local">Solo local</string>
|
||||||
|
<string name="todo_join">Unirse a un proyecto existente</string>
|
||||||
|
<string name="todo_create">Crear un proyecto nuevo</string>
|
||||||
|
<string name="import_tooltip">Importar desde un archivo</string>
|
||||||
|
<string name="choose_project_management_action">Proyecto</string>
|
||||||
|
<string name="project_added_success">Proyecto añadido correctamente.</string>
|
||||||
|
<string name="no_projects_text">Aún no tienes proyectos.</string>
|
||||||
|
<string name="configure_account_choice">Configurar una cuenta de Nextcloud</string>
|
||||||
|
<string name="add_project_choice">Añadir un proyecto manualmente</string>
|
||||||
|
<string name="no_members_text">No hay miembros en este proyecto.</string>
|
||||||
|
<string name="no_bills_text">No se encontraron facturas.</string>
|
||||||
|
<string name="member_already_exists">El miembro ya existe.</string>
|
||||||
|
<string name="activity_dialog_title">Proyecto: %1$s</string>
|
||||||
|
<string name="remove_project_confirmation">Proyecto %1$s eliminado.</string>
|
||||||
|
<string name="file_saved_success">Archivo guardado: %1$s</string>
|
||||||
|
<string name="import_error_header">Error de importación en la fila %d</string>
|
||||||
|
<string name="import_error_date">Formato de fecha no válido en la fila %d</string>
|
||||||
|
<string name="import_error_owers">Participantes no válidos en la fila %d</string>
|
||||||
|
<string name="add_member_dialog_title">Añadir miembro</string>
|
||||||
|
<string name="edit_member_dialog_title">Editar miembro</string>
|
||||||
|
<string name="member_edit_delete">Eliminar</string>
|
||||||
|
<string name="project_edition_no_change">No hay cambios que guardar.</string>
|
||||||
|
|
||||||
|
<!-- Settlement -->
|
||||||
|
<string name="center_none">Ninguno (óptimo)</string>
|
||||||
|
<string name="settle_who">Quién paga</string>
|
||||||
|
<string name="settle_to_whom">A quién</string>
|
||||||
|
<string name="settle_how_much">Importe</string>
|
||||||
|
<string name="simple_settle_share">Compartir</string>
|
||||||
|
<string name="simple_create_bills">Crear las facturas</string>
|
||||||
|
<string name="settle_bill_what">Liquidación</string>
|
||||||
|
|
||||||
|
<!-- Currencies -->
|
||||||
|
<string name="currency_dialog_title">Elegir moneda (%s)</string>
|
||||||
|
<string name="setting_none">Ninguna</string>
|
||||||
|
<string name="setting_all">Todas</string>
|
||||||
|
<string name="currency_saved_success">Ajustes de moneda guardados.</string>
|
||||||
|
<string name="main_currency">Moneda principal</string>
|
||||||
|
|
||||||
|
<!-- Statistics -->
|
||||||
|
<string name="label_bills_suggested">Categorías sugeridas</string>
|
||||||
|
<string name="label_bills_skip">Omitir</string>
|
||||||
|
<string name="stats_date_min">Desde</string>
|
||||||
|
<string name="stats_date_max">Hasta</string>
|
||||||
|
<string name="stats_who">Miembro</string>
|
||||||
|
<string name="stats_paid">Pagado</string>
|
||||||
|
<string name="stats_spent">Gastado</string>
|
||||||
|
<string name="stats_balance">Saldo</string>
|
||||||
|
<string name="total">Total: %1$s</string>
|
||||||
|
|
||||||
|
<!-- Errors Extra -->
|
||||||
|
<string name="error_project_connect_check">Error de conexión: %1$s</string>
|
||||||
|
<string name="error_create_remote_project_helper">Error al crear: %1$s</string>
|
||||||
|
<string name="error_edit_remote_project_helper">Error al actualizar el proyecto remoto: %1$s</string>
|
||||||
|
<string name="remote_project_operation_no_network">Red no disponible para esta operación remota.</string>
|
||||||
|
<string name="error_scanning_bill_qr_code">No se ha podido leer el código QR.</string>
|
||||||
|
<string name="error_token_mismatch">El token de autenticación no coincide. Vuelve a iniciar sesión.</string>
|
||||||
|
<string name="insufficient_access_level">No tienes permiso para realizar esta acción.</string>
|
||||||
|
<string name="delete_label_confirmation_title">Eliminar etiqueta</string>
|
||||||
|
<string name="delete_label_confirmation_message">¿Seguro que quieres eliminar esta etiqueta?</string>
|
||||||
|
|
||||||
|
<!-- About -->
|
||||||
|
<string name="about_version">Versión %1$s</string>
|
||||||
|
<string name="about_maintainer_title">Mantenedor</string>
|
||||||
|
<string name="about_license_title">Licencia</string>
|
||||||
|
<string name="about_source_title">Código fuente</string>
|
||||||
|
|
||||||
|
<!-- New constants for backward compatibility or shared use -->
|
||||||
|
<string name="share_intent_title">Proyecto %1$s</string>
|
||||||
|
<string name="share_chooser_title">Compartir %1$s</string>
|
||||||
|
|
||||||
|
</resources>
|
||||||
@@ -0,0 +1,272 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Untranslated: these are the English strings, kept here so a translation can be
|
||||||
|
contributed by simply replacing the values. Strings marked translatable="false" in
|
||||||
|
values/strings.xml (app and product names, preference keys) are deliberately absent
|
||||||
|
and must not be added.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- Actions -->
|
||||||
|
<string name="action_new_bill">New bill</string>
|
||||||
|
<string name="action_add_project">Add project</string>
|
||||||
|
<string name="action_save">Save</string>
|
||||||
|
<string name="action_edit">Edit</string>
|
||||||
|
<string name="action_share">Share</string>
|
||||||
|
<string name="action_search">Search</string>
|
||||||
|
<string name="action_open_menu">Open menu</string>
|
||||||
|
<string name="action_close_search">Close search</string>
|
||||||
|
<string name="action_clear_search">Clear search</string>
|
||||||
|
<string name="action_delete">Delete</string>
|
||||||
|
<string name="simple_back">Back</string>
|
||||||
|
<string name="action_archive">Archive</string>
|
||||||
|
<string name="action_unarchive">Unarchive</string>
|
||||||
|
<string name="action_export">Export</string>
|
||||||
|
<string name="action_stats">Stats</string>
|
||||||
|
<string name="action_settle">Settle</string>
|
||||||
|
<string name="action_scan_qrcode">Scan QR Code</string>
|
||||||
|
<string name="action_settings">Settings</string>
|
||||||
|
<string name="action_label_bills">Label missing categories</string>
|
||||||
|
<string name="action_logout">Logout</string>
|
||||||
|
<string name="action_connect">Connect</string>
|
||||||
|
<string name="action_discard">Discard</string>
|
||||||
|
<string name="action_members">Members</string>
|
||||||
|
<string name="action_labels">Labels</string>
|
||||||
|
<string name="action_currencies">Currencies</string>
|
||||||
|
|
||||||
|
<!-- Titles -->
|
||||||
|
<string name="title_stats">Statistics</string>
|
||||||
|
<string name="title_edit_project">Edit project</string>
|
||||||
|
<string name="title_label_bills">Label Bills</string>
|
||||||
|
<string name="title_labels">Manage Labels</string>
|
||||||
|
<string name="title_about">About</string>
|
||||||
|
<string name="title_settle">Settle Project</string>
|
||||||
|
<string name="title_share">Share Project</string>
|
||||||
|
<string name="title_add_project">Add Project</string>
|
||||||
|
<string name="title_add_category">Add Category</string>
|
||||||
|
<string name="title_add_payment_mode">Add Payment Mode</string>
|
||||||
|
<string name="title_account">Nextcloud Account</string>
|
||||||
|
<string name="title_share_web">Web link</string>
|
||||||
|
<string name="title_share_qr">Cowspent link</string>
|
||||||
|
<string name="title_confirm">Are you sure?</string>
|
||||||
|
|
||||||
|
<!-- Labels and Fields -->
|
||||||
|
<string name="label_all_bills">All bills</string>
|
||||||
|
<string name="label_categories">Categories</string>
|
||||||
|
<string name="label_payment_modes">Payment Modes</string>
|
||||||
|
<string name="label_name">Name</string>
|
||||||
|
<string name="label_icon">Icon / Emoji</string>
|
||||||
|
<string name="label_color">Color</string>
|
||||||
|
<string name="label_weight">Weight</string>
|
||||||
|
<string name="label_activated">Activated</string>
|
||||||
|
<string name="label_password">Password</string>
|
||||||
|
<string name="label_email">E-mail</string>
|
||||||
|
<string name="label_url">Server address</string>
|
||||||
|
<string name="label_username">Username</string>
|
||||||
|
<string name="label_comment">Comment</string>
|
||||||
|
<string name="label_what">What?</string>
|
||||||
|
<string name="label_payer">Who paid?</string>
|
||||||
|
<string name="label_owers">For whom?</string>
|
||||||
|
<string name="label_repeat">Repeat every</string>
|
||||||
|
<string name="label_mode">Mode</string>
|
||||||
|
<string name="label_category">Category</string>
|
||||||
|
<string name="label_project_id">Project ID/name</string>
|
||||||
|
<string name="label_project_title">Project title</string>
|
||||||
|
<string name="label_use_sso">Use Nextcloud App Account</string>
|
||||||
|
|
||||||
|
<!-- Dialogs and Messages -->
|
||||||
|
<string name="dialog_unsaved_changes_title">Unsaved changes</string>
|
||||||
|
<string name="dialog_unsaved_changes_msg">Save changes before leaving?</string>
|
||||||
|
<string name="dialog_confirm_remove_project_msg">The remote project will not be deleted.</string>
|
||||||
|
<string name="dialog_sync_error_title">Sync error</string>
|
||||||
|
<string name="dialog_sync_error_msg">Sync failed for %1$s.\n\n%2$s</string>
|
||||||
|
<string name="dialog_balanced_msg">Expenses are already balanced.</string>
|
||||||
|
<string name="msg_project_added">Project %1$s added</string>
|
||||||
|
<string name="msg_bill_labeled_done">All bills labeled</string>
|
||||||
|
<string name="msg_no_suggestions">No suggestions</string>
|
||||||
|
<string name="msg_auth_warning">Requires Cospend v0.3.4+.</string>
|
||||||
|
<string name="msg_link_copied">Link copied to clipboard</string>
|
||||||
|
<string name="msg_share_qr">Scan QR code or share the link to join.</string>
|
||||||
|
<string name="msg_share_web">Link for web browser access.</string>
|
||||||
|
<string name="msg_share_qr_warn">Share this link with a Cowspent user.</string>
|
||||||
|
<string name="msg_settle_intro">Settlement for %1$s:</string>
|
||||||
|
<string name="msg_settle_sentence">%1$s owes %3$.2f to %2$s</string>
|
||||||
|
<string name="msg_stats_intro">Stats for %1$s:</string>
|
||||||
|
<string name="msg_stats_header">Member (Paid | Spent | Balance)</string>
|
||||||
|
<string name="msg_logged_in_as">Logged in as %1$s</string>
|
||||||
|
|
||||||
|
<!-- Errors -->
|
||||||
|
<string name="error_generic">Error</string>
|
||||||
|
<string name="error_loading">Loading</string>
|
||||||
|
<string name="error_no_projects">No projects found</string>
|
||||||
|
<string name="error_no_members">No members found</string>
|
||||||
|
<string name="error_no_bills">No bills found</string>
|
||||||
|
<string name="error_no_member">At least one member required</string>
|
||||||
|
<string name="error_maintenance_mode">Server is in maintenance mode</string>
|
||||||
|
<string name="error_400">400 Bad request</string>
|
||||||
|
<string name="error_401">401 Unauthorized</string>
|
||||||
|
<string name="error_403">403 Forbidden</string>
|
||||||
|
<string name="error_404">404 Not Found</string>
|
||||||
|
<string name="error_sync">Sync failed: %1$s</string>
|
||||||
|
<string name="error_invalid_login">Invalid login: %1$s</string>
|
||||||
|
<string name="error_auth">Wrong username or password</string>
|
||||||
|
<string name="error_json">Invalid server response</string>
|
||||||
|
<string name="error_req_failed">Request failed</string>
|
||||||
|
<string name="error_invalid_email">Invalid e-mail</string>
|
||||||
|
<string name="error_invalid_project_id">Invalid project ID</string>
|
||||||
|
<string name="error_invalid_project_name">Invalid project title</string>
|
||||||
|
<string name="error_invalid_bill_name">Invalid bill name</string>
|
||||||
|
<string name="error_invalid_bill_date">Invalid bill date</string>
|
||||||
|
<string name="error_invalid_bill_payer">Payer required</string>
|
||||||
|
<string name="error_invalid_bill_owers">Owers required</string>
|
||||||
|
<string name="error_no_network">No network connection</string>
|
||||||
|
<string name="error_server">Server error</string>
|
||||||
|
<string name="error_io">Server connection broken</string>
|
||||||
|
<string name="error_share_impossible">Cannot share this project</string>
|
||||||
|
|
||||||
|
<!-- Drawer / Common UI -->
|
||||||
|
<string name="drawer_no_account">Connect to Nextcloud account</string>
|
||||||
|
<string name="drawer_last_sync">Last sync: %1$02d:%2$02d</string>
|
||||||
|
<string name="simple_cancel">Cancel</string>
|
||||||
|
<string name="simple_ok" tools:ignore="ButtonCase,Typos">Ok</string>
|
||||||
|
<string name="simple_yes">Yes</string>
|
||||||
|
<string name="simple_no">No</string>
|
||||||
|
<string name="simple_close">Close</string>
|
||||||
|
|
||||||
|
<!-- Settings -->
|
||||||
|
<string name="settings_appearance">Appearance</string>
|
||||||
|
<string name="settings_network">Network</string>
|
||||||
|
<string name="settings_other">Other</string>
|
||||||
|
<string name="settings_night_mode">Theme</string>
|
||||||
|
<string name="settings_offline_mode">Offline mode</string>
|
||||||
|
<string name="settings_offline_mode_summary">Only sync manually.</string>
|
||||||
|
<string name="settings_color_custom">Custom color</string>
|
||||||
|
<string name="settings_color_mode">Color Selection</string>
|
||||||
|
<string name="settings_show_archived">Show archived projects</string>
|
||||||
|
<string name="settings_beta_features">Beta Features</string>
|
||||||
|
<string name="settings_beta_features_summary">Enable experimental features. Use at your own risk.</string>
|
||||||
|
<string name="settings_fill_new_bill_from_last">Auto-fill from last bill</string>
|
||||||
|
<string name="settings_fill_new_bill_from_last_summary">Pre-fill payer, category, mode and owers from the last bill created in the project.</string>
|
||||||
|
<string name="settings_auto_sync_on_open">Sync interval</string>
|
||||||
|
<string name="settings_auto_sync_on_open_summary">How often to refresh the account and all projects when opening the app.</string>
|
||||||
|
<string name="pref_value_sync_1m">1 minute</string>
|
||||||
|
<string name="pref_value_sync_10m">10 minutes</string>
|
||||||
|
<string name="pref_value_sync_1h">1 hour</string>
|
||||||
|
<string name="pref_value_sync_1d">1 day</string>
|
||||||
|
<string name="settings_url_warn_http">WARNING: "http" is unsafe. Use "https".</string>
|
||||||
|
<string name="settings_colorpicker_title">Choose Color</string>
|
||||||
|
|
||||||
|
<string name="pref_value_color_system">System</string>
|
||||||
|
<string name="pref_value_color_manual">Manual</string>
|
||||||
|
<string name="pref_value_theme_light">Light</string>
|
||||||
|
<string name="pref_value_theme_dark">Dark</string>
|
||||||
|
<string name="pref_value_theme_system">Follow system</string>
|
||||||
|
|
||||||
|
<!-- Enums and Lists -->
|
||||||
|
<string name="repeat_no">No repeat</string>
|
||||||
|
<string name="repeat_day">Daily</string>
|
||||||
|
<string name="repeat_week">Weekly</string>
|
||||||
|
<string name="repeat_fortnight">Fortnightly</string>
|
||||||
|
<string name="repeat_month">Monthly</string>
|
||||||
|
<string name="repeat_year">Yearly</string>
|
||||||
|
|
||||||
|
<string name="payment_mode_none">None</string>
|
||||||
|
<string name="payment_mode_all">All</string>
|
||||||
|
<string name="payment_mode_credit_card">Credit card</string>
|
||||||
|
<string name="payment_mode_cash">Cash</string>
|
||||||
|
<string name="payment_mode_check">Check</string>
|
||||||
|
<string name="payment_mode_online">Online</string>
|
||||||
|
<string name="payment_mode_transfer">Transfer</string>
|
||||||
|
|
||||||
|
<string name="category_none">None</string>
|
||||||
|
<string name="category_all">All</string>
|
||||||
|
<string name="category_all_except_reimbursement">All except reimbursement</string>
|
||||||
|
<string name="category_groceries">Grocery</string>
|
||||||
|
<string name="category_leisure">Bar/Party</string>
|
||||||
|
<string name="category_rent">Rent</string>
|
||||||
|
<string name="category_bills">Bill</string>
|
||||||
|
<string name="category_excursion">Excursion/Culture</string>
|
||||||
|
<string name="category_health">Health</string>
|
||||||
|
<string name="category_shopping">Shopping</string>
|
||||||
|
<string name="category_reimbursement">Reimbursement</string>
|
||||||
|
<string name="category_restaurant">Restaurant</string>
|
||||||
|
<string name="category_accomodation">Accommodation</string>
|
||||||
|
<string name="category_transport">Transport</string>
|
||||||
|
<string name="category_sport">Sport</string>
|
||||||
|
|
||||||
|
<!-- Project specific -->
|
||||||
|
<string name="new_project_action">What</string>
|
||||||
|
<string name="new_project_where">Where</string>
|
||||||
|
<string name="where_local">Local only</string>
|
||||||
|
<string name="todo_join">Join existing project</string>
|
||||||
|
<string name="todo_create">Create new project</string>
|
||||||
|
<string name="import_tooltip">Import from file</string>
|
||||||
|
<string name="choose_project_management_action">Project</string>
|
||||||
|
<string name="project_added_success">Project added successfully.</string>
|
||||||
|
<string name="no_projects_text">You have no projects yet.</string>
|
||||||
|
<string name="configure_account_choice">Configure Nextcloud account</string>
|
||||||
|
<string name="add_project_choice">Add project manually</string>
|
||||||
|
<string name="no_members_text">No members in this project.</string>
|
||||||
|
<string name="no_bills_text">No bills found.</string>
|
||||||
|
<string name="member_already_exists">Member already exists.</string>
|
||||||
|
<string name="activity_dialog_title">Project: %1$s</string>
|
||||||
|
<string name="remove_project_confirmation">Project %1$s removed.</string>
|
||||||
|
<string name="file_saved_success">File saved: %1$s</string>
|
||||||
|
<string name="import_error_header">Import failed at row %d</string>
|
||||||
|
<string name="import_error_date">Invalid date format at row %d</string>
|
||||||
|
<string name="import_error_owers">Invalid owers at row %d</string>
|
||||||
|
<string name="add_member_dialog_title">Add Member</string>
|
||||||
|
<string name="edit_member_dialog_title">Edit Member</string>
|
||||||
|
<string name="member_edit_delete">Delete</string>
|
||||||
|
<string name="project_edition_no_change">No changes to save.</string>
|
||||||
|
|
||||||
|
<!-- Settlement -->
|
||||||
|
<string name="center_none">None (Optimal)</string>
|
||||||
|
<string name="settle_who">Who pays</string>
|
||||||
|
<string name="settle_to_whom">To whom</string>
|
||||||
|
<string name="settle_how_much">Amount</string>
|
||||||
|
<string name="simple_settle_share">Share</string>
|
||||||
|
<string name="simple_create_bills">Create bills</string>
|
||||||
|
<string name="settle_bill_what">Settlement</string>
|
||||||
|
|
||||||
|
<!-- Currencies -->
|
||||||
|
<string name="currency_dialog_title">Choose Currency (%s)</string>
|
||||||
|
<string name="setting_none">None</string>
|
||||||
|
<string name="setting_all">All</string>
|
||||||
|
<string name="currency_saved_success">Currency settings saved.</string>
|
||||||
|
<string name="main_currency">Main Currency</string>
|
||||||
|
|
||||||
|
<!-- Statistics -->
|
||||||
|
<string name="label_bills_suggested">Suggested Categories</string>
|
||||||
|
<string name="label_bills_skip">Skip</string>
|
||||||
|
<string name="stats_date_min">From</string>
|
||||||
|
<string name="stats_date_max">To</string>
|
||||||
|
<string name="stats_who">Member</string>
|
||||||
|
<string name="stats_paid">Paid</string>
|
||||||
|
<string name="stats_spent">Spent</string>
|
||||||
|
<string name="stats_balance">Balance</string>
|
||||||
|
<string name="total">Total: %1$s</string>
|
||||||
|
|
||||||
|
<!-- Errors Extra -->
|
||||||
|
<string name="error_project_connect_check">Connection failed: %1$s</string>
|
||||||
|
<string name="error_create_remote_project_helper">Creation failed: %1$s</string>
|
||||||
|
<string name="error_edit_remote_project_helper">Error updating remote project: %1$s</string>
|
||||||
|
<string name="remote_project_operation_no_network">Network unavailable for remote operation.</string>
|
||||||
|
<string name="error_scanning_bill_qr_code">Failed to parse QR code.</string>
|
||||||
|
<string name="error_token_mismatch">Authentication token mismatch. Please log in again.</string>
|
||||||
|
<string name="insufficient_access_level">You don\'t have permission to perform this action.</string>
|
||||||
|
<string name="delete_label_confirmation_title">Delete Label</string>
|
||||||
|
<string name="delete_label_confirmation_message">Are you sure you want to delete this label?</string>
|
||||||
|
|
||||||
|
<!-- About -->
|
||||||
|
<string name="about_version">Version %1$s</string>
|
||||||
|
<string name="about_maintainer_title">Maintainer</string>
|
||||||
|
<string name="about_license_title">License</string>
|
||||||
|
<string name="about_source_title">Source code</string>
|
||||||
|
|
||||||
|
<!-- New constants for backward compatibility or shared use -->
|
||||||
|
<string name="share_intent_title">Project %1$s</string>
|
||||||
|
<string name="share_chooser_title">Share %1$s</string>
|
||||||
|
|
||||||
|
</resources>
|
||||||
@@ -0,0 +1,268 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Actions -->
|
||||||
|
<string name="action_new_bill">Nouvelle facture</string>
|
||||||
|
<string name="action_add_project">Ajouter un projet</string>
|
||||||
|
<string name="action_save">Enregistrer</string>
|
||||||
|
<string name="action_edit">Modifier</string>
|
||||||
|
<string name="action_share">Partager</string>
|
||||||
|
<string name="action_search">Rechercher</string>
|
||||||
|
<string name="action_open_menu">Ouvrir le menu</string>
|
||||||
|
<string name="action_close_search">Fermer la recherche</string>
|
||||||
|
<string name="action_clear_search">Effacer la recherche</string>
|
||||||
|
<string name="action_delete">Supprimer</string>
|
||||||
|
<string name="simple_back">Retour</string>
|
||||||
|
<string name="action_archive">Archiver</string>
|
||||||
|
<string name="action_unarchive">Désarchiver</string>
|
||||||
|
<string name="action_export">Exporter</string>
|
||||||
|
<string name="action_stats">Stats</string>
|
||||||
|
<string name="action_settle">Régler</string>
|
||||||
|
<string name="action_scan_qrcode">Scanner un QR code</string>
|
||||||
|
<string name="action_settings">Réglages</string>
|
||||||
|
<string name="action_label_bills">Catégoriser les factures</string>
|
||||||
|
<string name="action_logout">Déconnecter</string>
|
||||||
|
<string name="action_connect">Connecter</string>
|
||||||
|
<string name="action_discard">Abandonner</string>
|
||||||
|
<string name="action_members">Membres</string>
|
||||||
|
<string name="action_labels">Étiquettes</string>
|
||||||
|
<string name="action_currencies">Devises</string>
|
||||||
|
|
||||||
|
<!-- Titles -->
|
||||||
|
<string name="title_stats">Statistiques</string>
|
||||||
|
<string name="title_edit_project">Modifier le projet</string>
|
||||||
|
<string name="title_label_bills">Catégoriser les factures</string>
|
||||||
|
<string name="title_labels">Gérer les étiquettes</string>
|
||||||
|
<string name="title_about">À propos</string>
|
||||||
|
<string name="title_settle">Régler le projet</string>
|
||||||
|
<string name="title_share">Partager le projet</string>
|
||||||
|
<string name="title_add_project">Ajouter un projet</string>
|
||||||
|
<string name="title_add_category">Ajouter une catégorie</string>
|
||||||
|
<string name="title_add_payment_mode">Ajouter un mode de paiement</string>
|
||||||
|
<string name="title_account">Compte Nextcloud</string>
|
||||||
|
<string name="title_share_web">Lien web</string>
|
||||||
|
<string name="title_share_qr">Lien Cowspent</string>
|
||||||
|
<string name="title_confirm">Êtes-vous sûr(e) ?</string>
|
||||||
|
|
||||||
|
<!-- Labels and Fields -->
|
||||||
|
<string name="label_all_bills">Toutes les factures</string>
|
||||||
|
<string name="label_categories">Catégories</string>
|
||||||
|
<string name="label_payment_modes">Modes de paiement</string>
|
||||||
|
<string name="label_name">Nom</string>
|
||||||
|
<string name="label_icon">Icône / Emoji</string>
|
||||||
|
<string name="label_color">Couleur</string>
|
||||||
|
<string name="label_weight">Poids</string>
|
||||||
|
<string name="label_activated">Activé</string>
|
||||||
|
<string name="label_password">Mot de passe</string>
|
||||||
|
<string name="label_email">Courriel</string>
|
||||||
|
<string name="label_url">Adresse du serveur</string>
|
||||||
|
<string name="label_username">Nom d\'utilisateur</string>
|
||||||
|
<string name="label_comment">Commentaire</string>
|
||||||
|
<string name="label_what">Quoi ?</string>
|
||||||
|
<string name="label_payer">Qui a payé ?</string>
|
||||||
|
<string name="label_owers">Pour qui ?</string>
|
||||||
|
<string name="label_repeat">Répétition</string>
|
||||||
|
<string name="label_mode">Mode</string>
|
||||||
|
<string name="label_category">Catégorie</string>
|
||||||
|
<string name="label_project_id">ID/nom du projet</string>
|
||||||
|
<string name="label_project_title">Titre du projet</string>
|
||||||
|
<string name="label_use_sso">Utiliser le compte de l\'application Nextcloud</string>
|
||||||
|
|
||||||
|
<!-- Dialogs and Messages -->
|
||||||
|
<string name="dialog_unsaved_changes_title">Modifications non enregistrées</string>
|
||||||
|
<string name="dialog_unsaved_changes_msg">Enregistrer les modifications avant de quitter ?</string>
|
||||||
|
<string name="dialog_confirm_remove_project_msg">Le projet distant ne sera pas supprimé.</string>
|
||||||
|
<string name="dialog_sync_error_title">Erreur de synchronisation</string>
|
||||||
|
<string name="dialog_sync_error_msg">Échec de la synchronisation pour %1$s.\n\n%2$s</string>
|
||||||
|
<string name="dialog_balanced_msg">Les dépenses sont déjà équilibrées.</string>
|
||||||
|
<string name="msg_project_added">Projet %1$s ajouté</string>
|
||||||
|
<string name="msg_bill_labeled_done">Toutes les factures sont catégorisées</string>
|
||||||
|
<string name="msg_no_suggestions">Aucune suggestion</string>
|
||||||
|
<string name="msg_auth_warning">Nécessite Cospend v0.3.4+.</string>
|
||||||
|
<string name="msg_link_copied">Lien copié dans le presse-papiers</string>
|
||||||
|
<string name="msg_share_qr">Scannez le QR code ou partagez le lien pour rejoindre le projet.</string>
|
||||||
|
<string name="msg_share_web">Lien d\'accès depuis un navigateur web.</string>
|
||||||
|
<string name="msg_share_qr_warn">Partagez ce lien avec un utilisateur de Cowspent.</string>
|
||||||
|
<string name="msg_settle_intro">Règlement pour %1$s :</string>
|
||||||
|
<string name="msg_settle_sentence">%1$s doit %3$.2f à %2$s</string>
|
||||||
|
<string name="msg_stats_intro">Statistiques pour %1$s :</string>
|
||||||
|
<string name="msg_stats_header">Membre (Payé | Dépensé | Solde)</string>
|
||||||
|
<string name="msg_logged_in_as">Connecté en tant que %1$s</string>
|
||||||
|
|
||||||
|
<!-- Errors -->
|
||||||
|
<string name="error_generic">Erreur</string>
|
||||||
|
<string name="error_loading">Chargement</string>
|
||||||
|
<string name="error_no_projects">Aucun projet trouvé</string>
|
||||||
|
<string name="error_no_members">Aucun membre trouvé</string>
|
||||||
|
<string name="error_no_bills">Aucune facture trouvée</string>
|
||||||
|
<string name="error_no_member">Au moins un membre est requis</string>
|
||||||
|
<string name="error_maintenance_mode">Le serveur est en mode maintenance</string>
|
||||||
|
<string name="error_400">400 Requête incorrecte</string>
|
||||||
|
<string name="error_401">401 Non autorisé</string>
|
||||||
|
<string name="error_403">403 Interdit</string>
|
||||||
|
<string name="error_404">404 Introuvable</string>
|
||||||
|
<string name="error_sync">Échec de la synchronisation : %1$s</string>
|
||||||
|
<string name="error_invalid_login">Identifiant invalide : %1$s</string>
|
||||||
|
<string name="error_auth">Mauvais nom d\'utilisateur ou mot de passe</string>
|
||||||
|
<string name="error_json">Réponse du serveur invalide</string>
|
||||||
|
<string name="error_req_failed">La requête a échoué</string>
|
||||||
|
<string name="error_invalid_email">Adresse e-mail invalide</string>
|
||||||
|
<string name="error_invalid_project_id">ID de projet invalide</string>
|
||||||
|
<string name="error_invalid_project_name">Titre de projet invalide</string>
|
||||||
|
<string name="error_invalid_bill_name">Nom de facture invalide</string>
|
||||||
|
<string name="error_invalid_bill_date">Date de facture invalide</string>
|
||||||
|
<string name="error_invalid_bill_payer">Payeur requis</string>
|
||||||
|
<string name="error_invalid_bill_owers">Participants requis</string>
|
||||||
|
<string name="error_no_network">Aucune connexion réseau</string>
|
||||||
|
<string name="error_server">Erreur serveur</string>
|
||||||
|
<string name="error_io">La connexion au serveur a échoué</string>
|
||||||
|
<string name="error_share_impossible">Impossible de partager ce projet</string>
|
||||||
|
|
||||||
|
<!-- Drawer / Common UI -->
|
||||||
|
<string name="drawer_no_account">Se connecter au compte Nextcloud</string>
|
||||||
|
<string name="drawer_last_sync">Dernière synchronisation : %1$02d:%2$02d</string>
|
||||||
|
<string name="simple_cancel">Annuler</string>
|
||||||
|
<string name="simple_ok" tools:ignore="ButtonCase,Typos">Ok</string>
|
||||||
|
<string name="simple_yes">Oui</string>
|
||||||
|
<string name="simple_no">Non</string>
|
||||||
|
<string name="simple_close">Fermer</string>
|
||||||
|
|
||||||
|
<!-- Settings -->
|
||||||
|
<string name="settings_appearance">Apparence</string>
|
||||||
|
<string name="settings_network">Réseau</string>
|
||||||
|
<string name="settings_other">Autres</string>
|
||||||
|
<string name="settings_night_mode">Thème</string>
|
||||||
|
<string name="settings_offline_mode">Mode hors ligne</string>
|
||||||
|
<string name="settings_offline_mode_summary">Synchroniser uniquement manuellement.</string>
|
||||||
|
<string name="settings_color_custom">Couleur personnalisée</string>
|
||||||
|
<string name="settings_color_mode">Sélection de la couleur</string>
|
||||||
|
<string name="settings_show_archived">Afficher les projets archivés</string>
|
||||||
|
<string name="settings_beta_features">Fonctionnalités bêta</string>
|
||||||
|
<string name="settings_beta_features_summary">Activer les fonctionnalités expérimentales. À utiliser à vos risques et périls.</string>
|
||||||
|
<string name="settings_fill_new_bill_from_last">Pré-remplir depuis la dernière facture</string>
|
||||||
|
<string name="settings_fill_new_bill_from_last_summary">Reprendre le payeur, la catégorie, le mode et les participants de la dernière facture créée dans le projet.</string>
|
||||||
|
<string name="settings_auto_sync_on_open">Intervalle de synchronisation</string>
|
||||||
|
<string name="settings_auto_sync_on_open_summary">Fréquence de rafraîchissement du compte et de tous les projets à l\'ouverture de l\'application.</string>
|
||||||
|
<string name="pref_value_sync_1m">1 minute</string>
|
||||||
|
<string name="pref_value_sync_10m">10 minutes</string>
|
||||||
|
<string name="pref_value_sync_1h">1 heure</string>
|
||||||
|
<string name="pref_value_sync_1d">1 jour</string>
|
||||||
|
<string name="settings_url_warn_http">AVERTISSEMENT : \"http\" n\'est pas sûr. Utilisez \"https\".</string>
|
||||||
|
<string name="settings_colorpicker_title">Choisir une couleur</string>
|
||||||
|
|
||||||
|
<string name="pref_value_color_system">Système</string>
|
||||||
|
<string name="pref_value_color_manual">Manuelle</string>
|
||||||
|
<string name="pref_value_theme_light">Clair</string>
|
||||||
|
<string name="pref_value_theme_dark">Sombre</string>
|
||||||
|
<string name="pref_value_theme_system">Suivre le système</string>
|
||||||
|
|
||||||
|
<!-- Constants (Do not translate) -->
|
||||||
|
|
||||||
|
<!-- Enums and Lists -->
|
||||||
|
<string name="repeat_no">Pas de répétition</string>
|
||||||
|
<string name="repeat_day">Quotidienne</string>
|
||||||
|
<string name="repeat_week">Hebdomadaire</string>
|
||||||
|
<string name="repeat_fortnight">Toutes les deux semaines</string>
|
||||||
|
<string name="repeat_month">Mensuelle</string>
|
||||||
|
<string name="repeat_year">Annuelle</string>
|
||||||
|
|
||||||
|
<string name="payment_mode_none">Aucun</string>
|
||||||
|
<string name="payment_mode_all">Tous</string>
|
||||||
|
<string name="payment_mode_credit_card">Carte bancaire</string>
|
||||||
|
<string name="payment_mode_cash">Espèces</string>
|
||||||
|
<string name="payment_mode_check">Chèque</string>
|
||||||
|
<string name="payment_mode_online">En ligne</string>
|
||||||
|
<string name="payment_mode_transfer">Virement</string>
|
||||||
|
|
||||||
|
<string name="category_none">Aucune</string>
|
||||||
|
<string name="category_all">Toutes</string>
|
||||||
|
<string name="category_all_except_reimbursement">Toutes sauf remboursement</string>
|
||||||
|
<string name="category_groceries">Courses</string>
|
||||||
|
<string name="category_leisure">Bar/Fête</string>
|
||||||
|
<string name="category_rent">Loyer</string>
|
||||||
|
<string name="category_bills">Facture</string>
|
||||||
|
<string name="category_excursion">Excursion/Culture</string>
|
||||||
|
<string name="category_health">Santé</string>
|
||||||
|
<string name="category_shopping">Achats</string>
|
||||||
|
<string name="category_reimbursement">Remboursement</string>
|
||||||
|
<string name="category_restaurant">Restaurant</string>
|
||||||
|
<string name="category_accomodation">Hébergement</string>
|
||||||
|
<string name="category_transport">Transport</string>
|
||||||
|
<string name="category_sport">Sport</string>
|
||||||
|
|
||||||
|
<!-- Project specific -->
|
||||||
|
<string name="new_project_action">Quoi</string>
|
||||||
|
<string name="new_project_where">Où</string>
|
||||||
|
<string name="where_local">Local uniquement</string>
|
||||||
|
<string name="todo_join">Rejoindre un projet existant</string>
|
||||||
|
<string name="todo_create">Créer un nouveau projet</string>
|
||||||
|
<string name="import_tooltip">Importer depuis un fichier</string>
|
||||||
|
<string name="choose_project_management_action">Projet</string>
|
||||||
|
<string name="project_added_success">Le projet a été ajouté avec succès.</string>
|
||||||
|
<string name="no_projects_text">Vous n\'avez pas encore de projet.</string>
|
||||||
|
<string name="configure_account_choice">Configurer le compte Nextcloud</string>
|
||||||
|
<string name="add_project_choice">Ajouter un projet manuellement</string>
|
||||||
|
<string name="no_members_text">Aucun membre dans ce projet.</string>
|
||||||
|
<string name="no_bills_text">Aucune facture trouvée.</string>
|
||||||
|
<string name="member_already_exists">Ce membre existe déjà.</string>
|
||||||
|
<string name="activity_dialog_title">Projet : %1$s</string>
|
||||||
|
<string name="remove_project_confirmation">Projet %1$s supprimé.</string>
|
||||||
|
<string name="file_saved_success">Fichier enregistré : %1$s</string>
|
||||||
|
<string name="import_error_header">Échec de l\'importation à la ligne %d</string>
|
||||||
|
<string name="import_error_date">Format de date invalide à la ligne %d</string>
|
||||||
|
<string name="import_error_owers">Participants invalides à la ligne %d</string>
|
||||||
|
<string name="add_member_dialog_title">Ajouter un membre</string>
|
||||||
|
<string name="edit_member_dialog_title">Modifier le membre</string>
|
||||||
|
<string name="member_edit_delete">Supprimer</string>
|
||||||
|
<string name="project_edition_no_change">Aucune modification à enregistrer.</string>
|
||||||
|
|
||||||
|
<!-- Settlement -->
|
||||||
|
<string name="center_none">Aucun (optimal)</string>
|
||||||
|
<string name="settle_who">Qui paie</string>
|
||||||
|
<string name="settle_to_whom">À qui</string>
|
||||||
|
<string name="settle_how_much">Montant</string>
|
||||||
|
<string name="simple_settle_share">Partager</string>
|
||||||
|
<string name="simple_create_bills">Créer les factures</string>
|
||||||
|
<string name="settle_bill_what">Règlement</string>
|
||||||
|
|
||||||
|
<!-- Currencies -->
|
||||||
|
<string name="currency_dialog_title">Choisir la devise (%s)</string>
|
||||||
|
<string name="setting_none">Aucune</string>
|
||||||
|
<string name="setting_all">Toutes</string>
|
||||||
|
<string name="currency_saved_success">Paramètres des devises enregistrés.</string>
|
||||||
|
<string name="main_currency">Devise principale</string>
|
||||||
|
|
||||||
|
<!-- Statistics -->
|
||||||
|
<string name="label_bills_suggested">Catégories suggérées</string>
|
||||||
|
<string name="label_bills_skip">Ignorer</string>
|
||||||
|
<string name="stats_date_min">Du</string>
|
||||||
|
<string name="stats_date_max">Au</string>
|
||||||
|
<string name="stats_who">Membre</string>
|
||||||
|
<string name="stats_paid">Payé</string>
|
||||||
|
<string name="stats_spent">Dépensé</string>
|
||||||
|
<string name="stats_balance">Solde</string>
|
||||||
|
<string name="total">Total : %1$s</string>
|
||||||
|
|
||||||
|
<!-- Errors Extra -->
|
||||||
|
<string name="error_project_connect_check">Échec de la connexion : %1$s</string>
|
||||||
|
<string name="error_create_remote_project_helper">Échec de la création : %1$s</string>
|
||||||
|
<string name="error_edit_remote_project_helper">Erreur lors de la mise à jour du projet distant : %1$s</string>
|
||||||
|
<string name="remote_project_operation_no_network">Réseau indisponible pour cette opération distante.</string>
|
||||||
|
<string name="error_scanning_bill_qr_code">Impossible de lire le QR code.</string>
|
||||||
|
<string name="error_token_mismatch">Jeton d\'authentification invalide. Veuillez vous reconnecter.</string>
|
||||||
|
<string name="insufficient_access_level">Vous n\'avez pas la permission d\'effectuer cette action.</string>
|
||||||
|
<string name="delete_label_confirmation_title">Supprimer l\'étiquette</string>
|
||||||
|
<string name="delete_label_confirmation_message">Voulez-vous vraiment supprimer cette étiquette ?</string>
|
||||||
|
|
||||||
|
<!-- About -->
|
||||||
|
<string name="about_version">Version %1$s</string>
|
||||||
|
<string name="about_maintainer_title">Mainteneur</string>
|
||||||
|
<string name="about_license_title">Licence</string>
|
||||||
|
<string name="about_source_title">Code source</string>
|
||||||
|
|
||||||
|
<!-- New constants for backward compatibility or shared use -->
|
||||||
|
<string name="share_intent_title">Projet %1$s</string>
|
||||||
|
<string name="share_chooser_title">Partager %1$s</string>
|
||||||
|
|
||||||
|
</resources>
|
||||||
@@ -0,0 +1,272 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Untranslated: these are the English strings, kept here so a translation can be
|
||||||
|
contributed by simply replacing the values. Strings marked translatable="false" in
|
||||||
|
values/strings.xml (app and product names, preference keys) are deliberately absent
|
||||||
|
and must not be added.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- Actions -->
|
||||||
|
<string name="action_new_bill">New bill</string>
|
||||||
|
<string name="action_add_project">Add project</string>
|
||||||
|
<string name="action_save">Save</string>
|
||||||
|
<string name="action_edit">Edit</string>
|
||||||
|
<string name="action_share">Share</string>
|
||||||
|
<string name="action_search">Search</string>
|
||||||
|
<string name="action_open_menu">Open menu</string>
|
||||||
|
<string name="action_close_search">Close search</string>
|
||||||
|
<string name="action_clear_search">Clear search</string>
|
||||||
|
<string name="action_delete">Delete</string>
|
||||||
|
<string name="simple_back">Back</string>
|
||||||
|
<string name="action_archive">Archive</string>
|
||||||
|
<string name="action_unarchive">Unarchive</string>
|
||||||
|
<string name="action_export">Export</string>
|
||||||
|
<string name="action_stats">Stats</string>
|
||||||
|
<string name="action_settle">Settle</string>
|
||||||
|
<string name="action_scan_qrcode">Scan QR Code</string>
|
||||||
|
<string name="action_settings">Settings</string>
|
||||||
|
<string name="action_label_bills">Label missing categories</string>
|
||||||
|
<string name="action_logout">Logout</string>
|
||||||
|
<string name="action_connect">Connect</string>
|
||||||
|
<string name="action_discard">Discard</string>
|
||||||
|
<string name="action_members">Members</string>
|
||||||
|
<string name="action_labels">Labels</string>
|
||||||
|
<string name="action_currencies">Currencies</string>
|
||||||
|
|
||||||
|
<!-- Titles -->
|
||||||
|
<string name="title_stats">Statistics</string>
|
||||||
|
<string name="title_edit_project">Edit project</string>
|
||||||
|
<string name="title_label_bills">Label Bills</string>
|
||||||
|
<string name="title_labels">Manage Labels</string>
|
||||||
|
<string name="title_about">About</string>
|
||||||
|
<string name="title_settle">Settle Project</string>
|
||||||
|
<string name="title_share">Share Project</string>
|
||||||
|
<string name="title_add_project">Add Project</string>
|
||||||
|
<string name="title_add_category">Add Category</string>
|
||||||
|
<string name="title_add_payment_mode">Add Payment Mode</string>
|
||||||
|
<string name="title_account">Nextcloud Account</string>
|
||||||
|
<string name="title_share_web">Web link</string>
|
||||||
|
<string name="title_share_qr">Cowspent link</string>
|
||||||
|
<string name="title_confirm">Are you sure?</string>
|
||||||
|
|
||||||
|
<!-- Labels and Fields -->
|
||||||
|
<string name="label_all_bills">All bills</string>
|
||||||
|
<string name="label_categories">Categories</string>
|
||||||
|
<string name="label_payment_modes">Payment Modes</string>
|
||||||
|
<string name="label_name">Name</string>
|
||||||
|
<string name="label_icon">Icon / Emoji</string>
|
||||||
|
<string name="label_color">Color</string>
|
||||||
|
<string name="label_weight">Weight</string>
|
||||||
|
<string name="label_activated">Activated</string>
|
||||||
|
<string name="label_password">Password</string>
|
||||||
|
<string name="label_email">E-mail</string>
|
||||||
|
<string name="label_url">Server address</string>
|
||||||
|
<string name="label_username">Username</string>
|
||||||
|
<string name="label_comment">Comment</string>
|
||||||
|
<string name="label_what">What?</string>
|
||||||
|
<string name="label_payer">Who paid?</string>
|
||||||
|
<string name="label_owers">For whom?</string>
|
||||||
|
<string name="label_repeat">Repeat every</string>
|
||||||
|
<string name="label_mode">Mode</string>
|
||||||
|
<string name="label_category">Category</string>
|
||||||
|
<string name="label_project_id">Project ID/name</string>
|
||||||
|
<string name="label_project_title">Project title</string>
|
||||||
|
<string name="label_use_sso">Use Nextcloud App Account</string>
|
||||||
|
|
||||||
|
<!-- Dialogs and Messages -->
|
||||||
|
<string name="dialog_unsaved_changes_title">Unsaved changes</string>
|
||||||
|
<string name="dialog_unsaved_changes_msg">Save changes before leaving?</string>
|
||||||
|
<string name="dialog_confirm_remove_project_msg">The remote project will not be deleted.</string>
|
||||||
|
<string name="dialog_sync_error_title">Sync error</string>
|
||||||
|
<string name="dialog_sync_error_msg">Sync failed for %1$s.\n\n%2$s</string>
|
||||||
|
<string name="dialog_balanced_msg">Expenses are already balanced.</string>
|
||||||
|
<string name="msg_project_added">Project %1$s added</string>
|
||||||
|
<string name="msg_bill_labeled_done">All bills labeled</string>
|
||||||
|
<string name="msg_no_suggestions">No suggestions</string>
|
||||||
|
<string name="msg_auth_warning">Requires Cospend v0.3.4+.</string>
|
||||||
|
<string name="msg_link_copied">Link copied to clipboard</string>
|
||||||
|
<string name="msg_share_qr">Scan QR code or share the link to join.</string>
|
||||||
|
<string name="msg_share_web">Link for web browser access.</string>
|
||||||
|
<string name="msg_share_qr_warn">Share this link with a Cowspent user.</string>
|
||||||
|
<string name="msg_settle_intro">Settlement for %1$s:</string>
|
||||||
|
<string name="msg_settle_sentence">%1$s owes %3$.2f to %2$s</string>
|
||||||
|
<string name="msg_stats_intro">Stats for %1$s:</string>
|
||||||
|
<string name="msg_stats_header">Member (Paid | Spent | Balance)</string>
|
||||||
|
<string name="msg_logged_in_as">Logged in as %1$s</string>
|
||||||
|
|
||||||
|
<!-- Errors -->
|
||||||
|
<string name="error_generic">Error</string>
|
||||||
|
<string name="error_loading">Loading</string>
|
||||||
|
<string name="error_no_projects">No projects found</string>
|
||||||
|
<string name="error_no_members">No members found</string>
|
||||||
|
<string name="error_no_bills">No bills found</string>
|
||||||
|
<string name="error_no_member">At least one member required</string>
|
||||||
|
<string name="error_maintenance_mode">Server is in maintenance mode</string>
|
||||||
|
<string name="error_400">400 Bad request</string>
|
||||||
|
<string name="error_401">401 Unauthorized</string>
|
||||||
|
<string name="error_403">403 Forbidden</string>
|
||||||
|
<string name="error_404">404 Not Found</string>
|
||||||
|
<string name="error_sync">Sync failed: %1$s</string>
|
||||||
|
<string name="error_invalid_login">Invalid login: %1$s</string>
|
||||||
|
<string name="error_auth">Wrong username or password</string>
|
||||||
|
<string name="error_json">Invalid server response</string>
|
||||||
|
<string name="error_req_failed">Request failed</string>
|
||||||
|
<string name="error_invalid_email">Invalid e-mail</string>
|
||||||
|
<string name="error_invalid_project_id">Invalid project ID</string>
|
||||||
|
<string name="error_invalid_project_name">Invalid project title</string>
|
||||||
|
<string name="error_invalid_bill_name">Invalid bill name</string>
|
||||||
|
<string name="error_invalid_bill_date">Invalid bill date</string>
|
||||||
|
<string name="error_invalid_bill_payer">Payer required</string>
|
||||||
|
<string name="error_invalid_bill_owers">Owers required</string>
|
||||||
|
<string name="error_no_network">No network connection</string>
|
||||||
|
<string name="error_server">Server error</string>
|
||||||
|
<string name="error_io">Server connection broken</string>
|
||||||
|
<string name="error_share_impossible">Cannot share this project</string>
|
||||||
|
|
||||||
|
<!-- Drawer / Common UI -->
|
||||||
|
<string name="drawer_no_account">Connect to Nextcloud account</string>
|
||||||
|
<string name="drawer_last_sync">Last sync: %1$02d:%2$02d</string>
|
||||||
|
<string name="simple_cancel">Cancel</string>
|
||||||
|
<string name="simple_ok" tools:ignore="ButtonCase,Typos">Ok</string>
|
||||||
|
<string name="simple_yes">Yes</string>
|
||||||
|
<string name="simple_no">No</string>
|
||||||
|
<string name="simple_close">Close</string>
|
||||||
|
|
||||||
|
<!-- Settings -->
|
||||||
|
<string name="settings_appearance">Appearance</string>
|
||||||
|
<string name="settings_network">Network</string>
|
||||||
|
<string name="settings_other">Other</string>
|
||||||
|
<string name="settings_night_mode">Theme</string>
|
||||||
|
<string name="settings_offline_mode">Offline mode</string>
|
||||||
|
<string name="settings_offline_mode_summary">Only sync manually.</string>
|
||||||
|
<string name="settings_color_custom">Custom color</string>
|
||||||
|
<string name="settings_color_mode">Color Selection</string>
|
||||||
|
<string name="settings_show_archived">Show archived projects</string>
|
||||||
|
<string name="settings_beta_features">Beta Features</string>
|
||||||
|
<string name="settings_beta_features_summary">Enable experimental features. Use at your own risk.</string>
|
||||||
|
<string name="settings_fill_new_bill_from_last">Auto-fill from last bill</string>
|
||||||
|
<string name="settings_fill_new_bill_from_last_summary">Pre-fill payer, category, mode and owers from the last bill created in the project.</string>
|
||||||
|
<string name="settings_auto_sync_on_open">Sync interval</string>
|
||||||
|
<string name="settings_auto_sync_on_open_summary">How often to refresh the account and all projects when opening the app.</string>
|
||||||
|
<string name="pref_value_sync_1m">1 minute</string>
|
||||||
|
<string name="pref_value_sync_10m">10 minutes</string>
|
||||||
|
<string name="pref_value_sync_1h">1 hour</string>
|
||||||
|
<string name="pref_value_sync_1d">1 day</string>
|
||||||
|
<string name="settings_url_warn_http">WARNING: "http" is unsafe. Use "https".</string>
|
||||||
|
<string name="settings_colorpicker_title">Choose Color</string>
|
||||||
|
|
||||||
|
<string name="pref_value_color_system">System</string>
|
||||||
|
<string name="pref_value_color_manual">Manual</string>
|
||||||
|
<string name="pref_value_theme_light">Light</string>
|
||||||
|
<string name="pref_value_theme_dark">Dark</string>
|
||||||
|
<string name="pref_value_theme_system">Follow system</string>
|
||||||
|
|
||||||
|
<!-- Enums and Lists -->
|
||||||
|
<string name="repeat_no">No repeat</string>
|
||||||
|
<string name="repeat_day">Daily</string>
|
||||||
|
<string name="repeat_week">Weekly</string>
|
||||||
|
<string name="repeat_fortnight">Fortnightly</string>
|
||||||
|
<string name="repeat_month">Monthly</string>
|
||||||
|
<string name="repeat_year">Yearly</string>
|
||||||
|
|
||||||
|
<string name="payment_mode_none">None</string>
|
||||||
|
<string name="payment_mode_all">All</string>
|
||||||
|
<string name="payment_mode_credit_card">Credit card</string>
|
||||||
|
<string name="payment_mode_cash">Cash</string>
|
||||||
|
<string name="payment_mode_check">Check</string>
|
||||||
|
<string name="payment_mode_online">Online</string>
|
||||||
|
<string name="payment_mode_transfer">Transfer</string>
|
||||||
|
|
||||||
|
<string name="category_none">None</string>
|
||||||
|
<string name="category_all">All</string>
|
||||||
|
<string name="category_all_except_reimbursement">All except reimbursement</string>
|
||||||
|
<string name="category_groceries">Grocery</string>
|
||||||
|
<string name="category_leisure">Bar/Party</string>
|
||||||
|
<string name="category_rent">Rent</string>
|
||||||
|
<string name="category_bills">Bill</string>
|
||||||
|
<string name="category_excursion">Excursion/Culture</string>
|
||||||
|
<string name="category_health">Health</string>
|
||||||
|
<string name="category_shopping">Shopping</string>
|
||||||
|
<string name="category_reimbursement">Reimbursement</string>
|
||||||
|
<string name="category_restaurant">Restaurant</string>
|
||||||
|
<string name="category_accomodation">Accommodation</string>
|
||||||
|
<string name="category_transport">Transport</string>
|
||||||
|
<string name="category_sport">Sport</string>
|
||||||
|
|
||||||
|
<!-- Project specific -->
|
||||||
|
<string name="new_project_action">What</string>
|
||||||
|
<string name="new_project_where">Where</string>
|
||||||
|
<string name="where_local">Local only</string>
|
||||||
|
<string name="todo_join">Join existing project</string>
|
||||||
|
<string name="todo_create">Create new project</string>
|
||||||
|
<string name="import_tooltip">Import from file</string>
|
||||||
|
<string name="choose_project_management_action">Project</string>
|
||||||
|
<string name="project_added_success">Project added successfully.</string>
|
||||||
|
<string name="no_projects_text">You have no projects yet.</string>
|
||||||
|
<string name="configure_account_choice">Configure Nextcloud account</string>
|
||||||
|
<string name="add_project_choice">Add project manually</string>
|
||||||
|
<string name="no_members_text">No members in this project.</string>
|
||||||
|
<string name="no_bills_text">No bills found.</string>
|
||||||
|
<string name="member_already_exists">Member already exists.</string>
|
||||||
|
<string name="activity_dialog_title">Project: %1$s</string>
|
||||||
|
<string name="remove_project_confirmation">Project %1$s removed.</string>
|
||||||
|
<string name="file_saved_success">File saved: %1$s</string>
|
||||||
|
<string name="import_error_header">Import failed at row %d</string>
|
||||||
|
<string name="import_error_date">Invalid date format at row %d</string>
|
||||||
|
<string name="import_error_owers">Invalid owers at row %d</string>
|
||||||
|
<string name="add_member_dialog_title">Add Member</string>
|
||||||
|
<string name="edit_member_dialog_title">Edit Member</string>
|
||||||
|
<string name="member_edit_delete">Delete</string>
|
||||||
|
<string name="project_edition_no_change">No changes to save.</string>
|
||||||
|
|
||||||
|
<!-- Settlement -->
|
||||||
|
<string name="center_none">None (Optimal)</string>
|
||||||
|
<string name="settle_who">Who pays</string>
|
||||||
|
<string name="settle_to_whom">To whom</string>
|
||||||
|
<string name="settle_how_much">Amount</string>
|
||||||
|
<string name="simple_settle_share">Share</string>
|
||||||
|
<string name="simple_create_bills">Create bills</string>
|
||||||
|
<string name="settle_bill_what">Settlement</string>
|
||||||
|
|
||||||
|
<!-- Currencies -->
|
||||||
|
<string name="currency_dialog_title">Choose Currency (%s)</string>
|
||||||
|
<string name="setting_none">None</string>
|
||||||
|
<string name="setting_all">All</string>
|
||||||
|
<string name="currency_saved_success">Currency settings saved.</string>
|
||||||
|
<string name="main_currency">Main Currency</string>
|
||||||
|
|
||||||
|
<!-- Statistics -->
|
||||||
|
<string name="label_bills_suggested">Suggested Categories</string>
|
||||||
|
<string name="label_bills_skip">Skip</string>
|
||||||
|
<string name="stats_date_min">From</string>
|
||||||
|
<string name="stats_date_max">To</string>
|
||||||
|
<string name="stats_who">Member</string>
|
||||||
|
<string name="stats_paid">Paid</string>
|
||||||
|
<string name="stats_spent">Spent</string>
|
||||||
|
<string name="stats_balance">Balance</string>
|
||||||
|
<string name="total">Total: %1$s</string>
|
||||||
|
|
||||||
|
<!-- Errors Extra -->
|
||||||
|
<string name="error_project_connect_check">Connection failed: %1$s</string>
|
||||||
|
<string name="error_create_remote_project_helper">Creation failed: %1$s</string>
|
||||||
|
<string name="error_edit_remote_project_helper">Error updating remote project: %1$s</string>
|
||||||
|
<string name="remote_project_operation_no_network">Network unavailable for remote operation.</string>
|
||||||
|
<string name="error_scanning_bill_qr_code">Failed to parse QR code.</string>
|
||||||
|
<string name="error_token_mismatch">Authentication token mismatch. Please log in again.</string>
|
||||||
|
<string name="insufficient_access_level">You don\'t have permission to perform this action.</string>
|
||||||
|
<string name="delete_label_confirmation_title">Delete Label</string>
|
||||||
|
<string name="delete_label_confirmation_message">Are you sure you want to delete this label?</string>
|
||||||
|
|
||||||
|
<!-- About -->
|
||||||
|
<string name="about_version">Version %1$s</string>
|
||||||
|
<string name="about_maintainer_title">Maintainer</string>
|
||||||
|
<string name="about_license_title">License</string>
|
||||||
|
<string name="about_source_title">Source code</string>
|
||||||
|
|
||||||
|
<!-- New constants for backward compatibility or shared use -->
|
||||||
|
<string name="share_intent_title">Project %1$s</string>
|
||||||
|
<string name="share_chooser_title">Share %1$s</string>
|
||||||
|
|
||||||
|
</resources>
|
||||||
@@ -0,0 +1,272 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Untranslated: these are the English strings, kept here so a translation can be
|
||||||
|
contributed by simply replacing the values. Strings marked translatable="false" in
|
||||||
|
values/strings.xml (app and product names, preference keys) are deliberately absent
|
||||||
|
and must not be added.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- Actions -->
|
||||||
|
<string name="action_new_bill">New bill</string>
|
||||||
|
<string name="action_add_project">Add project</string>
|
||||||
|
<string name="action_save">Save</string>
|
||||||
|
<string name="action_edit">Edit</string>
|
||||||
|
<string name="action_share">Share</string>
|
||||||
|
<string name="action_search">Search</string>
|
||||||
|
<string name="action_open_menu">Open menu</string>
|
||||||
|
<string name="action_close_search">Close search</string>
|
||||||
|
<string name="action_clear_search">Clear search</string>
|
||||||
|
<string name="action_delete">Delete</string>
|
||||||
|
<string name="simple_back">Back</string>
|
||||||
|
<string name="action_archive">Archive</string>
|
||||||
|
<string name="action_unarchive">Unarchive</string>
|
||||||
|
<string name="action_export">Export</string>
|
||||||
|
<string name="action_stats">Stats</string>
|
||||||
|
<string name="action_settle">Settle</string>
|
||||||
|
<string name="action_scan_qrcode">Scan QR Code</string>
|
||||||
|
<string name="action_settings">Settings</string>
|
||||||
|
<string name="action_label_bills">Label missing categories</string>
|
||||||
|
<string name="action_logout">Logout</string>
|
||||||
|
<string name="action_connect">Connect</string>
|
||||||
|
<string name="action_discard">Discard</string>
|
||||||
|
<string name="action_members">Members</string>
|
||||||
|
<string name="action_labels">Labels</string>
|
||||||
|
<string name="action_currencies">Currencies</string>
|
||||||
|
|
||||||
|
<!-- Titles -->
|
||||||
|
<string name="title_stats">Statistics</string>
|
||||||
|
<string name="title_edit_project">Edit project</string>
|
||||||
|
<string name="title_label_bills">Label Bills</string>
|
||||||
|
<string name="title_labels">Manage Labels</string>
|
||||||
|
<string name="title_about">About</string>
|
||||||
|
<string name="title_settle">Settle Project</string>
|
||||||
|
<string name="title_share">Share Project</string>
|
||||||
|
<string name="title_add_project">Add Project</string>
|
||||||
|
<string name="title_add_category">Add Category</string>
|
||||||
|
<string name="title_add_payment_mode">Add Payment Mode</string>
|
||||||
|
<string name="title_account">Nextcloud Account</string>
|
||||||
|
<string name="title_share_web">Web link</string>
|
||||||
|
<string name="title_share_qr">Cowspent link</string>
|
||||||
|
<string name="title_confirm">Are you sure?</string>
|
||||||
|
|
||||||
|
<!-- Labels and Fields -->
|
||||||
|
<string name="label_all_bills">All bills</string>
|
||||||
|
<string name="label_categories">Categories</string>
|
||||||
|
<string name="label_payment_modes">Payment Modes</string>
|
||||||
|
<string name="label_name">Name</string>
|
||||||
|
<string name="label_icon">Icon / Emoji</string>
|
||||||
|
<string name="label_color">Color</string>
|
||||||
|
<string name="label_weight">Weight</string>
|
||||||
|
<string name="label_activated">Activated</string>
|
||||||
|
<string name="label_password">Password</string>
|
||||||
|
<string name="label_email">E-mail</string>
|
||||||
|
<string name="label_url">Server address</string>
|
||||||
|
<string name="label_username">Username</string>
|
||||||
|
<string name="label_comment">Comment</string>
|
||||||
|
<string name="label_what">What?</string>
|
||||||
|
<string name="label_payer">Who paid?</string>
|
||||||
|
<string name="label_owers">For whom?</string>
|
||||||
|
<string name="label_repeat">Repeat every</string>
|
||||||
|
<string name="label_mode">Mode</string>
|
||||||
|
<string name="label_category">Category</string>
|
||||||
|
<string name="label_project_id">Project ID/name</string>
|
||||||
|
<string name="label_project_title">Project title</string>
|
||||||
|
<string name="label_use_sso">Use Nextcloud App Account</string>
|
||||||
|
|
||||||
|
<!-- Dialogs and Messages -->
|
||||||
|
<string name="dialog_unsaved_changes_title">Unsaved changes</string>
|
||||||
|
<string name="dialog_unsaved_changes_msg">Save changes before leaving?</string>
|
||||||
|
<string name="dialog_confirm_remove_project_msg">The remote project will not be deleted.</string>
|
||||||
|
<string name="dialog_sync_error_title">Sync error</string>
|
||||||
|
<string name="dialog_sync_error_msg">Sync failed for %1$s.\n\n%2$s</string>
|
||||||
|
<string name="dialog_balanced_msg">Expenses are already balanced.</string>
|
||||||
|
<string name="msg_project_added">Project %1$s added</string>
|
||||||
|
<string name="msg_bill_labeled_done">All bills labeled</string>
|
||||||
|
<string name="msg_no_suggestions">No suggestions</string>
|
||||||
|
<string name="msg_auth_warning">Requires Cospend v0.3.4+.</string>
|
||||||
|
<string name="msg_link_copied">Link copied to clipboard</string>
|
||||||
|
<string name="msg_share_qr">Scan QR code or share the link to join.</string>
|
||||||
|
<string name="msg_share_web">Link for web browser access.</string>
|
||||||
|
<string name="msg_share_qr_warn">Share this link with a Cowspent user.</string>
|
||||||
|
<string name="msg_settle_intro">Settlement for %1$s:</string>
|
||||||
|
<string name="msg_settle_sentence">%1$s owes %3$.2f to %2$s</string>
|
||||||
|
<string name="msg_stats_intro">Stats for %1$s:</string>
|
||||||
|
<string name="msg_stats_header">Member (Paid | Spent | Balance)</string>
|
||||||
|
<string name="msg_logged_in_as">Logged in as %1$s</string>
|
||||||
|
|
||||||
|
<!-- Errors -->
|
||||||
|
<string name="error_generic">Error</string>
|
||||||
|
<string name="error_loading">Loading</string>
|
||||||
|
<string name="error_no_projects">No projects found</string>
|
||||||
|
<string name="error_no_members">No members found</string>
|
||||||
|
<string name="error_no_bills">No bills found</string>
|
||||||
|
<string name="error_no_member">At least one member required</string>
|
||||||
|
<string name="error_maintenance_mode">Server is in maintenance mode</string>
|
||||||
|
<string name="error_400">400 Bad request</string>
|
||||||
|
<string name="error_401">401 Unauthorized</string>
|
||||||
|
<string name="error_403">403 Forbidden</string>
|
||||||
|
<string name="error_404">404 Not Found</string>
|
||||||
|
<string name="error_sync">Sync failed: %1$s</string>
|
||||||
|
<string name="error_invalid_login">Invalid login: %1$s</string>
|
||||||
|
<string name="error_auth">Wrong username or password</string>
|
||||||
|
<string name="error_json">Invalid server response</string>
|
||||||
|
<string name="error_req_failed">Request failed</string>
|
||||||
|
<string name="error_invalid_email">Invalid e-mail</string>
|
||||||
|
<string name="error_invalid_project_id">Invalid project ID</string>
|
||||||
|
<string name="error_invalid_project_name">Invalid project title</string>
|
||||||
|
<string name="error_invalid_bill_name">Invalid bill name</string>
|
||||||
|
<string name="error_invalid_bill_date">Invalid bill date</string>
|
||||||
|
<string name="error_invalid_bill_payer">Payer required</string>
|
||||||
|
<string name="error_invalid_bill_owers">Owers required</string>
|
||||||
|
<string name="error_no_network">No network connection</string>
|
||||||
|
<string name="error_server">Server error</string>
|
||||||
|
<string name="error_io">Server connection broken</string>
|
||||||
|
<string name="error_share_impossible">Cannot share this project</string>
|
||||||
|
|
||||||
|
<!-- Drawer / Common UI -->
|
||||||
|
<string name="drawer_no_account">Connect to Nextcloud account</string>
|
||||||
|
<string name="drawer_last_sync">Last sync: %1$02d:%2$02d</string>
|
||||||
|
<string name="simple_cancel">Cancel</string>
|
||||||
|
<string name="simple_ok" tools:ignore="ButtonCase,Typos">Ok</string>
|
||||||
|
<string name="simple_yes">Yes</string>
|
||||||
|
<string name="simple_no">No</string>
|
||||||
|
<string name="simple_close">Close</string>
|
||||||
|
|
||||||
|
<!-- Settings -->
|
||||||
|
<string name="settings_appearance">Appearance</string>
|
||||||
|
<string name="settings_network">Network</string>
|
||||||
|
<string name="settings_other">Other</string>
|
||||||
|
<string name="settings_night_mode">Theme</string>
|
||||||
|
<string name="settings_offline_mode">Offline mode</string>
|
||||||
|
<string name="settings_offline_mode_summary">Only sync manually.</string>
|
||||||
|
<string name="settings_color_custom">Custom color</string>
|
||||||
|
<string name="settings_color_mode">Color Selection</string>
|
||||||
|
<string name="settings_show_archived">Show archived projects</string>
|
||||||
|
<string name="settings_beta_features">Beta Features</string>
|
||||||
|
<string name="settings_beta_features_summary">Enable experimental features. Use at your own risk.</string>
|
||||||
|
<string name="settings_fill_new_bill_from_last">Auto-fill from last bill</string>
|
||||||
|
<string name="settings_fill_new_bill_from_last_summary">Pre-fill payer, category, mode and owers from the last bill created in the project.</string>
|
||||||
|
<string name="settings_auto_sync_on_open">Sync interval</string>
|
||||||
|
<string name="settings_auto_sync_on_open_summary">How often to refresh the account and all projects when opening the app.</string>
|
||||||
|
<string name="pref_value_sync_1m">1 minute</string>
|
||||||
|
<string name="pref_value_sync_10m">10 minutes</string>
|
||||||
|
<string name="pref_value_sync_1h">1 hour</string>
|
||||||
|
<string name="pref_value_sync_1d">1 day</string>
|
||||||
|
<string name="settings_url_warn_http">WARNING: "http" is unsafe. Use "https".</string>
|
||||||
|
<string name="settings_colorpicker_title">Choose Color</string>
|
||||||
|
|
||||||
|
<string name="pref_value_color_system">System</string>
|
||||||
|
<string name="pref_value_color_manual">Manual</string>
|
||||||
|
<string name="pref_value_theme_light">Light</string>
|
||||||
|
<string name="pref_value_theme_dark">Dark</string>
|
||||||
|
<string name="pref_value_theme_system">Follow system</string>
|
||||||
|
|
||||||
|
<!-- Enums and Lists -->
|
||||||
|
<string name="repeat_no">No repeat</string>
|
||||||
|
<string name="repeat_day">Daily</string>
|
||||||
|
<string name="repeat_week">Weekly</string>
|
||||||
|
<string name="repeat_fortnight">Fortnightly</string>
|
||||||
|
<string name="repeat_month">Monthly</string>
|
||||||
|
<string name="repeat_year">Yearly</string>
|
||||||
|
|
||||||
|
<string name="payment_mode_none">None</string>
|
||||||
|
<string name="payment_mode_all">All</string>
|
||||||
|
<string name="payment_mode_credit_card">Credit card</string>
|
||||||
|
<string name="payment_mode_cash">Cash</string>
|
||||||
|
<string name="payment_mode_check">Check</string>
|
||||||
|
<string name="payment_mode_online">Online</string>
|
||||||
|
<string name="payment_mode_transfer">Transfer</string>
|
||||||
|
|
||||||
|
<string name="category_none">None</string>
|
||||||
|
<string name="category_all">All</string>
|
||||||
|
<string name="category_all_except_reimbursement">All except reimbursement</string>
|
||||||
|
<string name="category_groceries">Grocery</string>
|
||||||
|
<string name="category_leisure">Bar/Party</string>
|
||||||
|
<string name="category_rent">Rent</string>
|
||||||
|
<string name="category_bills">Bill</string>
|
||||||
|
<string name="category_excursion">Excursion/Culture</string>
|
||||||
|
<string name="category_health">Health</string>
|
||||||
|
<string name="category_shopping">Shopping</string>
|
||||||
|
<string name="category_reimbursement">Reimbursement</string>
|
||||||
|
<string name="category_restaurant">Restaurant</string>
|
||||||
|
<string name="category_accomodation">Accommodation</string>
|
||||||
|
<string name="category_transport">Transport</string>
|
||||||
|
<string name="category_sport">Sport</string>
|
||||||
|
|
||||||
|
<!-- Project specific -->
|
||||||
|
<string name="new_project_action">What</string>
|
||||||
|
<string name="new_project_where">Where</string>
|
||||||
|
<string name="where_local">Local only</string>
|
||||||
|
<string name="todo_join">Join existing project</string>
|
||||||
|
<string name="todo_create">Create new project</string>
|
||||||
|
<string name="import_tooltip">Import from file</string>
|
||||||
|
<string name="choose_project_management_action">Project</string>
|
||||||
|
<string name="project_added_success">Project added successfully.</string>
|
||||||
|
<string name="no_projects_text">You have no projects yet.</string>
|
||||||
|
<string name="configure_account_choice">Configure Nextcloud account</string>
|
||||||
|
<string name="add_project_choice">Add project manually</string>
|
||||||
|
<string name="no_members_text">No members in this project.</string>
|
||||||
|
<string name="no_bills_text">No bills found.</string>
|
||||||
|
<string name="member_already_exists">Member already exists.</string>
|
||||||
|
<string name="activity_dialog_title">Project: %1$s</string>
|
||||||
|
<string name="remove_project_confirmation">Project %1$s removed.</string>
|
||||||
|
<string name="file_saved_success">File saved: %1$s</string>
|
||||||
|
<string name="import_error_header">Import failed at row %d</string>
|
||||||
|
<string name="import_error_date">Invalid date format at row %d</string>
|
||||||
|
<string name="import_error_owers">Invalid owers at row %d</string>
|
||||||
|
<string name="add_member_dialog_title">Add Member</string>
|
||||||
|
<string name="edit_member_dialog_title">Edit Member</string>
|
||||||
|
<string name="member_edit_delete">Delete</string>
|
||||||
|
<string name="project_edition_no_change">No changes to save.</string>
|
||||||
|
|
||||||
|
<!-- Settlement -->
|
||||||
|
<string name="center_none">None (Optimal)</string>
|
||||||
|
<string name="settle_who">Who pays</string>
|
||||||
|
<string name="settle_to_whom">To whom</string>
|
||||||
|
<string name="settle_how_much">Amount</string>
|
||||||
|
<string name="simple_settle_share">Share</string>
|
||||||
|
<string name="simple_create_bills">Create bills</string>
|
||||||
|
<string name="settle_bill_what">Settlement</string>
|
||||||
|
|
||||||
|
<!-- Currencies -->
|
||||||
|
<string name="currency_dialog_title">Choose Currency (%s)</string>
|
||||||
|
<string name="setting_none">None</string>
|
||||||
|
<string name="setting_all">All</string>
|
||||||
|
<string name="currency_saved_success">Currency settings saved.</string>
|
||||||
|
<string name="main_currency">Main Currency</string>
|
||||||
|
|
||||||
|
<!-- Statistics -->
|
||||||
|
<string name="label_bills_suggested">Suggested Categories</string>
|
||||||
|
<string name="label_bills_skip">Skip</string>
|
||||||
|
<string name="stats_date_min">From</string>
|
||||||
|
<string name="stats_date_max">To</string>
|
||||||
|
<string name="stats_who">Member</string>
|
||||||
|
<string name="stats_paid">Paid</string>
|
||||||
|
<string name="stats_spent">Spent</string>
|
||||||
|
<string name="stats_balance">Balance</string>
|
||||||
|
<string name="total">Total: %1$s</string>
|
||||||
|
|
||||||
|
<!-- Errors Extra -->
|
||||||
|
<string name="error_project_connect_check">Connection failed: %1$s</string>
|
||||||
|
<string name="error_create_remote_project_helper">Creation failed: %1$s</string>
|
||||||
|
<string name="error_edit_remote_project_helper">Error updating remote project: %1$s</string>
|
||||||
|
<string name="remote_project_operation_no_network">Network unavailable for remote operation.</string>
|
||||||
|
<string name="error_scanning_bill_qr_code">Failed to parse QR code.</string>
|
||||||
|
<string name="error_token_mismatch">Authentication token mismatch. Please log in again.</string>
|
||||||
|
<string name="insufficient_access_level">You don\'t have permission to perform this action.</string>
|
||||||
|
<string name="delete_label_confirmation_title">Delete Label</string>
|
||||||
|
<string name="delete_label_confirmation_message">Are you sure you want to delete this label?</string>
|
||||||
|
|
||||||
|
<!-- About -->
|
||||||
|
<string name="about_version">Version %1$s</string>
|
||||||
|
<string name="about_maintainer_title">Maintainer</string>
|
||||||
|
<string name="about_license_title">License</string>
|
||||||
|
<string name="about_source_title">Source code</string>
|
||||||
|
|
||||||
|
<!-- New constants for backward compatibility or shared use -->
|
||||||
|
<string name="share_intent_title">Project %1$s</string>
|
||||||
|
<string name="share_chooser_title">Share %1$s</string>
|
||||||
|
|
||||||
|
</resources>
|
||||||
@@ -0,0 +1,272 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Untranslated: these are the English strings, kept here so a translation can be
|
||||||
|
contributed by simply replacing the values. Strings marked translatable="false" in
|
||||||
|
values/strings.xml (app and product names, preference keys) are deliberately absent
|
||||||
|
and must not be added.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- Actions -->
|
||||||
|
<string name="action_new_bill">New bill</string>
|
||||||
|
<string name="action_add_project">Add project</string>
|
||||||
|
<string name="action_save">Save</string>
|
||||||
|
<string name="action_edit">Edit</string>
|
||||||
|
<string name="action_share">Share</string>
|
||||||
|
<string name="action_search">Search</string>
|
||||||
|
<string name="action_open_menu">Open menu</string>
|
||||||
|
<string name="action_close_search">Close search</string>
|
||||||
|
<string name="action_clear_search">Clear search</string>
|
||||||
|
<string name="action_delete">Delete</string>
|
||||||
|
<string name="simple_back">Back</string>
|
||||||
|
<string name="action_archive">Archive</string>
|
||||||
|
<string name="action_unarchive">Unarchive</string>
|
||||||
|
<string name="action_export">Export</string>
|
||||||
|
<string name="action_stats">Stats</string>
|
||||||
|
<string name="action_settle">Settle</string>
|
||||||
|
<string name="action_scan_qrcode">Scan QR Code</string>
|
||||||
|
<string name="action_settings">Settings</string>
|
||||||
|
<string name="action_label_bills">Label missing categories</string>
|
||||||
|
<string name="action_logout">Logout</string>
|
||||||
|
<string name="action_connect">Connect</string>
|
||||||
|
<string name="action_discard">Discard</string>
|
||||||
|
<string name="action_members">Members</string>
|
||||||
|
<string name="action_labels">Labels</string>
|
||||||
|
<string name="action_currencies">Currencies</string>
|
||||||
|
|
||||||
|
<!-- Titles -->
|
||||||
|
<string name="title_stats">Statistics</string>
|
||||||
|
<string name="title_edit_project">Edit project</string>
|
||||||
|
<string name="title_label_bills">Label Bills</string>
|
||||||
|
<string name="title_labels">Manage Labels</string>
|
||||||
|
<string name="title_about">About</string>
|
||||||
|
<string name="title_settle">Settle Project</string>
|
||||||
|
<string name="title_share">Share Project</string>
|
||||||
|
<string name="title_add_project">Add Project</string>
|
||||||
|
<string name="title_add_category">Add Category</string>
|
||||||
|
<string name="title_add_payment_mode">Add Payment Mode</string>
|
||||||
|
<string name="title_account">Nextcloud Account</string>
|
||||||
|
<string name="title_share_web">Web link</string>
|
||||||
|
<string name="title_share_qr">Cowspent link</string>
|
||||||
|
<string name="title_confirm">Are you sure?</string>
|
||||||
|
|
||||||
|
<!-- Labels and Fields -->
|
||||||
|
<string name="label_all_bills">All bills</string>
|
||||||
|
<string name="label_categories">Categories</string>
|
||||||
|
<string name="label_payment_modes">Payment Modes</string>
|
||||||
|
<string name="label_name">Name</string>
|
||||||
|
<string name="label_icon">Icon / Emoji</string>
|
||||||
|
<string name="label_color">Color</string>
|
||||||
|
<string name="label_weight">Weight</string>
|
||||||
|
<string name="label_activated">Activated</string>
|
||||||
|
<string name="label_password">Password</string>
|
||||||
|
<string name="label_email">E-mail</string>
|
||||||
|
<string name="label_url">Server address</string>
|
||||||
|
<string name="label_username">Username</string>
|
||||||
|
<string name="label_comment">Comment</string>
|
||||||
|
<string name="label_what">What?</string>
|
||||||
|
<string name="label_payer">Who paid?</string>
|
||||||
|
<string name="label_owers">For whom?</string>
|
||||||
|
<string name="label_repeat">Repeat every</string>
|
||||||
|
<string name="label_mode">Mode</string>
|
||||||
|
<string name="label_category">Category</string>
|
||||||
|
<string name="label_project_id">Project ID/name</string>
|
||||||
|
<string name="label_project_title">Project title</string>
|
||||||
|
<string name="label_use_sso">Use Nextcloud App Account</string>
|
||||||
|
|
||||||
|
<!-- Dialogs and Messages -->
|
||||||
|
<string name="dialog_unsaved_changes_title">Unsaved changes</string>
|
||||||
|
<string name="dialog_unsaved_changes_msg">Save changes before leaving?</string>
|
||||||
|
<string name="dialog_confirm_remove_project_msg">The remote project will not be deleted.</string>
|
||||||
|
<string name="dialog_sync_error_title">Sync error</string>
|
||||||
|
<string name="dialog_sync_error_msg">Sync failed for %1$s.\n\n%2$s</string>
|
||||||
|
<string name="dialog_balanced_msg">Expenses are already balanced.</string>
|
||||||
|
<string name="msg_project_added">Project %1$s added</string>
|
||||||
|
<string name="msg_bill_labeled_done">All bills labeled</string>
|
||||||
|
<string name="msg_no_suggestions">No suggestions</string>
|
||||||
|
<string name="msg_auth_warning">Requires Cospend v0.3.4+.</string>
|
||||||
|
<string name="msg_link_copied">Link copied to clipboard</string>
|
||||||
|
<string name="msg_share_qr">Scan QR code or share the link to join.</string>
|
||||||
|
<string name="msg_share_web">Link for web browser access.</string>
|
||||||
|
<string name="msg_share_qr_warn">Share this link with a Cowspent user.</string>
|
||||||
|
<string name="msg_settle_intro">Settlement for %1$s:</string>
|
||||||
|
<string name="msg_settle_sentence">%1$s owes %3$.2f to %2$s</string>
|
||||||
|
<string name="msg_stats_intro">Stats for %1$s:</string>
|
||||||
|
<string name="msg_stats_header">Member (Paid | Spent | Balance)</string>
|
||||||
|
<string name="msg_logged_in_as">Logged in as %1$s</string>
|
||||||
|
|
||||||
|
<!-- Errors -->
|
||||||
|
<string name="error_generic">Error</string>
|
||||||
|
<string name="error_loading">Loading</string>
|
||||||
|
<string name="error_no_projects">No projects found</string>
|
||||||
|
<string name="error_no_members">No members found</string>
|
||||||
|
<string name="error_no_bills">No bills found</string>
|
||||||
|
<string name="error_no_member">At least one member required</string>
|
||||||
|
<string name="error_maintenance_mode">Server is in maintenance mode</string>
|
||||||
|
<string name="error_400">400 Bad request</string>
|
||||||
|
<string name="error_401">401 Unauthorized</string>
|
||||||
|
<string name="error_403">403 Forbidden</string>
|
||||||
|
<string name="error_404">404 Not Found</string>
|
||||||
|
<string name="error_sync">Sync failed: %1$s</string>
|
||||||
|
<string name="error_invalid_login">Invalid login: %1$s</string>
|
||||||
|
<string name="error_auth">Wrong username or password</string>
|
||||||
|
<string name="error_json">Invalid server response</string>
|
||||||
|
<string name="error_req_failed">Request failed</string>
|
||||||
|
<string name="error_invalid_email">Invalid e-mail</string>
|
||||||
|
<string name="error_invalid_project_id">Invalid project ID</string>
|
||||||
|
<string name="error_invalid_project_name">Invalid project title</string>
|
||||||
|
<string name="error_invalid_bill_name">Invalid bill name</string>
|
||||||
|
<string name="error_invalid_bill_date">Invalid bill date</string>
|
||||||
|
<string name="error_invalid_bill_payer">Payer required</string>
|
||||||
|
<string name="error_invalid_bill_owers">Owers required</string>
|
||||||
|
<string name="error_no_network">No network connection</string>
|
||||||
|
<string name="error_server">Server error</string>
|
||||||
|
<string name="error_io">Server connection broken</string>
|
||||||
|
<string name="error_share_impossible">Cannot share this project</string>
|
||||||
|
|
||||||
|
<!-- Drawer / Common UI -->
|
||||||
|
<string name="drawer_no_account">Connect to Nextcloud account</string>
|
||||||
|
<string name="drawer_last_sync">Last sync: %1$02d:%2$02d</string>
|
||||||
|
<string name="simple_cancel">Cancel</string>
|
||||||
|
<string name="simple_ok" tools:ignore="ButtonCase,Typos">Ok</string>
|
||||||
|
<string name="simple_yes">Yes</string>
|
||||||
|
<string name="simple_no">No</string>
|
||||||
|
<string name="simple_close">Close</string>
|
||||||
|
|
||||||
|
<!-- Settings -->
|
||||||
|
<string name="settings_appearance">Appearance</string>
|
||||||
|
<string name="settings_network">Network</string>
|
||||||
|
<string name="settings_other">Other</string>
|
||||||
|
<string name="settings_night_mode">Theme</string>
|
||||||
|
<string name="settings_offline_mode">Offline mode</string>
|
||||||
|
<string name="settings_offline_mode_summary">Only sync manually.</string>
|
||||||
|
<string name="settings_color_custom">Custom color</string>
|
||||||
|
<string name="settings_color_mode">Color Selection</string>
|
||||||
|
<string name="settings_show_archived">Show archived projects</string>
|
||||||
|
<string name="settings_beta_features">Beta Features</string>
|
||||||
|
<string name="settings_beta_features_summary">Enable experimental features. Use at your own risk.</string>
|
||||||
|
<string name="settings_fill_new_bill_from_last">Auto-fill from last bill</string>
|
||||||
|
<string name="settings_fill_new_bill_from_last_summary">Pre-fill payer, category, mode and owers from the last bill created in the project.</string>
|
||||||
|
<string name="settings_auto_sync_on_open">Sync interval</string>
|
||||||
|
<string name="settings_auto_sync_on_open_summary">How often to refresh the account and all projects when opening the app.</string>
|
||||||
|
<string name="pref_value_sync_1m">1 minute</string>
|
||||||
|
<string name="pref_value_sync_10m">10 minutes</string>
|
||||||
|
<string name="pref_value_sync_1h">1 hour</string>
|
||||||
|
<string name="pref_value_sync_1d">1 day</string>
|
||||||
|
<string name="settings_url_warn_http">WARNING: "http" is unsafe. Use "https".</string>
|
||||||
|
<string name="settings_colorpicker_title">Choose Color</string>
|
||||||
|
|
||||||
|
<string name="pref_value_color_system">System</string>
|
||||||
|
<string name="pref_value_color_manual">Manual</string>
|
||||||
|
<string name="pref_value_theme_light">Light</string>
|
||||||
|
<string name="pref_value_theme_dark">Dark</string>
|
||||||
|
<string name="pref_value_theme_system">Follow system</string>
|
||||||
|
|
||||||
|
<!-- Enums and Lists -->
|
||||||
|
<string name="repeat_no">No repeat</string>
|
||||||
|
<string name="repeat_day">Daily</string>
|
||||||
|
<string name="repeat_week">Weekly</string>
|
||||||
|
<string name="repeat_fortnight">Fortnightly</string>
|
||||||
|
<string name="repeat_month">Monthly</string>
|
||||||
|
<string name="repeat_year">Yearly</string>
|
||||||
|
|
||||||
|
<string name="payment_mode_none">None</string>
|
||||||
|
<string name="payment_mode_all">All</string>
|
||||||
|
<string name="payment_mode_credit_card">Credit card</string>
|
||||||
|
<string name="payment_mode_cash">Cash</string>
|
||||||
|
<string name="payment_mode_check">Check</string>
|
||||||
|
<string name="payment_mode_online">Online</string>
|
||||||
|
<string name="payment_mode_transfer">Transfer</string>
|
||||||
|
|
||||||
|
<string name="category_none">None</string>
|
||||||
|
<string name="category_all">All</string>
|
||||||
|
<string name="category_all_except_reimbursement">All except reimbursement</string>
|
||||||
|
<string name="category_groceries">Grocery</string>
|
||||||
|
<string name="category_leisure">Bar/Party</string>
|
||||||
|
<string name="category_rent">Rent</string>
|
||||||
|
<string name="category_bills">Bill</string>
|
||||||
|
<string name="category_excursion">Excursion/Culture</string>
|
||||||
|
<string name="category_health">Health</string>
|
||||||
|
<string name="category_shopping">Shopping</string>
|
||||||
|
<string name="category_reimbursement">Reimbursement</string>
|
||||||
|
<string name="category_restaurant">Restaurant</string>
|
||||||
|
<string name="category_accomodation">Accommodation</string>
|
||||||
|
<string name="category_transport">Transport</string>
|
||||||
|
<string name="category_sport">Sport</string>
|
||||||
|
|
||||||
|
<!-- Project specific -->
|
||||||
|
<string name="new_project_action">What</string>
|
||||||
|
<string name="new_project_where">Where</string>
|
||||||
|
<string name="where_local">Local only</string>
|
||||||
|
<string name="todo_join">Join existing project</string>
|
||||||
|
<string name="todo_create">Create new project</string>
|
||||||
|
<string name="import_tooltip">Import from file</string>
|
||||||
|
<string name="choose_project_management_action">Project</string>
|
||||||
|
<string name="project_added_success">Project added successfully.</string>
|
||||||
|
<string name="no_projects_text">You have no projects yet.</string>
|
||||||
|
<string name="configure_account_choice">Configure Nextcloud account</string>
|
||||||
|
<string name="add_project_choice">Add project manually</string>
|
||||||
|
<string name="no_members_text">No members in this project.</string>
|
||||||
|
<string name="no_bills_text">No bills found.</string>
|
||||||
|
<string name="member_already_exists">Member already exists.</string>
|
||||||
|
<string name="activity_dialog_title">Project: %1$s</string>
|
||||||
|
<string name="remove_project_confirmation">Project %1$s removed.</string>
|
||||||
|
<string name="file_saved_success">File saved: %1$s</string>
|
||||||
|
<string name="import_error_header">Import failed at row %d</string>
|
||||||
|
<string name="import_error_date">Invalid date format at row %d</string>
|
||||||
|
<string name="import_error_owers">Invalid owers at row %d</string>
|
||||||
|
<string name="add_member_dialog_title">Add Member</string>
|
||||||
|
<string name="edit_member_dialog_title">Edit Member</string>
|
||||||
|
<string name="member_edit_delete">Delete</string>
|
||||||
|
<string name="project_edition_no_change">No changes to save.</string>
|
||||||
|
|
||||||
|
<!-- Settlement -->
|
||||||
|
<string name="center_none">None (Optimal)</string>
|
||||||
|
<string name="settle_who">Who pays</string>
|
||||||
|
<string name="settle_to_whom">To whom</string>
|
||||||
|
<string name="settle_how_much">Amount</string>
|
||||||
|
<string name="simple_settle_share">Share</string>
|
||||||
|
<string name="simple_create_bills">Create bills</string>
|
||||||
|
<string name="settle_bill_what">Settlement</string>
|
||||||
|
|
||||||
|
<!-- Currencies -->
|
||||||
|
<string name="currency_dialog_title">Choose Currency (%s)</string>
|
||||||
|
<string name="setting_none">None</string>
|
||||||
|
<string name="setting_all">All</string>
|
||||||
|
<string name="currency_saved_success">Currency settings saved.</string>
|
||||||
|
<string name="main_currency">Main Currency</string>
|
||||||
|
|
||||||
|
<!-- Statistics -->
|
||||||
|
<string name="label_bills_suggested">Suggested Categories</string>
|
||||||
|
<string name="label_bills_skip">Skip</string>
|
||||||
|
<string name="stats_date_min">From</string>
|
||||||
|
<string name="stats_date_max">To</string>
|
||||||
|
<string name="stats_who">Member</string>
|
||||||
|
<string name="stats_paid">Paid</string>
|
||||||
|
<string name="stats_spent">Spent</string>
|
||||||
|
<string name="stats_balance">Balance</string>
|
||||||
|
<string name="total">Total: %1$s</string>
|
||||||
|
|
||||||
|
<!-- Errors Extra -->
|
||||||
|
<string name="error_project_connect_check">Connection failed: %1$s</string>
|
||||||
|
<string name="error_create_remote_project_helper">Creation failed: %1$s</string>
|
||||||
|
<string name="error_edit_remote_project_helper">Error updating remote project: %1$s</string>
|
||||||
|
<string name="remote_project_operation_no_network">Network unavailable for remote operation.</string>
|
||||||
|
<string name="error_scanning_bill_qr_code">Failed to parse QR code.</string>
|
||||||
|
<string name="error_token_mismatch">Authentication token mismatch. Please log in again.</string>
|
||||||
|
<string name="insufficient_access_level">You don\'t have permission to perform this action.</string>
|
||||||
|
<string name="delete_label_confirmation_title">Delete Label</string>
|
||||||
|
<string name="delete_label_confirmation_message">Are you sure you want to delete this label?</string>
|
||||||
|
|
||||||
|
<!-- About -->
|
||||||
|
<string name="about_version">Version %1$s</string>
|
||||||
|
<string name="about_maintainer_title">Maintainer</string>
|
||||||
|
<string name="about_license_title">License</string>
|
||||||
|
<string name="about_source_title">Source code</string>
|
||||||
|
|
||||||
|
<!-- New constants for backward compatibility or shared use -->
|
||||||
|
<string name="share_intent_title">Project %1$s</string>
|
||||||
|
<string name="share_chooser_title">Share %1$s</string>
|
||||||
|
|
||||||
|
</resources>
|
||||||
@@ -0,0 +1,272 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Untranslated: these are the English strings, kept here so a translation can be
|
||||||
|
contributed by simply replacing the values. Strings marked translatable="false" in
|
||||||
|
values/strings.xml (app and product names, preference keys) are deliberately absent
|
||||||
|
and must not be added.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- Actions -->
|
||||||
|
<string name="action_new_bill">New bill</string>
|
||||||
|
<string name="action_add_project">Add project</string>
|
||||||
|
<string name="action_save">Save</string>
|
||||||
|
<string name="action_edit">Edit</string>
|
||||||
|
<string name="action_share">Share</string>
|
||||||
|
<string name="action_search">Search</string>
|
||||||
|
<string name="action_open_menu">Open menu</string>
|
||||||
|
<string name="action_close_search">Close search</string>
|
||||||
|
<string name="action_clear_search">Clear search</string>
|
||||||
|
<string name="action_delete">Delete</string>
|
||||||
|
<string name="simple_back">Back</string>
|
||||||
|
<string name="action_archive">Archive</string>
|
||||||
|
<string name="action_unarchive">Unarchive</string>
|
||||||
|
<string name="action_export">Export</string>
|
||||||
|
<string name="action_stats">Stats</string>
|
||||||
|
<string name="action_settle">Settle</string>
|
||||||
|
<string name="action_scan_qrcode">Scan QR Code</string>
|
||||||
|
<string name="action_settings">Settings</string>
|
||||||
|
<string name="action_label_bills">Label missing categories</string>
|
||||||
|
<string name="action_logout">Logout</string>
|
||||||
|
<string name="action_connect">Connect</string>
|
||||||
|
<string name="action_discard">Discard</string>
|
||||||
|
<string name="action_members">Members</string>
|
||||||
|
<string name="action_labels">Labels</string>
|
||||||
|
<string name="action_currencies">Currencies</string>
|
||||||
|
|
||||||
|
<!-- Titles -->
|
||||||
|
<string name="title_stats">Statistics</string>
|
||||||
|
<string name="title_edit_project">Edit project</string>
|
||||||
|
<string name="title_label_bills">Label Bills</string>
|
||||||
|
<string name="title_labels">Manage Labels</string>
|
||||||
|
<string name="title_about">About</string>
|
||||||
|
<string name="title_settle">Settle Project</string>
|
||||||
|
<string name="title_share">Share Project</string>
|
||||||
|
<string name="title_add_project">Add Project</string>
|
||||||
|
<string name="title_add_category">Add Category</string>
|
||||||
|
<string name="title_add_payment_mode">Add Payment Mode</string>
|
||||||
|
<string name="title_account">Nextcloud Account</string>
|
||||||
|
<string name="title_share_web">Web link</string>
|
||||||
|
<string name="title_share_qr">Cowspent link</string>
|
||||||
|
<string name="title_confirm">Are you sure?</string>
|
||||||
|
|
||||||
|
<!-- Labels and Fields -->
|
||||||
|
<string name="label_all_bills">All bills</string>
|
||||||
|
<string name="label_categories">Categories</string>
|
||||||
|
<string name="label_payment_modes">Payment Modes</string>
|
||||||
|
<string name="label_name">Name</string>
|
||||||
|
<string name="label_icon">Icon / Emoji</string>
|
||||||
|
<string name="label_color">Color</string>
|
||||||
|
<string name="label_weight">Weight</string>
|
||||||
|
<string name="label_activated">Activated</string>
|
||||||
|
<string name="label_password">Password</string>
|
||||||
|
<string name="label_email">E-mail</string>
|
||||||
|
<string name="label_url">Server address</string>
|
||||||
|
<string name="label_username">Username</string>
|
||||||
|
<string name="label_comment">Comment</string>
|
||||||
|
<string name="label_what">What?</string>
|
||||||
|
<string name="label_payer">Who paid?</string>
|
||||||
|
<string name="label_owers">For whom?</string>
|
||||||
|
<string name="label_repeat">Repeat every</string>
|
||||||
|
<string name="label_mode">Mode</string>
|
||||||
|
<string name="label_category">Category</string>
|
||||||
|
<string name="label_project_id">Project ID/name</string>
|
||||||
|
<string name="label_project_title">Project title</string>
|
||||||
|
<string name="label_use_sso">Use Nextcloud App Account</string>
|
||||||
|
|
||||||
|
<!-- Dialogs and Messages -->
|
||||||
|
<string name="dialog_unsaved_changes_title">Unsaved changes</string>
|
||||||
|
<string name="dialog_unsaved_changes_msg">Save changes before leaving?</string>
|
||||||
|
<string name="dialog_confirm_remove_project_msg">The remote project will not be deleted.</string>
|
||||||
|
<string name="dialog_sync_error_title">Sync error</string>
|
||||||
|
<string name="dialog_sync_error_msg">Sync failed for %1$s.\n\n%2$s</string>
|
||||||
|
<string name="dialog_balanced_msg">Expenses are already balanced.</string>
|
||||||
|
<string name="msg_project_added">Project %1$s added</string>
|
||||||
|
<string name="msg_bill_labeled_done">All bills labeled</string>
|
||||||
|
<string name="msg_no_suggestions">No suggestions</string>
|
||||||
|
<string name="msg_auth_warning">Requires Cospend v0.3.4+.</string>
|
||||||
|
<string name="msg_link_copied">Link copied to clipboard</string>
|
||||||
|
<string name="msg_share_qr">Scan QR code or share the link to join.</string>
|
||||||
|
<string name="msg_share_web">Link for web browser access.</string>
|
||||||
|
<string name="msg_share_qr_warn">Share this link with a Cowspent user.</string>
|
||||||
|
<string name="msg_settle_intro">Settlement for %1$s:</string>
|
||||||
|
<string name="msg_settle_sentence">%1$s owes %3$.2f to %2$s</string>
|
||||||
|
<string name="msg_stats_intro">Stats for %1$s:</string>
|
||||||
|
<string name="msg_stats_header">Member (Paid | Spent | Balance)</string>
|
||||||
|
<string name="msg_logged_in_as">Logged in as %1$s</string>
|
||||||
|
|
||||||
|
<!-- Errors -->
|
||||||
|
<string name="error_generic">Error</string>
|
||||||
|
<string name="error_loading">Loading</string>
|
||||||
|
<string name="error_no_projects">No projects found</string>
|
||||||
|
<string name="error_no_members">No members found</string>
|
||||||
|
<string name="error_no_bills">No bills found</string>
|
||||||
|
<string name="error_no_member">At least one member required</string>
|
||||||
|
<string name="error_maintenance_mode">Server is in maintenance mode</string>
|
||||||
|
<string name="error_400">400 Bad request</string>
|
||||||
|
<string name="error_401">401 Unauthorized</string>
|
||||||
|
<string name="error_403">403 Forbidden</string>
|
||||||
|
<string name="error_404">404 Not Found</string>
|
||||||
|
<string name="error_sync">Sync failed: %1$s</string>
|
||||||
|
<string name="error_invalid_login">Invalid login: %1$s</string>
|
||||||
|
<string name="error_auth">Wrong username or password</string>
|
||||||
|
<string name="error_json">Invalid server response</string>
|
||||||
|
<string name="error_req_failed">Request failed</string>
|
||||||
|
<string name="error_invalid_email">Invalid e-mail</string>
|
||||||
|
<string name="error_invalid_project_id">Invalid project ID</string>
|
||||||
|
<string name="error_invalid_project_name">Invalid project title</string>
|
||||||
|
<string name="error_invalid_bill_name">Invalid bill name</string>
|
||||||
|
<string name="error_invalid_bill_date">Invalid bill date</string>
|
||||||
|
<string name="error_invalid_bill_payer">Payer required</string>
|
||||||
|
<string name="error_invalid_bill_owers">Owers required</string>
|
||||||
|
<string name="error_no_network">No network connection</string>
|
||||||
|
<string name="error_server">Server error</string>
|
||||||
|
<string name="error_io">Server connection broken</string>
|
||||||
|
<string name="error_share_impossible">Cannot share this project</string>
|
||||||
|
|
||||||
|
<!-- Drawer / Common UI -->
|
||||||
|
<string name="drawer_no_account">Connect to Nextcloud account</string>
|
||||||
|
<string name="drawer_last_sync">Last sync: %1$02d:%2$02d</string>
|
||||||
|
<string name="simple_cancel">Cancel</string>
|
||||||
|
<string name="simple_ok" tools:ignore="ButtonCase,Typos">Ok</string>
|
||||||
|
<string name="simple_yes">Yes</string>
|
||||||
|
<string name="simple_no">No</string>
|
||||||
|
<string name="simple_close">Close</string>
|
||||||
|
|
||||||
|
<!-- Settings -->
|
||||||
|
<string name="settings_appearance">Appearance</string>
|
||||||
|
<string name="settings_network">Network</string>
|
||||||
|
<string name="settings_other">Other</string>
|
||||||
|
<string name="settings_night_mode">Theme</string>
|
||||||
|
<string name="settings_offline_mode">Offline mode</string>
|
||||||
|
<string name="settings_offline_mode_summary">Only sync manually.</string>
|
||||||
|
<string name="settings_color_custom">Custom color</string>
|
||||||
|
<string name="settings_color_mode">Color Selection</string>
|
||||||
|
<string name="settings_show_archived">Show archived projects</string>
|
||||||
|
<string name="settings_beta_features">Beta Features</string>
|
||||||
|
<string name="settings_beta_features_summary">Enable experimental features. Use at your own risk.</string>
|
||||||
|
<string name="settings_fill_new_bill_from_last">Auto-fill from last bill</string>
|
||||||
|
<string name="settings_fill_new_bill_from_last_summary">Pre-fill payer, category, mode and owers from the last bill created in the project.</string>
|
||||||
|
<string name="settings_auto_sync_on_open">Sync interval</string>
|
||||||
|
<string name="settings_auto_sync_on_open_summary">How often to refresh the account and all projects when opening the app.</string>
|
||||||
|
<string name="pref_value_sync_1m">1 minute</string>
|
||||||
|
<string name="pref_value_sync_10m">10 minutes</string>
|
||||||
|
<string name="pref_value_sync_1h">1 hour</string>
|
||||||
|
<string name="pref_value_sync_1d">1 day</string>
|
||||||
|
<string name="settings_url_warn_http">WARNING: "http" is unsafe. Use "https".</string>
|
||||||
|
<string name="settings_colorpicker_title">Choose Color</string>
|
||||||
|
|
||||||
|
<string name="pref_value_color_system">System</string>
|
||||||
|
<string name="pref_value_color_manual">Manual</string>
|
||||||
|
<string name="pref_value_theme_light">Light</string>
|
||||||
|
<string name="pref_value_theme_dark">Dark</string>
|
||||||
|
<string name="pref_value_theme_system">Follow system</string>
|
||||||
|
|
||||||
|
<!-- Enums and Lists -->
|
||||||
|
<string name="repeat_no">No repeat</string>
|
||||||
|
<string name="repeat_day">Daily</string>
|
||||||
|
<string name="repeat_week">Weekly</string>
|
||||||
|
<string name="repeat_fortnight">Fortnightly</string>
|
||||||
|
<string name="repeat_month">Monthly</string>
|
||||||
|
<string name="repeat_year">Yearly</string>
|
||||||
|
|
||||||
|
<string name="payment_mode_none">None</string>
|
||||||
|
<string name="payment_mode_all">All</string>
|
||||||
|
<string name="payment_mode_credit_card">Credit card</string>
|
||||||
|
<string name="payment_mode_cash">Cash</string>
|
||||||
|
<string name="payment_mode_check">Check</string>
|
||||||
|
<string name="payment_mode_online">Online</string>
|
||||||
|
<string name="payment_mode_transfer">Transfer</string>
|
||||||
|
|
||||||
|
<string name="category_none">None</string>
|
||||||
|
<string name="category_all">All</string>
|
||||||
|
<string name="category_all_except_reimbursement">All except reimbursement</string>
|
||||||
|
<string name="category_groceries">Grocery</string>
|
||||||
|
<string name="category_leisure">Bar/Party</string>
|
||||||
|
<string name="category_rent">Rent</string>
|
||||||
|
<string name="category_bills">Bill</string>
|
||||||
|
<string name="category_excursion">Excursion/Culture</string>
|
||||||
|
<string name="category_health">Health</string>
|
||||||
|
<string name="category_shopping">Shopping</string>
|
||||||
|
<string name="category_reimbursement">Reimbursement</string>
|
||||||
|
<string name="category_restaurant">Restaurant</string>
|
||||||
|
<string name="category_accomodation">Accommodation</string>
|
||||||
|
<string name="category_transport">Transport</string>
|
||||||
|
<string name="category_sport">Sport</string>
|
||||||
|
|
||||||
|
<!-- Project specific -->
|
||||||
|
<string name="new_project_action">What</string>
|
||||||
|
<string name="new_project_where">Where</string>
|
||||||
|
<string name="where_local">Local only</string>
|
||||||
|
<string name="todo_join">Join existing project</string>
|
||||||
|
<string name="todo_create">Create new project</string>
|
||||||
|
<string name="import_tooltip">Import from file</string>
|
||||||
|
<string name="choose_project_management_action">Project</string>
|
||||||
|
<string name="project_added_success">Project added successfully.</string>
|
||||||
|
<string name="no_projects_text">You have no projects yet.</string>
|
||||||
|
<string name="configure_account_choice">Configure Nextcloud account</string>
|
||||||
|
<string name="add_project_choice">Add project manually</string>
|
||||||
|
<string name="no_members_text">No members in this project.</string>
|
||||||
|
<string name="no_bills_text">No bills found.</string>
|
||||||
|
<string name="member_already_exists">Member already exists.</string>
|
||||||
|
<string name="activity_dialog_title">Project: %1$s</string>
|
||||||
|
<string name="remove_project_confirmation">Project %1$s removed.</string>
|
||||||
|
<string name="file_saved_success">File saved: %1$s</string>
|
||||||
|
<string name="import_error_header">Import failed at row %d</string>
|
||||||
|
<string name="import_error_date">Invalid date format at row %d</string>
|
||||||
|
<string name="import_error_owers">Invalid owers at row %d</string>
|
||||||
|
<string name="add_member_dialog_title">Add Member</string>
|
||||||
|
<string name="edit_member_dialog_title">Edit Member</string>
|
||||||
|
<string name="member_edit_delete">Delete</string>
|
||||||
|
<string name="project_edition_no_change">No changes to save.</string>
|
||||||
|
|
||||||
|
<!-- Settlement -->
|
||||||
|
<string name="center_none">None (Optimal)</string>
|
||||||
|
<string name="settle_who">Who pays</string>
|
||||||
|
<string name="settle_to_whom">To whom</string>
|
||||||
|
<string name="settle_how_much">Amount</string>
|
||||||
|
<string name="simple_settle_share">Share</string>
|
||||||
|
<string name="simple_create_bills">Create bills</string>
|
||||||
|
<string name="settle_bill_what">Settlement</string>
|
||||||
|
|
||||||
|
<!-- Currencies -->
|
||||||
|
<string name="currency_dialog_title">Choose Currency (%s)</string>
|
||||||
|
<string name="setting_none">None</string>
|
||||||
|
<string name="setting_all">All</string>
|
||||||
|
<string name="currency_saved_success">Currency settings saved.</string>
|
||||||
|
<string name="main_currency">Main Currency</string>
|
||||||
|
|
||||||
|
<!-- Statistics -->
|
||||||
|
<string name="label_bills_suggested">Suggested Categories</string>
|
||||||
|
<string name="label_bills_skip">Skip</string>
|
||||||
|
<string name="stats_date_min">From</string>
|
||||||
|
<string name="stats_date_max">To</string>
|
||||||
|
<string name="stats_who">Member</string>
|
||||||
|
<string name="stats_paid">Paid</string>
|
||||||
|
<string name="stats_spent">Spent</string>
|
||||||
|
<string name="stats_balance">Balance</string>
|
||||||
|
<string name="total">Total: %1$s</string>
|
||||||
|
|
||||||
|
<!-- Errors Extra -->
|
||||||
|
<string name="error_project_connect_check">Connection failed: %1$s</string>
|
||||||
|
<string name="error_create_remote_project_helper">Creation failed: %1$s</string>
|
||||||
|
<string name="error_edit_remote_project_helper">Error updating remote project: %1$s</string>
|
||||||
|
<string name="remote_project_operation_no_network">Network unavailable for remote operation.</string>
|
||||||
|
<string name="error_scanning_bill_qr_code">Failed to parse QR code.</string>
|
||||||
|
<string name="error_token_mismatch">Authentication token mismatch. Please log in again.</string>
|
||||||
|
<string name="insufficient_access_level">You don\'t have permission to perform this action.</string>
|
||||||
|
<string name="delete_label_confirmation_title">Delete Label</string>
|
||||||
|
<string name="delete_label_confirmation_message">Are you sure you want to delete this label?</string>
|
||||||
|
|
||||||
|
<!-- About -->
|
||||||
|
<string name="about_version">Version %1$s</string>
|
||||||
|
<string name="about_maintainer_title">Maintainer</string>
|
||||||
|
<string name="about_license_title">License</string>
|
||||||
|
<string name="about_source_title">Source code</string>
|
||||||
|
|
||||||
|
<!-- New constants for backward compatibility or shared use -->
|
||||||
|
<string name="share_intent_title">Project %1$s</string>
|
||||||
|
<string name="share_chooser_title">Share %1$s</string>
|
||||||
|
|
||||||
|
</resources>
|
||||||
@@ -0,0 +1,272 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Untranslated: these are the English strings, kept here so a translation can be
|
||||||
|
contributed by simply replacing the values. Strings marked translatable="false" in
|
||||||
|
values/strings.xml (app and product names, preference keys) are deliberately absent
|
||||||
|
and must not be added.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- Actions -->
|
||||||
|
<string name="action_new_bill">New bill</string>
|
||||||
|
<string name="action_add_project">Add project</string>
|
||||||
|
<string name="action_save">Save</string>
|
||||||
|
<string name="action_edit">Edit</string>
|
||||||
|
<string name="action_share">Share</string>
|
||||||
|
<string name="action_search">Search</string>
|
||||||
|
<string name="action_open_menu">Open menu</string>
|
||||||
|
<string name="action_close_search">Close search</string>
|
||||||
|
<string name="action_clear_search">Clear search</string>
|
||||||
|
<string name="action_delete">Delete</string>
|
||||||
|
<string name="simple_back">Back</string>
|
||||||
|
<string name="action_archive">Archive</string>
|
||||||
|
<string name="action_unarchive">Unarchive</string>
|
||||||
|
<string name="action_export">Export</string>
|
||||||
|
<string name="action_stats">Stats</string>
|
||||||
|
<string name="action_settle">Settle</string>
|
||||||
|
<string name="action_scan_qrcode">Scan QR Code</string>
|
||||||
|
<string name="action_settings">Settings</string>
|
||||||
|
<string name="action_label_bills">Label missing categories</string>
|
||||||
|
<string name="action_logout">Logout</string>
|
||||||
|
<string name="action_connect">Connect</string>
|
||||||
|
<string name="action_discard">Discard</string>
|
||||||
|
<string name="action_members">Members</string>
|
||||||
|
<string name="action_labels">Labels</string>
|
||||||
|
<string name="action_currencies">Currencies</string>
|
||||||
|
|
||||||
|
<!-- Titles -->
|
||||||
|
<string name="title_stats">Statistics</string>
|
||||||
|
<string name="title_edit_project">Edit project</string>
|
||||||
|
<string name="title_label_bills">Label Bills</string>
|
||||||
|
<string name="title_labels">Manage Labels</string>
|
||||||
|
<string name="title_about">About</string>
|
||||||
|
<string name="title_settle">Settle Project</string>
|
||||||
|
<string name="title_share">Share Project</string>
|
||||||
|
<string name="title_add_project">Add Project</string>
|
||||||
|
<string name="title_add_category">Add Category</string>
|
||||||
|
<string name="title_add_payment_mode">Add Payment Mode</string>
|
||||||
|
<string name="title_account">Nextcloud Account</string>
|
||||||
|
<string name="title_share_web">Web link</string>
|
||||||
|
<string name="title_share_qr">Cowspent link</string>
|
||||||
|
<string name="title_confirm">Are you sure?</string>
|
||||||
|
|
||||||
|
<!-- Labels and Fields -->
|
||||||
|
<string name="label_all_bills">All bills</string>
|
||||||
|
<string name="label_categories">Categories</string>
|
||||||
|
<string name="label_payment_modes">Payment Modes</string>
|
||||||
|
<string name="label_name">Name</string>
|
||||||
|
<string name="label_icon">Icon / Emoji</string>
|
||||||
|
<string name="label_color">Color</string>
|
||||||
|
<string name="label_weight">Weight</string>
|
||||||
|
<string name="label_activated">Activated</string>
|
||||||
|
<string name="label_password">Password</string>
|
||||||
|
<string name="label_email">E-mail</string>
|
||||||
|
<string name="label_url">Server address</string>
|
||||||
|
<string name="label_username">Username</string>
|
||||||
|
<string name="label_comment">Comment</string>
|
||||||
|
<string name="label_what">What?</string>
|
||||||
|
<string name="label_payer">Who paid?</string>
|
||||||
|
<string name="label_owers">For whom?</string>
|
||||||
|
<string name="label_repeat">Repeat every</string>
|
||||||
|
<string name="label_mode">Mode</string>
|
||||||
|
<string name="label_category">Category</string>
|
||||||
|
<string name="label_project_id">Project ID/name</string>
|
||||||
|
<string name="label_project_title">Project title</string>
|
||||||
|
<string name="label_use_sso">Use Nextcloud App Account</string>
|
||||||
|
|
||||||
|
<!-- Dialogs and Messages -->
|
||||||
|
<string name="dialog_unsaved_changes_title">Unsaved changes</string>
|
||||||
|
<string name="dialog_unsaved_changes_msg">Save changes before leaving?</string>
|
||||||
|
<string name="dialog_confirm_remove_project_msg">The remote project will not be deleted.</string>
|
||||||
|
<string name="dialog_sync_error_title">Sync error</string>
|
||||||
|
<string name="dialog_sync_error_msg">Sync failed for %1$s.\n\n%2$s</string>
|
||||||
|
<string name="dialog_balanced_msg">Expenses are already balanced.</string>
|
||||||
|
<string name="msg_project_added">Project %1$s added</string>
|
||||||
|
<string name="msg_bill_labeled_done">All bills labeled</string>
|
||||||
|
<string name="msg_no_suggestions">No suggestions</string>
|
||||||
|
<string name="msg_auth_warning">Requires Cospend v0.3.4+.</string>
|
||||||
|
<string name="msg_link_copied">Link copied to clipboard</string>
|
||||||
|
<string name="msg_share_qr">Scan QR code or share the link to join.</string>
|
||||||
|
<string name="msg_share_web">Link for web browser access.</string>
|
||||||
|
<string name="msg_share_qr_warn">Share this link with a Cowspent user.</string>
|
||||||
|
<string name="msg_settle_intro">Settlement for %1$s:</string>
|
||||||
|
<string name="msg_settle_sentence">%1$s owes %3$.2f to %2$s</string>
|
||||||
|
<string name="msg_stats_intro">Stats for %1$s:</string>
|
||||||
|
<string name="msg_stats_header">Member (Paid | Spent | Balance)</string>
|
||||||
|
<string name="msg_logged_in_as">Logged in as %1$s</string>
|
||||||
|
|
||||||
|
<!-- Errors -->
|
||||||
|
<string name="error_generic">Error</string>
|
||||||
|
<string name="error_loading">Loading</string>
|
||||||
|
<string name="error_no_projects">No projects found</string>
|
||||||
|
<string name="error_no_members">No members found</string>
|
||||||
|
<string name="error_no_bills">No bills found</string>
|
||||||
|
<string name="error_no_member">At least one member required</string>
|
||||||
|
<string name="error_maintenance_mode">Server is in maintenance mode</string>
|
||||||
|
<string name="error_400">400 Bad request</string>
|
||||||
|
<string name="error_401">401 Unauthorized</string>
|
||||||
|
<string name="error_403">403 Forbidden</string>
|
||||||
|
<string name="error_404">404 Not Found</string>
|
||||||
|
<string name="error_sync">Sync failed: %1$s</string>
|
||||||
|
<string name="error_invalid_login">Invalid login: %1$s</string>
|
||||||
|
<string name="error_auth">Wrong username or password</string>
|
||||||
|
<string name="error_json">Invalid server response</string>
|
||||||
|
<string name="error_req_failed">Request failed</string>
|
||||||
|
<string name="error_invalid_email">Invalid e-mail</string>
|
||||||
|
<string name="error_invalid_project_id">Invalid project ID</string>
|
||||||
|
<string name="error_invalid_project_name">Invalid project title</string>
|
||||||
|
<string name="error_invalid_bill_name">Invalid bill name</string>
|
||||||
|
<string name="error_invalid_bill_date">Invalid bill date</string>
|
||||||
|
<string name="error_invalid_bill_payer">Payer required</string>
|
||||||
|
<string name="error_invalid_bill_owers">Owers required</string>
|
||||||
|
<string name="error_no_network">No network connection</string>
|
||||||
|
<string name="error_server">Server error</string>
|
||||||
|
<string name="error_io">Server connection broken</string>
|
||||||
|
<string name="error_share_impossible">Cannot share this project</string>
|
||||||
|
|
||||||
|
<!-- Drawer / Common UI -->
|
||||||
|
<string name="drawer_no_account">Connect to Nextcloud account</string>
|
||||||
|
<string name="drawer_last_sync">Last sync: %1$02d:%2$02d</string>
|
||||||
|
<string name="simple_cancel">Cancel</string>
|
||||||
|
<string name="simple_ok" tools:ignore="ButtonCase,Typos">Ok</string>
|
||||||
|
<string name="simple_yes">Yes</string>
|
||||||
|
<string name="simple_no">No</string>
|
||||||
|
<string name="simple_close">Close</string>
|
||||||
|
|
||||||
|
<!-- Settings -->
|
||||||
|
<string name="settings_appearance">Appearance</string>
|
||||||
|
<string name="settings_network">Network</string>
|
||||||
|
<string name="settings_other">Other</string>
|
||||||
|
<string name="settings_night_mode">Theme</string>
|
||||||
|
<string name="settings_offline_mode">Offline mode</string>
|
||||||
|
<string name="settings_offline_mode_summary">Only sync manually.</string>
|
||||||
|
<string name="settings_color_custom">Custom color</string>
|
||||||
|
<string name="settings_color_mode">Color Selection</string>
|
||||||
|
<string name="settings_show_archived">Show archived projects</string>
|
||||||
|
<string name="settings_beta_features">Beta Features</string>
|
||||||
|
<string name="settings_beta_features_summary">Enable experimental features. Use at your own risk.</string>
|
||||||
|
<string name="settings_fill_new_bill_from_last">Auto-fill from last bill</string>
|
||||||
|
<string name="settings_fill_new_bill_from_last_summary">Pre-fill payer, category, mode and owers from the last bill created in the project.</string>
|
||||||
|
<string name="settings_auto_sync_on_open">Sync interval</string>
|
||||||
|
<string name="settings_auto_sync_on_open_summary">How often to refresh the account and all projects when opening the app.</string>
|
||||||
|
<string name="pref_value_sync_1m">1 minute</string>
|
||||||
|
<string name="pref_value_sync_10m">10 minutes</string>
|
||||||
|
<string name="pref_value_sync_1h">1 hour</string>
|
||||||
|
<string name="pref_value_sync_1d">1 day</string>
|
||||||
|
<string name="settings_url_warn_http">WARNING: "http" is unsafe. Use "https".</string>
|
||||||
|
<string name="settings_colorpicker_title">Choose Color</string>
|
||||||
|
|
||||||
|
<string name="pref_value_color_system">System</string>
|
||||||
|
<string name="pref_value_color_manual">Manual</string>
|
||||||
|
<string name="pref_value_theme_light">Light</string>
|
||||||
|
<string name="pref_value_theme_dark">Dark</string>
|
||||||
|
<string name="pref_value_theme_system">Follow system</string>
|
||||||
|
|
||||||
|
<!-- Enums and Lists -->
|
||||||
|
<string name="repeat_no">No repeat</string>
|
||||||
|
<string name="repeat_day">Daily</string>
|
||||||
|
<string name="repeat_week">Weekly</string>
|
||||||
|
<string name="repeat_fortnight">Fortnightly</string>
|
||||||
|
<string name="repeat_month">Monthly</string>
|
||||||
|
<string name="repeat_year">Yearly</string>
|
||||||
|
|
||||||
|
<string name="payment_mode_none">None</string>
|
||||||
|
<string name="payment_mode_all">All</string>
|
||||||
|
<string name="payment_mode_credit_card">Credit card</string>
|
||||||
|
<string name="payment_mode_cash">Cash</string>
|
||||||
|
<string name="payment_mode_check">Check</string>
|
||||||
|
<string name="payment_mode_online">Online</string>
|
||||||
|
<string name="payment_mode_transfer">Transfer</string>
|
||||||
|
|
||||||
|
<string name="category_none">None</string>
|
||||||
|
<string name="category_all">All</string>
|
||||||
|
<string name="category_all_except_reimbursement">All except reimbursement</string>
|
||||||
|
<string name="category_groceries">Grocery</string>
|
||||||
|
<string name="category_leisure">Bar/Party</string>
|
||||||
|
<string name="category_rent">Rent</string>
|
||||||
|
<string name="category_bills">Bill</string>
|
||||||
|
<string name="category_excursion">Excursion/Culture</string>
|
||||||
|
<string name="category_health">Health</string>
|
||||||
|
<string name="category_shopping">Shopping</string>
|
||||||
|
<string name="category_reimbursement">Reimbursement</string>
|
||||||
|
<string name="category_restaurant">Restaurant</string>
|
||||||
|
<string name="category_accomodation">Accommodation</string>
|
||||||
|
<string name="category_transport">Transport</string>
|
||||||
|
<string name="category_sport">Sport</string>
|
||||||
|
|
||||||
|
<!-- Project specific -->
|
||||||
|
<string name="new_project_action">What</string>
|
||||||
|
<string name="new_project_where">Where</string>
|
||||||
|
<string name="where_local">Local only</string>
|
||||||
|
<string name="todo_join">Join existing project</string>
|
||||||
|
<string name="todo_create">Create new project</string>
|
||||||
|
<string name="import_tooltip">Import from file</string>
|
||||||
|
<string name="choose_project_management_action">Project</string>
|
||||||
|
<string name="project_added_success">Project added successfully.</string>
|
||||||
|
<string name="no_projects_text">You have no projects yet.</string>
|
||||||
|
<string name="configure_account_choice">Configure Nextcloud account</string>
|
||||||
|
<string name="add_project_choice">Add project manually</string>
|
||||||
|
<string name="no_members_text">No members in this project.</string>
|
||||||
|
<string name="no_bills_text">No bills found.</string>
|
||||||
|
<string name="member_already_exists">Member already exists.</string>
|
||||||
|
<string name="activity_dialog_title">Project: %1$s</string>
|
||||||
|
<string name="remove_project_confirmation">Project %1$s removed.</string>
|
||||||
|
<string name="file_saved_success">File saved: %1$s</string>
|
||||||
|
<string name="import_error_header">Import failed at row %d</string>
|
||||||
|
<string name="import_error_date">Invalid date format at row %d</string>
|
||||||
|
<string name="import_error_owers">Invalid owers at row %d</string>
|
||||||
|
<string name="add_member_dialog_title">Add Member</string>
|
||||||
|
<string name="edit_member_dialog_title">Edit Member</string>
|
||||||
|
<string name="member_edit_delete">Delete</string>
|
||||||
|
<string name="project_edition_no_change">No changes to save.</string>
|
||||||
|
|
||||||
|
<!-- Settlement -->
|
||||||
|
<string name="center_none">None (Optimal)</string>
|
||||||
|
<string name="settle_who">Who pays</string>
|
||||||
|
<string name="settle_to_whom">To whom</string>
|
||||||
|
<string name="settle_how_much">Amount</string>
|
||||||
|
<string name="simple_settle_share">Share</string>
|
||||||
|
<string name="simple_create_bills">Create bills</string>
|
||||||
|
<string name="settle_bill_what">Settlement</string>
|
||||||
|
|
||||||
|
<!-- Currencies -->
|
||||||
|
<string name="currency_dialog_title">Choose Currency (%s)</string>
|
||||||
|
<string name="setting_none">None</string>
|
||||||
|
<string name="setting_all">All</string>
|
||||||
|
<string name="currency_saved_success">Currency settings saved.</string>
|
||||||
|
<string name="main_currency">Main Currency</string>
|
||||||
|
|
||||||
|
<!-- Statistics -->
|
||||||
|
<string name="label_bills_suggested">Suggested Categories</string>
|
||||||
|
<string name="label_bills_skip">Skip</string>
|
||||||
|
<string name="stats_date_min">From</string>
|
||||||
|
<string name="stats_date_max">To</string>
|
||||||
|
<string name="stats_who">Member</string>
|
||||||
|
<string name="stats_paid">Paid</string>
|
||||||
|
<string name="stats_spent">Spent</string>
|
||||||
|
<string name="stats_balance">Balance</string>
|
||||||
|
<string name="total">Total: %1$s</string>
|
||||||
|
|
||||||
|
<!-- Errors Extra -->
|
||||||
|
<string name="error_project_connect_check">Connection failed: %1$s</string>
|
||||||
|
<string name="error_create_remote_project_helper">Creation failed: %1$s</string>
|
||||||
|
<string name="error_edit_remote_project_helper">Error updating remote project: %1$s</string>
|
||||||
|
<string name="remote_project_operation_no_network">Network unavailable for remote operation.</string>
|
||||||
|
<string name="error_scanning_bill_qr_code">Failed to parse QR code.</string>
|
||||||
|
<string name="error_token_mismatch">Authentication token mismatch. Please log in again.</string>
|
||||||
|
<string name="insufficient_access_level">You don\'t have permission to perform this action.</string>
|
||||||
|
<string name="delete_label_confirmation_title">Delete Label</string>
|
||||||
|
<string name="delete_label_confirmation_message">Are you sure you want to delete this label?</string>
|
||||||
|
|
||||||
|
<!-- About -->
|
||||||
|
<string name="about_version">Version %1$s</string>
|
||||||
|
<string name="about_maintainer_title">Maintainer</string>
|
||||||
|
<string name="about_license_title">License</string>
|
||||||
|
<string name="about_source_title">Source code</string>
|
||||||
|
|
||||||
|
<!-- New constants for backward compatibility or shared use -->
|
||||||
|
<string name="share_intent_title">Project %1$s</string>
|
||||||
|
<string name="share_chooser_title">Share %1$s</string>
|
||||||
|
|
||||||
|
</resources>
|
||||||
@@ -0,0 +1,272 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Untranslated: these are the English strings, kept here so a translation can be
|
||||||
|
contributed by simply replacing the values. Strings marked translatable="false" in
|
||||||
|
values/strings.xml (app and product names, preference keys) are deliberately absent
|
||||||
|
and must not be added.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- Actions -->
|
||||||
|
<string name="action_new_bill">New bill</string>
|
||||||
|
<string name="action_add_project">Add project</string>
|
||||||
|
<string name="action_save">Save</string>
|
||||||
|
<string name="action_edit">Edit</string>
|
||||||
|
<string name="action_share">Share</string>
|
||||||
|
<string name="action_search">Search</string>
|
||||||
|
<string name="action_open_menu">Open menu</string>
|
||||||
|
<string name="action_close_search">Close search</string>
|
||||||
|
<string name="action_clear_search">Clear search</string>
|
||||||
|
<string name="action_delete">Delete</string>
|
||||||
|
<string name="simple_back">Back</string>
|
||||||
|
<string name="action_archive">Archive</string>
|
||||||
|
<string name="action_unarchive">Unarchive</string>
|
||||||
|
<string name="action_export">Export</string>
|
||||||
|
<string name="action_stats">Stats</string>
|
||||||
|
<string name="action_settle">Settle</string>
|
||||||
|
<string name="action_scan_qrcode">Scan QR Code</string>
|
||||||
|
<string name="action_settings">Settings</string>
|
||||||
|
<string name="action_label_bills">Label missing categories</string>
|
||||||
|
<string name="action_logout">Logout</string>
|
||||||
|
<string name="action_connect">Connect</string>
|
||||||
|
<string name="action_discard">Discard</string>
|
||||||
|
<string name="action_members">Members</string>
|
||||||
|
<string name="action_labels">Labels</string>
|
||||||
|
<string name="action_currencies">Currencies</string>
|
||||||
|
|
||||||
|
<!-- Titles -->
|
||||||
|
<string name="title_stats">Statistics</string>
|
||||||
|
<string name="title_edit_project">Edit project</string>
|
||||||
|
<string name="title_label_bills">Label Bills</string>
|
||||||
|
<string name="title_labels">Manage Labels</string>
|
||||||
|
<string name="title_about">About</string>
|
||||||
|
<string name="title_settle">Settle Project</string>
|
||||||
|
<string name="title_share">Share Project</string>
|
||||||
|
<string name="title_add_project">Add Project</string>
|
||||||
|
<string name="title_add_category">Add Category</string>
|
||||||
|
<string name="title_add_payment_mode">Add Payment Mode</string>
|
||||||
|
<string name="title_account">Nextcloud Account</string>
|
||||||
|
<string name="title_share_web">Web link</string>
|
||||||
|
<string name="title_share_qr">Cowspent link</string>
|
||||||
|
<string name="title_confirm">Are you sure?</string>
|
||||||
|
|
||||||
|
<!-- Labels and Fields -->
|
||||||
|
<string name="label_all_bills">All bills</string>
|
||||||
|
<string name="label_categories">Categories</string>
|
||||||
|
<string name="label_payment_modes">Payment Modes</string>
|
||||||
|
<string name="label_name">Name</string>
|
||||||
|
<string name="label_icon">Icon / Emoji</string>
|
||||||
|
<string name="label_color">Color</string>
|
||||||
|
<string name="label_weight">Weight</string>
|
||||||
|
<string name="label_activated">Activated</string>
|
||||||
|
<string name="label_password">Password</string>
|
||||||
|
<string name="label_email">E-mail</string>
|
||||||
|
<string name="label_url">Server address</string>
|
||||||
|
<string name="label_username">Username</string>
|
||||||
|
<string name="label_comment">Comment</string>
|
||||||
|
<string name="label_what">What?</string>
|
||||||
|
<string name="label_payer">Who paid?</string>
|
||||||
|
<string name="label_owers">For whom?</string>
|
||||||
|
<string name="label_repeat">Repeat every</string>
|
||||||
|
<string name="label_mode">Mode</string>
|
||||||
|
<string name="label_category">Category</string>
|
||||||
|
<string name="label_project_id">Project ID/name</string>
|
||||||
|
<string name="label_project_title">Project title</string>
|
||||||
|
<string name="label_use_sso">Use Nextcloud App Account</string>
|
||||||
|
|
||||||
|
<!-- Dialogs and Messages -->
|
||||||
|
<string name="dialog_unsaved_changes_title">Unsaved changes</string>
|
||||||
|
<string name="dialog_unsaved_changes_msg">Save changes before leaving?</string>
|
||||||
|
<string name="dialog_confirm_remove_project_msg">The remote project will not be deleted.</string>
|
||||||
|
<string name="dialog_sync_error_title">Sync error</string>
|
||||||
|
<string name="dialog_sync_error_msg">Sync failed for %1$s.\n\n%2$s</string>
|
||||||
|
<string name="dialog_balanced_msg">Expenses are already balanced.</string>
|
||||||
|
<string name="msg_project_added">Project %1$s added</string>
|
||||||
|
<string name="msg_bill_labeled_done">All bills labeled</string>
|
||||||
|
<string name="msg_no_suggestions">No suggestions</string>
|
||||||
|
<string name="msg_auth_warning">Requires Cospend v0.3.4+.</string>
|
||||||
|
<string name="msg_link_copied">Link copied to clipboard</string>
|
||||||
|
<string name="msg_share_qr">Scan QR code or share the link to join.</string>
|
||||||
|
<string name="msg_share_web">Link for web browser access.</string>
|
||||||
|
<string name="msg_share_qr_warn">Share this link with a Cowspent user.</string>
|
||||||
|
<string name="msg_settle_intro">Settlement for %1$s:</string>
|
||||||
|
<string name="msg_settle_sentence">%1$s owes %3$.2f to %2$s</string>
|
||||||
|
<string name="msg_stats_intro">Stats for %1$s:</string>
|
||||||
|
<string name="msg_stats_header">Member (Paid | Spent | Balance)</string>
|
||||||
|
<string name="msg_logged_in_as">Logged in as %1$s</string>
|
||||||
|
|
||||||
|
<!-- Errors -->
|
||||||
|
<string name="error_generic">Error</string>
|
||||||
|
<string name="error_loading">Loading</string>
|
||||||
|
<string name="error_no_projects">No projects found</string>
|
||||||
|
<string name="error_no_members">No members found</string>
|
||||||
|
<string name="error_no_bills">No bills found</string>
|
||||||
|
<string name="error_no_member">At least one member required</string>
|
||||||
|
<string name="error_maintenance_mode">Server is in maintenance mode</string>
|
||||||
|
<string name="error_400">400 Bad request</string>
|
||||||
|
<string name="error_401">401 Unauthorized</string>
|
||||||
|
<string name="error_403">403 Forbidden</string>
|
||||||
|
<string name="error_404">404 Not Found</string>
|
||||||
|
<string name="error_sync">Sync failed: %1$s</string>
|
||||||
|
<string name="error_invalid_login">Invalid login: %1$s</string>
|
||||||
|
<string name="error_auth">Wrong username or password</string>
|
||||||
|
<string name="error_json">Invalid server response</string>
|
||||||
|
<string name="error_req_failed">Request failed</string>
|
||||||
|
<string name="error_invalid_email">Invalid e-mail</string>
|
||||||
|
<string name="error_invalid_project_id">Invalid project ID</string>
|
||||||
|
<string name="error_invalid_project_name">Invalid project title</string>
|
||||||
|
<string name="error_invalid_bill_name">Invalid bill name</string>
|
||||||
|
<string name="error_invalid_bill_date">Invalid bill date</string>
|
||||||
|
<string name="error_invalid_bill_payer">Payer required</string>
|
||||||
|
<string name="error_invalid_bill_owers">Owers required</string>
|
||||||
|
<string name="error_no_network">No network connection</string>
|
||||||
|
<string name="error_server">Server error</string>
|
||||||
|
<string name="error_io">Server connection broken</string>
|
||||||
|
<string name="error_share_impossible">Cannot share this project</string>
|
||||||
|
|
||||||
|
<!-- Drawer / Common UI -->
|
||||||
|
<string name="drawer_no_account">Connect to Nextcloud account</string>
|
||||||
|
<string name="drawer_last_sync">Last sync: %1$02d:%2$02d</string>
|
||||||
|
<string name="simple_cancel">Cancel</string>
|
||||||
|
<string name="simple_ok" tools:ignore="ButtonCase,Typos">Ok</string>
|
||||||
|
<string name="simple_yes">Yes</string>
|
||||||
|
<string name="simple_no">No</string>
|
||||||
|
<string name="simple_close">Close</string>
|
||||||
|
|
||||||
|
<!-- Settings -->
|
||||||
|
<string name="settings_appearance">Appearance</string>
|
||||||
|
<string name="settings_network">Network</string>
|
||||||
|
<string name="settings_other">Other</string>
|
||||||
|
<string name="settings_night_mode">Theme</string>
|
||||||
|
<string name="settings_offline_mode">Offline mode</string>
|
||||||
|
<string name="settings_offline_mode_summary">Only sync manually.</string>
|
||||||
|
<string name="settings_color_custom">Custom color</string>
|
||||||
|
<string name="settings_color_mode">Color Selection</string>
|
||||||
|
<string name="settings_show_archived">Show archived projects</string>
|
||||||
|
<string name="settings_beta_features">Beta Features</string>
|
||||||
|
<string name="settings_beta_features_summary">Enable experimental features. Use at your own risk.</string>
|
||||||
|
<string name="settings_fill_new_bill_from_last">Auto-fill from last bill</string>
|
||||||
|
<string name="settings_fill_new_bill_from_last_summary">Pre-fill payer, category, mode and owers from the last bill created in the project.</string>
|
||||||
|
<string name="settings_auto_sync_on_open">Sync interval</string>
|
||||||
|
<string name="settings_auto_sync_on_open_summary">How often to refresh the account and all projects when opening the app.</string>
|
||||||
|
<string name="pref_value_sync_1m">1 minute</string>
|
||||||
|
<string name="pref_value_sync_10m">10 minutes</string>
|
||||||
|
<string name="pref_value_sync_1h">1 hour</string>
|
||||||
|
<string name="pref_value_sync_1d">1 day</string>
|
||||||
|
<string name="settings_url_warn_http">WARNING: "http" is unsafe. Use "https".</string>
|
||||||
|
<string name="settings_colorpicker_title">Choose Color</string>
|
||||||
|
|
||||||
|
<string name="pref_value_color_system">System</string>
|
||||||
|
<string name="pref_value_color_manual">Manual</string>
|
||||||
|
<string name="pref_value_theme_light">Light</string>
|
||||||
|
<string name="pref_value_theme_dark">Dark</string>
|
||||||
|
<string name="pref_value_theme_system">Follow system</string>
|
||||||
|
|
||||||
|
<!-- Enums and Lists -->
|
||||||
|
<string name="repeat_no">No repeat</string>
|
||||||
|
<string name="repeat_day">Daily</string>
|
||||||
|
<string name="repeat_week">Weekly</string>
|
||||||
|
<string name="repeat_fortnight">Fortnightly</string>
|
||||||
|
<string name="repeat_month">Monthly</string>
|
||||||
|
<string name="repeat_year">Yearly</string>
|
||||||
|
|
||||||
|
<string name="payment_mode_none">None</string>
|
||||||
|
<string name="payment_mode_all">All</string>
|
||||||
|
<string name="payment_mode_credit_card">Credit card</string>
|
||||||
|
<string name="payment_mode_cash">Cash</string>
|
||||||
|
<string name="payment_mode_check">Check</string>
|
||||||
|
<string name="payment_mode_online">Online</string>
|
||||||
|
<string name="payment_mode_transfer">Transfer</string>
|
||||||
|
|
||||||
|
<string name="category_none">None</string>
|
||||||
|
<string name="category_all">All</string>
|
||||||
|
<string name="category_all_except_reimbursement">All except reimbursement</string>
|
||||||
|
<string name="category_groceries">Grocery</string>
|
||||||
|
<string name="category_leisure">Bar/Party</string>
|
||||||
|
<string name="category_rent">Rent</string>
|
||||||
|
<string name="category_bills">Bill</string>
|
||||||
|
<string name="category_excursion">Excursion/Culture</string>
|
||||||
|
<string name="category_health">Health</string>
|
||||||
|
<string name="category_shopping">Shopping</string>
|
||||||
|
<string name="category_reimbursement">Reimbursement</string>
|
||||||
|
<string name="category_restaurant">Restaurant</string>
|
||||||
|
<string name="category_accomodation">Accommodation</string>
|
||||||
|
<string name="category_transport">Transport</string>
|
||||||
|
<string name="category_sport">Sport</string>
|
||||||
|
|
||||||
|
<!-- Project specific -->
|
||||||
|
<string name="new_project_action">What</string>
|
||||||
|
<string name="new_project_where">Where</string>
|
||||||
|
<string name="where_local">Local only</string>
|
||||||
|
<string name="todo_join">Join existing project</string>
|
||||||
|
<string name="todo_create">Create new project</string>
|
||||||
|
<string name="import_tooltip">Import from file</string>
|
||||||
|
<string name="choose_project_management_action">Project</string>
|
||||||
|
<string name="project_added_success">Project added successfully.</string>
|
||||||
|
<string name="no_projects_text">You have no projects yet.</string>
|
||||||
|
<string name="configure_account_choice">Configure Nextcloud account</string>
|
||||||
|
<string name="add_project_choice">Add project manually</string>
|
||||||
|
<string name="no_members_text">No members in this project.</string>
|
||||||
|
<string name="no_bills_text">No bills found.</string>
|
||||||
|
<string name="member_already_exists">Member already exists.</string>
|
||||||
|
<string name="activity_dialog_title">Project: %1$s</string>
|
||||||
|
<string name="remove_project_confirmation">Project %1$s removed.</string>
|
||||||
|
<string name="file_saved_success">File saved: %1$s</string>
|
||||||
|
<string name="import_error_header">Import failed at row %d</string>
|
||||||
|
<string name="import_error_date">Invalid date format at row %d</string>
|
||||||
|
<string name="import_error_owers">Invalid owers at row %d</string>
|
||||||
|
<string name="add_member_dialog_title">Add Member</string>
|
||||||
|
<string name="edit_member_dialog_title">Edit Member</string>
|
||||||
|
<string name="member_edit_delete">Delete</string>
|
||||||
|
<string name="project_edition_no_change">No changes to save.</string>
|
||||||
|
|
||||||
|
<!-- Settlement -->
|
||||||
|
<string name="center_none">None (Optimal)</string>
|
||||||
|
<string name="settle_who">Who pays</string>
|
||||||
|
<string name="settle_to_whom">To whom</string>
|
||||||
|
<string name="settle_how_much">Amount</string>
|
||||||
|
<string name="simple_settle_share">Share</string>
|
||||||
|
<string name="simple_create_bills">Create bills</string>
|
||||||
|
<string name="settle_bill_what">Settlement</string>
|
||||||
|
|
||||||
|
<!-- Currencies -->
|
||||||
|
<string name="currency_dialog_title">Choose Currency (%s)</string>
|
||||||
|
<string name="setting_none">None</string>
|
||||||
|
<string name="setting_all">All</string>
|
||||||
|
<string name="currency_saved_success">Currency settings saved.</string>
|
||||||
|
<string name="main_currency">Main Currency</string>
|
||||||
|
|
||||||
|
<!-- Statistics -->
|
||||||
|
<string name="label_bills_suggested">Suggested Categories</string>
|
||||||
|
<string name="label_bills_skip">Skip</string>
|
||||||
|
<string name="stats_date_min">From</string>
|
||||||
|
<string name="stats_date_max">To</string>
|
||||||
|
<string name="stats_who">Member</string>
|
||||||
|
<string name="stats_paid">Paid</string>
|
||||||
|
<string name="stats_spent">Spent</string>
|
||||||
|
<string name="stats_balance">Balance</string>
|
||||||
|
<string name="total">Total: %1$s</string>
|
||||||
|
|
||||||
|
<!-- Errors Extra -->
|
||||||
|
<string name="error_project_connect_check">Connection failed: %1$s</string>
|
||||||
|
<string name="error_create_remote_project_helper">Creation failed: %1$s</string>
|
||||||
|
<string name="error_edit_remote_project_helper">Error updating remote project: %1$s</string>
|
||||||
|
<string name="remote_project_operation_no_network">Network unavailable for remote operation.</string>
|
||||||
|
<string name="error_scanning_bill_qr_code">Failed to parse QR code.</string>
|
||||||
|
<string name="error_token_mismatch">Authentication token mismatch. Please log in again.</string>
|
||||||
|
<string name="insufficient_access_level">You don\'t have permission to perform this action.</string>
|
||||||
|
<string name="delete_label_confirmation_title">Delete Label</string>
|
||||||
|
<string name="delete_label_confirmation_message">Are you sure you want to delete this label?</string>
|
||||||
|
|
||||||
|
<!-- About -->
|
||||||
|
<string name="about_version">Version %1$s</string>
|
||||||
|
<string name="about_maintainer_title">Maintainer</string>
|
||||||
|
<string name="about_license_title">License</string>
|
||||||
|
<string name="about_source_title">Source code</string>
|
||||||
|
|
||||||
|
<!-- New constants for backward compatibility or shared use -->
|
||||||
|
<string name="share_intent_title">Project %1$s</string>
|
||||||
|
<string name="share_chooser_title">Share %1$s</string>
|
||||||
|
|
||||||
|
</resources>
|
||||||
@@ -0,0 +1,272 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Untranslated: these are the English strings, kept here so a translation can be
|
||||||
|
contributed by simply replacing the values. Strings marked translatable="false" in
|
||||||
|
values/strings.xml (app and product names, preference keys) are deliberately absent
|
||||||
|
and must not be added.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- Actions -->
|
||||||
|
<string name="action_new_bill">New bill</string>
|
||||||
|
<string name="action_add_project">Add project</string>
|
||||||
|
<string name="action_save">Save</string>
|
||||||
|
<string name="action_edit">Edit</string>
|
||||||
|
<string name="action_share">Share</string>
|
||||||
|
<string name="action_search">Search</string>
|
||||||
|
<string name="action_open_menu">Open menu</string>
|
||||||
|
<string name="action_close_search">Close search</string>
|
||||||
|
<string name="action_clear_search">Clear search</string>
|
||||||
|
<string name="action_delete">Delete</string>
|
||||||
|
<string name="simple_back">Back</string>
|
||||||
|
<string name="action_archive">Archive</string>
|
||||||
|
<string name="action_unarchive">Unarchive</string>
|
||||||
|
<string name="action_export">Export</string>
|
||||||
|
<string name="action_stats">Stats</string>
|
||||||
|
<string name="action_settle">Settle</string>
|
||||||
|
<string name="action_scan_qrcode">Scan QR Code</string>
|
||||||
|
<string name="action_settings">Settings</string>
|
||||||
|
<string name="action_label_bills">Label missing categories</string>
|
||||||
|
<string name="action_logout">Logout</string>
|
||||||
|
<string name="action_connect">Connect</string>
|
||||||
|
<string name="action_discard">Discard</string>
|
||||||
|
<string name="action_members">Members</string>
|
||||||
|
<string name="action_labels">Labels</string>
|
||||||
|
<string name="action_currencies">Currencies</string>
|
||||||
|
|
||||||
|
<!-- Titles -->
|
||||||
|
<string name="title_stats">Statistics</string>
|
||||||
|
<string name="title_edit_project">Edit project</string>
|
||||||
|
<string name="title_label_bills">Label Bills</string>
|
||||||
|
<string name="title_labels">Manage Labels</string>
|
||||||
|
<string name="title_about">About</string>
|
||||||
|
<string name="title_settle">Settle Project</string>
|
||||||
|
<string name="title_share">Share Project</string>
|
||||||
|
<string name="title_add_project">Add Project</string>
|
||||||
|
<string name="title_add_category">Add Category</string>
|
||||||
|
<string name="title_add_payment_mode">Add Payment Mode</string>
|
||||||
|
<string name="title_account">Nextcloud Account</string>
|
||||||
|
<string name="title_share_web">Web link</string>
|
||||||
|
<string name="title_share_qr">Cowspent link</string>
|
||||||
|
<string name="title_confirm">Are you sure?</string>
|
||||||
|
|
||||||
|
<!-- Labels and Fields -->
|
||||||
|
<string name="label_all_bills">All bills</string>
|
||||||
|
<string name="label_categories">Categories</string>
|
||||||
|
<string name="label_payment_modes">Payment Modes</string>
|
||||||
|
<string name="label_name">Name</string>
|
||||||
|
<string name="label_icon">Icon / Emoji</string>
|
||||||
|
<string name="label_color">Color</string>
|
||||||
|
<string name="label_weight">Weight</string>
|
||||||
|
<string name="label_activated">Activated</string>
|
||||||
|
<string name="label_password">Password</string>
|
||||||
|
<string name="label_email">E-mail</string>
|
||||||
|
<string name="label_url">Server address</string>
|
||||||
|
<string name="label_username">Username</string>
|
||||||
|
<string name="label_comment">Comment</string>
|
||||||
|
<string name="label_what">What?</string>
|
||||||
|
<string name="label_payer">Who paid?</string>
|
||||||
|
<string name="label_owers">For whom?</string>
|
||||||
|
<string name="label_repeat">Repeat every</string>
|
||||||
|
<string name="label_mode">Mode</string>
|
||||||
|
<string name="label_category">Category</string>
|
||||||
|
<string name="label_project_id">Project ID/name</string>
|
||||||
|
<string name="label_project_title">Project title</string>
|
||||||
|
<string name="label_use_sso">Use Nextcloud App Account</string>
|
||||||
|
|
||||||
|
<!-- Dialogs and Messages -->
|
||||||
|
<string name="dialog_unsaved_changes_title">Unsaved changes</string>
|
||||||
|
<string name="dialog_unsaved_changes_msg">Save changes before leaving?</string>
|
||||||
|
<string name="dialog_confirm_remove_project_msg">The remote project will not be deleted.</string>
|
||||||
|
<string name="dialog_sync_error_title">Sync error</string>
|
||||||
|
<string name="dialog_sync_error_msg">Sync failed for %1$s.\n\n%2$s</string>
|
||||||
|
<string name="dialog_balanced_msg">Expenses are already balanced.</string>
|
||||||
|
<string name="msg_project_added">Project %1$s added</string>
|
||||||
|
<string name="msg_bill_labeled_done">All bills labeled</string>
|
||||||
|
<string name="msg_no_suggestions">No suggestions</string>
|
||||||
|
<string name="msg_auth_warning">Requires Cospend v0.3.4+.</string>
|
||||||
|
<string name="msg_link_copied">Link copied to clipboard</string>
|
||||||
|
<string name="msg_share_qr">Scan QR code or share the link to join.</string>
|
||||||
|
<string name="msg_share_web">Link for web browser access.</string>
|
||||||
|
<string name="msg_share_qr_warn">Share this link with a Cowspent user.</string>
|
||||||
|
<string name="msg_settle_intro">Settlement for %1$s:</string>
|
||||||
|
<string name="msg_settle_sentence">%1$s owes %3$.2f to %2$s</string>
|
||||||
|
<string name="msg_stats_intro">Stats for %1$s:</string>
|
||||||
|
<string name="msg_stats_header">Member (Paid | Spent | Balance)</string>
|
||||||
|
<string name="msg_logged_in_as">Logged in as %1$s</string>
|
||||||
|
|
||||||
|
<!-- Errors -->
|
||||||
|
<string name="error_generic">Error</string>
|
||||||
|
<string name="error_loading">Loading</string>
|
||||||
|
<string name="error_no_projects">No projects found</string>
|
||||||
|
<string name="error_no_members">No members found</string>
|
||||||
|
<string name="error_no_bills">No bills found</string>
|
||||||
|
<string name="error_no_member">At least one member required</string>
|
||||||
|
<string name="error_maintenance_mode">Server is in maintenance mode</string>
|
||||||
|
<string name="error_400">400 Bad request</string>
|
||||||
|
<string name="error_401">401 Unauthorized</string>
|
||||||
|
<string name="error_403">403 Forbidden</string>
|
||||||
|
<string name="error_404">404 Not Found</string>
|
||||||
|
<string name="error_sync">Sync failed: %1$s</string>
|
||||||
|
<string name="error_invalid_login">Invalid login: %1$s</string>
|
||||||
|
<string name="error_auth">Wrong username or password</string>
|
||||||
|
<string name="error_json">Invalid server response</string>
|
||||||
|
<string name="error_req_failed">Request failed</string>
|
||||||
|
<string name="error_invalid_email">Invalid e-mail</string>
|
||||||
|
<string name="error_invalid_project_id">Invalid project ID</string>
|
||||||
|
<string name="error_invalid_project_name">Invalid project title</string>
|
||||||
|
<string name="error_invalid_bill_name">Invalid bill name</string>
|
||||||
|
<string name="error_invalid_bill_date">Invalid bill date</string>
|
||||||
|
<string name="error_invalid_bill_payer">Payer required</string>
|
||||||
|
<string name="error_invalid_bill_owers">Owers required</string>
|
||||||
|
<string name="error_no_network">No network connection</string>
|
||||||
|
<string name="error_server">Server error</string>
|
||||||
|
<string name="error_io">Server connection broken</string>
|
||||||
|
<string name="error_share_impossible">Cannot share this project</string>
|
||||||
|
|
||||||
|
<!-- Drawer / Common UI -->
|
||||||
|
<string name="drawer_no_account">Connect to Nextcloud account</string>
|
||||||
|
<string name="drawer_last_sync">Last sync: %1$02d:%2$02d</string>
|
||||||
|
<string name="simple_cancel">Cancel</string>
|
||||||
|
<string name="simple_ok" tools:ignore="ButtonCase,Typos">Ok</string>
|
||||||
|
<string name="simple_yes">Yes</string>
|
||||||
|
<string name="simple_no">No</string>
|
||||||
|
<string name="simple_close">Close</string>
|
||||||
|
|
||||||
|
<!-- Settings -->
|
||||||
|
<string name="settings_appearance">Appearance</string>
|
||||||
|
<string name="settings_network">Network</string>
|
||||||
|
<string name="settings_other">Other</string>
|
||||||
|
<string name="settings_night_mode">Theme</string>
|
||||||
|
<string name="settings_offline_mode">Offline mode</string>
|
||||||
|
<string name="settings_offline_mode_summary">Only sync manually.</string>
|
||||||
|
<string name="settings_color_custom">Custom color</string>
|
||||||
|
<string name="settings_color_mode">Color Selection</string>
|
||||||
|
<string name="settings_show_archived">Show archived projects</string>
|
||||||
|
<string name="settings_beta_features">Beta Features</string>
|
||||||
|
<string name="settings_beta_features_summary">Enable experimental features. Use at your own risk.</string>
|
||||||
|
<string name="settings_fill_new_bill_from_last">Auto-fill from last bill</string>
|
||||||
|
<string name="settings_fill_new_bill_from_last_summary">Pre-fill payer, category, mode and owers from the last bill created in the project.</string>
|
||||||
|
<string name="settings_auto_sync_on_open">Sync interval</string>
|
||||||
|
<string name="settings_auto_sync_on_open_summary">How often to refresh the account and all projects when opening the app.</string>
|
||||||
|
<string name="pref_value_sync_1m">1 minute</string>
|
||||||
|
<string name="pref_value_sync_10m">10 minutes</string>
|
||||||
|
<string name="pref_value_sync_1h">1 hour</string>
|
||||||
|
<string name="pref_value_sync_1d">1 day</string>
|
||||||
|
<string name="settings_url_warn_http">WARNING: "http" is unsafe. Use "https".</string>
|
||||||
|
<string name="settings_colorpicker_title">Choose Color</string>
|
||||||
|
|
||||||
|
<string name="pref_value_color_system">System</string>
|
||||||
|
<string name="pref_value_color_manual">Manual</string>
|
||||||
|
<string name="pref_value_theme_light">Light</string>
|
||||||
|
<string name="pref_value_theme_dark">Dark</string>
|
||||||
|
<string name="pref_value_theme_system">Follow system</string>
|
||||||
|
|
||||||
|
<!-- Enums and Lists -->
|
||||||
|
<string name="repeat_no">No repeat</string>
|
||||||
|
<string name="repeat_day">Daily</string>
|
||||||
|
<string name="repeat_week">Weekly</string>
|
||||||
|
<string name="repeat_fortnight">Fortnightly</string>
|
||||||
|
<string name="repeat_month">Monthly</string>
|
||||||
|
<string name="repeat_year">Yearly</string>
|
||||||
|
|
||||||
|
<string name="payment_mode_none">None</string>
|
||||||
|
<string name="payment_mode_all">All</string>
|
||||||
|
<string name="payment_mode_credit_card">Credit card</string>
|
||||||
|
<string name="payment_mode_cash">Cash</string>
|
||||||
|
<string name="payment_mode_check">Check</string>
|
||||||
|
<string name="payment_mode_online">Online</string>
|
||||||
|
<string name="payment_mode_transfer">Transfer</string>
|
||||||
|
|
||||||
|
<string name="category_none">None</string>
|
||||||
|
<string name="category_all">All</string>
|
||||||
|
<string name="category_all_except_reimbursement">All except reimbursement</string>
|
||||||
|
<string name="category_groceries">Grocery</string>
|
||||||
|
<string name="category_leisure">Bar/Party</string>
|
||||||
|
<string name="category_rent">Rent</string>
|
||||||
|
<string name="category_bills">Bill</string>
|
||||||
|
<string name="category_excursion">Excursion/Culture</string>
|
||||||
|
<string name="category_health">Health</string>
|
||||||
|
<string name="category_shopping">Shopping</string>
|
||||||
|
<string name="category_reimbursement">Reimbursement</string>
|
||||||
|
<string name="category_restaurant">Restaurant</string>
|
||||||
|
<string name="category_accomodation">Accommodation</string>
|
||||||
|
<string name="category_transport">Transport</string>
|
||||||
|
<string name="category_sport">Sport</string>
|
||||||
|
|
||||||
|
<!-- Project specific -->
|
||||||
|
<string name="new_project_action">What</string>
|
||||||
|
<string name="new_project_where">Where</string>
|
||||||
|
<string name="where_local">Local only</string>
|
||||||
|
<string name="todo_join">Join existing project</string>
|
||||||
|
<string name="todo_create">Create new project</string>
|
||||||
|
<string name="import_tooltip">Import from file</string>
|
||||||
|
<string name="choose_project_management_action">Project</string>
|
||||||
|
<string name="project_added_success">Project added successfully.</string>
|
||||||
|
<string name="no_projects_text">You have no projects yet.</string>
|
||||||
|
<string name="configure_account_choice">Configure Nextcloud account</string>
|
||||||
|
<string name="add_project_choice">Add project manually</string>
|
||||||
|
<string name="no_members_text">No members in this project.</string>
|
||||||
|
<string name="no_bills_text">No bills found.</string>
|
||||||
|
<string name="member_already_exists">Member already exists.</string>
|
||||||
|
<string name="activity_dialog_title">Project: %1$s</string>
|
||||||
|
<string name="remove_project_confirmation">Project %1$s removed.</string>
|
||||||
|
<string name="file_saved_success">File saved: %1$s</string>
|
||||||
|
<string name="import_error_header">Import failed at row %d</string>
|
||||||
|
<string name="import_error_date">Invalid date format at row %d</string>
|
||||||
|
<string name="import_error_owers">Invalid owers at row %d</string>
|
||||||
|
<string name="add_member_dialog_title">Add Member</string>
|
||||||
|
<string name="edit_member_dialog_title">Edit Member</string>
|
||||||
|
<string name="member_edit_delete">Delete</string>
|
||||||
|
<string name="project_edition_no_change">No changes to save.</string>
|
||||||
|
|
||||||
|
<!-- Settlement -->
|
||||||
|
<string name="center_none">None (Optimal)</string>
|
||||||
|
<string name="settle_who">Who pays</string>
|
||||||
|
<string name="settle_to_whom">To whom</string>
|
||||||
|
<string name="settle_how_much">Amount</string>
|
||||||
|
<string name="simple_settle_share">Share</string>
|
||||||
|
<string name="simple_create_bills">Create bills</string>
|
||||||
|
<string name="settle_bill_what">Settlement</string>
|
||||||
|
|
||||||
|
<!-- Currencies -->
|
||||||
|
<string name="currency_dialog_title">Choose Currency (%s)</string>
|
||||||
|
<string name="setting_none">None</string>
|
||||||
|
<string name="setting_all">All</string>
|
||||||
|
<string name="currency_saved_success">Currency settings saved.</string>
|
||||||
|
<string name="main_currency">Main Currency</string>
|
||||||
|
|
||||||
|
<!-- Statistics -->
|
||||||
|
<string name="label_bills_suggested">Suggested Categories</string>
|
||||||
|
<string name="label_bills_skip">Skip</string>
|
||||||
|
<string name="stats_date_min">From</string>
|
||||||
|
<string name="stats_date_max">To</string>
|
||||||
|
<string name="stats_who">Member</string>
|
||||||
|
<string name="stats_paid">Paid</string>
|
||||||
|
<string name="stats_spent">Spent</string>
|
||||||
|
<string name="stats_balance">Balance</string>
|
||||||
|
<string name="total">Total: %1$s</string>
|
||||||
|
|
||||||
|
<!-- Errors Extra -->
|
||||||
|
<string name="error_project_connect_check">Connection failed: %1$s</string>
|
||||||
|
<string name="error_create_remote_project_helper">Creation failed: %1$s</string>
|
||||||
|
<string name="error_edit_remote_project_helper">Error updating remote project: %1$s</string>
|
||||||
|
<string name="remote_project_operation_no_network">Network unavailable for remote operation.</string>
|
||||||
|
<string name="error_scanning_bill_qr_code">Failed to parse QR code.</string>
|
||||||
|
<string name="error_token_mismatch">Authentication token mismatch. Please log in again.</string>
|
||||||
|
<string name="insufficient_access_level">You don\'t have permission to perform this action.</string>
|
||||||
|
<string name="delete_label_confirmation_title">Delete Label</string>
|
||||||
|
<string name="delete_label_confirmation_message">Are you sure you want to delete this label?</string>
|
||||||
|
|
||||||
|
<!-- About -->
|
||||||
|
<string name="about_version">Version %1$s</string>
|
||||||
|
<string name="about_maintainer_title">Maintainer</string>
|
||||||
|
<string name="about_license_title">License</string>
|
||||||
|
<string name="about_source_title">Source code</string>
|
||||||
|
|
||||||
|
<!-- New constants for backward compatibility or shared use -->
|
||||||
|
<string name="share_intent_title">Project %1$s</string>
|
||||||
|
<string name="share_chooser_title">Share %1$s</string>
|
||||||
|
|
||||||
|
</resources>
|
||||||
@@ -0,0 +1,272 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Untranslated: these are the English strings, kept here so a translation can be
|
||||||
|
contributed by simply replacing the values. Strings marked translatable="false" in
|
||||||
|
values/strings.xml (app and product names, preference keys) are deliberately absent
|
||||||
|
and must not be added.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- Actions -->
|
||||||
|
<string name="action_new_bill">New bill</string>
|
||||||
|
<string name="action_add_project">Add project</string>
|
||||||
|
<string name="action_save">Save</string>
|
||||||
|
<string name="action_edit">Edit</string>
|
||||||
|
<string name="action_share">Share</string>
|
||||||
|
<string name="action_search">Search</string>
|
||||||
|
<string name="action_open_menu">Open menu</string>
|
||||||
|
<string name="action_close_search">Close search</string>
|
||||||
|
<string name="action_clear_search">Clear search</string>
|
||||||
|
<string name="action_delete">Delete</string>
|
||||||
|
<string name="simple_back">Back</string>
|
||||||
|
<string name="action_archive">Archive</string>
|
||||||
|
<string name="action_unarchive">Unarchive</string>
|
||||||
|
<string name="action_export">Export</string>
|
||||||
|
<string name="action_stats">Stats</string>
|
||||||
|
<string name="action_settle">Settle</string>
|
||||||
|
<string name="action_scan_qrcode">Scan QR Code</string>
|
||||||
|
<string name="action_settings">Settings</string>
|
||||||
|
<string name="action_label_bills">Label missing categories</string>
|
||||||
|
<string name="action_logout">Logout</string>
|
||||||
|
<string name="action_connect">Connect</string>
|
||||||
|
<string name="action_discard">Discard</string>
|
||||||
|
<string name="action_members">Members</string>
|
||||||
|
<string name="action_labels">Labels</string>
|
||||||
|
<string name="action_currencies">Currencies</string>
|
||||||
|
|
||||||
|
<!-- Titles -->
|
||||||
|
<string name="title_stats">Statistics</string>
|
||||||
|
<string name="title_edit_project">Edit project</string>
|
||||||
|
<string name="title_label_bills">Label Bills</string>
|
||||||
|
<string name="title_labels">Manage Labels</string>
|
||||||
|
<string name="title_about">About</string>
|
||||||
|
<string name="title_settle">Settle Project</string>
|
||||||
|
<string name="title_share">Share Project</string>
|
||||||
|
<string name="title_add_project">Add Project</string>
|
||||||
|
<string name="title_add_category">Add Category</string>
|
||||||
|
<string name="title_add_payment_mode">Add Payment Mode</string>
|
||||||
|
<string name="title_account">Nextcloud Account</string>
|
||||||
|
<string name="title_share_web">Web link</string>
|
||||||
|
<string name="title_share_qr">Cowspent link</string>
|
||||||
|
<string name="title_confirm">Are you sure?</string>
|
||||||
|
|
||||||
|
<!-- Labels and Fields -->
|
||||||
|
<string name="label_all_bills">All bills</string>
|
||||||
|
<string name="label_categories">Categories</string>
|
||||||
|
<string name="label_payment_modes">Payment Modes</string>
|
||||||
|
<string name="label_name">Name</string>
|
||||||
|
<string name="label_icon">Icon / Emoji</string>
|
||||||
|
<string name="label_color">Color</string>
|
||||||
|
<string name="label_weight">Weight</string>
|
||||||
|
<string name="label_activated">Activated</string>
|
||||||
|
<string name="label_password">Password</string>
|
||||||
|
<string name="label_email">E-mail</string>
|
||||||
|
<string name="label_url">Server address</string>
|
||||||
|
<string name="label_username">Username</string>
|
||||||
|
<string name="label_comment">Comment</string>
|
||||||
|
<string name="label_what">What?</string>
|
||||||
|
<string name="label_payer">Who paid?</string>
|
||||||
|
<string name="label_owers">For whom?</string>
|
||||||
|
<string name="label_repeat">Repeat every</string>
|
||||||
|
<string name="label_mode">Mode</string>
|
||||||
|
<string name="label_category">Category</string>
|
||||||
|
<string name="label_project_id">Project ID/name</string>
|
||||||
|
<string name="label_project_title">Project title</string>
|
||||||
|
<string name="label_use_sso">Use Nextcloud App Account</string>
|
||||||
|
|
||||||
|
<!-- Dialogs and Messages -->
|
||||||
|
<string name="dialog_unsaved_changes_title">Unsaved changes</string>
|
||||||
|
<string name="dialog_unsaved_changes_msg">Save changes before leaving?</string>
|
||||||
|
<string name="dialog_confirm_remove_project_msg">The remote project will not be deleted.</string>
|
||||||
|
<string name="dialog_sync_error_title">Sync error</string>
|
||||||
|
<string name="dialog_sync_error_msg">Sync failed for %1$s.\n\n%2$s</string>
|
||||||
|
<string name="dialog_balanced_msg">Expenses are already balanced.</string>
|
||||||
|
<string name="msg_project_added">Project %1$s added</string>
|
||||||
|
<string name="msg_bill_labeled_done">All bills labeled</string>
|
||||||
|
<string name="msg_no_suggestions">No suggestions</string>
|
||||||
|
<string name="msg_auth_warning">Requires Cospend v0.3.4+.</string>
|
||||||
|
<string name="msg_link_copied">Link copied to clipboard</string>
|
||||||
|
<string name="msg_share_qr">Scan QR code or share the link to join.</string>
|
||||||
|
<string name="msg_share_web">Link for web browser access.</string>
|
||||||
|
<string name="msg_share_qr_warn">Share this link with a Cowspent user.</string>
|
||||||
|
<string name="msg_settle_intro">Settlement for %1$s:</string>
|
||||||
|
<string name="msg_settle_sentence">%1$s owes %3$.2f to %2$s</string>
|
||||||
|
<string name="msg_stats_intro">Stats for %1$s:</string>
|
||||||
|
<string name="msg_stats_header">Member (Paid | Spent | Balance)</string>
|
||||||
|
<string name="msg_logged_in_as">Logged in as %1$s</string>
|
||||||
|
|
||||||
|
<!-- Errors -->
|
||||||
|
<string name="error_generic">Error</string>
|
||||||
|
<string name="error_loading">Loading</string>
|
||||||
|
<string name="error_no_projects">No projects found</string>
|
||||||
|
<string name="error_no_members">No members found</string>
|
||||||
|
<string name="error_no_bills">No bills found</string>
|
||||||
|
<string name="error_no_member">At least one member required</string>
|
||||||
|
<string name="error_maintenance_mode">Server is in maintenance mode</string>
|
||||||
|
<string name="error_400">400 Bad request</string>
|
||||||
|
<string name="error_401">401 Unauthorized</string>
|
||||||
|
<string name="error_403">403 Forbidden</string>
|
||||||
|
<string name="error_404">404 Not Found</string>
|
||||||
|
<string name="error_sync">Sync failed: %1$s</string>
|
||||||
|
<string name="error_invalid_login">Invalid login: %1$s</string>
|
||||||
|
<string name="error_auth">Wrong username or password</string>
|
||||||
|
<string name="error_json">Invalid server response</string>
|
||||||
|
<string name="error_req_failed">Request failed</string>
|
||||||
|
<string name="error_invalid_email">Invalid e-mail</string>
|
||||||
|
<string name="error_invalid_project_id">Invalid project ID</string>
|
||||||
|
<string name="error_invalid_project_name">Invalid project title</string>
|
||||||
|
<string name="error_invalid_bill_name">Invalid bill name</string>
|
||||||
|
<string name="error_invalid_bill_date">Invalid bill date</string>
|
||||||
|
<string name="error_invalid_bill_payer">Payer required</string>
|
||||||
|
<string name="error_invalid_bill_owers">Owers required</string>
|
||||||
|
<string name="error_no_network">No network connection</string>
|
||||||
|
<string name="error_server">Server error</string>
|
||||||
|
<string name="error_io">Server connection broken</string>
|
||||||
|
<string name="error_share_impossible">Cannot share this project</string>
|
||||||
|
|
||||||
|
<!-- Drawer / Common UI -->
|
||||||
|
<string name="drawer_no_account">Connect to Nextcloud account</string>
|
||||||
|
<string name="drawer_last_sync">Last sync: %1$02d:%2$02d</string>
|
||||||
|
<string name="simple_cancel">Cancel</string>
|
||||||
|
<string name="simple_ok" tools:ignore="ButtonCase,Typos">Ok</string>
|
||||||
|
<string name="simple_yes">Yes</string>
|
||||||
|
<string name="simple_no">No</string>
|
||||||
|
<string name="simple_close">Close</string>
|
||||||
|
|
||||||
|
<!-- Settings -->
|
||||||
|
<string name="settings_appearance">Appearance</string>
|
||||||
|
<string name="settings_network">Network</string>
|
||||||
|
<string name="settings_other">Other</string>
|
||||||
|
<string name="settings_night_mode">Theme</string>
|
||||||
|
<string name="settings_offline_mode">Offline mode</string>
|
||||||
|
<string name="settings_offline_mode_summary">Only sync manually.</string>
|
||||||
|
<string name="settings_color_custom">Custom color</string>
|
||||||
|
<string name="settings_color_mode">Color Selection</string>
|
||||||
|
<string name="settings_show_archived">Show archived projects</string>
|
||||||
|
<string name="settings_beta_features">Beta Features</string>
|
||||||
|
<string name="settings_beta_features_summary">Enable experimental features. Use at your own risk.</string>
|
||||||
|
<string name="settings_fill_new_bill_from_last">Auto-fill from last bill</string>
|
||||||
|
<string name="settings_fill_new_bill_from_last_summary">Pre-fill payer, category, mode and owers from the last bill created in the project.</string>
|
||||||
|
<string name="settings_auto_sync_on_open">Sync interval</string>
|
||||||
|
<string name="settings_auto_sync_on_open_summary">How often to refresh the account and all projects when opening the app.</string>
|
||||||
|
<string name="pref_value_sync_1m">1 minute</string>
|
||||||
|
<string name="pref_value_sync_10m">10 minutes</string>
|
||||||
|
<string name="pref_value_sync_1h">1 hour</string>
|
||||||
|
<string name="pref_value_sync_1d">1 day</string>
|
||||||
|
<string name="settings_url_warn_http">WARNING: "http" is unsafe. Use "https".</string>
|
||||||
|
<string name="settings_colorpicker_title">Choose Color</string>
|
||||||
|
|
||||||
|
<string name="pref_value_color_system">System</string>
|
||||||
|
<string name="pref_value_color_manual">Manual</string>
|
||||||
|
<string name="pref_value_theme_light">Light</string>
|
||||||
|
<string name="pref_value_theme_dark">Dark</string>
|
||||||
|
<string name="pref_value_theme_system">Follow system</string>
|
||||||
|
|
||||||
|
<!-- Enums and Lists -->
|
||||||
|
<string name="repeat_no">No repeat</string>
|
||||||
|
<string name="repeat_day">Daily</string>
|
||||||
|
<string name="repeat_week">Weekly</string>
|
||||||
|
<string name="repeat_fortnight">Fortnightly</string>
|
||||||
|
<string name="repeat_month">Monthly</string>
|
||||||
|
<string name="repeat_year">Yearly</string>
|
||||||
|
|
||||||
|
<string name="payment_mode_none">None</string>
|
||||||
|
<string name="payment_mode_all">All</string>
|
||||||
|
<string name="payment_mode_credit_card">Credit card</string>
|
||||||
|
<string name="payment_mode_cash">Cash</string>
|
||||||
|
<string name="payment_mode_check">Check</string>
|
||||||
|
<string name="payment_mode_online">Online</string>
|
||||||
|
<string name="payment_mode_transfer">Transfer</string>
|
||||||
|
|
||||||
|
<string name="category_none">None</string>
|
||||||
|
<string name="category_all">All</string>
|
||||||
|
<string name="category_all_except_reimbursement">All except reimbursement</string>
|
||||||
|
<string name="category_groceries">Grocery</string>
|
||||||
|
<string name="category_leisure">Bar/Party</string>
|
||||||
|
<string name="category_rent">Rent</string>
|
||||||
|
<string name="category_bills">Bill</string>
|
||||||
|
<string name="category_excursion">Excursion/Culture</string>
|
||||||
|
<string name="category_health">Health</string>
|
||||||
|
<string name="category_shopping">Shopping</string>
|
||||||
|
<string name="category_reimbursement">Reimbursement</string>
|
||||||
|
<string name="category_restaurant">Restaurant</string>
|
||||||
|
<string name="category_accomodation">Accommodation</string>
|
||||||
|
<string name="category_transport">Transport</string>
|
||||||
|
<string name="category_sport">Sport</string>
|
||||||
|
|
||||||
|
<!-- Project specific -->
|
||||||
|
<string name="new_project_action">What</string>
|
||||||
|
<string name="new_project_where">Where</string>
|
||||||
|
<string name="where_local">Local only</string>
|
||||||
|
<string name="todo_join">Join existing project</string>
|
||||||
|
<string name="todo_create">Create new project</string>
|
||||||
|
<string name="import_tooltip">Import from file</string>
|
||||||
|
<string name="choose_project_management_action">Project</string>
|
||||||
|
<string name="project_added_success">Project added successfully.</string>
|
||||||
|
<string name="no_projects_text">You have no projects yet.</string>
|
||||||
|
<string name="configure_account_choice">Configure Nextcloud account</string>
|
||||||
|
<string name="add_project_choice">Add project manually</string>
|
||||||
|
<string name="no_members_text">No members in this project.</string>
|
||||||
|
<string name="no_bills_text">No bills found.</string>
|
||||||
|
<string name="member_already_exists">Member already exists.</string>
|
||||||
|
<string name="activity_dialog_title">Project: %1$s</string>
|
||||||
|
<string name="remove_project_confirmation">Project %1$s removed.</string>
|
||||||
|
<string name="file_saved_success">File saved: %1$s</string>
|
||||||
|
<string name="import_error_header">Import failed at row %d</string>
|
||||||
|
<string name="import_error_date">Invalid date format at row %d</string>
|
||||||
|
<string name="import_error_owers">Invalid owers at row %d</string>
|
||||||
|
<string name="add_member_dialog_title">Add Member</string>
|
||||||
|
<string name="edit_member_dialog_title">Edit Member</string>
|
||||||
|
<string name="member_edit_delete">Delete</string>
|
||||||
|
<string name="project_edition_no_change">No changes to save.</string>
|
||||||
|
|
||||||
|
<!-- Settlement -->
|
||||||
|
<string name="center_none">None (Optimal)</string>
|
||||||
|
<string name="settle_who">Who pays</string>
|
||||||
|
<string name="settle_to_whom">To whom</string>
|
||||||
|
<string name="settle_how_much">Amount</string>
|
||||||
|
<string name="simple_settle_share">Share</string>
|
||||||
|
<string name="simple_create_bills">Create bills</string>
|
||||||
|
<string name="settle_bill_what">Settlement</string>
|
||||||
|
|
||||||
|
<!-- Currencies -->
|
||||||
|
<string name="currency_dialog_title">Choose Currency (%s)</string>
|
||||||
|
<string name="setting_none">None</string>
|
||||||
|
<string name="setting_all">All</string>
|
||||||
|
<string name="currency_saved_success">Currency settings saved.</string>
|
||||||
|
<string name="main_currency">Main Currency</string>
|
||||||
|
|
||||||
|
<!-- Statistics -->
|
||||||
|
<string name="label_bills_suggested">Suggested Categories</string>
|
||||||
|
<string name="label_bills_skip">Skip</string>
|
||||||
|
<string name="stats_date_min">From</string>
|
||||||
|
<string name="stats_date_max">To</string>
|
||||||
|
<string name="stats_who">Member</string>
|
||||||
|
<string name="stats_paid">Paid</string>
|
||||||
|
<string name="stats_spent">Spent</string>
|
||||||
|
<string name="stats_balance">Balance</string>
|
||||||
|
<string name="total">Total: %1$s</string>
|
||||||
|
|
||||||
|
<!-- Errors Extra -->
|
||||||
|
<string name="error_project_connect_check">Connection failed: %1$s</string>
|
||||||
|
<string name="error_create_remote_project_helper">Creation failed: %1$s</string>
|
||||||
|
<string name="error_edit_remote_project_helper">Error updating remote project: %1$s</string>
|
||||||
|
<string name="remote_project_operation_no_network">Network unavailable for remote operation.</string>
|
||||||
|
<string name="error_scanning_bill_qr_code">Failed to parse QR code.</string>
|
||||||
|
<string name="error_token_mismatch">Authentication token mismatch. Please log in again.</string>
|
||||||
|
<string name="insufficient_access_level">You don\'t have permission to perform this action.</string>
|
||||||
|
<string name="delete_label_confirmation_title">Delete Label</string>
|
||||||
|
<string name="delete_label_confirmation_message">Are you sure you want to delete this label?</string>
|
||||||
|
|
||||||
|
<!-- About -->
|
||||||
|
<string name="about_version">Version %1$s</string>
|
||||||
|
<string name="about_maintainer_title">Maintainer</string>
|
||||||
|
<string name="about_license_title">License</string>
|
||||||
|
<string name="about_source_title">Source code</string>
|
||||||
|
|
||||||
|
<!-- New constants for backward compatibility or shared use -->
|
||||||
|
<string name="share_intent_title">Project %1$s</string>
|
||||||
|
<string name="share_chooser_title">Share %1$s</string>
|
||||||
|
|
||||||
|
</resources>
|
||||||
@@ -0,0 +1,272 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Untranslated: these are the English strings, kept here so a translation can be
|
||||||
|
contributed by simply replacing the values. Strings marked translatable="false" in
|
||||||
|
values/strings.xml (app and product names, preference keys) are deliberately absent
|
||||||
|
and must not be added.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- Actions -->
|
||||||
|
<string name="action_new_bill">New bill</string>
|
||||||
|
<string name="action_add_project">Add project</string>
|
||||||
|
<string name="action_save">Save</string>
|
||||||
|
<string name="action_edit">Edit</string>
|
||||||
|
<string name="action_share">Share</string>
|
||||||
|
<string name="action_search">Search</string>
|
||||||
|
<string name="action_open_menu">Open menu</string>
|
||||||
|
<string name="action_close_search">Close search</string>
|
||||||
|
<string name="action_clear_search">Clear search</string>
|
||||||
|
<string name="action_delete">Delete</string>
|
||||||
|
<string name="simple_back">Back</string>
|
||||||
|
<string name="action_archive">Archive</string>
|
||||||
|
<string name="action_unarchive">Unarchive</string>
|
||||||
|
<string name="action_export">Export</string>
|
||||||
|
<string name="action_stats">Stats</string>
|
||||||
|
<string name="action_settle">Settle</string>
|
||||||
|
<string name="action_scan_qrcode">Scan QR Code</string>
|
||||||
|
<string name="action_settings">Settings</string>
|
||||||
|
<string name="action_label_bills">Label missing categories</string>
|
||||||
|
<string name="action_logout">Logout</string>
|
||||||
|
<string name="action_connect">Connect</string>
|
||||||
|
<string name="action_discard">Discard</string>
|
||||||
|
<string name="action_members">Members</string>
|
||||||
|
<string name="action_labels">Labels</string>
|
||||||
|
<string name="action_currencies">Currencies</string>
|
||||||
|
|
||||||
|
<!-- Titles -->
|
||||||
|
<string name="title_stats">Statistics</string>
|
||||||
|
<string name="title_edit_project">Edit project</string>
|
||||||
|
<string name="title_label_bills">Label Bills</string>
|
||||||
|
<string name="title_labels">Manage Labels</string>
|
||||||
|
<string name="title_about">About</string>
|
||||||
|
<string name="title_settle">Settle Project</string>
|
||||||
|
<string name="title_share">Share Project</string>
|
||||||
|
<string name="title_add_project">Add Project</string>
|
||||||
|
<string name="title_add_category">Add Category</string>
|
||||||
|
<string name="title_add_payment_mode">Add Payment Mode</string>
|
||||||
|
<string name="title_account">Nextcloud Account</string>
|
||||||
|
<string name="title_share_web">Web link</string>
|
||||||
|
<string name="title_share_qr">Cowspent link</string>
|
||||||
|
<string name="title_confirm">Are you sure?</string>
|
||||||
|
|
||||||
|
<!-- Labels and Fields -->
|
||||||
|
<string name="label_all_bills">All bills</string>
|
||||||
|
<string name="label_categories">Categories</string>
|
||||||
|
<string name="label_payment_modes">Payment Modes</string>
|
||||||
|
<string name="label_name">Name</string>
|
||||||
|
<string name="label_icon">Icon / Emoji</string>
|
||||||
|
<string name="label_color">Color</string>
|
||||||
|
<string name="label_weight">Weight</string>
|
||||||
|
<string name="label_activated">Activated</string>
|
||||||
|
<string name="label_password">Password</string>
|
||||||
|
<string name="label_email">E-mail</string>
|
||||||
|
<string name="label_url">Server address</string>
|
||||||
|
<string name="label_username">Username</string>
|
||||||
|
<string name="label_comment">Comment</string>
|
||||||
|
<string name="label_what">What?</string>
|
||||||
|
<string name="label_payer">Who paid?</string>
|
||||||
|
<string name="label_owers">For whom?</string>
|
||||||
|
<string name="label_repeat">Repeat every</string>
|
||||||
|
<string name="label_mode">Mode</string>
|
||||||
|
<string name="label_category">Category</string>
|
||||||
|
<string name="label_project_id">Project ID/name</string>
|
||||||
|
<string name="label_project_title">Project title</string>
|
||||||
|
<string name="label_use_sso">Use Nextcloud App Account</string>
|
||||||
|
|
||||||
|
<!-- Dialogs and Messages -->
|
||||||
|
<string name="dialog_unsaved_changes_title">Unsaved changes</string>
|
||||||
|
<string name="dialog_unsaved_changes_msg">Save changes before leaving?</string>
|
||||||
|
<string name="dialog_confirm_remove_project_msg">The remote project will not be deleted.</string>
|
||||||
|
<string name="dialog_sync_error_title">Sync error</string>
|
||||||
|
<string name="dialog_sync_error_msg">Sync failed for %1$s.\n\n%2$s</string>
|
||||||
|
<string name="dialog_balanced_msg">Expenses are already balanced.</string>
|
||||||
|
<string name="msg_project_added">Project %1$s added</string>
|
||||||
|
<string name="msg_bill_labeled_done">All bills labeled</string>
|
||||||
|
<string name="msg_no_suggestions">No suggestions</string>
|
||||||
|
<string name="msg_auth_warning">Requires Cospend v0.3.4+.</string>
|
||||||
|
<string name="msg_link_copied">Link copied to clipboard</string>
|
||||||
|
<string name="msg_share_qr">Scan QR code or share the link to join.</string>
|
||||||
|
<string name="msg_share_web">Link for web browser access.</string>
|
||||||
|
<string name="msg_share_qr_warn">Share this link with a Cowspent user.</string>
|
||||||
|
<string name="msg_settle_intro">Settlement for %1$s:</string>
|
||||||
|
<string name="msg_settle_sentence">%1$s owes %3$.2f to %2$s</string>
|
||||||
|
<string name="msg_stats_intro">Stats for %1$s:</string>
|
||||||
|
<string name="msg_stats_header">Member (Paid | Spent | Balance)</string>
|
||||||
|
<string name="msg_logged_in_as">Logged in as %1$s</string>
|
||||||
|
|
||||||
|
<!-- Errors -->
|
||||||
|
<string name="error_generic">Error</string>
|
||||||
|
<string name="error_loading">Loading</string>
|
||||||
|
<string name="error_no_projects">No projects found</string>
|
||||||
|
<string name="error_no_members">No members found</string>
|
||||||
|
<string name="error_no_bills">No bills found</string>
|
||||||
|
<string name="error_no_member">At least one member required</string>
|
||||||
|
<string name="error_maintenance_mode">Server is in maintenance mode</string>
|
||||||
|
<string name="error_400">400 Bad request</string>
|
||||||
|
<string name="error_401">401 Unauthorized</string>
|
||||||
|
<string name="error_403">403 Forbidden</string>
|
||||||
|
<string name="error_404">404 Not Found</string>
|
||||||
|
<string name="error_sync">Sync failed: %1$s</string>
|
||||||
|
<string name="error_invalid_login">Invalid login: %1$s</string>
|
||||||
|
<string name="error_auth">Wrong username or password</string>
|
||||||
|
<string name="error_json">Invalid server response</string>
|
||||||
|
<string name="error_req_failed">Request failed</string>
|
||||||
|
<string name="error_invalid_email">Invalid e-mail</string>
|
||||||
|
<string name="error_invalid_project_id">Invalid project ID</string>
|
||||||
|
<string name="error_invalid_project_name">Invalid project title</string>
|
||||||
|
<string name="error_invalid_bill_name">Invalid bill name</string>
|
||||||
|
<string name="error_invalid_bill_date">Invalid bill date</string>
|
||||||
|
<string name="error_invalid_bill_payer">Payer required</string>
|
||||||
|
<string name="error_invalid_bill_owers">Owers required</string>
|
||||||
|
<string name="error_no_network">No network connection</string>
|
||||||
|
<string name="error_server">Server error</string>
|
||||||
|
<string name="error_io">Server connection broken</string>
|
||||||
|
<string name="error_share_impossible">Cannot share this project</string>
|
||||||
|
|
||||||
|
<!-- Drawer / Common UI -->
|
||||||
|
<string name="drawer_no_account">Connect to Nextcloud account</string>
|
||||||
|
<string name="drawer_last_sync">Last sync: %1$02d:%2$02d</string>
|
||||||
|
<string name="simple_cancel">Cancel</string>
|
||||||
|
<string name="simple_ok" tools:ignore="ButtonCase,Typos">Ok</string>
|
||||||
|
<string name="simple_yes">Yes</string>
|
||||||
|
<string name="simple_no">No</string>
|
||||||
|
<string name="simple_close">Close</string>
|
||||||
|
|
||||||
|
<!-- Settings -->
|
||||||
|
<string name="settings_appearance">Appearance</string>
|
||||||
|
<string name="settings_network">Network</string>
|
||||||
|
<string name="settings_other">Other</string>
|
||||||
|
<string name="settings_night_mode">Theme</string>
|
||||||
|
<string name="settings_offline_mode">Offline mode</string>
|
||||||
|
<string name="settings_offline_mode_summary">Only sync manually.</string>
|
||||||
|
<string name="settings_color_custom">Custom color</string>
|
||||||
|
<string name="settings_color_mode">Color Selection</string>
|
||||||
|
<string name="settings_show_archived">Show archived projects</string>
|
||||||
|
<string name="settings_beta_features">Beta Features</string>
|
||||||
|
<string name="settings_beta_features_summary">Enable experimental features. Use at your own risk.</string>
|
||||||
|
<string name="settings_fill_new_bill_from_last">Auto-fill from last bill</string>
|
||||||
|
<string name="settings_fill_new_bill_from_last_summary">Pre-fill payer, category, mode and owers from the last bill created in the project.</string>
|
||||||
|
<string name="settings_auto_sync_on_open">Sync interval</string>
|
||||||
|
<string name="settings_auto_sync_on_open_summary">How often to refresh the account and all projects when opening the app.</string>
|
||||||
|
<string name="pref_value_sync_1m">1 minute</string>
|
||||||
|
<string name="pref_value_sync_10m">10 minutes</string>
|
||||||
|
<string name="pref_value_sync_1h">1 hour</string>
|
||||||
|
<string name="pref_value_sync_1d">1 day</string>
|
||||||
|
<string name="settings_url_warn_http">WARNING: "http" is unsafe. Use "https".</string>
|
||||||
|
<string name="settings_colorpicker_title">Choose Color</string>
|
||||||
|
|
||||||
|
<string name="pref_value_color_system">System</string>
|
||||||
|
<string name="pref_value_color_manual">Manual</string>
|
||||||
|
<string name="pref_value_theme_light">Light</string>
|
||||||
|
<string name="pref_value_theme_dark">Dark</string>
|
||||||
|
<string name="pref_value_theme_system">Follow system</string>
|
||||||
|
|
||||||
|
<!-- Enums and Lists -->
|
||||||
|
<string name="repeat_no">No repeat</string>
|
||||||
|
<string name="repeat_day">Daily</string>
|
||||||
|
<string name="repeat_week">Weekly</string>
|
||||||
|
<string name="repeat_fortnight">Fortnightly</string>
|
||||||
|
<string name="repeat_month">Monthly</string>
|
||||||
|
<string name="repeat_year">Yearly</string>
|
||||||
|
|
||||||
|
<string name="payment_mode_none">None</string>
|
||||||
|
<string name="payment_mode_all">All</string>
|
||||||
|
<string name="payment_mode_credit_card">Credit card</string>
|
||||||
|
<string name="payment_mode_cash">Cash</string>
|
||||||
|
<string name="payment_mode_check">Check</string>
|
||||||
|
<string name="payment_mode_online">Online</string>
|
||||||
|
<string name="payment_mode_transfer">Transfer</string>
|
||||||
|
|
||||||
|
<string name="category_none">None</string>
|
||||||
|
<string name="category_all">All</string>
|
||||||
|
<string name="category_all_except_reimbursement">All except reimbursement</string>
|
||||||
|
<string name="category_groceries">Grocery</string>
|
||||||
|
<string name="category_leisure">Bar/Party</string>
|
||||||
|
<string name="category_rent">Rent</string>
|
||||||
|
<string name="category_bills">Bill</string>
|
||||||
|
<string name="category_excursion">Excursion/Culture</string>
|
||||||
|
<string name="category_health">Health</string>
|
||||||
|
<string name="category_shopping">Shopping</string>
|
||||||
|
<string name="category_reimbursement">Reimbursement</string>
|
||||||
|
<string name="category_restaurant">Restaurant</string>
|
||||||
|
<string name="category_accomodation">Accommodation</string>
|
||||||
|
<string name="category_transport">Transport</string>
|
||||||
|
<string name="category_sport">Sport</string>
|
||||||
|
|
||||||
|
<!-- Project specific -->
|
||||||
|
<string name="new_project_action">What</string>
|
||||||
|
<string name="new_project_where">Where</string>
|
||||||
|
<string name="where_local">Local only</string>
|
||||||
|
<string name="todo_join">Join existing project</string>
|
||||||
|
<string name="todo_create">Create new project</string>
|
||||||
|
<string name="import_tooltip">Import from file</string>
|
||||||
|
<string name="choose_project_management_action">Project</string>
|
||||||
|
<string name="project_added_success">Project added successfully.</string>
|
||||||
|
<string name="no_projects_text">You have no projects yet.</string>
|
||||||
|
<string name="configure_account_choice">Configure Nextcloud account</string>
|
||||||
|
<string name="add_project_choice">Add project manually</string>
|
||||||
|
<string name="no_members_text">No members in this project.</string>
|
||||||
|
<string name="no_bills_text">No bills found.</string>
|
||||||
|
<string name="member_already_exists">Member already exists.</string>
|
||||||
|
<string name="activity_dialog_title">Project: %1$s</string>
|
||||||
|
<string name="remove_project_confirmation">Project %1$s removed.</string>
|
||||||
|
<string name="file_saved_success">File saved: %1$s</string>
|
||||||
|
<string name="import_error_header">Import failed at row %d</string>
|
||||||
|
<string name="import_error_date">Invalid date format at row %d</string>
|
||||||
|
<string name="import_error_owers">Invalid owers at row %d</string>
|
||||||
|
<string name="add_member_dialog_title">Add Member</string>
|
||||||
|
<string name="edit_member_dialog_title">Edit Member</string>
|
||||||
|
<string name="member_edit_delete">Delete</string>
|
||||||
|
<string name="project_edition_no_change">No changes to save.</string>
|
||||||
|
|
||||||
|
<!-- Settlement -->
|
||||||
|
<string name="center_none">None (Optimal)</string>
|
||||||
|
<string name="settle_who">Who pays</string>
|
||||||
|
<string name="settle_to_whom">To whom</string>
|
||||||
|
<string name="settle_how_much">Amount</string>
|
||||||
|
<string name="simple_settle_share">Share</string>
|
||||||
|
<string name="simple_create_bills">Create bills</string>
|
||||||
|
<string name="settle_bill_what">Settlement</string>
|
||||||
|
|
||||||
|
<!-- Currencies -->
|
||||||
|
<string name="currency_dialog_title">Choose Currency (%s)</string>
|
||||||
|
<string name="setting_none">None</string>
|
||||||
|
<string name="setting_all">All</string>
|
||||||
|
<string name="currency_saved_success">Currency settings saved.</string>
|
||||||
|
<string name="main_currency">Main Currency</string>
|
||||||
|
|
||||||
|
<!-- Statistics -->
|
||||||
|
<string name="label_bills_suggested">Suggested Categories</string>
|
||||||
|
<string name="label_bills_skip">Skip</string>
|
||||||
|
<string name="stats_date_min">From</string>
|
||||||
|
<string name="stats_date_max">To</string>
|
||||||
|
<string name="stats_who">Member</string>
|
||||||
|
<string name="stats_paid">Paid</string>
|
||||||
|
<string name="stats_spent">Spent</string>
|
||||||
|
<string name="stats_balance">Balance</string>
|
||||||
|
<string name="total">Total: %1$s</string>
|
||||||
|
|
||||||
|
<!-- Errors Extra -->
|
||||||
|
<string name="error_project_connect_check">Connection failed: %1$s</string>
|
||||||
|
<string name="error_create_remote_project_helper">Creation failed: %1$s</string>
|
||||||
|
<string name="error_edit_remote_project_helper">Error updating remote project: %1$s</string>
|
||||||
|
<string name="remote_project_operation_no_network">Network unavailable for remote operation.</string>
|
||||||
|
<string name="error_scanning_bill_qr_code">Failed to parse QR code.</string>
|
||||||
|
<string name="error_token_mismatch">Authentication token mismatch. Please log in again.</string>
|
||||||
|
<string name="insufficient_access_level">You don\'t have permission to perform this action.</string>
|
||||||
|
<string name="delete_label_confirmation_title">Delete Label</string>
|
||||||
|
<string name="delete_label_confirmation_message">Are you sure you want to delete this label?</string>
|
||||||
|
|
||||||
|
<!-- About -->
|
||||||
|
<string name="about_version">Version %1$s</string>
|
||||||
|
<string name="about_maintainer_title">Maintainer</string>
|
||||||
|
<string name="about_license_title">License</string>
|
||||||
|
<string name="about_source_title">Source code</string>
|
||||||
|
|
||||||
|
<!-- New constants for backward compatibility or shared use -->
|
||||||
|
<string name="share_intent_title">Project %1$s</string>
|
||||||
|
<string name="share_chooser_title">Share %1$s</string>
|
||||||
|
|
||||||
|
</resources>
|
||||||
@@ -0,0 +1,272 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Untranslated: these are the English strings, kept here so a translation can be
|
||||||
|
contributed by simply replacing the values. Strings marked translatable="false" in
|
||||||
|
values/strings.xml (app and product names, preference keys) are deliberately absent
|
||||||
|
and must not be added.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- Actions -->
|
||||||
|
<string name="action_new_bill">New bill</string>
|
||||||
|
<string name="action_add_project">Add project</string>
|
||||||
|
<string name="action_save">Save</string>
|
||||||
|
<string name="action_edit">Edit</string>
|
||||||
|
<string name="action_share">Share</string>
|
||||||
|
<string name="action_search">Search</string>
|
||||||
|
<string name="action_open_menu">Open menu</string>
|
||||||
|
<string name="action_close_search">Close search</string>
|
||||||
|
<string name="action_clear_search">Clear search</string>
|
||||||
|
<string name="action_delete">Delete</string>
|
||||||
|
<string name="simple_back">Back</string>
|
||||||
|
<string name="action_archive">Archive</string>
|
||||||
|
<string name="action_unarchive">Unarchive</string>
|
||||||
|
<string name="action_export">Export</string>
|
||||||
|
<string name="action_stats">Stats</string>
|
||||||
|
<string name="action_settle">Settle</string>
|
||||||
|
<string name="action_scan_qrcode">Scan QR Code</string>
|
||||||
|
<string name="action_settings">Settings</string>
|
||||||
|
<string name="action_label_bills">Label missing categories</string>
|
||||||
|
<string name="action_logout">Logout</string>
|
||||||
|
<string name="action_connect">Connect</string>
|
||||||
|
<string name="action_discard">Discard</string>
|
||||||
|
<string name="action_members">Members</string>
|
||||||
|
<string name="action_labels">Labels</string>
|
||||||
|
<string name="action_currencies">Currencies</string>
|
||||||
|
|
||||||
|
<!-- Titles -->
|
||||||
|
<string name="title_stats">Statistics</string>
|
||||||
|
<string name="title_edit_project">Edit project</string>
|
||||||
|
<string name="title_label_bills">Label Bills</string>
|
||||||
|
<string name="title_labels">Manage Labels</string>
|
||||||
|
<string name="title_about">About</string>
|
||||||
|
<string name="title_settle">Settle Project</string>
|
||||||
|
<string name="title_share">Share Project</string>
|
||||||
|
<string name="title_add_project">Add Project</string>
|
||||||
|
<string name="title_add_category">Add Category</string>
|
||||||
|
<string name="title_add_payment_mode">Add Payment Mode</string>
|
||||||
|
<string name="title_account">Nextcloud Account</string>
|
||||||
|
<string name="title_share_web">Web link</string>
|
||||||
|
<string name="title_share_qr">Cowspent link</string>
|
||||||
|
<string name="title_confirm">Are you sure?</string>
|
||||||
|
|
||||||
|
<!-- Labels and Fields -->
|
||||||
|
<string name="label_all_bills">All bills</string>
|
||||||
|
<string name="label_categories">Categories</string>
|
||||||
|
<string name="label_payment_modes">Payment Modes</string>
|
||||||
|
<string name="label_name">Name</string>
|
||||||
|
<string name="label_icon">Icon / Emoji</string>
|
||||||
|
<string name="label_color">Color</string>
|
||||||
|
<string name="label_weight">Weight</string>
|
||||||
|
<string name="label_activated">Activated</string>
|
||||||
|
<string name="label_password">Password</string>
|
||||||
|
<string name="label_email">E-mail</string>
|
||||||
|
<string name="label_url">Server address</string>
|
||||||
|
<string name="label_username">Username</string>
|
||||||
|
<string name="label_comment">Comment</string>
|
||||||
|
<string name="label_what">What?</string>
|
||||||
|
<string name="label_payer">Who paid?</string>
|
||||||
|
<string name="label_owers">For whom?</string>
|
||||||
|
<string name="label_repeat">Repeat every</string>
|
||||||
|
<string name="label_mode">Mode</string>
|
||||||
|
<string name="label_category">Category</string>
|
||||||
|
<string name="label_project_id">Project ID/name</string>
|
||||||
|
<string name="label_project_title">Project title</string>
|
||||||
|
<string name="label_use_sso">Use Nextcloud App Account</string>
|
||||||
|
|
||||||
|
<!-- Dialogs and Messages -->
|
||||||
|
<string name="dialog_unsaved_changes_title">Unsaved changes</string>
|
||||||
|
<string name="dialog_unsaved_changes_msg">Save changes before leaving?</string>
|
||||||
|
<string name="dialog_confirm_remove_project_msg">The remote project will not be deleted.</string>
|
||||||
|
<string name="dialog_sync_error_title">Sync error</string>
|
||||||
|
<string name="dialog_sync_error_msg">Sync failed for %1$s.\n\n%2$s</string>
|
||||||
|
<string name="dialog_balanced_msg">Expenses are already balanced.</string>
|
||||||
|
<string name="msg_project_added">Project %1$s added</string>
|
||||||
|
<string name="msg_bill_labeled_done">All bills labeled</string>
|
||||||
|
<string name="msg_no_suggestions">No suggestions</string>
|
||||||
|
<string name="msg_auth_warning">Requires Cospend v0.3.4+.</string>
|
||||||
|
<string name="msg_link_copied">Link copied to clipboard</string>
|
||||||
|
<string name="msg_share_qr">Scan QR code or share the link to join.</string>
|
||||||
|
<string name="msg_share_web">Link for web browser access.</string>
|
||||||
|
<string name="msg_share_qr_warn">Share this link with a Cowspent user.</string>
|
||||||
|
<string name="msg_settle_intro">Settlement for %1$s:</string>
|
||||||
|
<string name="msg_settle_sentence">%1$s owes %3$.2f to %2$s</string>
|
||||||
|
<string name="msg_stats_intro">Stats for %1$s:</string>
|
||||||
|
<string name="msg_stats_header">Member (Paid | Spent | Balance)</string>
|
||||||
|
<string name="msg_logged_in_as">Logged in as %1$s</string>
|
||||||
|
|
||||||
|
<!-- Errors -->
|
||||||
|
<string name="error_generic">Error</string>
|
||||||
|
<string name="error_loading">Loading</string>
|
||||||
|
<string name="error_no_projects">No projects found</string>
|
||||||
|
<string name="error_no_members">No members found</string>
|
||||||
|
<string name="error_no_bills">No bills found</string>
|
||||||
|
<string name="error_no_member">At least one member required</string>
|
||||||
|
<string name="error_maintenance_mode">Server is in maintenance mode</string>
|
||||||
|
<string name="error_400">400 Bad request</string>
|
||||||
|
<string name="error_401">401 Unauthorized</string>
|
||||||
|
<string name="error_403">403 Forbidden</string>
|
||||||
|
<string name="error_404">404 Not Found</string>
|
||||||
|
<string name="error_sync">Sync failed: %1$s</string>
|
||||||
|
<string name="error_invalid_login">Invalid login: %1$s</string>
|
||||||
|
<string name="error_auth">Wrong username or password</string>
|
||||||
|
<string name="error_json">Invalid server response</string>
|
||||||
|
<string name="error_req_failed">Request failed</string>
|
||||||
|
<string name="error_invalid_email">Invalid e-mail</string>
|
||||||
|
<string name="error_invalid_project_id">Invalid project ID</string>
|
||||||
|
<string name="error_invalid_project_name">Invalid project title</string>
|
||||||
|
<string name="error_invalid_bill_name">Invalid bill name</string>
|
||||||
|
<string name="error_invalid_bill_date">Invalid bill date</string>
|
||||||
|
<string name="error_invalid_bill_payer">Payer required</string>
|
||||||
|
<string name="error_invalid_bill_owers">Owers required</string>
|
||||||
|
<string name="error_no_network">No network connection</string>
|
||||||
|
<string name="error_server">Server error</string>
|
||||||
|
<string name="error_io">Server connection broken</string>
|
||||||
|
<string name="error_share_impossible">Cannot share this project</string>
|
||||||
|
|
||||||
|
<!-- Drawer / Common UI -->
|
||||||
|
<string name="drawer_no_account">Connect to Nextcloud account</string>
|
||||||
|
<string name="drawer_last_sync">Last sync: %1$02d:%2$02d</string>
|
||||||
|
<string name="simple_cancel">Cancel</string>
|
||||||
|
<string name="simple_ok" tools:ignore="ButtonCase,Typos">Ok</string>
|
||||||
|
<string name="simple_yes">Yes</string>
|
||||||
|
<string name="simple_no">No</string>
|
||||||
|
<string name="simple_close">Close</string>
|
||||||
|
|
||||||
|
<!-- Settings -->
|
||||||
|
<string name="settings_appearance">Appearance</string>
|
||||||
|
<string name="settings_network">Network</string>
|
||||||
|
<string name="settings_other">Other</string>
|
||||||
|
<string name="settings_night_mode">Theme</string>
|
||||||
|
<string name="settings_offline_mode">Offline mode</string>
|
||||||
|
<string name="settings_offline_mode_summary">Only sync manually.</string>
|
||||||
|
<string name="settings_color_custom">Custom color</string>
|
||||||
|
<string name="settings_color_mode">Color Selection</string>
|
||||||
|
<string name="settings_show_archived">Show archived projects</string>
|
||||||
|
<string name="settings_beta_features">Beta Features</string>
|
||||||
|
<string name="settings_beta_features_summary">Enable experimental features. Use at your own risk.</string>
|
||||||
|
<string name="settings_fill_new_bill_from_last">Auto-fill from last bill</string>
|
||||||
|
<string name="settings_fill_new_bill_from_last_summary">Pre-fill payer, category, mode and owers from the last bill created in the project.</string>
|
||||||
|
<string name="settings_auto_sync_on_open">Sync interval</string>
|
||||||
|
<string name="settings_auto_sync_on_open_summary">How often to refresh the account and all projects when opening the app.</string>
|
||||||
|
<string name="pref_value_sync_1m">1 minute</string>
|
||||||
|
<string name="pref_value_sync_10m">10 minutes</string>
|
||||||
|
<string name="pref_value_sync_1h">1 hour</string>
|
||||||
|
<string name="pref_value_sync_1d">1 day</string>
|
||||||
|
<string name="settings_url_warn_http">WARNING: "http" is unsafe. Use "https".</string>
|
||||||
|
<string name="settings_colorpicker_title">Choose Color</string>
|
||||||
|
|
||||||
|
<string name="pref_value_color_system">System</string>
|
||||||
|
<string name="pref_value_color_manual">Manual</string>
|
||||||
|
<string name="pref_value_theme_light">Light</string>
|
||||||
|
<string name="pref_value_theme_dark">Dark</string>
|
||||||
|
<string name="pref_value_theme_system">Follow system</string>
|
||||||
|
|
||||||
|
<!-- Enums and Lists -->
|
||||||
|
<string name="repeat_no">No repeat</string>
|
||||||
|
<string name="repeat_day">Daily</string>
|
||||||
|
<string name="repeat_week">Weekly</string>
|
||||||
|
<string name="repeat_fortnight">Fortnightly</string>
|
||||||
|
<string name="repeat_month">Monthly</string>
|
||||||
|
<string name="repeat_year">Yearly</string>
|
||||||
|
|
||||||
|
<string name="payment_mode_none">None</string>
|
||||||
|
<string name="payment_mode_all">All</string>
|
||||||
|
<string name="payment_mode_credit_card">Credit card</string>
|
||||||
|
<string name="payment_mode_cash">Cash</string>
|
||||||
|
<string name="payment_mode_check">Check</string>
|
||||||
|
<string name="payment_mode_online">Online</string>
|
||||||
|
<string name="payment_mode_transfer">Transfer</string>
|
||||||
|
|
||||||
|
<string name="category_none">None</string>
|
||||||
|
<string name="category_all">All</string>
|
||||||
|
<string name="category_all_except_reimbursement">All except reimbursement</string>
|
||||||
|
<string name="category_groceries">Grocery</string>
|
||||||
|
<string name="category_leisure">Bar/Party</string>
|
||||||
|
<string name="category_rent">Rent</string>
|
||||||
|
<string name="category_bills">Bill</string>
|
||||||
|
<string name="category_excursion">Excursion/Culture</string>
|
||||||
|
<string name="category_health">Health</string>
|
||||||
|
<string name="category_shopping">Shopping</string>
|
||||||
|
<string name="category_reimbursement">Reimbursement</string>
|
||||||
|
<string name="category_restaurant">Restaurant</string>
|
||||||
|
<string name="category_accomodation">Accommodation</string>
|
||||||
|
<string name="category_transport">Transport</string>
|
||||||
|
<string name="category_sport">Sport</string>
|
||||||
|
|
||||||
|
<!-- Project specific -->
|
||||||
|
<string name="new_project_action">What</string>
|
||||||
|
<string name="new_project_where">Where</string>
|
||||||
|
<string name="where_local">Local only</string>
|
||||||
|
<string name="todo_join">Join existing project</string>
|
||||||
|
<string name="todo_create">Create new project</string>
|
||||||
|
<string name="import_tooltip">Import from file</string>
|
||||||
|
<string name="choose_project_management_action">Project</string>
|
||||||
|
<string name="project_added_success">Project added successfully.</string>
|
||||||
|
<string name="no_projects_text">You have no projects yet.</string>
|
||||||
|
<string name="configure_account_choice">Configure Nextcloud account</string>
|
||||||
|
<string name="add_project_choice">Add project manually</string>
|
||||||
|
<string name="no_members_text">No members in this project.</string>
|
||||||
|
<string name="no_bills_text">No bills found.</string>
|
||||||
|
<string name="member_already_exists">Member already exists.</string>
|
||||||
|
<string name="activity_dialog_title">Project: %1$s</string>
|
||||||
|
<string name="remove_project_confirmation">Project %1$s removed.</string>
|
||||||
|
<string name="file_saved_success">File saved: %1$s</string>
|
||||||
|
<string name="import_error_header">Import failed at row %d</string>
|
||||||
|
<string name="import_error_date">Invalid date format at row %d</string>
|
||||||
|
<string name="import_error_owers">Invalid owers at row %d</string>
|
||||||
|
<string name="add_member_dialog_title">Add Member</string>
|
||||||
|
<string name="edit_member_dialog_title">Edit Member</string>
|
||||||
|
<string name="member_edit_delete">Delete</string>
|
||||||
|
<string name="project_edition_no_change">No changes to save.</string>
|
||||||
|
|
||||||
|
<!-- Settlement -->
|
||||||
|
<string name="center_none">None (Optimal)</string>
|
||||||
|
<string name="settle_who">Who pays</string>
|
||||||
|
<string name="settle_to_whom">To whom</string>
|
||||||
|
<string name="settle_how_much">Amount</string>
|
||||||
|
<string name="simple_settle_share">Share</string>
|
||||||
|
<string name="simple_create_bills">Create bills</string>
|
||||||
|
<string name="settle_bill_what">Settlement</string>
|
||||||
|
|
||||||
|
<!-- Currencies -->
|
||||||
|
<string name="currency_dialog_title">Choose Currency (%s)</string>
|
||||||
|
<string name="setting_none">None</string>
|
||||||
|
<string name="setting_all">All</string>
|
||||||
|
<string name="currency_saved_success">Currency settings saved.</string>
|
||||||
|
<string name="main_currency">Main Currency</string>
|
||||||
|
|
||||||
|
<!-- Statistics -->
|
||||||
|
<string name="label_bills_suggested">Suggested Categories</string>
|
||||||
|
<string name="label_bills_skip">Skip</string>
|
||||||
|
<string name="stats_date_min">From</string>
|
||||||
|
<string name="stats_date_max">To</string>
|
||||||
|
<string name="stats_who">Member</string>
|
||||||
|
<string name="stats_paid">Paid</string>
|
||||||
|
<string name="stats_spent">Spent</string>
|
||||||
|
<string name="stats_balance">Balance</string>
|
||||||
|
<string name="total">Total: %1$s</string>
|
||||||
|
|
||||||
|
<!-- Errors Extra -->
|
||||||
|
<string name="error_project_connect_check">Connection failed: %1$s</string>
|
||||||
|
<string name="error_create_remote_project_helper">Creation failed: %1$s</string>
|
||||||
|
<string name="error_edit_remote_project_helper">Error updating remote project: %1$s</string>
|
||||||
|
<string name="remote_project_operation_no_network">Network unavailable for remote operation.</string>
|
||||||
|
<string name="error_scanning_bill_qr_code">Failed to parse QR code.</string>
|
||||||
|
<string name="error_token_mismatch">Authentication token mismatch. Please log in again.</string>
|
||||||
|
<string name="insufficient_access_level">You don\'t have permission to perform this action.</string>
|
||||||
|
<string name="delete_label_confirmation_title">Delete Label</string>
|
||||||
|
<string name="delete_label_confirmation_message">Are you sure you want to delete this label?</string>
|
||||||
|
|
||||||
|
<!-- About -->
|
||||||
|
<string name="about_version">Version %1$s</string>
|
||||||
|
<string name="about_maintainer_title">Maintainer</string>
|
||||||
|
<string name="about_license_title">License</string>
|
||||||
|
<string name="about_source_title">Source code</string>
|
||||||
|
|
||||||
|
<!-- New constants for backward compatibility or shared use -->
|
||||||
|
<string name="share_intent_title">Project %1$s</string>
|
||||||
|
<string name="share_chooser_title">Share %1$s</string>
|
||||||
|
|
||||||
|
</resources>
|
||||||
@@ -0,0 +1,272 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Untranslated: these are the English strings, kept here so a translation can be
|
||||||
|
contributed by simply replacing the values. Strings marked translatable="false" in
|
||||||
|
values/strings.xml (app and product names, preference keys) are deliberately absent
|
||||||
|
and must not be added.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- Actions -->
|
||||||
|
<string name="action_new_bill">New bill</string>
|
||||||
|
<string name="action_add_project">Add project</string>
|
||||||
|
<string name="action_save">Save</string>
|
||||||
|
<string name="action_edit">Edit</string>
|
||||||
|
<string name="action_share">Share</string>
|
||||||
|
<string name="action_search">Search</string>
|
||||||
|
<string name="action_open_menu">Open menu</string>
|
||||||
|
<string name="action_close_search">Close search</string>
|
||||||
|
<string name="action_clear_search">Clear search</string>
|
||||||
|
<string name="action_delete">Delete</string>
|
||||||
|
<string name="simple_back">Back</string>
|
||||||
|
<string name="action_archive">Archive</string>
|
||||||
|
<string name="action_unarchive">Unarchive</string>
|
||||||
|
<string name="action_export">Export</string>
|
||||||
|
<string name="action_stats">Stats</string>
|
||||||
|
<string name="action_settle">Settle</string>
|
||||||
|
<string name="action_scan_qrcode">Scan QR Code</string>
|
||||||
|
<string name="action_settings">Settings</string>
|
||||||
|
<string name="action_label_bills">Label missing categories</string>
|
||||||
|
<string name="action_logout">Logout</string>
|
||||||
|
<string name="action_connect">Connect</string>
|
||||||
|
<string name="action_discard">Discard</string>
|
||||||
|
<string name="action_members">Members</string>
|
||||||
|
<string name="action_labels">Labels</string>
|
||||||
|
<string name="action_currencies">Currencies</string>
|
||||||
|
|
||||||
|
<!-- Titles -->
|
||||||
|
<string name="title_stats">Statistics</string>
|
||||||
|
<string name="title_edit_project">Edit project</string>
|
||||||
|
<string name="title_label_bills">Label Bills</string>
|
||||||
|
<string name="title_labels">Manage Labels</string>
|
||||||
|
<string name="title_about">About</string>
|
||||||
|
<string name="title_settle">Settle Project</string>
|
||||||
|
<string name="title_share">Share Project</string>
|
||||||
|
<string name="title_add_project">Add Project</string>
|
||||||
|
<string name="title_add_category">Add Category</string>
|
||||||
|
<string name="title_add_payment_mode">Add Payment Mode</string>
|
||||||
|
<string name="title_account">Nextcloud Account</string>
|
||||||
|
<string name="title_share_web">Web link</string>
|
||||||
|
<string name="title_share_qr">Cowspent link</string>
|
||||||
|
<string name="title_confirm">Are you sure?</string>
|
||||||
|
|
||||||
|
<!-- Labels and Fields -->
|
||||||
|
<string name="label_all_bills">All bills</string>
|
||||||
|
<string name="label_categories">Categories</string>
|
||||||
|
<string name="label_payment_modes">Payment Modes</string>
|
||||||
|
<string name="label_name">Name</string>
|
||||||
|
<string name="label_icon">Icon / Emoji</string>
|
||||||
|
<string name="label_color">Color</string>
|
||||||
|
<string name="label_weight">Weight</string>
|
||||||
|
<string name="label_activated">Activated</string>
|
||||||
|
<string name="label_password">Password</string>
|
||||||
|
<string name="label_email">E-mail</string>
|
||||||
|
<string name="label_url">Server address</string>
|
||||||
|
<string name="label_username">Username</string>
|
||||||
|
<string name="label_comment">Comment</string>
|
||||||
|
<string name="label_what">What?</string>
|
||||||
|
<string name="label_payer">Who paid?</string>
|
||||||
|
<string name="label_owers">For whom?</string>
|
||||||
|
<string name="label_repeat">Repeat every</string>
|
||||||
|
<string name="label_mode">Mode</string>
|
||||||
|
<string name="label_category">Category</string>
|
||||||
|
<string name="label_project_id">Project ID/name</string>
|
||||||
|
<string name="label_project_title">Project title</string>
|
||||||
|
<string name="label_use_sso">Use Nextcloud App Account</string>
|
||||||
|
|
||||||
|
<!-- Dialogs and Messages -->
|
||||||
|
<string name="dialog_unsaved_changes_title">Unsaved changes</string>
|
||||||
|
<string name="dialog_unsaved_changes_msg">Save changes before leaving?</string>
|
||||||
|
<string name="dialog_confirm_remove_project_msg">The remote project will not be deleted.</string>
|
||||||
|
<string name="dialog_sync_error_title">Sync error</string>
|
||||||
|
<string name="dialog_sync_error_msg">Sync failed for %1$s.\n\n%2$s</string>
|
||||||
|
<string name="dialog_balanced_msg">Expenses are already balanced.</string>
|
||||||
|
<string name="msg_project_added">Project %1$s added</string>
|
||||||
|
<string name="msg_bill_labeled_done">All bills labeled</string>
|
||||||
|
<string name="msg_no_suggestions">No suggestions</string>
|
||||||
|
<string name="msg_auth_warning">Requires Cospend v0.3.4+.</string>
|
||||||
|
<string name="msg_link_copied">Link copied to clipboard</string>
|
||||||
|
<string name="msg_share_qr">Scan QR code or share the link to join.</string>
|
||||||
|
<string name="msg_share_web">Link for web browser access.</string>
|
||||||
|
<string name="msg_share_qr_warn">Share this link with a Cowspent user.</string>
|
||||||
|
<string name="msg_settle_intro">Settlement for %1$s:</string>
|
||||||
|
<string name="msg_settle_sentence">%1$s owes %3$.2f to %2$s</string>
|
||||||
|
<string name="msg_stats_intro">Stats for %1$s:</string>
|
||||||
|
<string name="msg_stats_header">Member (Paid | Spent | Balance)</string>
|
||||||
|
<string name="msg_logged_in_as">Logged in as %1$s</string>
|
||||||
|
|
||||||
|
<!-- Errors -->
|
||||||
|
<string name="error_generic">Error</string>
|
||||||
|
<string name="error_loading">Loading</string>
|
||||||
|
<string name="error_no_projects">No projects found</string>
|
||||||
|
<string name="error_no_members">No members found</string>
|
||||||
|
<string name="error_no_bills">No bills found</string>
|
||||||
|
<string name="error_no_member">At least one member required</string>
|
||||||
|
<string name="error_maintenance_mode">Server is in maintenance mode</string>
|
||||||
|
<string name="error_400">400 Bad request</string>
|
||||||
|
<string name="error_401">401 Unauthorized</string>
|
||||||
|
<string name="error_403">403 Forbidden</string>
|
||||||
|
<string name="error_404">404 Not Found</string>
|
||||||
|
<string name="error_sync">Sync failed: %1$s</string>
|
||||||
|
<string name="error_invalid_login">Invalid login: %1$s</string>
|
||||||
|
<string name="error_auth">Wrong username or password</string>
|
||||||
|
<string name="error_json">Invalid server response</string>
|
||||||
|
<string name="error_req_failed">Request failed</string>
|
||||||
|
<string name="error_invalid_email">Invalid e-mail</string>
|
||||||
|
<string name="error_invalid_project_id">Invalid project ID</string>
|
||||||
|
<string name="error_invalid_project_name">Invalid project title</string>
|
||||||
|
<string name="error_invalid_bill_name">Invalid bill name</string>
|
||||||
|
<string name="error_invalid_bill_date">Invalid bill date</string>
|
||||||
|
<string name="error_invalid_bill_payer">Payer required</string>
|
||||||
|
<string name="error_invalid_bill_owers">Owers required</string>
|
||||||
|
<string name="error_no_network">No network connection</string>
|
||||||
|
<string name="error_server">Server error</string>
|
||||||
|
<string name="error_io">Server connection broken</string>
|
||||||
|
<string name="error_share_impossible">Cannot share this project</string>
|
||||||
|
|
||||||
|
<!-- Drawer / Common UI -->
|
||||||
|
<string name="drawer_no_account">Connect to Nextcloud account</string>
|
||||||
|
<string name="drawer_last_sync">Last sync: %1$02d:%2$02d</string>
|
||||||
|
<string name="simple_cancel">Cancel</string>
|
||||||
|
<string name="simple_ok" tools:ignore="ButtonCase,Typos">Ok</string>
|
||||||
|
<string name="simple_yes">Yes</string>
|
||||||
|
<string name="simple_no">No</string>
|
||||||
|
<string name="simple_close">Close</string>
|
||||||
|
|
||||||
|
<!-- Settings -->
|
||||||
|
<string name="settings_appearance">Appearance</string>
|
||||||
|
<string name="settings_network">Network</string>
|
||||||
|
<string name="settings_other">Other</string>
|
||||||
|
<string name="settings_night_mode">Theme</string>
|
||||||
|
<string name="settings_offline_mode">Offline mode</string>
|
||||||
|
<string name="settings_offline_mode_summary">Only sync manually.</string>
|
||||||
|
<string name="settings_color_custom">Custom color</string>
|
||||||
|
<string name="settings_color_mode">Color Selection</string>
|
||||||
|
<string name="settings_show_archived">Show archived projects</string>
|
||||||
|
<string name="settings_beta_features">Beta Features</string>
|
||||||
|
<string name="settings_beta_features_summary">Enable experimental features. Use at your own risk.</string>
|
||||||
|
<string name="settings_fill_new_bill_from_last">Auto-fill from last bill</string>
|
||||||
|
<string name="settings_fill_new_bill_from_last_summary">Pre-fill payer, category, mode and owers from the last bill created in the project.</string>
|
||||||
|
<string name="settings_auto_sync_on_open">Sync interval</string>
|
||||||
|
<string name="settings_auto_sync_on_open_summary">How often to refresh the account and all projects when opening the app.</string>
|
||||||
|
<string name="pref_value_sync_1m">1 minute</string>
|
||||||
|
<string name="pref_value_sync_10m">10 minutes</string>
|
||||||
|
<string name="pref_value_sync_1h">1 hour</string>
|
||||||
|
<string name="pref_value_sync_1d">1 day</string>
|
||||||
|
<string name="settings_url_warn_http">WARNING: "http" is unsafe. Use "https".</string>
|
||||||
|
<string name="settings_colorpicker_title">Choose Color</string>
|
||||||
|
|
||||||
|
<string name="pref_value_color_system">System</string>
|
||||||
|
<string name="pref_value_color_manual">Manual</string>
|
||||||
|
<string name="pref_value_theme_light">Light</string>
|
||||||
|
<string name="pref_value_theme_dark">Dark</string>
|
||||||
|
<string name="pref_value_theme_system">Follow system</string>
|
||||||
|
|
||||||
|
<!-- Enums and Lists -->
|
||||||
|
<string name="repeat_no">No repeat</string>
|
||||||
|
<string name="repeat_day">Daily</string>
|
||||||
|
<string name="repeat_week">Weekly</string>
|
||||||
|
<string name="repeat_fortnight">Fortnightly</string>
|
||||||
|
<string name="repeat_month">Monthly</string>
|
||||||
|
<string name="repeat_year">Yearly</string>
|
||||||
|
|
||||||
|
<string name="payment_mode_none">None</string>
|
||||||
|
<string name="payment_mode_all">All</string>
|
||||||
|
<string name="payment_mode_credit_card">Credit card</string>
|
||||||
|
<string name="payment_mode_cash">Cash</string>
|
||||||
|
<string name="payment_mode_check">Check</string>
|
||||||
|
<string name="payment_mode_online">Online</string>
|
||||||
|
<string name="payment_mode_transfer">Transfer</string>
|
||||||
|
|
||||||
|
<string name="category_none">None</string>
|
||||||
|
<string name="category_all">All</string>
|
||||||
|
<string name="category_all_except_reimbursement">All except reimbursement</string>
|
||||||
|
<string name="category_groceries">Grocery</string>
|
||||||
|
<string name="category_leisure">Bar/Party</string>
|
||||||
|
<string name="category_rent">Rent</string>
|
||||||
|
<string name="category_bills">Bill</string>
|
||||||
|
<string name="category_excursion">Excursion/Culture</string>
|
||||||
|
<string name="category_health">Health</string>
|
||||||
|
<string name="category_shopping">Shopping</string>
|
||||||
|
<string name="category_reimbursement">Reimbursement</string>
|
||||||
|
<string name="category_restaurant">Restaurant</string>
|
||||||
|
<string name="category_accomodation">Accommodation</string>
|
||||||
|
<string name="category_transport">Transport</string>
|
||||||
|
<string name="category_sport">Sport</string>
|
||||||
|
|
||||||
|
<!-- Project specific -->
|
||||||
|
<string name="new_project_action">What</string>
|
||||||
|
<string name="new_project_where">Where</string>
|
||||||
|
<string name="where_local">Local only</string>
|
||||||
|
<string name="todo_join">Join existing project</string>
|
||||||
|
<string name="todo_create">Create new project</string>
|
||||||
|
<string name="import_tooltip">Import from file</string>
|
||||||
|
<string name="choose_project_management_action">Project</string>
|
||||||
|
<string name="project_added_success">Project added successfully.</string>
|
||||||
|
<string name="no_projects_text">You have no projects yet.</string>
|
||||||
|
<string name="configure_account_choice">Configure Nextcloud account</string>
|
||||||
|
<string name="add_project_choice">Add project manually</string>
|
||||||
|
<string name="no_members_text">No members in this project.</string>
|
||||||
|
<string name="no_bills_text">No bills found.</string>
|
||||||
|
<string name="member_already_exists">Member already exists.</string>
|
||||||
|
<string name="activity_dialog_title">Project: %1$s</string>
|
||||||
|
<string name="remove_project_confirmation">Project %1$s removed.</string>
|
||||||
|
<string name="file_saved_success">File saved: %1$s</string>
|
||||||
|
<string name="import_error_header">Import failed at row %d</string>
|
||||||
|
<string name="import_error_date">Invalid date format at row %d</string>
|
||||||
|
<string name="import_error_owers">Invalid owers at row %d</string>
|
||||||
|
<string name="add_member_dialog_title">Add Member</string>
|
||||||
|
<string name="edit_member_dialog_title">Edit Member</string>
|
||||||
|
<string name="member_edit_delete">Delete</string>
|
||||||
|
<string name="project_edition_no_change">No changes to save.</string>
|
||||||
|
|
||||||
|
<!-- Settlement -->
|
||||||
|
<string name="center_none">None (Optimal)</string>
|
||||||
|
<string name="settle_who">Who pays</string>
|
||||||
|
<string name="settle_to_whom">To whom</string>
|
||||||
|
<string name="settle_how_much">Amount</string>
|
||||||
|
<string name="simple_settle_share">Share</string>
|
||||||
|
<string name="simple_create_bills">Create bills</string>
|
||||||
|
<string name="settle_bill_what">Settlement</string>
|
||||||
|
|
||||||
|
<!-- Currencies -->
|
||||||
|
<string name="currency_dialog_title">Choose Currency (%s)</string>
|
||||||
|
<string name="setting_none">None</string>
|
||||||
|
<string name="setting_all">All</string>
|
||||||
|
<string name="currency_saved_success">Currency settings saved.</string>
|
||||||
|
<string name="main_currency">Main Currency</string>
|
||||||
|
|
||||||
|
<!-- Statistics -->
|
||||||
|
<string name="label_bills_suggested">Suggested Categories</string>
|
||||||
|
<string name="label_bills_skip">Skip</string>
|
||||||
|
<string name="stats_date_min">From</string>
|
||||||
|
<string name="stats_date_max">To</string>
|
||||||
|
<string name="stats_who">Member</string>
|
||||||
|
<string name="stats_paid">Paid</string>
|
||||||
|
<string name="stats_spent">Spent</string>
|
||||||
|
<string name="stats_balance">Balance</string>
|
||||||
|
<string name="total">Total: %1$s</string>
|
||||||
|
|
||||||
|
<!-- Errors Extra -->
|
||||||
|
<string name="error_project_connect_check">Connection failed: %1$s</string>
|
||||||
|
<string name="error_create_remote_project_helper">Creation failed: %1$s</string>
|
||||||
|
<string name="error_edit_remote_project_helper">Error updating remote project: %1$s</string>
|
||||||
|
<string name="remote_project_operation_no_network">Network unavailable for remote operation.</string>
|
||||||
|
<string name="error_scanning_bill_qr_code">Failed to parse QR code.</string>
|
||||||
|
<string name="error_token_mismatch">Authentication token mismatch. Please log in again.</string>
|
||||||
|
<string name="insufficient_access_level">You don\'t have permission to perform this action.</string>
|
||||||
|
<string name="delete_label_confirmation_title">Delete Label</string>
|
||||||
|
<string name="delete_label_confirmation_message">Are you sure you want to delete this label?</string>
|
||||||
|
|
||||||
|
<!-- About -->
|
||||||
|
<string name="about_version">Version %1$s</string>
|
||||||
|
<string name="about_maintainer_title">Maintainer</string>
|
||||||
|
<string name="about_license_title">License</string>
|
||||||
|
<string name="about_source_title">Source code</string>
|
||||||
|
|
||||||
|
<!-- New constants for backward compatibility or shared use -->
|
||||||
|
<string name="share_intent_title">Project %1$s</string>
|
||||||
|
<string name="share_chooser_title">Share %1$s</string>
|
||||||
|
|
||||||
|
</resources>
|
||||||
@@ -0,0 +1,272 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Untranslated: these are the English strings, kept here so a translation can be
|
||||||
|
contributed by simply replacing the values. Strings marked translatable="false" in
|
||||||
|
values/strings.xml (app and product names, preference keys) are deliberately absent
|
||||||
|
and must not be added.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- Actions -->
|
||||||
|
<string name="action_new_bill">New bill</string>
|
||||||
|
<string name="action_add_project">Add project</string>
|
||||||
|
<string name="action_save">Save</string>
|
||||||
|
<string name="action_edit">Edit</string>
|
||||||
|
<string name="action_share">Share</string>
|
||||||
|
<string name="action_search">Search</string>
|
||||||
|
<string name="action_open_menu">Open menu</string>
|
||||||
|
<string name="action_close_search">Close search</string>
|
||||||
|
<string name="action_clear_search">Clear search</string>
|
||||||
|
<string name="action_delete">Delete</string>
|
||||||
|
<string name="simple_back">Back</string>
|
||||||
|
<string name="action_archive">Archive</string>
|
||||||
|
<string name="action_unarchive">Unarchive</string>
|
||||||
|
<string name="action_export">Export</string>
|
||||||
|
<string name="action_stats">Stats</string>
|
||||||
|
<string name="action_settle">Settle</string>
|
||||||
|
<string name="action_scan_qrcode">Scan QR Code</string>
|
||||||
|
<string name="action_settings">Settings</string>
|
||||||
|
<string name="action_label_bills">Label missing categories</string>
|
||||||
|
<string name="action_logout">Logout</string>
|
||||||
|
<string name="action_connect">Connect</string>
|
||||||
|
<string name="action_discard">Discard</string>
|
||||||
|
<string name="action_members">Members</string>
|
||||||
|
<string name="action_labels">Labels</string>
|
||||||
|
<string name="action_currencies">Currencies</string>
|
||||||
|
|
||||||
|
<!-- Titles -->
|
||||||
|
<string name="title_stats">Statistics</string>
|
||||||
|
<string name="title_edit_project">Edit project</string>
|
||||||
|
<string name="title_label_bills">Label Bills</string>
|
||||||
|
<string name="title_labels">Manage Labels</string>
|
||||||
|
<string name="title_about">About</string>
|
||||||
|
<string name="title_settle">Settle Project</string>
|
||||||
|
<string name="title_share">Share Project</string>
|
||||||
|
<string name="title_add_project">Add Project</string>
|
||||||
|
<string name="title_add_category">Add Category</string>
|
||||||
|
<string name="title_add_payment_mode">Add Payment Mode</string>
|
||||||
|
<string name="title_account">Nextcloud Account</string>
|
||||||
|
<string name="title_share_web">Web link</string>
|
||||||
|
<string name="title_share_qr">Cowspent link</string>
|
||||||
|
<string name="title_confirm">Are you sure?</string>
|
||||||
|
|
||||||
|
<!-- Labels and Fields -->
|
||||||
|
<string name="label_all_bills">All bills</string>
|
||||||
|
<string name="label_categories">Categories</string>
|
||||||
|
<string name="label_payment_modes">Payment Modes</string>
|
||||||
|
<string name="label_name">Name</string>
|
||||||
|
<string name="label_icon">Icon / Emoji</string>
|
||||||
|
<string name="label_color">Color</string>
|
||||||
|
<string name="label_weight">Weight</string>
|
||||||
|
<string name="label_activated">Activated</string>
|
||||||
|
<string name="label_password">Password</string>
|
||||||
|
<string name="label_email">E-mail</string>
|
||||||
|
<string name="label_url">Server address</string>
|
||||||
|
<string name="label_username">Username</string>
|
||||||
|
<string name="label_comment">Comment</string>
|
||||||
|
<string name="label_what">What?</string>
|
||||||
|
<string name="label_payer">Who paid?</string>
|
||||||
|
<string name="label_owers">For whom?</string>
|
||||||
|
<string name="label_repeat">Repeat every</string>
|
||||||
|
<string name="label_mode">Mode</string>
|
||||||
|
<string name="label_category">Category</string>
|
||||||
|
<string name="label_project_id">Project ID/name</string>
|
||||||
|
<string name="label_project_title">Project title</string>
|
||||||
|
<string name="label_use_sso">Use Nextcloud App Account</string>
|
||||||
|
|
||||||
|
<!-- Dialogs and Messages -->
|
||||||
|
<string name="dialog_unsaved_changes_title">Unsaved changes</string>
|
||||||
|
<string name="dialog_unsaved_changes_msg">Save changes before leaving?</string>
|
||||||
|
<string name="dialog_confirm_remove_project_msg">The remote project will not be deleted.</string>
|
||||||
|
<string name="dialog_sync_error_title">Sync error</string>
|
||||||
|
<string name="dialog_sync_error_msg">Sync failed for %1$s.\n\n%2$s</string>
|
||||||
|
<string name="dialog_balanced_msg">Expenses are already balanced.</string>
|
||||||
|
<string name="msg_project_added">Project %1$s added</string>
|
||||||
|
<string name="msg_bill_labeled_done">All bills labeled</string>
|
||||||
|
<string name="msg_no_suggestions">No suggestions</string>
|
||||||
|
<string name="msg_auth_warning">Requires Cospend v0.3.4+.</string>
|
||||||
|
<string name="msg_link_copied">Link copied to clipboard</string>
|
||||||
|
<string name="msg_share_qr">Scan QR code or share the link to join.</string>
|
||||||
|
<string name="msg_share_web">Link for web browser access.</string>
|
||||||
|
<string name="msg_share_qr_warn">Share this link with a Cowspent user.</string>
|
||||||
|
<string name="msg_settle_intro">Settlement for %1$s:</string>
|
||||||
|
<string name="msg_settle_sentence">%1$s owes %3$.2f to %2$s</string>
|
||||||
|
<string name="msg_stats_intro">Stats for %1$s:</string>
|
||||||
|
<string name="msg_stats_header">Member (Paid | Spent | Balance)</string>
|
||||||
|
<string name="msg_logged_in_as">Logged in as %1$s</string>
|
||||||
|
|
||||||
|
<!-- Errors -->
|
||||||
|
<string name="error_generic">Error</string>
|
||||||
|
<string name="error_loading">Loading</string>
|
||||||
|
<string name="error_no_projects">No projects found</string>
|
||||||
|
<string name="error_no_members">No members found</string>
|
||||||
|
<string name="error_no_bills">No bills found</string>
|
||||||
|
<string name="error_no_member">At least one member required</string>
|
||||||
|
<string name="error_maintenance_mode">Server is in maintenance mode</string>
|
||||||
|
<string name="error_400">400 Bad request</string>
|
||||||
|
<string name="error_401">401 Unauthorized</string>
|
||||||
|
<string name="error_403">403 Forbidden</string>
|
||||||
|
<string name="error_404">404 Not Found</string>
|
||||||
|
<string name="error_sync">Sync failed: %1$s</string>
|
||||||
|
<string name="error_invalid_login">Invalid login: %1$s</string>
|
||||||
|
<string name="error_auth">Wrong username or password</string>
|
||||||
|
<string name="error_json">Invalid server response</string>
|
||||||
|
<string name="error_req_failed">Request failed</string>
|
||||||
|
<string name="error_invalid_email">Invalid e-mail</string>
|
||||||
|
<string name="error_invalid_project_id">Invalid project ID</string>
|
||||||
|
<string name="error_invalid_project_name">Invalid project title</string>
|
||||||
|
<string name="error_invalid_bill_name">Invalid bill name</string>
|
||||||
|
<string name="error_invalid_bill_date">Invalid bill date</string>
|
||||||
|
<string name="error_invalid_bill_payer">Payer required</string>
|
||||||
|
<string name="error_invalid_bill_owers">Owers required</string>
|
||||||
|
<string name="error_no_network">No network connection</string>
|
||||||
|
<string name="error_server">Server error</string>
|
||||||
|
<string name="error_io">Server connection broken</string>
|
||||||
|
<string name="error_share_impossible">Cannot share this project</string>
|
||||||
|
|
||||||
|
<!-- Drawer / Common UI -->
|
||||||
|
<string name="drawer_no_account">Connect to Nextcloud account</string>
|
||||||
|
<string name="drawer_last_sync">Last sync: %1$02d:%2$02d</string>
|
||||||
|
<string name="simple_cancel">Cancel</string>
|
||||||
|
<string name="simple_ok" tools:ignore="ButtonCase,Typos">Ok</string>
|
||||||
|
<string name="simple_yes">Yes</string>
|
||||||
|
<string name="simple_no">No</string>
|
||||||
|
<string name="simple_close">Close</string>
|
||||||
|
|
||||||
|
<!-- Settings -->
|
||||||
|
<string name="settings_appearance">Appearance</string>
|
||||||
|
<string name="settings_network">Network</string>
|
||||||
|
<string name="settings_other">Other</string>
|
||||||
|
<string name="settings_night_mode">Theme</string>
|
||||||
|
<string name="settings_offline_mode">Offline mode</string>
|
||||||
|
<string name="settings_offline_mode_summary">Only sync manually.</string>
|
||||||
|
<string name="settings_color_custom">Custom color</string>
|
||||||
|
<string name="settings_color_mode">Color Selection</string>
|
||||||
|
<string name="settings_show_archived">Show archived projects</string>
|
||||||
|
<string name="settings_beta_features">Beta Features</string>
|
||||||
|
<string name="settings_beta_features_summary">Enable experimental features. Use at your own risk.</string>
|
||||||
|
<string name="settings_fill_new_bill_from_last">Auto-fill from last bill</string>
|
||||||
|
<string name="settings_fill_new_bill_from_last_summary">Pre-fill payer, category, mode and owers from the last bill created in the project.</string>
|
||||||
|
<string name="settings_auto_sync_on_open">Sync interval</string>
|
||||||
|
<string name="settings_auto_sync_on_open_summary">How often to refresh the account and all projects when opening the app.</string>
|
||||||
|
<string name="pref_value_sync_1m">1 minute</string>
|
||||||
|
<string name="pref_value_sync_10m">10 minutes</string>
|
||||||
|
<string name="pref_value_sync_1h">1 hour</string>
|
||||||
|
<string name="pref_value_sync_1d">1 day</string>
|
||||||
|
<string name="settings_url_warn_http">WARNING: "http" is unsafe. Use "https".</string>
|
||||||
|
<string name="settings_colorpicker_title">Choose Color</string>
|
||||||
|
|
||||||
|
<string name="pref_value_color_system">System</string>
|
||||||
|
<string name="pref_value_color_manual">Manual</string>
|
||||||
|
<string name="pref_value_theme_light">Light</string>
|
||||||
|
<string name="pref_value_theme_dark">Dark</string>
|
||||||
|
<string name="pref_value_theme_system">Follow system</string>
|
||||||
|
|
||||||
|
<!-- Enums and Lists -->
|
||||||
|
<string name="repeat_no">No repeat</string>
|
||||||
|
<string name="repeat_day">Daily</string>
|
||||||
|
<string name="repeat_week">Weekly</string>
|
||||||
|
<string name="repeat_fortnight">Fortnightly</string>
|
||||||
|
<string name="repeat_month">Monthly</string>
|
||||||
|
<string name="repeat_year">Yearly</string>
|
||||||
|
|
||||||
|
<string name="payment_mode_none">None</string>
|
||||||
|
<string name="payment_mode_all">All</string>
|
||||||
|
<string name="payment_mode_credit_card">Credit card</string>
|
||||||
|
<string name="payment_mode_cash">Cash</string>
|
||||||
|
<string name="payment_mode_check">Check</string>
|
||||||
|
<string name="payment_mode_online">Online</string>
|
||||||
|
<string name="payment_mode_transfer">Transfer</string>
|
||||||
|
|
||||||
|
<string name="category_none">None</string>
|
||||||
|
<string name="category_all">All</string>
|
||||||
|
<string name="category_all_except_reimbursement">All except reimbursement</string>
|
||||||
|
<string name="category_groceries">Grocery</string>
|
||||||
|
<string name="category_leisure">Bar/Party</string>
|
||||||
|
<string name="category_rent">Rent</string>
|
||||||
|
<string name="category_bills">Bill</string>
|
||||||
|
<string name="category_excursion">Excursion/Culture</string>
|
||||||
|
<string name="category_health">Health</string>
|
||||||
|
<string name="category_shopping">Shopping</string>
|
||||||
|
<string name="category_reimbursement">Reimbursement</string>
|
||||||
|
<string name="category_restaurant">Restaurant</string>
|
||||||
|
<string name="category_accomodation">Accommodation</string>
|
||||||
|
<string name="category_transport">Transport</string>
|
||||||
|
<string name="category_sport">Sport</string>
|
||||||
|
|
||||||
|
<!-- Project specific -->
|
||||||
|
<string name="new_project_action">What</string>
|
||||||
|
<string name="new_project_where">Where</string>
|
||||||
|
<string name="where_local">Local only</string>
|
||||||
|
<string name="todo_join">Join existing project</string>
|
||||||
|
<string name="todo_create">Create new project</string>
|
||||||
|
<string name="import_tooltip">Import from file</string>
|
||||||
|
<string name="choose_project_management_action">Project</string>
|
||||||
|
<string name="project_added_success">Project added successfully.</string>
|
||||||
|
<string name="no_projects_text">You have no projects yet.</string>
|
||||||
|
<string name="configure_account_choice">Configure Nextcloud account</string>
|
||||||
|
<string name="add_project_choice">Add project manually</string>
|
||||||
|
<string name="no_members_text">No members in this project.</string>
|
||||||
|
<string name="no_bills_text">No bills found.</string>
|
||||||
|
<string name="member_already_exists">Member already exists.</string>
|
||||||
|
<string name="activity_dialog_title">Project: %1$s</string>
|
||||||
|
<string name="remove_project_confirmation">Project %1$s removed.</string>
|
||||||
|
<string name="file_saved_success">File saved: %1$s</string>
|
||||||
|
<string name="import_error_header">Import failed at row %d</string>
|
||||||
|
<string name="import_error_date">Invalid date format at row %d</string>
|
||||||
|
<string name="import_error_owers">Invalid owers at row %d</string>
|
||||||
|
<string name="add_member_dialog_title">Add Member</string>
|
||||||
|
<string name="edit_member_dialog_title">Edit Member</string>
|
||||||
|
<string name="member_edit_delete">Delete</string>
|
||||||
|
<string name="project_edition_no_change">No changes to save.</string>
|
||||||
|
|
||||||
|
<!-- Settlement -->
|
||||||
|
<string name="center_none">None (Optimal)</string>
|
||||||
|
<string name="settle_who">Who pays</string>
|
||||||
|
<string name="settle_to_whom">To whom</string>
|
||||||
|
<string name="settle_how_much">Amount</string>
|
||||||
|
<string name="simple_settle_share">Share</string>
|
||||||
|
<string name="simple_create_bills">Create bills</string>
|
||||||
|
<string name="settle_bill_what">Settlement</string>
|
||||||
|
|
||||||
|
<!-- Currencies -->
|
||||||
|
<string name="currency_dialog_title">Choose Currency (%s)</string>
|
||||||
|
<string name="setting_none">None</string>
|
||||||
|
<string name="setting_all">All</string>
|
||||||
|
<string name="currency_saved_success">Currency settings saved.</string>
|
||||||
|
<string name="main_currency">Main Currency</string>
|
||||||
|
|
||||||
|
<!-- Statistics -->
|
||||||
|
<string name="label_bills_suggested">Suggested Categories</string>
|
||||||
|
<string name="label_bills_skip">Skip</string>
|
||||||
|
<string name="stats_date_min">From</string>
|
||||||
|
<string name="stats_date_max">To</string>
|
||||||
|
<string name="stats_who">Member</string>
|
||||||
|
<string name="stats_paid">Paid</string>
|
||||||
|
<string name="stats_spent">Spent</string>
|
||||||
|
<string name="stats_balance">Balance</string>
|
||||||
|
<string name="total">Total: %1$s</string>
|
||||||
|
|
||||||
|
<!-- Errors Extra -->
|
||||||
|
<string name="error_project_connect_check">Connection failed: %1$s</string>
|
||||||
|
<string name="error_create_remote_project_helper">Creation failed: %1$s</string>
|
||||||
|
<string name="error_edit_remote_project_helper">Error updating remote project: %1$s</string>
|
||||||
|
<string name="remote_project_operation_no_network">Network unavailable for remote operation.</string>
|
||||||
|
<string name="error_scanning_bill_qr_code">Failed to parse QR code.</string>
|
||||||
|
<string name="error_token_mismatch">Authentication token mismatch. Please log in again.</string>
|
||||||
|
<string name="insufficient_access_level">You don\'t have permission to perform this action.</string>
|
||||||
|
<string name="delete_label_confirmation_title">Delete Label</string>
|
||||||
|
<string name="delete_label_confirmation_message">Are you sure you want to delete this label?</string>
|
||||||
|
|
||||||
|
<!-- About -->
|
||||||
|
<string name="about_version">Version %1$s</string>
|
||||||
|
<string name="about_maintainer_title">Maintainer</string>
|
||||||
|
<string name="about_license_title">License</string>
|
||||||
|
<string name="about_source_title">Source code</string>
|
||||||
|
|
||||||
|
<!-- New constants for backward compatibility or shared use -->
|
||||||
|
<string name="share_intent_title">Project %1$s</string>
|
||||||
|
<string name="share_chooser_title">Share %1$s</string>
|
||||||
|
|
||||||
|
</resources>
|
||||||
@@ -0,0 +1,272 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Untranslated: these are the English strings, kept here so a translation can be
|
||||||
|
contributed by simply replacing the values. Strings marked translatable="false" in
|
||||||
|
values/strings.xml (app and product names, preference keys) are deliberately absent
|
||||||
|
and must not be added.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- Actions -->
|
||||||
|
<string name="action_new_bill">New bill</string>
|
||||||
|
<string name="action_add_project">Add project</string>
|
||||||
|
<string name="action_save">Save</string>
|
||||||
|
<string name="action_edit">Edit</string>
|
||||||
|
<string name="action_share">Share</string>
|
||||||
|
<string name="action_search">Search</string>
|
||||||
|
<string name="action_open_menu">Open menu</string>
|
||||||
|
<string name="action_close_search">Close search</string>
|
||||||
|
<string name="action_clear_search">Clear search</string>
|
||||||
|
<string name="action_delete">Delete</string>
|
||||||
|
<string name="simple_back">Back</string>
|
||||||
|
<string name="action_archive">Archive</string>
|
||||||
|
<string name="action_unarchive">Unarchive</string>
|
||||||
|
<string name="action_export">Export</string>
|
||||||
|
<string name="action_stats">Stats</string>
|
||||||
|
<string name="action_settle">Settle</string>
|
||||||
|
<string name="action_scan_qrcode">Scan QR Code</string>
|
||||||
|
<string name="action_settings">Settings</string>
|
||||||
|
<string name="action_label_bills">Label missing categories</string>
|
||||||
|
<string name="action_logout">Logout</string>
|
||||||
|
<string name="action_connect">Connect</string>
|
||||||
|
<string name="action_discard">Discard</string>
|
||||||
|
<string name="action_members">Members</string>
|
||||||
|
<string name="action_labels">Labels</string>
|
||||||
|
<string name="action_currencies">Currencies</string>
|
||||||
|
|
||||||
|
<!-- Titles -->
|
||||||
|
<string name="title_stats">Statistics</string>
|
||||||
|
<string name="title_edit_project">Edit project</string>
|
||||||
|
<string name="title_label_bills">Label Bills</string>
|
||||||
|
<string name="title_labels">Manage Labels</string>
|
||||||
|
<string name="title_about">About</string>
|
||||||
|
<string name="title_settle">Settle Project</string>
|
||||||
|
<string name="title_share">Share Project</string>
|
||||||
|
<string name="title_add_project">Add Project</string>
|
||||||
|
<string name="title_add_category">Add Category</string>
|
||||||
|
<string name="title_add_payment_mode">Add Payment Mode</string>
|
||||||
|
<string name="title_account">Nextcloud Account</string>
|
||||||
|
<string name="title_share_web">Web link</string>
|
||||||
|
<string name="title_share_qr">Cowspent link</string>
|
||||||
|
<string name="title_confirm">Are you sure?</string>
|
||||||
|
|
||||||
|
<!-- Labels and Fields -->
|
||||||
|
<string name="label_all_bills">All bills</string>
|
||||||
|
<string name="label_categories">Categories</string>
|
||||||
|
<string name="label_payment_modes">Payment Modes</string>
|
||||||
|
<string name="label_name">Name</string>
|
||||||
|
<string name="label_icon">Icon / Emoji</string>
|
||||||
|
<string name="label_color">Color</string>
|
||||||
|
<string name="label_weight">Weight</string>
|
||||||
|
<string name="label_activated">Activated</string>
|
||||||
|
<string name="label_password">Password</string>
|
||||||
|
<string name="label_email">E-mail</string>
|
||||||
|
<string name="label_url">Server address</string>
|
||||||
|
<string name="label_username">Username</string>
|
||||||
|
<string name="label_comment">Comment</string>
|
||||||
|
<string name="label_what">What?</string>
|
||||||
|
<string name="label_payer">Who paid?</string>
|
||||||
|
<string name="label_owers">For whom?</string>
|
||||||
|
<string name="label_repeat">Repeat every</string>
|
||||||
|
<string name="label_mode">Mode</string>
|
||||||
|
<string name="label_category">Category</string>
|
||||||
|
<string name="label_project_id">Project ID/name</string>
|
||||||
|
<string name="label_project_title">Project title</string>
|
||||||
|
<string name="label_use_sso">Use Nextcloud App Account</string>
|
||||||
|
|
||||||
|
<!-- Dialogs and Messages -->
|
||||||
|
<string name="dialog_unsaved_changes_title">Unsaved changes</string>
|
||||||
|
<string name="dialog_unsaved_changes_msg">Save changes before leaving?</string>
|
||||||
|
<string name="dialog_confirm_remove_project_msg">The remote project will not be deleted.</string>
|
||||||
|
<string name="dialog_sync_error_title">Sync error</string>
|
||||||
|
<string name="dialog_sync_error_msg">Sync failed for %1$s.\n\n%2$s</string>
|
||||||
|
<string name="dialog_balanced_msg">Expenses are already balanced.</string>
|
||||||
|
<string name="msg_project_added">Project %1$s added</string>
|
||||||
|
<string name="msg_bill_labeled_done">All bills labeled</string>
|
||||||
|
<string name="msg_no_suggestions">No suggestions</string>
|
||||||
|
<string name="msg_auth_warning">Requires Cospend v0.3.4+.</string>
|
||||||
|
<string name="msg_link_copied">Link copied to clipboard</string>
|
||||||
|
<string name="msg_share_qr">Scan QR code or share the link to join.</string>
|
||||||
|
<string name="msg_share_web">Link for web browser access.</string>
|
||||||
|
<string name="msg_share_qr_warn">Share this link with a Cowspent user.</string>
|
||||||
|
<string name="msg_settle_intro">Settlement for %1$s:</string>
|
||||||
|
<string name="msg_settle_sentence">%1$s owes %3$.2f to %2$s</string>
|
||||||
|
<string name="msg_stats_intro">Stats for %1$s:</string>
|
||||||
|
<string name="msg_stats_header">Member (Paid | Spent | Balance)</string>
|
||||||
|
<string name="msg_logged_in_as">Logged in as %1$s</string>
|
||||||
|
|
||||||
|
<!-- Errors -->
|
||||||
|
<string name="error_generic">Error</string>
|
||||||
|
<string name="error_loading">Loading</string>
|
||||||
|
<string name="error_no_projects">No projects found</string>
|
||||||
|
<string name="error_no_members">No members found</string>
|
||||||
|
<string name="error_no_bills">No bills found</string>
|
||||||
|
<string name="error_no_member">At least one member required</string>
|
||||||
|
<string name="error_maintenance_mode">Server is in maintenance mode</string>
|
||||||
|
<string name="error_400">400 Bad request</string>
|
||||||
|
<string name="error_401">401 Unauthorized</string>
|
||||||
|
<string name="error_403">403 Forbidden</string>
|
||||||
|
<string name="error_404">404 Not Found</string>
|
||||||
|
<string name="error_sync">Sync failed: %1$s</string>
|
||||||
|
<string name="error_invalid_login">Invalid login: %1$s</string>
|
||||||
|
<string name="error_auth">Wrong username or password</string>
|
||||||
|
<string name="error_json">Invalid server response</string>
|
||||||
|
<string name="error_req_failed">Request failed</string>
|
||||||
|
<string name="error_invalid_email">Invalid e-mail</string>
|
||||||
|
<string name="error_invalid_project_id">Invalid project ID</string>
|
||||||
|
<string name="error_invalid_project_name">Invalid project title</string>
|
||||||
|
<string name="error_invalid_bill_name">Invalid bill name</string>
|
||||||
|
<string name="error_invalid_bill_date">Invalid bill date</string>
|
||||||
|
<string name="error_invalid_bill_payer">Payer required</string>
|
||||||
|
<string name="error_invalid_bill_owers">Owers required</string>
|
||||||
|
<string name="error_no_network">No network connection</string>
|
||||||
|
<string name="error_server">Server error</string>
|
||||||
|
<string name="error_io">Server connection broken</string>
|
||||||
|
<string name="error_share_impossible">Cannot share this project</string>
|
||||||
|
|
||||||
|
<!-- Drawer / Common UI -->
|
||||||
|
<string name="drawer_no_account">Connect to Nextcloud account</string>
|
||||||
|
<string name="drawer_last_sync">Last sync: %1$02d:%2$02d</string>
|
||||||
|
<string name="simple_cancel">Cancel</string>
|
||||||
|
<string name="simple_ok" tools:ignore="ButtonCase,Typos">Ok</string>
|
||||||
|
<string name="simple_yes">Yes</string>
|
||||||
|
<string name="simple_no">No</string>
|
||||||
|
<string name="simple_close">Close</string>
|
||||||
|
|
||||||
|
<!-- Settings -->
|
||||||
|
<string name="settings_appearance">Appearance</string>
|
||||||
|
<string name="settings_network">Network</string>
|
||||||
|
<string name="settings_other">Other</string>
|
||||||
|
<string name="settings_night_mode">Theme</string>
|
||||||
|
<string name="settings_offline_mode">Offline mode</string>
|
||||||
|
<string name="settings_offline_mode_summary">Only sync manually.</string>
|
||||||
|
<string name="settings_color_custom">Custom color</string>
|
||||||
|
<string name="settings_color_mode">Color Selection</string>
|
||||||
|
<string name="settings_show_archived">Show archived projects</string>
|
||||||
|
<string name="settings_beta_features">Beta Features</string>
|
||||||
|
<string name="settings_beta_features_summary">Enable experimental features. Use at your own risk.</string>
|
||||||
|
<string name="settings_fill_new_bill_from_last">Auto-fill from last bill</string>
|
||||||
|
<string name="settings_fill_new_bill_from_last_summary">Pre-fill payer, category, mode and owers from the last bill created in the project.</string>
|
||||||
|
<string name="settings_auto_sync_on_open">Sync interval</string>
|
||||||
|
<string name="settings_auto_sync_on_open_summary">How often to refresh the account and all projects when opening the app.</string>
|
||||||
|
<string name="pref_value_sync_1m">1 minute</string>
|
||||||
|
<string name="pref_value_sync_10m">10 minutes</string>
|
||||||
|
<string name="pref_value_sync_1h">1 hour</string>
|
||||||
|
<string name="pref_value_sync_1d">1 day</string>
|
||||||
|
<string name="settings_url_warn_http">WARNING: "http" is unsafe. Use "https".</string>
|
||||||
|
<string name="settings_colorpicker_title">Choose Color</string>
|
||||||
|
|
||||||
|
<string name="pref_value_color_system">System</string>
|
||||||
|
<string name="pref_value_color_manual">Manual</string>
|
||||||
|
<string name="pref_value_theme_light">Light</string>
|
||||||
|
<string name="pref_value_theme_dark">Dark</string>
|
||||||
|
<string name="pref_value_theme_system">Follow system</string>
|
||||||
|
|
||||||
|
<!-- Enums and Lists -->
|
||||||
|
<string name="repeat_no">No repeat</string>
|
||||||
|
<string name="repeat_day">Daily</string>
|
||||||
|
<string name="repeat_week">Weekly</string>
|
||||||
|
<string name="repeat_fortnight">Fortnightly</string>
|
||||||
|
<string name="repeat_month">Monthly</string>
|
||||||
|
<string name="repeat_year">Yearly</string>
|
||||||
|
|
||||||
|
<string name="payment_mode_none">None</string>
|
||||||
|
<string name="payment_mode_all">All</string>
|
||||||
|
<string name="payment_mode_credit_card">Credit card</string>
|
||||||
|
<string name="payment_mode_cash">Cash</string>
|
||||||
|
<string name="payment_mode_check">Check</string>
|
||||||
|
<string name="payment_mode_online">Online</string>
|
||||||
|
<string name="payment_mode_transfer">Transfer</string>
|
||||||
|
|
||||||
|
<string name="category_none">None</string>
|
||||||
|
<string name="category_all">All</string>
|
||||||
|
<string name="category_all_except_reimbursement">All except reimbursement</string>
|
||||||
|
<string name="category_groceries">Grocery</string>
|
||||||
|
<string name="category_leisure">Bar/Party</string>
|
||||||
|
<string name="category_rent">Rent</string>
|
||||||
|
<string name="category_bills">Bill</string>
|
||||||
|
<string name="category_excursion">Excursion/Culture</string>
|
||||||
|
<string name="category_health">Health</string>
|
||||||
|
<string name="category_shopping">Shopping</string>
|
||||||
|
<string name="category_reimbursement">Reimbursement</string>
|
||||||
|
<string name="category_restaurant">Restaurant</string>
|
||||||
|
<string name="category_accomodation">Accommodation</string>
|
||||||
|
<string name="category_transport">Transport</string>
|
||||||
|
<string name="category_sport">Sport</string>
|
||||||
|
|
||||||
|
<!-- Project specific -->
|
||||||
|
<string name="new_project_action">What</string>
|
||||||
|
<string name="new_project_where">Where</string>
|
||||||
|
<string name="where_local">Local only</string>
|
||||||
|
<string name="todo_join">Join existing project</string>
|
||||||
|
<string name="todo_create">Create new project</string>
|
||||||
|
<string name="import_tooltip">Import from file</string>
|
||||||
|
<string name="choose_project_management_action">Project</string>
|
||||||
|
<string name="project_added_success">Project added successfully.</string>
|
||||||
|
<string name="no_projects_text">You have no projects yet.</string>
|
||||||
|
<string name="configure_account_choice">Configure Nextcloud account</string>
|
||||||
|
<string name="add_project_choice">Add project manually</string>
|
||||||
|
<string name="no_members_text">No members in this project.</string>
|
||||||
|
<string name="no_bills_text">No bills found.</string>
|
||||||
|
<string name="member_already_exists">Member already exists.</string>
|
||||||
|
<string name="activity_dialog_title">Project: %1$s</string>
|
||||||
|
<string name="remove_project_confirmation">Project %1$s removed.</string>
|
||||||
|
<string name="file_saved_success">File saved: %1$s</string>
|
||||||
|
<string name="import_error_header">Import failed at row %d</string>
|
||||||
|
<string name="import_error_date">Invalid date format at row %d</string>
|
||||||
|
<string name="import_error_owers">Invalid owers at row %d</string>
|
||||||
|
<string name="add_member_dialog_title">Add Member</string>
|
||||||
|
<string name="edit_member_dialog_title">Edit Member</string>
|
||||||
|
<string name="member_edit_delete">Delete</string>
|
||||||
|
<string name="project_edition_no_change">No changes to save.</string>
|
||||||
|
|
||||||
|
<!-- Settlement -->
|
||||||
|
<string name="center_none">None (Optimal)</string>
|
||||||
|
<string name="settle_who">Who pays</string>
|
||||||
|
<string name="settle_to_whom">To whom</string>
|
||||||
|
<string name="settle_how_much">Amount</string>
|
||||||
|
<string name="simple_settle_share">Share</string>
|
||||||
|
<string name="simple_create_bills">Create bills</string>
|
||||||
|
<string name="settle_bill_what">Settlement</string>
|
||||||
|
|
||||||
|
<!-- Currencies -->
|
||||||
|
<string name="currency_dialog_title">Choose Currency (%s)</string>
|
||||||
|
<string name="setting_none">None</string>
|
||||||
|
<string name="setting_all">All</string>
|
||||||
|
<string name="currency_saved_success">Currency settings saved.</string>
|
||||||
|
<string name="main_currency">Main Currency</string>
|
||||||
|
|
||||||
|
<!-- Statistics -->
|
||||||
|
<string name="label_bills_suggested">Suggested Categories</string>
|
||||||
|
<string name="label_bills_skip">Skip</string>
|
||||||
|
<string name="stats_date_min">From</string>
|
||||||
|
<string name="stats_date_max">To</string>
|
||||||
|
<string name="stats_who">Member</string>
|
||||||
|
<string name="stats_paid">Paid</string>
|
||||||
|
<string name="stats_spent">Spent</string>
|
||||||
|
<string name="stats_balance">Balance</string>
|
||||||
|
<string name="total">Total: %1$s</string>
|
||||||
|
|
||||||
|
<!-- Errors Extra -->
|
||||||
|
<string name="error_project_connect_check">Connection failed: %1$s</string>
|
||||||
|
<string name="error_create_remote_project_helper">Creation failed: %1$s</string>
|
||||||
|
<string name="error_edit_remote_project_helper">Error updating remote project: %1$s</string>
|
||||||
|
<string name="remote_project_operation_no_network">Network unavailable for remote operation.</string>
|
||||||
|
<string name="error_scanning_bill_qr_code">Failed to parse QR code.</string>
|
||||||
|
<string name="error_token_mismatch">Authentication token mismatch. Please log in again.</string>
|
||||||
|
<string name="insufficient_access_level">You don\'t have permission to perform this action.</string>
|
||||||
|
<string name="delete_label_confirmation_title">Delete Label</string>
|
||||||
|
<string name="delete_label_confirmation_message">Are you sure you want to delete this label?</string>
|
||||||
|
|
||||||
|
<!-- About -->
|
||||||
|
<string name="about_version">Version %1$s</string>
|
||||||
|
<string name="about_maintainer_title">Maintainer</string>
|
||||||
|
<string name="about_license_title">License</string>
|
||||||
|
<string name="about_source_title">Source code</string>
|
||||||
|
|
||||||
|
<!-- New constants for backward compatibility or shared use -->
|
||||||
|
<string name="share_intent_title">Project %1$s</string>
|
||||||
|
<string name="share_chooser_title">Share %1$s</string>
|
||||||
|
|
||||||
|
</resources>
|
||||||
@@ -0,0 +1,272 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Untranslated: these are the English strings, kept here so a translation can be
|
||||||
|
contributed by simply replacing the values. Strings marked translatable="false" in
|
||||||
|
values/strings.xml (app and product names, preference keys) are deliberately absent
|
||||||
|
and must not be added.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- Actions -->
|
||||||
|
<string name="action_new_bill">New bill</string>
|
||||||
|
<string name="action_add_project">Add project</string>
|
||||||
|
<string name="action_save">Save</string>
|
||||||
|
<string name="action_edit">Edit</string>
|
||||||
|
<string name="action_share">Share</string>
|
||||||
|
<string name="action_search">Search</string>
|
||||||
|
<string name="action_open_menu">Open menu</string>
|
||||||
|
<string name="action_close_search">Close search</string>
|
||||||
|
<string name="action_clear_search">Clear search</string>
|
||||||
|
<string name="action_delete">Delete</string>
|
||||||
|
<string name="simple_back">Back</string>
|
||||||
|
<string name="action_archive">Archive</string>
|
||||||
|
<string name="action_unarchive">Unarchive</string>
|
||||||
|
<string name="action_export">Export</string>
|
||||||
|
<string name="action_stats">Stats</string>
|
||||||
|
<string name="action_settle">Settle</string>
|
||||||
|
<string name="action_scan_qrcode">Scan QR Code</string>
|
||||||
|
<string name="action_settings">Settings</string>
|
||||||
|
<string name="action_label_bills">Label missing categories</string>
|
||||||
|
<string name="action_logout">Logout</string>
|
||||||
|
<string name="action_connect">Connect</string>
|
||||||
|
<string name="action_discard">Discard</string>
|
||||||
|
<string name="action_members">Members</string>
|
||||||
|
<string name="action_labels">Labels</string>
|
||||||
|
<string name="action_currencies">Currencies</string>
|
||||||
|
|
||||||
|
<!-- Titles -->
|
||||||
|
<string name="title_stats">Statistics</string>
|
||||||
|
<string name="title_edit_project">Edit project</string>
|
||||||
|
<string name="title_label_bills">Label Bills</string>
|
||||||
|
<string name="title_labels">Manage Labels</string>
|
||||||
|
<string name="title_about">About</string>
|
||||||
|
<string name="title_settle">Settle Project</string>
|
||||||
|
<string name="title_share">Share Project</string>
|
||||||
|
<string name="title_add_project">Add Project</string>
|
||||||
|
<string name="title_add_category">Add Category</string>
|
||||||
|
<string name="title_add_payment_mode">Add Payment Mode</string>
|
||||||
|
<string name="title_account">Nextcloud Account</string>
|
||||||
|
<string name="title_share_web">Web link</string>
|
||||||
|
<string name="title_share_qr">Cowspent link</string>
|
||||||
|
<string name="title_confirm">Are you sure?</string>
|
||||||
|
|
||||||
|
<!-- Labels and Fields -->
|
||||||
|
<string name="label_all_bills">All bills</string>
|
||||||
|
<string name="label_categories">Categories</string>
|
||||||
|
<string name="label_payment_modes">Payment Modes</string>
|
||||||
|
<string name="label_name">Name</string>
|
||||||
|
<string name="label_icon">Icon / Emoji</string>
|
||||||
|
<string name="label_color">Color</string>
|
||||||
|
<string name="label_weight">Weight</string>
|
||||||
|
<string name="label_activated">Activated</string>
|
||||||
|
<string name="label_password">Password</string>
|
||||||
|
<string name="label_email">E-mail</string>
|
||||||
|
<string name="label_url">Server address</string>
|
||||||
|
<string name="label_username">Username</string>
|
||||||
|
<string name="label_comment">Comment</string>
|
||||||
|
<string name="label_what">What?</string>
|
||||||
|
<string name="label_payer">Who paid?</string>
|
||||||
|
<string name="label_owers">For whom?</string>
|
||||||
|
<string name="label_repeat">Repeat every</string>
|
||||||
|
<string name="label_mode">Mode</string>
|
||||||
|
<string name="label_category">Category</string>
|
||||||
|
<string name="label_project_id">Project ID/name</string>
|
||||||
|
<string name="label_project_title">Project title</string>
|
||||||
|
<string name="label_use_sso">Use Nextcloud App Account</string>
|
||||||
|
|
||||||
|
<!-- Dialogs and Messages -->
|
||||||
|
<string name="dialog_unsaved_changes_title">Unsaved changes</string>
|
||||||
|
<string name="dialog_unsaved_changes_msg">Save changes before leaving?</string>
|
||||||
|
<string name="dialog_confirm_remove_project_msg">The remote project will not be deleted.</string>
|
||||||
|
<string name="dialog_sync_error_title">Sync error</string>
|
||||||
|
<string name="dialog_sync_error_msg">Sync failed for %1$s.\n\n%2$s</string>
|
||||||
|
<string name="dialog_balanced_msg">Expenses are already balanced.</string>
|
||||||
|
<string name="msg_project_added">Project %1$s added</string>
|
||||||
|
<string name="msg_bill_labeled_done">All bills labeled</string>
|
||||||
|
<string name="msg_no_suggestions">No suggestions</string>
|
||||||
|
<string name="msg_auth_warning">Requires Cospend v0.3.4+.</string>
|
||||||
|
<string name="msg_link_copied">Link copied to clipboard</string>
|
||||||
|
<string name="msg_share_qr">Scan QR code or share the link to join.</string>
|
||||||
|
<string name="msg_share_web">Link for web browser access.</string>
|
||||||
|
<string name="msg_share_qr_warn">Share this link with a Cowspent user.</string>
|
||||||
|
<string name="msg_settle_intro">Settlement for %1$s:</string>
|
||||||
|
<string name="msg_settle_sentence">%1$s owes %3$.2f to %2$s</string>
|
||||||
|
<string name="msg_stats_intro">Stats for %1$s:</string>
|
||||||
|
<string name="msg_stats_header">Member (Paid | Spent | Balance)</string>
|
||||||
|
<string name="msg_logged_in_as">Logged in as %1$s</string>
|
||||||
|
|
||||||
|
<!-- Errors -->
|
||||||
|
<string name="error_generic">Error</string>
|
||||||
|
<string name="error_loading">Loading</string>
|
||||||
|
<string name="error_no_projects">No projects found</string>
|
||||||
|
<string name="error_no_members">No members found</string>
|
||||||
|
<string name="error_no_bills">No bills found</string>
|
||||||
|
<string name="error_no_member">At least one member required</string>
|
||||||
|
<string name="error_maintenance_mode">Server is in maintenance mode</string>
|
||||||
|
<string name="error_400">400 Bad request</string>
|
||||||
|
<string name="error_401">401 Unauthorized</string>
|
||||||
|
<string name="error_403">403 Forbidden</string>
|
||||||
|
<string name="error_404">404 Not Found</string>
|
||||||
|
<string name="error_sync">Sync failed: %1$s</string>
|
||||||
|
<string name="error_invalid_login">Invalid login: %1$s</string>
|
||||||
|
<string name="error_auth">Wrong username or password</string>
|
||||||
|
<string name="error_json">Invalid server response</string>
|
||||||
|
<string name="error_req_failed">Request failed</string>
|
||||||
|
<string name="error_invalid_email">Invalid e-mail</string>
|
||||||
|
<string name="error_invalid_project_id">Invalid project ID</string>
|
||||||
|
<string name="error_invalid_project_name">Invalid project title</string>
|
||||||
|
<string name="error_invalid_bill_name">Invalid bill name</string>
|
||||||
|
<string name="error_invalid_bill_date">Invalid bill date</string>
|
||||||
|
<string name="error_invalid_bill_payer">Payer required</string>
|
||||||
|
<string name="error_invalid_bill_owers">Owers required</string>
|
||||||
|
<string name="error_no_network">No network connection</string>
|
||||||
|
<string name="error_server">Server error</string>
|
||||||
|
<string name="error_io">Server connection broken</string>
|
||||||
|
<string name="error_share_impossible">Cannot share this project</string>
|
||||||
|
|
||||||
|
<!-- Drawer / Common UI -->
|
||||||
|
<string name="drawer_no_account">Connect to Nextcloud account</string>
|
||||||
|
<string name="drawer_last_sync">Last sync: %1$02d:%2$02d</string>
|
||||||
|
<string name="simple_cancel">Cancel</string>
|
||||||
|
<string name="simple_ok" tools:ignore="ButtonCase,Typos">Ok</string>
|
||||||
|
<string name="simple_yes">Yes</string>
|
||||||
|
<string name="simple_no">No</string>
|
||||||
|
<string name="simple_close">Close</string>
|
||||||
|
|
||||||
|
<!-- Settings -->
|
||||||
|
<string name="settings_appearance">Appearance</string>
|
||||||
|
<string name="settings_network">Network</string>
|
||||||
|
<string name="settings_other">Other</string>
|
||||||
|
<string name="settings_night_mode">Theme</string>
|
||||||
|
<string name="settings_offline_mode">Offline mode</string>
|
||||||
|
<string name="settings_offline_mode_summary">Only sync manually.</string>
|
||||||
|
<string name="settings_color_custom">Custom color</string>
|
||||||
|
<string name="settings_color_mode">Color Selection</string>
|
||||||
|
<string name="settings_show_archived">Show archived projects</string>
|
||||||
|
<string name="settings_beta_features">Beta Features</string>
|
||||||
|
<string name="settings_beta_features_summary">Enable experimental features. Use at your own risk.</string>
|
||||||
|
<string name="settings_fill_new_bill_from_last">Auto-fill from last bill</string>
|
||||||
|
<string name="settings_fill_new_bill_from_last_summary">Pre-fill payer, category, mode and owers from the last bill created in the project.</string>
|
||||||
|
<string name="settings_auto_sync_on_open">Sync interval</string>
|
||||||
|
<string name="settings_auto_sync_on_open_summary">How often to refresh the account and all projects when opening the app.</string>
|
||||||
|
<string name="pref_value_sync_1m">1 minute</string>
|
||||||
|
<string name="pref_value_sync_10m">10 minutes</string>
|
||||||
|
<string name="pref_value_sync_1h">1 hour</string>
|
||||||
|
<string name="pref_value_sync_1d">1 day</string>
|
||||||
|
<string name="settings_url_warn_http">WARNING: "http" is unsafe. Use "https".</string>
|
||||||
|
<string name="settings_colorpicker_title">Choose Color</string>
|
||||||
|
|
||||||
|
<string name="pref_value_color_system">System</string>
|
||||||
|
<string name="pref_value_color_manual">Manual</string>
|
||||||
|
<string name="pref_value_theme_light">Light</string>
|
||||||
|
<string name="pref_value_theme_dark">Dark</string>
|
||||||
|
<string name="pref_value_theme_system">Follow system</string>
|
||||||
|
|
||||||
|
<!-- Enums and Lists -->
|
||||||
|
<string name="repeat_no">No repeat</string>
|
||||||
|
<string name="repeat_day">Daily</string>
|
||||||
|
<string name="repeat_week">Weekly</string>
|
||||||
|
<string name="repeat_fortnight">Fortnightly</string>
|
||||||
|
<string name="repeat_month">Monthly</string>
|
||||||
|
<string name="repeat_year">Yearly</string>
|
||||||
|
|
||||||
|
<string name="payment_mode_none">None</string>
|
||||||
|
<string name="payment_mode_all">All</string>
|
||||||
|
<string name="payment_mode_credit_card">Credit card</string>
|
||||||
|
<string name="payment_mode_cash">Cash</string>
|
||||||
|
<string name="payment_mode_check">Check</string>
|
||||||
|
<string name="payment_mode_online">Online</string>
|
||||||
|
<string name="payment_mode_transfer">Transfer</string>
|
||||||
|
|
||||||
|
<string name="category_none">None</string>
|
||||||
|
<string name="category_all">All</string>
|
||||||
|
<string name="category_all_except_reimbursement">All except reimbursement</string>
|
||||||
|
<string name="category_groceries">Grocery</string>
|
||||||
|
<string name="category_leisure">Bar/Party</string>
|
||||||
|
<string name="category_rent">Rent</string>
|
||||||
|
<string name="category_bills">Bill</string>
|
||||||
|
<string name="category_excursion">Excursion/Culture</string>
|
||||||
|
<string name="category_health">Health</string>
|
||||||
|
<string name="category_shopping">Shopping</string>
|
||||||
|
<string name="category_reimbursement">Reimbursement</string>
|
||||||
|
<string name="category_restaurant">Restaurant</string>
|
||||||
|
<string name="category_accomodation">Accommodation</string>
|
||||||
|
<string name="category_transport">Transport</string>
|
||||||
|
<string name="category_sport">Sport</string>
|
||||||
|
|
||||||
|
<!-- Project specific -->
|
||||||
|
<string name="new_project_action">What</string>
|
||||||
|
<string name="new_project_where">Where</string>
|
||||||
|
<string name="where_local">Local only</string>
|
||||||
|
<string name="todo_join">Join existing project</string>
|
||||||
|
<string name="todo_create">Create new project</string>
|
||||||
|
<string name="import_tooltip">Import from file</string>
|
||||||
|
<string name="choose_project_management_action">Project</string>
|
||||||
|
<string name="project_added_success">Project added successfully.</string>
|
||||||
|
<string name="no_projects_text">You have no projects yet.</string>
|
||||||
|
<string name="configure_account_choice">Configure Nextcloud account</string>
|
||||||
|
<string name="add_project_choice">Add project manually</string>
|
||||||
|
<string name="no_members_text">No members in this project.</string>
|
||||||
|
<string name="no_bills_text">No bills found.</string>
|
||||||
|
<string name="member_already_exists">Member already exists.</string>
|
||||||
|
<string name="activity_dialog_title">Project: %1$s</string>
|
||||||
|
<string name="remove_project_confirmation">Project %1$s removed.</string>
|
||||||
|
<string name="file_saved_success">File saved: %1$s</string>
|
||||||
|
<string name="import_error_header">Import failed at row %d</string>
|
||||||
|
<string name="import_error_date">Invalid date format at row %d</string>
|
||||||
|
<string name="import_error_owers">Invalid owers at row %d</string>
|
||||||
|
<string name="add_member_dialog_title">Add Member</string>
|
||||||
|
<string name="edit_member_dialog_title">Edit Member</string>
|
||||||
|
<string name="member_edit_delete">Delete</string>
|
||||||
|
<string name="project_edition_no_change">No changes to save.</string>
|
||||||
|
|
||||||
|
<!-- Settlement -->
|
||||||
|
<string name="center_none">None (Optimal)</string>
|
||||||
|
<string name="settle_who">Who pays</string>
|
||||||
|
<string name="settle_to_whom">To whom</string>
|
||||||
|
<string name="settle_how_much">Amount</string>
|
||||||
|
<string name="simple_settle_share">Share</string>
|
||||||
|
<string name="simple_create_bills">Create bills</string>
|
||||||
|
<string name="settle_bill_what">Settlement</string>
|
||||||
|
|
||||||
|
<!-- Currencies -->
|
||||||
|
<string name="currency_dialog_title">Choose Currency (%s)</string>
|
||||||
|
<string name="setting_none">None</string>
|
||||||
|
<string name="setting_all">All</string>
|
||||||
|
<string name="currency_saved_success">Currency settings saved.</string>
|
||||||
|
<string name="main_currency">Main Currency</string>
|
||||||
|
|
||||||
|
<!-- Statistics -->
|
||||||
|
<string name="label_bills_suggested">Suggested Categories</string>
|
||||||
|
<string name="label_bills_skip">Skip</string>
|
||||||
|
<string name="stats_date_min">From</string>
|
||||||
|
<string name="stats_date_max">To</string>
|
||||||
|
<string name="stats_who">Member</string>
|
||||||
|
<string name="stats_paid">Paid</string>
|
||||||
|
<string name="stats_spent">Spent</string>
|
||||||
|
<string name="stats_balance">Balance</string>
|
||||||
|
<string name="total">Total: %1$s</string>
|
||||||
|
|
||||||
|
<!-- Errors Extra -->
|
||||||
|
<string name="error_project_connect_check">Connection failed: %1$s</string>
|
||||||
|
<string name="error_create_remote_project_helper">Creation failed: %1$s</string>
|
||||||
|
<string name="error_edit_remote_project_helper">Error updating remote project: %1$s</string>
|
||||||
|
<string name="remote_project_operation_no_network">Network unavailable for remote operation.</string>
|
||||||
|
<string name="error_scanning_bill_qr_code">Failed to parse QR code.</string>
|
||||||
|
<string name="error_token_mismatch">Authentication token mismatch. Please log in again.</string>
|
||||||
|
<string name="insufficient_access_level">You don\'t have permission to perform this action.</string>
|
||||||
|
<string name="delete_label_confirmation_title">Delete Label</string>
|
||||||
|
<string name="delete_label_confirmation_message">Are you sure you want to delete this label?</string>
|
||||||
|
|
||||||
|
<!-- About -->
|
||||||
|
<string name="about_version">Version %1$s</string>
|
||||||
|
<string name="about_maintainer_title">Maintainer</string>
|
||||||
|
<string name="about_license_title">License</string>
|
||||||
|
<string name="about_source_title">Source code</string>
|
||||||
|
|
||||||
|
<!-- New constants for backward compatibility or shared use -->
|
||||||
|
<string name="share_intent_title">Project %1$s</string>
|
||||||
|
<string name="share_chooser_title">Share %1$s</string>
|
||||||
|
|
||||||
|
</resources>
|
||||||
@@ -0,0 +1,272 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Untranslated: these are the English strings, kept here so a translation can be
|
||||||
|
contributed by simply replacing the values. Strings marked translatable="false" in
|
||||||
|
values/strings.xml (app and product names, preference keys) are deliberately absent
|
||||||
|
and must not be added.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- Actions -->
|
||||||
|
<string name="action_new_bill">New bill</string>
|
||||||
|
<string name="action_add_project">Add project</string>
|
||||||
|
<string name="action_save">Save</string>
|
||||||
|
<string name="action_edit">Edit</string>
|
||||||
|
<string name="action_share">Share</string>
|
||||||
|
<string name="action_search">Search</string>
|
||||||
|
<string name="action_open_menu">Open menu</string>
|
||||||
|
<string name="action_close_search">Close search</string>
|
||||||
|
<string name="action_clear_search">Clear search</string>
|
||||||
|
<string name="action_delete">Delete</string>
|
||||||
|
<string name="simple_back">Back</string>
|
||||||
|
<string name="action_archive">Archive</string>
|
||||||
|
<string name="action_unarchive">Unarchive</string>
|
||||||
|
<string name="action_export">Export</string>
|
||||||
|
<string name="action_stats">Stats</string>
|
||||||
|
<string name="action_settle">Settle</string>
|
||||||
|
<string name="action_scan_qrcode">Scan QR Code</string>
|
||||||
|
<string name="action_settings">Settings</string>
|
||||||
|
<string name="action_label_bills">Label missing categories</string>
|
||||||
|
<string name="action_logout">Logout</string>
|
||||||
|
<string name="action_connect">Connect</string>
|
||||||
|
<string name="action_discard">Discard</string>
|
||||||
|
<string name="action_members">Members</string>
|
||||||
|
<string name="action_labels">Labels</string>
|
||||||
|
<string name="action_currencies">Currencies</string>
|
||||||
|
|
||||||
|
<!-- Titles -->
|
||||||
|
<string name="title_stats">Statistics</string>
|
||||||
|
<string name="title_edit_project">Edit project</string>
|
||||||
|
<string name="title_label_bills">Label Bills</string>
|
||||||
|
<string name="title_labels">Manage Labels</string>
|
||||||
|
<string name="title_about">About</string>
|
||||||
|
<string name="title_settle">Settle Project</string>
|
||||||
|
<string name="title_share">Share Project</string>
|
||||||
|
<string name="title_add_project">Add Project</string>
|
||||||
|
<string name="title_add_category">Add Category</string>
|
||||||
|
<string name="title_add_payment_mode">Add Payment Mode</string>
|
||||||
|
<string name="title_account">Nextcloud Account</string>
|
||||||
|
<string name="title_share_web">Web link</string>
|
||||||
|
<string name="title_share_qr">Cowspent link</string>
|
||||||
|
<string name="title_confirm">Are you sure?</string>
|
||||||
|
|
||||||
|
<!-- Labels and Fields -->
|
||||||
|
<string name="label_all_bills">All bills</string>
|
||||||
|
<string name="label_categories">Categories</string>
|
||||||
|
<string name="label_payment_modes">Payment Modes</string>
|
||||||
|
<string name="label_name">Name</string>
|
||||||
|
<string name="label_icon">Icon / Emoji</string>
|
||||||
|
<string name="label_color">Color</string>
|
||||||
|
<string name="label_weight">Weight</string>
|
||||||
|
<string name="label_activated">Activated</string>
|
||||||
|
<string name="label_password">Password</string>
|
||||||
|
<string name="label_email">E-mail</string>
|
||||||
|
<string name="label_url">Server address</string>
|
||||||
|
<string name="label_username">Username</string>
|
||||||
|
<string name="label_comment">Comment</string>
|
||||||
|
<string name="label_what">What?</string>
|
||||||
|
<string name="label_payer">Who paid?</string>
|
||||||
|
<string name="label_owers">For whom?</string>
|
||||||
|
<string name="label_repeat">Repeat every</string>
|
||||||
|
<string name="label_mode">Mode</string>
|
||||||
|
<string name="label_category">Category</string>
|
||||||
|
<string name="label_project_id">Project ID/name</string>
|
||||||
|
<string name="label_project_title">Project title</string>
|
||||||
|
<string name="label_use_sso">Use Nextcloud App Account</string>
|
||||||
|
|
||||||
|
<!-- Dialogs and Messages -->
|
||||||
|
<string name="dialog_unsaved_changes_title">Unsaved changes</string>
|
||||||
|
<string name="dialog_unsaved_changes_msg">Save changes before leaving?</string>
|
||||||
|
<string name="dialog_confirm_remove_project_msg">The remote project will not be deleted.</string>
|
||||||
|
<string name="dialog_sync_error_title">Sync error</string>
|
||||||
|
<string name="dialog_sync_error_msg">Sync failed for %1$s.\n\n%2$s</string>
|
||||||
|
<string name="dialog_balanced_msg">Expenses are already balanced.</string>
|
||||||
|
<string name="msg_project_added">Project %1$s added</string>
|
||||||
|
<string name="msg_bill_labeled_done">All bills labeled</string>
|
||||||
|
<string name="msg_no_suggestions">No suggestions</string>
|
||||||
|
<string name="msg_auth_warning">Requires Cospend v0.3.4+.</string>
|
||||||
|
<string name="msg_link_copied">Link copied to clipboard</string>
|
||||||
|
<string name="msg_share_qr">Scan QR code or share the link to join.</string>
|
||||||
|
<string name="msg_share_web">Link for web browser access.</string>
|
||||||
|
<string name="msg_share_qr_warn">Share this link with a Cowspent user.</string>
|
||||||
|
<string name="msg_settle_intro">Settlement for %1$s:</string>
|
||||||
|
<string name="msg_settle_sentence">%1$s owes %3$.2f to %2$s</string>
|
||||||
|
<string name="msg_stats_intro">Stats for %1$s:</string>
|
||||||
|
<string name="msg_stats_header">Member (Paid | Spent | Balance)</string>
|
||||||
|
<string name="msg_logged_in_as">Logged in as %1$s</string>
|
||||||
|
|
||||||
|
<!-- Errors -->
|
||||||
|
<string name="error_generic">Error</string>
|
||||||
|
<string name="error_loading">Loading</string>
|
||||||
|
<string name="error_no_projects">No projects found</string>
|
||||||
|
<string name="error_no_members">No members found</string>
|
||||||
|
<string name="error_no_bills">No bills found</string>
|
||||||
|
<string name="error_no_member">At least one member required</string>
|
||||||
|
<string name="error_maintenance_mode">Server is in maintenance mode</string>
|
||||||
|
<string name="error_400">400 Bad request</string>
|
||||||
|
<string name="error_401">401 Unauthorized</string>
|
||||||
|
<string name="error_403">403 Forbidden</string>
|
||||||
|
<string name="error_404">404 Not Found</string>
|
||||||
|
<string name="error_sync">Sync failed: %1$s</string>
|
||||||
|
<string name="error_invalid_login">Invalid login: %1$s</string>
|
||||||
|
<string name="error_auth">Wrong username or password</string>
|
||||||
|
<string name="error_json">Invalid server response</string>
|
||||||
|
<string name="error_req_failed">Request failed</string>
|
||||||
|
<string name="error_invalid_email">Invalid e-mail</string>
|
||||||
|
<string name="error_invalid_project_id">Invalid project ID</string>
|
||||||
|
<string name="error_invalid_project_name">Invalid project title</string>
|
||||||
|
<string name="error_invalid_bill_name">Invalid bill name</string>
|
||||||
|
<string name="error_invalid_bill_date">Invalid bill date</string>
|
||||||
|
<string name="error_invalid_bill_payer">Payer required</string>
|
||||||
|
<string name="error_invalid_bill_owers">Owers required</string>
|
||||||
|
<string name="error_no_network">No network connection</string>
|
||||||
|
<string name="error_server">Server error</string>
|
||||||
|
<string name="error_io">Server connection broken</string>
|
||||||
|
<string name="error_share_impossible">Cannot share this project</string>
|
||||||
|
|
||||||
|
<!-- Drawer / Common UI -->
|
||||||
|
<string name="drawer_no_account">Connect to Nextcloud account</string>
|
||||||
|
<string name="drawer_last_sync">Last sync: %1$02d:%2$02d</string>
|
||||||
|
<string name="simple_cancel">Cancel</string>
|
||||||
|
<string name="simple_ok" tools:ignore="ButtonCase,Typos">Ok</string>
|
||||||
|
<string name="simple_yes">Yes</string>
|
||||||
|
<string name="simple_no">No</string>
|
||||||
|
<string name="simple_close">Close</string>
|
||||||
|
|
||||||
|
<!-- Settings -->
|
||||||
|
<string name="settings_appearance">Appearance</string>
|
||||||
|
<string name="settings_network">Network</string>
|
||||||
|
<string name="settings_other">Other</string>
|
||||||
|
<string name="settings_night_mode">Theme</string>
|
||||||
|
<string name="settings_offline_mode">Offline mode</string>
|
||||||
|
<string name="settings_offline_mode_summary">Only sync manually.</string>
|
||||||
|
<string name="settings_color_custom">Custom color</string>
|
||||||
|
<string name="settings_color_mode">Color Selection</string>
|
||||||
|
<string name="settings_show_archived">Show archived projects</string>
|
||||||
|
<string name="settings_beta_features">Beta Features</string>
|
||||||
|
<string name="settings_beta_features_summary">Enable experimental features. Use at your own risk.</string>
|
||||||
|
<string name="settings_fill_new_bill_from_last">Auto-fill from last bill</string>
|
||||||
|
<string name="settings_fill_new_bill_from_last_summary">Pre-fill payer, category, mode and owers from the last bill created in the project.</string>
|
||||||
|
<string name="settings_auto_sync_on_open">Sync interval</string>
|
||||||
|
<string name="settings_auto_sync_on_open_summary">How often to refresh the account and all projects when opening the app.</string>
|
||||||
|
<string name="pref_value_sync_1m">1 minute</string>
|
||||||
|
<string name="pref_value_sync_10m">10 minutes</string>
|
||||||
|
<string name="pref_value_sync_1h">1 hour</string>
|
||||||
|
<string name="pref_value_sync_1d">1 day</string>
|
||||||
|
<string name="settings_url_warn_http">WARNING: "http" is unsafe. Use "https".</string>
|
||||||
|
<string name="settings_colorpicker_title">Choose Color</string>
|
||||||
|
|
||||||
|
<string name="pref_value_color_system">System</string>
|
||||||
|
<string name="pref_value_color_manual">Manual</string>
|
||||||
|
<string name="pref_value_theme_light">Light</string>
|
||||||
|
<string name="pref_value_theme_dark">Dark</string>
|
||||||
|
<string name="pref_value_theme_system">Follow system</string>
|
||||||
|
|
||||||
|
<!-- Enums and Lists -->
|
||||||
|
<string name="repeat_no">No repeat</string>
|
||||||
|
<string name="repeat_day">Daily</string>
|
||||||
|
<string name="repeat_week">Weekly</string>
|
||||||
|
<string name="repeat_fortnight">Fortnightly</string>
|
||||||
|
<string name="repeat_month">Monthly</string>
|
||||||
|
<string name="repeat_year">Yearly</string>
|
||||||
|
|
||||||
|
<string name="payment_mode_none">None</string>
|
||||||
|
<string name="payment_mode_all">All</string>
|
||||||
|
<string name="payment_mode_credit_card">Credit card</string>
|
||||||
|
<string name="payment_mode_cash">Cash</string>
|
||||||
|
<string name="payment_mode_check">Check</string>
|
||||||
|
<string name="payment_mode_online">Online</string>
|
||||||
|
<string name="payment_mode_transfer">Transfer</string>
|
||||||
|
|
||||||
|
<string name="category_none">None</string>
|
||||||
|
<string name="category_all">All</string>
|
||||||
|
<string name="category_all_except_reimbursement">All except reimbursement</string>
|
||||||
|
<string name="category_groceries">Grocery</string>
|
||||||
|
<string name="category_leisure">Bar/Party</string>
|
||||||
|
<string name="category_rent">Rent</string>
|
||||||
|
<string name="category_bills">Bill</string>
|
||||||
|
<string name="category_excursion">Excursion/Culture</string>
|
||||||
|
<string name="category_health">Health</string>
|
||||||
|
<string name="category_shopping">Shopping</string>
|
||||||
|
<string name="category_reimbursement">Reimbursement</string>
|
||||||
|
<string name="category_restaurant">Restaurant</string>
|
||||||
|
<string name="category_accomodation">Accommodation</string>
|
||||||
|
<string name="category_transport">Transport</string>
|
||||||
|
<string name="category_sport">Sport</string>
|
||||||
|
|
||||||
|
<!-- Project specific -->
|
||||||
|
<string name="new_project_action">What</string>
|
||||||
|
<string name="new_project_where">Where</string>
|
||||||
|
<string name="where_local">Local only</string>
|
||||||
|
<string name="todo_join">Join existing project</string>
|
||||||
|
<string name="todo_create">Create new project</string>
|
||||||
|
<string name="import_tooltip">Import from file</string>
|
||||||
|
<string name="choose_project_management_action">Project</string>
|
||||||
|
<string name="project_added_success">Project added successfully.</string>
|
||||||
|
<string name="no_projects_text">You have no projects yet.</string>
|
||||||
|
<string name="configure_account_choice">Configure Nextcloud account</string>
|
||||||
|
<string name="add_project_choice">Add project manually</string>
|
||||||
|
<string name="no_members_text">No members in this project.</string>
|
||||||
|
<string name="no_bills_text">No bills found.</string>
|
||||||
|
<string name="member_already_exists">Member already exists.</string>
|
||||||
|
<string name="activity_dialog_title">Project: %1$s</string>
|
||||||
|
<string name="remove_project_confirmation">Project %1$s removed.</string>
|
||||||
|
<string name="file_saved_success">File saved: %1$s</string>
|
||||||
|
<string name="import_error_header">Import failed at row %d</string>
|
||||||
|
<string name="import_error_date">Invalid date format at row %d</string>
|
||||||
|
<string name="import_error_owers">Invalid owers at row %d</string>
|
||||||
|
<string name="add_member_dialog_title">Add Member</string>
|
||||||
|
<string name="edit_member_dialog_title">Edit Member</string>
|
||||||
|
<string name="member_edit_delete">Delete</string>
|
||||||
|
<string name="project_edition_no_change">No changes to save.</string>
|
||||||
|
|
||||||
|
<!-- Settlement -->
|
||||||
|
<string name="center_none">None (Optimal)</string>
|
||||||
|
<string name="settle_who">Who pays</string>
|
||||||
|
<string name="settle_to_whom">To whom</string>
|
||||||
|
<string name="settle_how_much">Amount</string>
|
||||||
|
<string name="simple_settle_share">Share</string>
|
||||||
|
<string name="simple_create_bills">Create bills</string>
|
||||||
|
<string name="settle_bill_what">Settlement</string>
|
||||||
|
|
||||||
|
<!-- Currencies -->
|
||||||
|
<string name="currency_dialog_title">Choose Currency (%s)</string>
|
||||||
|
<string name="setting_none">None</string>
|
||||||
|
<string name="setting_all">All</string>
|
||||||
|
<string name="currency_saved_success">Currency settings saved.</string>
|
||||||
|
<string name="main_currency">Main Currency</string>
|
||||||
|
|
||||||
|
<!-- Statistics -->
|
||||||
|
<string name="label_bills_suggested">Suggested Categories</string>
|
||||||
|
<string name="label_bills_skip">Skip</string>
|
||||||
|
<string name="stats_date_min">From</string>
|
||||||
|
<string name="stats_date_max">To</string>
|
||||||
|
<string name="stats_who">Member</string>
|
||||||
|
<string name="stats_paid">Paid</string>
|
||||||
|
<string name="stats_spent">Spent</string>
|
||||||
|
<string name="stats_balance">Balance</string>
|
||||||
|
<string name="total">Total: %1$s</string>
|
||||||
|
|
||||||
|
<!-- Errors Extra -->
|
||||||
|
<string name="error_project_connect_check">Connection failed: %1$s</string>
|
||||||
|
<string name="error_create_remote_project_helper">Creation failed: %1$s</string>
|
||||||
|
<string name="error_edit_remote_project_helper">Error updating remote project: %1$s</string>
|
||||||
|
<string name="remote_project_operation_no_network">Network unavailable for remote operation.</string>
|
||||||
|
<string name="error_scanning_bill_qr_code">Failed to parse QR code.</string>
|
||||||
|
<string name="error_token_mismatch">Authentication token mismatch. Please log in again.</string>
|
||||||
|
<string name="insufficient_access_level">You don\'t have permission to perform this action.</string>
|
||||||
|
<string name="delete_label_confirmation_title">Delete Label</string>
|
||||||
|
<string name="delete_label_confirmation_message">Are you sure you want to delete this label?</string>
|
||||||
|
|
||||||
|
<!-- About -->
|
||||||
|
<string name="about_version">Version %1$s</string>
|
||||||
|
<string name="about_maintainer_title">Maintainer</string>
|
||||||
|
<string name="about_license_title">License</string>
|
||||||
|
<string name="about_source_title">Source code</string>
|
||||||
|
|
||||||
|
<!-- New constants for backward compatibility or shared use -->
|
||||||
|
<string name="share_intent_title">Project %1$s</string>
|
||||||
|
<string name="share_chooser_title">Share %1$s</string>
|
||||||
|
|
||||||
|
</resources>
|
||||||
@@ -0,0 +1,272 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Untranslated: these are the English strings, kept here so a translation can be
|
||||||
|
contributed by simply replacing the values. Strings marked translatable="false" in
|
||||||
|
values/strings.xml (app and product names, preference keys) are deliberately absent
|
||||||
|
and must not be added.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- Actions -->
|
||||||
|
<string name="action_new_bill">New bill</string>
|
||||||
|
<string name="action_add_project">Add project</string>
|
||||||
|
<string name="action_save">Save</string>
|
||||||
|
<string name="action_edit">Edit</string>
|
||||||
|
<string name="action_share">Share</string>
|
||||||
|
<string name="action_search">Search</string>
|
||||||
|
<string name="action_open_menu">Open menu</string>
|
||||||
|
<string name="action_close_search">Close search</string>
|
||||||
|
<string name="action_clear_search">Clear search</string>
|
||||||
|
<string name="action_delete">Delete</string>
|
||||||
|
<string name="simple_back">Back</string>
|
||||||
|
<string name="action_archive">Archive</string>
|
||||||
|
<string name="action_unarchive">Unarchive</string>
|
||||||
|
<string name="action_export">Export</string>
|
||||||
|
<string name="action_stats">Stats</string>
|
||||||
|
<string name="action_settle">Settle</string>
|
||||||
|
<string name="action_scan_qrcode">Scan QR Code</string>
|
||||||
|
<string name="action_settings">Settings</string>
|
||||||
|
<string name="action_label_bills">Label missing categories</string>
|
||||||
|
<string name="action_logout">Logout</string>
|
||||||
|
<string name="action_connect">Connect</string>
|
||||||
|
<string name="action_discard">Discard</string>
|
||||||
|
<string name="action_members">Members</string>
|
||||||
|
<string name="action_labels">Labels</string>
|
||||||
|
<string name="action_currencies">Currencies</string>
|
||||||
|
|
||||||
|
<!-- Titles -->
|
||||||
|
<string name="title_stats">Statistics</string>
|
||||||
|
<string name="title_edit_project">Edit project</string>
|
||||||
|
<string name="title_label_bills">Label Bills</string>
|
||||||
|
<string name="title_labels">Manage Labels</string>
|
||||||
|
<string name="title_about">About</string>
|
||||||
|
<string name="title_settle">Settle Project</string>
|
||||||
|
<string name="title_share">Share Project</string>
|
||||||
|
<string name="title_add_project">Add Project</string>
|
||||||
|
<string name="title_add_category">Add Category</string>
|
||||||
|
<string name="title_add_payment_mode">Add Payment Mode</string>
|
||||||
|
<string name="title_account">Nextcloud Account</string>
|
||||||
|
<string name="title_share_web">Web link</string>
|
||||||
|
<string name="title_share_qr">Cowspent link</string>
|
||||||
|
<string name="title_confirm">Are you sure?</string>
|
||||||
|
|
||||||
|
<!-- Labels and Fields -->
|
||||||
|
<string name="label_all_bills">All bills</string>
|
||||||
|
<string name="label_categories">Categories</string>
|
||||||
|
<string name="label_payment_modes">Payment Modes</string>
|
||||||
|
<string name="label_name">Name</string>
|
||||||
|
<string name="label_icon">Icon / Emoji</string>
|
||||||
|
<string name="label_color">Color</string>
|
||||||
|
<string name="label_weight">Weight</string>
|
||||||
|
<string name="label_activated">Activated</string>
|
||||||
|
<string name="label_password">Password</string>
|
||||||
|
<string name="label_email">E-mail</string>
|
||||||
|
<string name="label_url">Server address</string>
|
||||||
|
<string name="label_username">Username</string>
|
||||||
|
<string name="label_comment">Comment</string>
|
||||||
|
<string name="label_what">What?</string>
|
||||||
|
<string name="label_payer">Who paid?</string>
|
||||||
|
<string name="label_owers">For whom?</string>
|
||||||
|
<string name="label_repeat">Repeat every</string>
|
||||||
|
<string name="label_mode">Mode</string>
|
||||||
|
<string name="label_category">Category</string>
|
||||||
|
<string name="label_project_id">Project ID/name</string>
|
||||||
|
<string name="label_project_title">Project title</string>
|
||||||
|
<string name="label_use_sso">Use Nextcloud App Account</string>
|
||||||
|
|
||||||
|
<!-- Dialogs and Messages -->
|
||||||
|
<string name="dialog_unsaved_changes_title">Unsaved changes</string>
|
||||||
|
<string name="dialog_unsaved_changes_msg">Save changes before leaving?</string>
|
||||||
|
<string name="dialog_confirm_remove_project_msg">The remote project will not be deleted.</string>
|
||||||
|
<string name="dialog_sync_error_title">Sync error</string>
|
||||||
|
<string name="dialog_sync_error_msg">Sync failed for %1$s.\n\n%2$s</string>
|
||||||
|
<string name="dialog_balanced_msg">Expenses are already balanced.</string>
|
||||||
|
<string name="msg_project_added">Project %1$s added</string>
|
||||||
|
<string name="msg_bill_labeled_done">All bills labeled</string>
|
||||||
|
<string name="msg_no_suggestions">No suggestions</string>
|
||||||
|
<string name="msg_auth_warning">Requires Cospend v0.3.4+.</string>
|
||||||
|
<string name="msg_link_copied">Link copied to clipboard</string>
|
||||||
|
<string name="msg_share_qr">Scan QR code or share the link to join.</string>
|
||||||
|
<string name="msg_share_web">Link for web browser access.</string>
|
||||||
|
<string name="msg_share_qr_warn">Share this link with a Cowspent user.</string>
|
||||||
|
<string name="msg_settle_intro">Settlement for %1$s:</string>
|
||||||
|
<string name="msg_settle_sentence">%1$s owes %3$.2f to %2$s</string>
|
||||||
|
<string name="msg_stats_intro">Stats for %1$s:</string>
|
||||||
|
<string name="msg_stats_header">Member (Paid | Spent | Balance)</string>
|
||||||
|
<string name="msg_logged_in_as">Logged in as %1$s</string>
|
||||||
|
|
||||||
|
<!-- Errors -->
|
||||||
|
<string name="error_generic">Error</string>
|
||||||
|
<string name="error_loading">Loading</string>
|
||||||
|
<string name="error_no_projects">No projects found</string>
|
||||||
|
<string name="error_no_members">No members found</string>
|
||||||
|
<string name="error_no_bills">No bills found</string>
|
||||||
|
<string name="error_no_member">At least one member required</string>
|
||||||
|
<string name="error_maintenance_mode">Server is in maintenance mode</string>
|
||||||
|
<string name="error_400">400 Bad request</string>
|
||||||
|
<string name="error_401">401 Unauthorized</string>
|
||||||
|
<string name="error_403">403 Forbidden</string>
|
||||||
|
<string name="error_404">404 Not Found</string>
|
||||||
|
<string name="error_sync">Sync failed: %1$s</string>
|
||||||
|
<string name="error_invalid_login">Invalid login: %1$s</string>
|
||||||
|
<string name="error_auth">Wrong username or password</string>
|
||||||
|
<string name="error_json">Invalid server response</string>
|
||||||
|
<string name="error_req_failed">Request failed</string>
|
||||||
|
<string name="error_invalid_email">Invalid e-mail</string>
|
||||||
|
<string name="error_invalid_project_id">Invalid project ID</string>
|
||||||
|
<string name="error_invalid_project_name">Invalid project title</string>
|
||||||
|
<string name="error_invalid_bill_name">Invalid bill name</string>
|
||||||
|
<string name="error_invalid_bill_date">Invalid bill date</string>
|
||||||
|
<string name="error_invalid_bill_payer">Payer required</string>
|
||||||
|
<string name="error_invalid_bill_owers">Owers required</string>
|
||||||
|
<string name="error_no_network">No network connection</string>
|
||||||
|
<string name="error_server">Server error</string>
|
||||||
|
<string name="error_io">Server connection broken</string>
|
||||||
|
<string name="error_share_impossible">Cannot share this project</string>
|
||||||
|
|
||||||
|
<!-- Drawer / Common UI -->
|
||||||
|
<string name="drawer_no_account">Connect to Nextcloud account</string>
|
||||||
|
<string name="drawer_last_sync">Last sync: %1$02d:%2$02d</string>
|
||||||
|
<string name="simple_cancel">Cancel</string>
|
||||||
|
<string name="simple_ok" tools:ignore="ButtonCase,Typos">Ok</string>
|
||||||
|
<string name="simple_yes">Yes</string>
|
||||||
|
<string name="simple_no">No</string>
|
||||||
|
<string name="simple_close">Close</string>
|
||||||
|
|
||||||
|
<!-- Settings -->
|
||||||
|
<string name="settings_appearance">Appearance</string>
|
||||||
|
<string name="settings_network">Network</string>
|
||||||
|
<string name="settings_other">Other</string>
|
||||||
|
<string name="settings_night_mode">Theme</string>
|
||||||
|
<string name="settings_offline_mode">Offline mode</string>
|
||||||
|
<string name="settings_offline_mode_summary">Only sync manually.</string>
|
||||||
|
<string name="settings_color_custom">Custom color</string>
|
||||||
|
<string name="settings_color_mode">Color Selection</string>
|
||||||
|
<string name="settings_show_archived">Show archived projects</string>
|
||||||
|
<string name="settings_beta_features">Beta Features</string>
|
||||||
|
<string name="settings_beta_features_summary">Enable experimental features. Use at your own risk.</string>
|
||||||
|
<string name="settings_fill_new_bill_from_last">Auto-fill from last bill</string>
|
||||||
|
<string name="settings_fill_new_bill_from_last_summary">Pre-fill payer, category, mode and owers from the last bill created in the project.</string>
|
||||||
|
<string name="settings_auto_sync_on_open">Sync interval</string>
|
||||||
|
<string name="settings_auto_sync_on_open_summary">How often to refresh the account and all projects when opening the app.</string>
|
||||||
|
<string name="pref_value_sync_1m">1 minute</string>
|
||||||
|
<string name="pref_value_sync_10m">10 minutes</string>
|
||||||
|
<string name="pref_value_sync_1h">1 hour</string>
|
||||||
|
<string name="pref_value_sync_1d">1 day</string>
|
||||||
|
<string name="settings_url_warn_http">WARNING: "http" is unsafe. Use "https".</string>
|
||||||
|
<string name="settings_colorpicker_title">Choose Color</string>
|
||||||
|
|
||||||
|
<string name="pref_value_color_system">System</string>
|
||||||
|
<string name="pref_value_color_manual">Manual</string>
|
||||||
|
<string name="pref_value_theme_light">Light</string>
|
||||||
|
<string name="pref_value_theme_dark">Dark</string>
|
||||||
|
<string name="pref_value_theme_system">Follow system</string>
|
||||||
|
|
||||||
|
<!-- Enums and Lists -->
|
||||||
|
<string name="repeat_no">No repeat</string>
|
||||||
|
<string name="repeat_day">Daily</string>
|
||||||
|
<string name="repeat_week">Weekly</string>
|
||||||
|
<string name="repeat_fortnight">Fortnightly</string>
|
||||||
|
<string name="repeat_month">Monthly</string>
|
||||||
|
<string name="repeat_year">Yearly</string>
|
||||||
|
|
||||||
|
<string name="payment_mode_none">None</string>
|
||||||
|
<string name="payment_mode_all">All</string>
|
||||||
|
<string name="payment_mode_credit_card">Credit card</string>
|
||||||
|
<string name="payment_mode_cash">Cash</string>
|
||||||
|
<string name="payment_mode_check">Check</string>
|
||||||
|
<string name="payment_mode_online">Online</string>
|
||||||
|
<string name="payment_mode_transfer">Transfer</string>
|
||||||
|
|
||||||
|
<string name="category_none">None</string>
|
||||||
|
<string name="category_all">All</string>
|
||||||
|
<string name="category_all_except_reimbursement">All except reimbursement</string>
|
||||||
|
<string name="category_groceries">Grocery</string>
|
||||||
|
<string name="category_leisure">Bar/Party</string>
|
||||||
|
<string name="category_rent">Rent</string>
|
||||||
|
<string name="category_bills">Bill</string>
|
||||||
|
<string name="category_excursion">Excursion/Culture</string>
|
||||||
|
<string name="category_health">Health</string>
|
||||||
|
<string name="category_shopping">Shopping</string>
|
||||||
|
<string name="category_reimbursement">Reimbursement</string>
|
||||||
|
<string name="category_restaurant">Restaurant</string>
|
||||||
|
<string name="category_accomodation">Accommodation</string>
|
||||||
|
<string name="category_transport">Transport</string>
|
||||||
|
<string name="category_sport">Sport</string>
|
||||||
|
|
||||||
|
<!-- Project specific -->
|
||||||
|
<string name="new_project_action">What</string>
|
||||||
|
<string name="new_project_where">Where</string>
|
||||||
|
<string name="where_local">Local only</string>
|
||||||
|
<string name="todo_join">Join existing project</string>
|
||||||
|
<string name="todo_create">Create new project</string>
|
||||||
|
<string name="import_tooltip">Import from file</string>
|
||||||
|
<string name="choose_project_management_action">Project</string>
|
||||||
|
<string name="project_added_success">Project added successfully.</string>
|
||||||
|
<string name="no_projects_text">You have no projects yet.</string>
|
||||||
|
<string name="configure_account_choice">Configure Nextcloud account</string>
|
||||||
|
<string name="add_project_choice">Add project manually</string>
|
||||||
|
<string name="no_members_text">No members in this project.</string>
|
||||||
|
<string name="no_bills_text">No bills found.</string>
|
||||||
|
<string name="member_already_exists">Member already exists.</string>
|
||||||
|
<string name="activity_dialog_title">Project: %1$s</string>
|
||||||
|
<string name="remove_project_confirmation">Project %1$s removed.</string>
|
||||||
|
<string name="file_saved_success">File saved: %1$s</string>
|
||||||
|
<string name="import_error_header">Import failed at row %d</string>
|
||||||
|
<string name="import_error_date">Invalid date format at row %d</string>
|
||||||
|
<string name="import_error_owers">Invalid owers at row %d</string>
|
||||||
|
<string name="add_member_dialog_title">Add Member</string>
|
||||||
|
<string name="edit_member_dialog_title">Edit Member</string>
|
||||||
|
<string name="member_edit_delete">Delete</string>
|
||||||
|
<string name="project_edition_no_change">No changes to save.</string>
|
||||||
|
|
||||||
|
<!-- Settlement -->
|
||||||
|
<string name="center_none">None (Optimal)</string>
|
||||||
|
<string name="settle_who">Who pays</string>
|
||||||
|
<string name="settle_to_whom">To whom</string>
|
||||||
|
<string name="settle_how_much">Amount</string>
|
||||||
|
<string name="simple_settle_share">Share</string>
|
||||||
|
<string name="simple_create_bills">Create bills</string>
|
||||||
|
<string name="settle_bill_what">Settlement</string>
|
||||||
|
|
||||||
|
<!-- Currencies -->
|
||||||
|
<string name="currency_dialog_title">Choose Currency (%s)</string>
|
||||||
|
<string name="setting_none">None</string>
|
||||||
|
<string name="setting_all">All</string>
|
||||||
|
<string name="currency_saved_success">Currency settings saved.</string>
|
||||||
|
<string name="main_currency">Main Currency</string>
|
||||||
|
|
||||||
|
<!-- Statistics -->
|
||||||
|
<string name="label_bills_suggested">Suggested Categories</string>
|
||||||
|
<string name="label_bills_skip">Skip</string>
|
||||||
|
<string name="stats_date_min">From</string>
|
||||||
|
<string name="stats_date_max">To</string>
|
||||||
|
<string name="stats_who">Member</string>
|
||||||
|
<string name="stats_paid">Paid</string>
|
||||||
|
<string name="stats_spent">Spent</string>
|
||||||
|
<string name="stats_balance">Balance</string>
|
||||||
|
<string name="total">Total: %1$s</string>
|
||||||
|
|
||||||
|
<!-- Errors Extra -->
|
||||||
|
<string name="error_project_connect_check">Connection failed: %1$s</string>
|
||||||
|
<string name="error_create_remote_project_helper">Creation failed: %1$s</string>
|
||||||
|
<string name="error_edit_remote_project_helper">Error updating remote project: %1$s</string>
|
||||||
|
<string name="remote_project_operation_no_network">Network unavailable for remote operation.</string>
|
||||||
|
<string name="error_scanning_bill_qr_code">Failed to parse QR code.</string>
|
||||||
|
<string name="error_token_mismatch">Authentication token mismatch. Please log in again.</string>
|
||||||
|
<string name="insufficient_access_level">You don\'t have permission to perform this action.</string>
|
||||||
|
<string name="delete_label_confirmation_title">Delete Label</string>
|
||||||
|
<string name="delete_label_confirmation_message">Are you sure you want to delete this label?</string>
|
||||||
|
|
||||||
|
<!-- About -->
|
||||||
|
<string name="about_version">Version %1$s</string>
|
||||||
|
<string name="about_maintainer_title">Maintainer</string>
|
||||||
|
<string name="about_license_title">License</string>
|
||||||
|
<string name="about_source_title">Source code</string>
|
||||||
|
|
||||||
|
<!-- New constants for backward compatibility or shared use -->
|
||||||
|
<string name="share_intent_title">Project %1$s</string>
|
||||||
|
<string name="share_chooser_title">Share %1$s</string>
|
||||||
|
|
||||||
|
</resources>
|
||||||
@@ -0,0 +1,272 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Untranslated: these are the English strings, kept here so a translation can be
|
||||||
|
contributed by simply replacing the values. Strings marked translatable="false" in
|
||||||
|
values/strings.xml (app and product names, preference keys) are deliberately absent
|
||||||
|
and must not be added.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- Actions -->
|
||||||
|
<string name="action_new_bill">New bill</string>
|
||||||
|
<string name="action_add_project">Add project</string>
|
||||||
|
<string name="action_save">Save</string>
|
||||||
|
<string name="action_edit">Edit</string>
|
||||||
|
<string name="action_share">Share</string>
|
||||||
|
<string name="action_search">Search</string>
|
||||||
|
<string name="action_open_menu">Open menu</string>
|
||||||
|
<string name="action_close_search">Close search</string>
|
||||||
|
<string name="action_clear_search">Clear search</string>
|
||||||
|
<string name="action_delete">Delete</string>
|
||||||
|
<string name="simple_back">Back</string>
|
||||||
|
<string name="action_archive">Archive</string>
|
||||||
|
<string name="action_unarchive">Unarchive</string>
|
||||||
|
<string name="action_export">Export</string>
|
||||||
|
<string name="action_stats">Stats</string>
|
||||||
|
<string name="action_settle">Settle</string>
|
||||||
|
<string name="action_scan_qrcode">Scan QR Code</string>
|
||||||
|
<string name="action_settings">Settings</string>
|
||||||
|
<string name="action_label_bills">Label missing categories</string>
|
||||||
|
<string name="action_logout">Logout</string>
|
||||||
|
<string name="action_connect">Connect</string>
|
||||||
|
<string name="action_discard">Discard</string>
|
||||||
|
<string name="action_members">Members</string>
|
||||||
|
<string name="action_labels">Labels</string>
|
||||||
|
<string name="action_currencies">Currencies</string>
|
||||||
|
|
||||||
|
<!-- Titles -->
|
||||||
|
<string name="title_stats">Statistics</string>
|
||||||
|
<string name="title_edit_project">Edit project</string>
|
||||||
|
<string name="title_label_bills">Label Bills</string>
|
||||||
|
<string name="title_labels">Manage Labels</string>
|
||||||
|
<string name="title_about">About</string>
|
||||||
|
<string name="title_settle">Settle Project</string>
|
||||||
|
<string name="title_share">Share Project</string>
|
||||||
|
<string name="title_add_project">Add Project</string>
|
||||||
|
<string name="title_add_category">Add Category</string>
|
||||||
|
<string name="title_add_payment_mode">Add Payment Mode</string>
|
||||||
|
<string name="title_account">Nextcloud Account</string>
|
||||||
|
<string name="title_share_web">Web link</string>
|
||||||
|
<string name="title_share_qr">Cowspent link</string>
|
||||||
|
<string name="title_confirm">Are you sure?</string>
|
||||||
|
|
||||||
|
<!-- Labels and Fields -->
|
||||||
|
<string name="label_all_bills">All bills</string>
|
||||||
|
<string name="label_categories">Categories</string>
|
||||||
|
<string name="label_payment_modes">Payment Modes</string>
|
||||||
|
<string name="label_name">Name</string>
|
||||||
|
<string name="label_icon">Icon / Emoji</string>
|
||||||
|
<string name="label_color">Color</string>
|
||||||
|
<string name="label_weight">Weight</string>
|
||||||
|
<string name="label_activated">Activated</string>
|
||||||
|
<string name="label_password">Password</string>
|
||||||
|
<string name="label_email">E-mail</string>
|
||||||
|
<string name="label_url">Server address</string>
|
||||||
|
<string name="label_username">Username</string>
|
||||||
|
<string name="label_comment">Comment</string>
|
||||||
|
<string name="label_what">What?</string>
|
||||||
|
<string name="label_payer">Who paid?</string>
|
||||||
|
<string name="label_owers">For whom?</string>
|
||||||
|
<string name="label_repeat">Repeat every</string>
|
||||||
|
<string name="label_mode">Mode</string>
|
||||||
|
<string name="label_category">Category</string>
|
||||||
|
<string name="label_project_id">Project ID/name</string>
|
||||||
|
<string name="label_project_title">Project title</string>
|
||||||
|
<string name="label_use_sso">Use Nextcloud App Account</string>
|
||||||
|
|
||||||
|
<!-- Dialogs and Messages -->
|
||||||
|
<string name="dialog_unsaved_changes_title">Unsaved changes</string>
|
||||||
|
<string name="dialog_unsaved_changes_msg">Save changes before leaving?</string>
|
||||||
|
<string name="dialog_confirm_remove_project_msg">The remote project will not be deleted.</string>
|
||||||
|
<string name="dialog_sync_error_title">Sync error</string>
|
||||||
|
<string name="dialog_sync_error_msg">Sync failed for %1$s.\n\n%2$s</string>
|
||||||
|
<string name="dialog_balanced_msg">Expenses are already balanced.</string>
|
||||||
|
<string name="msg_project_added">Project %1$s added</string>
|
||||||
|
<string name="msg_bill_labeled_done">All bills labeled</string>
|
||||||
|
<string name="msg_no_suggestions">No suggestions</string>
|
||||||
|
<string name="msg_auth_warning">Requires Cospend v0.3.4+.</string>
|
||||||
|
<string name="msg_link_copied">Link copied to clipboard</string>
|
||||||
|
<string name="msg_share_qr">Scan QR code or share the link to join.</string>
|
||||||
|
<string name="msg_share_web">Link for web browser access.</string>
|
||||||
|
<string name="msg_share_qr_warn">Share this link with a Cowspent user.</string>
|
||||||
|
<string name="msg_settle_intro">Settlement for %1$s:</string>
|
||||||
|
<string name="msg_settle_sentence">%1$s owes %3$.2f to %2$s</string>
|
||||||
|
<string name="msg_stats_intro">Stats for %1$s:</string>
|
||||||
|
<string name="msg_stats_header">Member (Paid | Spent | Balance)</string>
|
||||||
|
<string name="msg_logged_in_as">Logged in as %1$s</string>
|
||||||
|
|
||||||
|
<!-- Errors -->
|
||||||
|
<string name="error_generic">Error</string>
|
||||||
|
<string name="error_loading">Loading</string>
|
||||||
|
<string name="error_no_projects">No projects found</string>
|
||||||
|
<string name="error_no_members">No members found</string>
|
||||||
|
<string name="error_no_bills">No bills found</string>
|
||||||
|
<string name="error_no_member">At least one member required</string>
|
||||||
|
<string name="error_maintenance_mode">Server is in maintenance mode</string>
|
||||||
|
<string name="error_400">400 Bad request</string>
|
||||||
|
<string name="error_401">401 Unauthorized</string>
|
||||||
|
<string name="error_403">403 Forbidden</string>
|
||||||
|
<string name="error_404">404 Not Found</string>
|
||||||
|
<string name="error_sync">Sync failed: %1$s</string>
|
||||||
|
<string name="error_invalid_login">Invalid login: %1$s</string>
|
||||||
|
<string name="error_auth">Wrong username or password</string>
|
||||||
|
<string name="error_json">Invalid server response</string>
|
||||||
|
<string name="error_req_failed">Request failed</string>
|
||||||
|
<string name="error_invalid_email">Invalid e-mail</string>
|
||||||
|
<string name="error_invalid_project_id">Invalid project ID</string>
|
||||||
|
<string name="error_invalid_project_name">Invalid project title</string>
|
||||||
|
<string name="error_invalid_bill_name">Invalid bill name</string>
|
||||||
|
<string name="error_invalid_bill_date">Invalid bill date</string>
|
||||||
|
<string name="error_invalid_bill_payer">Payer required</string>
|
||||||
|
<string name="error_invalid_bill_owers">Owers required</string>
|
||||||
|
<string name="error_no_network">No network connection</string>
|
||||||
|
<string name="error_server">Server error</string>
|
||||||
|
<string name="error_io">Server connection broken</string>
|
||||||
|
<string name="error_share_impossible">Cannot share this project</string>
|
||||||
|
|
||||||
|
<!-- Drawer / Common UI -->
|
||||||
|
<string name="drawer_no_account">Connect to Nextcloud account</string>
|
||||||
|
<string name="drawer_last_sync">Last sync: %1$02d:%2$02d</string>
|
||||||
|
<string name="simple_cancel">Cancel</string>
|
||||||
|
<string name="simple_ok" tools:ignore="ButtonCase,Typos">Ok</string>
|
||||||
|
<string name="simple_yes">Yes</string>
|
||||||
|
<string name="simple_no">No</string>
|
||||||
|
<string name="simple_close">Close</string>
|
||||||
|
|
||||||
|
<!-- Settings -->
|
||||||
|
<string name="settings_appearance">Appearance</string>
|
||||||
|
<string name="settings_network">Network</string>
|
||||||
|
<string name="settings_other">Other</string>
|
||||||
|
<string name="settings_night_mode">Theme</string>
|
||||||
|
<string name="settings_offline_mode">Offline mode</string>
|
||||||
|
<string name="settings_offline_mode_summary">Only sync manually.</string>
|
||||||
|
<string name="settings_color_custom">Custom color</string>
|
||||||
|
<string name="settings_color_mode">Color Selection</string>
|
||||||
|
<string name="settings_show_archived">Show archived projects</string>
|
||||||
|
<string name="settings_beta_features">Beta Features</string>
|
||||||
|
<string name="settings_beta_features_summary">Enable experimental features. Use at your own risk.</string>
|
||||||
|
<string name="settings_fill_new_bill_from_last">Auto-fill from last bill</string>
|
||||||
|
<string name="settings_fill_new_bill_from_last_summary">Pre-fill payer, category, mode and owers from the last bill created in the project.</string>
|
||||||
|
<string name="settings_auto_sync_on_open">Sync interval</string>
|
||||||
|
<string name="settings_auto_sync_on_open_summary">How often to refresh the account and all projects when opening the app.</string>
|
||||||
|
<string name="pref_value_sync_1m">1 minute</string>
|
||||||
|
<string name="pref_value_sync_10m">10 minutes</string>
|
||||||
|
<string name="pref_value_sync_1h">1 hour</string>
|
||||||
|
<string name="pref_value_sync_1d">1 day</string>
|
||||||
|
<string name="settings_url_warn_http">WARNING: "http" is unsafe. Use "https".</string>
|
||||||
|
<string name="settings_colorpicker_title">Choose Color</string>
|
||||||
|
|
||||||
|
<string name="pref_value_color_system">System</string>
|
||||||
|
<string name="pref_value_color_manual">Manual</string>
|
||||||
|
<string name="pref_value_theme_light">Light</string>
|
||||||
|
<string name="pref_value_theme_dark">Dark</string>
|
||||||
|
<string name="pref_value_theme_system">Follow system</string>
|
||||||
|
|
||||||
|
<!-- Enums and Lists -->
|
||||||
|
<string name="repeat_no">No repeat</string>
|
||||||
|
<string name="repeat_day">Daily</string>
|
||||||
|
<string name="repeat_week">Weekly</string>
|
||||||
|
<string name="repeat_fortnight">Fortnightly</string>
|
||||||
|
<string name="repeat_month">Monthly</string>
|
||||||
|
<string name="repeat_year">Yearly</string>
|
||||||
|
|
||||||
|
<string name="payment_mode_none">None</string>
|
||||||
|
<string name="payment_mode_all">All</string>
|
||||||
|
<string name="payment_mode_credit_card">Credit card</string>
|
||||||
|
<string name="payment_mode_cash">Cash</string>
|
||||||
|
<string name="payment_mode_check">Check</string>
|
||||||
|
<string name="payment_mode_online">Online</string>
|
||||||
|
<string name="payment_mode_transfer">Transfer</string>
|
||||||
|
|
||||||
|
<string name="category_none">None</string>
|
||||||
|
<string name="category_all">All</string>
|
||||||
|
<string name="category_all_except_reimbursement">All except reimbursement</string>
|
||||||
|
<string name="category_groceries">Grocery</string>
|
||||||
|
<string name="category_leisure">Bar/Party</string>
|
||||||
|
<string name="category_rent">Rent</string>
|
||||||
|
<string name="category_bills">Bill</string>
|
||||||
|
<string name="category_excursion">Excursion/Culture</string>
|
||||||
|
<string name="category_health">Health</string>
|
||||||
|
<string name="category_shopping">Shopping</string>
|
||||||
|
<string name="category_reimbursement">Reimbursement</string>
|
||||||
|
<string name="category_restaurant">Restaurant</string>
|
||||||
|
<string name="category_accomodation">Accommodation</string>
|
||||||
|
<string name="category_transport">Transport</string>
|
||||||
|
<string name="category_sport">Sport</string>
|
||||||
|
|
||||||
|
<!-- Project specific -->
|
||||||
|
<string name="new_project_action">What</string>
|
||||||
|
<string name="new_project_where">Where</string>
|
||||||
|
<string name="where_local">Local only</string>
|
||||||
|
<string name="todo_join">Join existing project</string>
|
||||||
|
<string name="todo_create">Create new project</string>
|
||||||
|
<string name="import_tooltip">Import from file</string>
|
||||||
|
<string name="choose_project_management_action">Project</string>
|
||||||
|
<string name="project_added_success">Project added successfully.</string>
|
||||||
|
<string name="no_projects_text">You have no projects yet.</string>
|
||||||
|
<string name="configure_account_choice">Configure Nextcloud account</string>
|
||||||
|
<string name="add_project_choice">Add project manually</string>
|
||||||
|
<string name="no_members_text">No members in this project.</string>
|
||||||
|
<string name="no_bills_text">No bills found.</string>
|
||||||
|
<string name="member_already_exists">Member already exists.</string>
|
||||||
|
<string name="activity_dialog_title">Project: %1$s</string>
|
||||||
|
<string name="remove_project_confirmation">Project %1$s removed.</string>
|
||||||
|
<string name="file_saved_success">File saved: %1$s</string>
|
||||||
|
<string name="import_error_header">Import failed at row %d</string>
|
||||||
|
<string name="import_error_date">Invalid date format at row %d</string>
|
||||||
|
<string name="import_error_owers">Invalid owers at row %d</string>
|
||||||
|
<string name="add_member_dialog_title">Add Member</string>
|
||||||
|
<string name="edit_member_dialog_title">Edit Member</string>
|
||||||
|
<string name="member_edit_delete">Delete</string>
|
||||||
|
<string name="project_edition_no_change">No changes to save.</string>
|
||||||
|
|
||||||
|
<!-- Settlement -->
|
||||||
|
<string name="center_none">None (Optimal)</string>
|
||||||
|
<string name="settle_who">Who pays</string>
|
||||||
|
<string name="settle_to_whom">To whom</string>
|
||||||
|
<string name="settle_how_much">Amount</string>
|
||||||
|
<string name="simple_settle_share">Share</string>
|
||||||
|
<string name="simple_create_bills">Create bills</string>
|
||||||
|
<string name="settle_bill_what">Settlement</string>
|
||||||
|
|
||||||
|
<!-- Currencies -->
|
||||||
|
<string name="currency_dialog_title">Choose Currency (%s)</string>
|
||||||
|
<string name="setting_none">None</string>
|
||||||
|
<string name="setting_all">All</string>
|
||||||
|
<string name="currency_saved_success">Currency settings saved.</string>
|
||||||
|
<string name="main_currency">Main Currency</string>
|
||||||
|
|
||||||
|
<!-- Statistics -->
|
||||||
|
<string name="label_bills_suggested">Suggested Categories</string>
|
||||||
|
<string name="label_bills_skip">Skip</string>
|
||||||
|
<string name="stats_date_min">From</string>
|
||||||
|
<string name="stats_date_max">To</string>
|
||||||
|
<string name="stats_who">Member</string>
|
||||||
|
<string name="stats_paid">Paid</string>
|
||||||
|
<string name="stats_spent">Spent</string>
|
||||||
|
<string name="stats_balance">Balance</string>
|
||||||
|
<string name="total">Total: %1$s</string>
|
||||||
|
|
||||||
|
<!-- Errors Extra -->
|
||||||
|
<string name="error_project_connect_check">Connection failed: %1$s</string>
|
||||||
|
<string name="error_create_remote_project_helper">Creation failed: %1$s</string>
|
||||||
|
<string name="error_edit_remote_project_helper">Error updating remote project: %1$s</string>
|
||||||
|
<string name="remote_project_operation_no_network">Network unavailable for remote operation.</string>
|
||||||
|
<string name="error_scanning_bill_qr_code">Failed to parse QR code.</string>
|
||||||
|
<string name="error_token_mismatch">Authentication token mismatch. Please log in again.</string>
|
||||||
|
<string name="insufficient_access_level">You don\'t have permission to perform this action.</string>
|
||||||
|
<string name="delete_label_confirmation_title">Delete Label</string>
|
||||||
|
<string name="delete_label_confirmation_message">Are you sure you want to delete this label?</string>
|
||||||
|
|
||||||
|
<!-- About -->
|
||||||
|
<string name="about_version">Version %1$s</string>
|
||||||
|
<string name="about_maintainer_title">Maintainer</string>
|
||||||
|
<string name="about_license_title">License</string>
|
||||||
|
<string name="about_source_title">Source code</string>
|
||||||
|
|
||||||
|
<!-- New constants for backward compatibility or shared use -->
|
||||||
|
<string name="share_intent_title">Project %1$s</string>
|
||||||
|
<string name="share_chooser_title">Share %1$s</string>
|
||||||
|
|
||||||
|
</resources>
|
||||||
@@ -0,0 +1,272 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Untranslated: these are the English strings, kept here so a translation can be
|
||||||
|
contributed by simply replacing the values. Strings marked translatable="false" in
|
||||||
|
values/strings.xml (app and product names, preference keys) are deliberately absent
|
||||||
|
and must not be added.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- Actions -->
|
||||||
|
<string name="action_new_bill">New bill</string>
|
||||||
|
<string name="action_add_project">Add project</string>
|
||||||
|
<string name="action_save">Save</string>
|
||||||
|
<string name="action_edit">Edit</string>
|
||||||
|
<string name="action_share">Share</string>
|
||||||
|
<string name="action_search">Search</string>
|
||||||
|
<string name="action_open_menu">Open menu</string>
|
||||||
|
<string name="action_close_search">Close search</string>
|
||||||
|
<string name="action_clear_search">Clear search</string>
|
||||||
|
<string name="action_delete">Delete</string>
|
||||||
|
<string name="simple_back">Back</string>
|
||||||
|
<string name="action_archive">Archive</string>
|
||||||
|
<string name="action_unarchive">Unarchive</string>
|
||||||
|
<string name="action_export">Export</string>
|
||||||
|
<string name="action_stats">Stats</string>
|
||||||
|
<string name="action_settle">Settle</string>
|
||||||
|
<string name="action_scan_qrcode">Scan QR Code</string>
|
||||||
|
<string name="action_settings">Settings</string>
|
||||||
|
<string name="action_label_bills">Label missing categories</string>
|
||||||
|
<string name="action_logout">Logout</string>
|
||||||
|
<string name="action_connect">Connect</string>
|
||||||
|
<string name="action_discard">Discard</string>
|
||||||
|
<string name="action_members">Members</string>
|
||||||
|
<string name="action_labels">Labels</string>
|
||||||
|
<string name="action_currencies">Currencies</string>
|
||||||
|
|
||||||
|
<!-- Titles -->
|
||||||
|
<string name="title_stats">Statistics</string>
|
||||||
|
<string name="title_edit_project">Edit project</string>
|
||||||
|
<string name="title_label_bills">Label Bills</string>
|
||||||
|
<string name="title_labels">Manage Labels</string>
|
||||||
|
<string name="title_about">About</string>
|
||||||
|
<string name="title_settle">Settle Project</string>
|
||||||
|
<string name="title_share">Share Project</string>
|
||||||
|
<string name="title_add_project">Add Project</string>
|
||||||
|
<string name="title_add_category">Add Category</string>
|
||||||
|
<string name="title_add_payment_mode">Add Payment Mode</string>
|
||||||
|
<string name="title_account">Nextcloud Account</string>
|
||||||
|
<string name="title_share_web">Web link</string>
|
||||||
|
<string name="title_share_qr">Cowspent link</string>
|
||||||
|
<string name="title_confirm">Are you sure?</string>
|
||||||
|
|
||||||
|
<!-- Labels and Fields -->
|
||||||
|
<string name="label_all_bills">All bills</string>
|
||||||
|
<string name="label_categories">Categories</string>
|
||||||
|
<string name="label_payment_modes">Payment Modes</string>
|
||||||
|
<string name="label_name">Name</string>
|
||||||
|
<string name="label_icon">Icon / Emoji</string>
|
||||||
|
<string name="label_color">Color</string>
|
||||||
|
<string name="label_weight">Weight</string>
|
||||||
|
<string name="label_activated">Activated</string>
|
||||||
|
<string name="label_password">Password</string>
|
||||||
|
<string name="label_email">E-mail</string>
|
||||||
|
<string name="label_url">Server address</string>
|
||||||
|
<string name="label_username">Username</string>
|
||||||
|
<string name="label_comment">Comment</string>
|
||||||
|
<string name="label_what">What?</string>
|
||||||
|
<string name="label_payer">Who paid?</string>
|
||||||
|
<string name="label_owers">For whom?</string>
|
||||||
|
<string name="label_repeat">Repeat every</string>
|
||||||
|
<string name="label_mode">Mode</string>
|
||||||
|
<string name="label_category">Category</string>
|
||||||
|
<string name="label_project_id">Project ID/name</string>
|
||||||
|
<string name="label_project_title">Project title</string>
|
||||||
|
<string name="label_use_sso">Use Nextcloud App Account</string>
|
||||||
|
|
||||||
|
<!-- Dialogs and Messages -->
|
||||||
|
<string name="dialog_unsaved_changes_title">Unsaved changes</string>
|
||||||
|
<string name="dialog_unsaved_changes_msg">Save changes before leaving?</string>
|
||||||
|
<string name="dialog_confirm_remove_project_msg">The remote project will not be deleted.</string>
|
||||||
|
<string name="dialog_sync_error_title">Sync error</string>
|
||||||
|
<string name="dialog_sync_error_msg">Sync failed for %1$s.\n\n%2$s</string>
|
||||||
|
<string name="dialog_balanced_msg">Expenses are already balanced.</string>
|
||||||
|
<string name="msg_project_added">Project %1$s added</string>
|
||||||
|
<string name="msg_bill_labeled_done">All bills labeled</string>
|
||||||
|
<string name="msg_no_suggestions">No suggestions</string>
|
||||||
|
<string name="msg_auth_warning">Requires Cospend v0.3.4+.</string>
|
||||||
|
<string name="msg_link_copied">Link copied to clipboard</string>
|
||||||
|
<string name="msg_share_qr">Scan QR code or share the link to join.</string>
|
||||||
|
<string name="msg_share_web">Link for web browser access.</string>
|
||||||
|
<string name="msg_share_qr_warn">Share this link with a Cowspent user.</string>
|
||||||
|
<string name="msg_settle_intro">Settlement for %1$s:</string>
|
||||||
|
<string name="msg_settle_sentence">%1$s owes %3$.2f to %2$s</string>
|
||||||
|
<string name="msg_stats_intro">Stats for %1$s:</string>
|
||||||
|
<string name="msg_stats_header">Member (Paid | Spent | Balance)</string>
|
||||||
|
<string name="msg_logged_in_as">Logged in as %1$s</string>
|
||||||
|
|
||||||
|
<!-- Errors -->
|
||||||
|
<string name="error_generic">Error</string>
|
||||||
|
<string name="error_loading">Loading</string>
|
||||||
|
<string name="error_no_projects">No projects found</string>
|
||||||
|
<string name="error_no_members">No members found</string>
|
||||||
|
<string name="error_no_bills">No bills found</string>
|
||||||
|
<string name="error_no_member">At least one member required</string>
|
||||||
|
<string name="error_maintenance_mode">Server is in maintenance mode</string>
|
||||||
|
<string name="error_400">400 Bad request</string>
|
||||||
|
<string name="error_401">401 Unauthorized</string>
|
||||||
|
<string name="error_403">403 Forbidden</string>
|
||||||
|
<string name="error_404">404 Not Found</string>
|
||||||
|
<string name="error_sync">Sync failed: %1$s</string>
|
||||||
|
<string name="error_invalid_login">Invalid login: %1$s</string>
|
||||||
|
<string name="error_auth">Wrong username or password</string>
|
||||||
|
<string name="error_json">Invalid server response</string>
|
||||||
|
<string name="error_req_failed">Request failed</string>
|
||||||
|
<string name="error_invalid_email">Invalid e-mail</string>
|
||||||
|
<string name="error_invalid_project_id">Invalid project ID</string>
|
||||||
|
<string name="error_invalid_project_name">Invalid project title</string>
|
||||||
|
<string name="error_invalid_bill_name">Invalid bill name</string>
|
||||||
|
<string name="error_invalid_bill_date">Invalid bill date</string>
|
||||||
|
<string name="error_invalid_bill_payer">Payer required</string>
|
||||||
|
<string name="error_invalid_bill_owers">Owers required</string>
|
||||||
|
<string name="error_no_network">No network connection</string>
|
||||||
|
<string name="error_server">Server error</string>
|
||||||
|
<string name="error_io">Server connection broken</string>
|
||||||
|
<string name="error_share_impossible">Cannot share this project</string>
|
||||||
|
|
||||||
|
<!-- Drawer / Common UI -->
|
||||||
|
<string name="drawer_no_account">Connect to Nextcloud account</string>
|
||||||
|
<string name="drawer_last_sync">Last sync: %1$02d:%2$02d</string>
|
||||||
|
<string name="simple_cancel">Cancel</string>
|
||||||
|
<string name="simple_ok" tools:ignore="ButtonCase,Typos">Ok</string>
|
||||||
|
<string name="simple_yes">Yes</string>
|
||||||
|
<string name="simple_no">No</string>
|
||||||
|
<string name="simple_close">Close</string>
|
||||||
|
|
||||||
|
<!-- Settings -->
|
||||||
|
<string name="settings_appearance">Appearance</string>
|
||||||
|
<string name="settings_network">Network</string>
|
||||||
|
<string name="settings_other">Other</string>
|
||||||
|
<string name="settings_night_mode">Theme</string>
|
||||||
|
<string name="settings_offline_mode">Offline mode</string>
|
||||||
|
<string name="settings_offline_mode_summary">Only sync manually.</string>
|
||||||
|
<string name="settings_color_custom">Custom color</string>
|
||||||
|
<string name="settings_color_mode">Color Selection</string>
|
||||||
|
<string name="settings_show_archived">Show archived projects</string>
|
||||||
|
<string name="settings_beta_features">Beta Features</string>
|
||||||
|
<string name="settings_beta_features_summary">Enable experimental features. Use at your own risk.</string>
|
||||||
|
<string name="settings_fill_new_bill_from_last">Auto-fill from last bill</string>
|
||||||
|
<string name="settings_fill_new_bill_from_last_summary">Pre-fill payer, category, mode and owers from the last bill created in the project.</string>
|
||||||
|
<string name="settings_auto_sync_on_open">Sync interval</string>
|
||||||
|
<string name="settings_auto_sync_on_open_summary">How often to refresh the account and all projects when opening the app.</string>
|
||||||
|
<string name="pref_value_sync_1m">1 minute</string>
|
||||||
|
<string name="pref_value_sync_10m">10 minutes</string>
|
||||||
|
<string name="pref_value_sync_1h">1 hour</string>
|
||||||
|
<string name="pref_value_sync_1d">1 day</string>
|
||||||
|
<string name="settings_url_warn_http">WARNING: "http" is unsafe. Use "https".</string>
|
||||||
|
<string name="settings_colorpicker_title">Choose Color</string>
|
||||||
|
|
||||||
|
<string name="pref_value_color_system">System</string>
|
||||||
|
<string name="pref_value_color_manual">Manual</string>
|
||||||
|
<string name="pref_value_theme_light">Light</string>
|
||||||
|
<string name="pref_value_theme_dark">Dark</string>
|
||||||
|
<string name="pref_value_theme_system">Follow system</string>
|
||||||
|
|
||||||
|
<!-- Enums and Lists -->
|
||||||
|
<string name="repeat_no">No repeat</string>
|
||||||
|
<string name="repeat_day">Daily</string>
|
||||||
|
<string name="repeat_week">Weekly</string>
|
||||||
|
<string name="repeat_fortnight">Fortnightly</string>
|
||||||
|
<string name="repeat_month">Monthly</string>
|
||||||
|
<string name="repeat_year">Yearly</string>
|
||||||
|
|
||||||
|
<string name="payment_mode_none">None</string>
|
||||||
|
<string name="payment_mode_all">All</string>
|
||||||
|
<string name="payment_mode_credit_card">Credit card</string>
|
||||||
|
<string name="payment_mode_cash">Cash</string>
|
||||||
|
<string name="payment_mode_check">Check</string>
|
||||||
|
<string name="payment_mode_online">Online</string>
|
||||||
|
<string name="payment_mode_transfer">Transfer</string>
|
||||||
|
|
||||||
|
<string name="category_none">None</string>
|
||||||
|
<string name="category_all">All</string>
|
||||||
|
<string name="category_all_except_reimbursement">All except reimbursement</string>
|
||||||
|
<string name="category_groceries">Grocery</string>
|
||||||
|
<string name="category_leisure">Bar/Party</string>
|
||||||
|
<string name="category_rent">Rent</string>
|
||||||
|
<string name="category_bills">Bill</string>
|
||||||
|
<string name="category_excursion">Excursion/Culture</string>
|
||||||
|
<string name="category_health">Health</string>
|
||||||
|
<string name="category_shopping">Shopping</string>
|
||||||
|
<string name="category_reimbursement">Reimbursement</string>
|
||||||
|
<string name="category_restaurant">Restaurant</string>
|
||||||
|
<string name="category_accomodation">Accommodation</string>
|
||||||
|
<string name="category_transport">Transport</string>
|
||||||
|
<string name="category_sport">Sport</string>
|
||||||
|
|
||||||
|
<!-- Project specific -->
|
||||||
|
<string name="new_project_action">What</string>
|
||||||
|
<string name="new_project_where">Where</string>
|
||||||
|
<string name="where_local">Local only</string>
|
||||||
|
<string name="todo_join">Join existing project</string>
|
||||||
|
<string name="todo_create">Create new project</string>
|
||||||
|
<string name="import_tooltip">Import from file</string>
|
||||||
|
<string name="choose_project_management_action">Project</string>
|
||||||
|
<string name="project_added_success">Project added successfully.</string>
|
||||||
|
<string name="no_projects_text">You have no projects yet.</string>
|
||||||
|
<string name="configure_account_choice">Configure Nextcloud account</string>
|
||||||
|
<string name="add_project_choice">Add project manually</string>
|
||||||
|
<string name="no_members_text">No members in this project.</string>
|
||||||
|
<string name="no_bills_text">No bills found.</string>
|
||||||
|
<string name="member_already_exists">Member already exists.</string>
|
||||||
|
<string name="activity_dialog_title">Project: %1$s</string>
|
||||||
|
<string name="remove_project_confirmation">Project %1$s removed.</string>
|
||||||
|
<string name="file_saved_success">File saved: %1$s</string>
|
||||||
|
<string name="import_error_header">Import failed at row %d</string>
|
||||||
|
<string name="import_error_date">Invalid date format at row %d</string>
|
||||||
|
<string name="import_error_owers">Invalid owers at row %d</string>
|
||||||
|
<string name="add_member_dialog_title">Add Member</string>
|
||||||
|
<string name="edit_member_dialog_title">Edit Member</string>
|
||||||
|
<string name="member_edit_delete">Delete</string>
|
||||||
|
<string name="project_edition_no_change">No changes to save.</string>
|
||||||
|
|
||||||
|
<!-- Settlement -->
|
||||||
|
<string name="center_none">None (Optimal)</string>
|
||||||
|
<string name="settle_who">Who pays</string>
|
||||||
|
<string name="settle_to_whom">To whom</string>
|
||||||
|
<string name="settle_how_much">Amount</string>
|
||||||
|
<string name="simple_settle_share">Share</string>
|
||||||
|
<string name="simple_create_bills">Create bills</string>
|
||||||
|
<string name="settle_bill_what">Settlement</string>
|
||||||
|
|
||||||
|
<!-- Currencies -->
|
||||||
|
<string name="currency_dialog_title">Choose Currency (%s)</string>
|
||||||
|
<string name="setting_none">None</string>
|
||||||
|
<string name="setting_all">All</string>
|
||||||
|
<string name="currency_saved_success">Currency settings saved.</string>
|
||||||
|
<string name="main_currency">Main Currency</string>
|
||||||
|
|
||||||
|
<!-- Statistics -->
|
||||||
|
<string name="label_bills_suggested">Suggested Categories</string>
|
||||||
|
<string name="label_bills_skip">Skip</string>
|
||||||
|
<string name="stats_date_min">From</string>
|
||||||
|
<string name="stats_date_max">To</string>
|
||||||
|
<string name="stats_who">Member</string>
|
||||||
|
<string name="stats_paid">Paid</string>
|
||||||
|
<string name="stats_spent">Spent</string>
|
||||||
|
<string name="stats_balance">Balance</string>
|
||||||
|
<string name="total">Total: %1$s</string>
|
||||||
|
|
||||||
|
<!-- Errors Extra -->
|
||||||
|
<string name="error_project_connect_check">Connection failed: %1$s</string>
|
||||||
|
<string name="error_create_remote_project_helper">Creation failed: %1$s</string>
|
||||||
|
<string name="error_edit_remote_project_helper">Error updating remote project: %1$s</string>
|
||||||
|
<string name="remote_project_operation_no_network">Network unavailable for remote operation.</string>
|
||||||
|
<string name="error_scanning_bill_qr_code">Failed to parse QR code.</string>
|
||||||
|
<string name="error_token_mismatch">Authentication token mismatch. Please log in again.</string>
|
||||||
|
<string name="insufficient_access_level">You don\'t have permission to perform this action.</string>
|
||||||
|
<string name="delete_label_confirmation_title">Delete Label</string>
|
||||||
|
<string name="delete_label_confirmation_message">Are you sure you want to delete this label?</string>
|
||||||
|
|
||||||
|
<!-- About -->
|
||||||
|
<string name="about_version">Version %1$s</string>
|
||||||
|
<string name="about_maintainer_title">Maintainer</string>
|
||||||
|
<string name="about_license_title">License</string>
|
||||||
|
<string name="about_source_title">Source code</string>
|
||||||
|
|
||||||
|
<!-- New constants for backward compatibility or shared use -->
|
||||||
|
<string name="share_intent_title">Project %1$s</string>
|
||||||
|
<string name="share_chooser_title">Share %1$s</string>
|
||||||
|
|
||||||
|
</resources>
|
||||||
@@ -0,0 +1,272 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Untranslated: these are the English strings, kept here so a translation can be
|
||||||
|
contributed by simply replacing the values. Strings marked translatable="false" in
|
||||||
|
values/strings.xml (app and product names, preference keys) are deliberately absent
|
||||||
|
and must not be added.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- Actions -->
|
||||||
|
<string name="action_new_bill">New bill</string>
|
||||||
|
<string name="action_add_project">Add project</string>
|
||||||
|
<string name="action_save">Save</string>
|
||||||
|
<string name="action_edit">Edit</string>
|
||||||
|
<string name="action_share">Share</string>
|
||||||
|
<string name="action_search">Search</string>
|
||||||
|
<string name="action_open_menu">Open menu</string>
|
||||||
|
<string name="action_close_search">Close search</string>
|
||||||
|
<string name="action_clear_search">Clear search</string>
|
||||||
|
<string name="action_delete">Delete</string>
|
||||||
|
<string name="simple_back">Back</string>
|
||||||
|
<string name="action_archive">Archive</string>
|
||||||
|
<string name="action_unarchive">Unarchive</string>
|
||||||
|
<string name="action_export">Export</string>
|
||||||
|
<string name="action_stats">Stats</string>
|
||||||
|
<string name="action_settle">Settle</string>
|
||||||
|
<string name="action_scan_qrcode">Scan QR Code</string>
|
||||||
|
<string name="action_settings">Settings</string>
|
||||||
|
<string name="action_label_bills">Label missing categories</string>
|
||||||
|
<string name="action_logout">Logout</string>
|
||||||
|
<string name="action_connect">Connect</string>
|
||||||
|
<string name="action_discard">Discard</string>
|
||||||
|
<string name="action_members">Members</string>
|
||||||
|
<string name="action_labels">Labels</string>
|
||||||
|
<string name="action_currencies">Currencies</string>
|
||||||
|
|
||||||
|
<!-- Titles -->
|
||||||
|
<string name="title_stats">Statistics</string>
|
||||||
|
<string name="title_edit_project">Edit project</string>
|
||||||
|
<string name="title_label_bills">Label Bills</string>
|
||||||
|
<string name="title_labels">Manage Labels</string>
|
||||||
|
<string name="title_about">About</string>
|
||||||
|
<string name="title_settle">Settle Project</string>
|
||||||
|
<string name="title_share">Share Project</string>
|
||||||
|
<string name="title_add_project">Add Project</string>
|
||||||
|
<string name="title_add_category">Add Category</string>
|
||||||
|
<string name="title_add_payment_mode">Add Payment Mode</string>
|
||||||
|
<string name="title_account">Nextcloud Account</string>
|
||||||
|
<string name="title_share_web">Web link</string>
|
||||||
|
<string name="title_share_qr">Cowspent link</string>
|
||||||
|
<string name="title_confirm">Are you sure?</string>
|
||||||
|
|
||||||
|
<!-- Labels and Fields -->
|
||||||
|
<string name="label_all_bills">All bills</string>
|
||||||
|
<string name="label_categories">Categories</string>
|
||||||
|
<string name="label_payment_modes">Payment Modes</string>
|
||||||
|
<string name="label_name">Name</string>
|
||||||
|
<string name="label_icon">Icon / Emoji</string>
|
||||||
|
<string name="label_color">Color</string>
|
||||||
|
<string name="label_weight">Weight</string>
|
||||||
|
<string name="label_activated">Activated</string>
|
||||||
|
<string name="label_password">Password</string>
|
||||||
|
<string name="label_email">E-mail</string>
|
||||||
|
<string name="label_url">Server address</string>
|
||||||
|
<string name="label_username">Username</string>
|
||||||
|
<string name="label_comment">Comment</string>
|
||||||
|
<string name="label_what">What?</string>
|
||||||
|
<string name="label_payer">Who paid?</string>
|
||||||
|
<string name="label_owers">For whom?</string>
|
||||||
|
<string name="label_repeat">Repeat every</string>
|
||||||
|
<string name="label_mode">Mode</string>
|
||||||
|
<string name="label_category">Category</string>
|
||||||
|
<string name="label_project_id">Project ID/name</string>
|
||||||
|
<string name="label_project_title">Project title</string>
|
||||||
|
<string name="label_use_sso">Use Nextcloud App Account</string>
|
||||||
|
|
||||||
|
<!-- Dialogs and Messages -->
|
||||||
|
<string name="dialog_unsaved_changes_title">Unsaved changes</string>
|
||||||
|
<string name="dialog_unsaved_changes_msg">Save changes before leaving?</string>
|
||||||
|
<string name="dialog_confirm_remove_project_msg">The remote project will not be deleted.</string>
|
||||||
|
<string name="dialog_sync_error_title">Sync error</string>
|
||||||
|
<string name="dialog_sync_error_msg">Sync failed for %1$s.\n\n%2$s</string>
|
||||||
|
<string name="dialog_balanced_msg">Expenses are already balanced.</string>
|
||||||
|
<string name="msg_project_added">Project %1$s added</string>
|
||||||
|
<string name="msg_bill_labeled_done">All bills labeled</string>
|
||||||
|
<string name="msg_no_suggestions">No suggestions</string>
|
||||||
|
<string name="msg_auth_warning">Requires Cospend v0.3.4+.</string>
|
||||||
|
<string name="msg_link_copied">Link copied to clipboard</string>
|
||||||
|
<string name="msg_share_qr">Scan QR code or share the link to join.</string>
|
||||||
|
<string name="msg_share_web">Link for web browser access.</string>
|
||||||
|
<string name="msg_share_qr_warn">Share this link with a Cowspent user.</string>
|
||||||
|
<string name="msg_settle_intro">Settlement for %1$s:</string>
|
||||||
|
<string name="msg_settle_sentence">%1$s owes %3$.2f to %2$s</string>
|
||||||
|
<string name="msg_stats_intro">Stats for %1$s:</string>
|
||||||
|
<string name="msg_stats_header">Member (Paid | Spent | Balance)</string>
|
||||||
|
<string name="msg_logged_in_as">Logged in as %1$s</string>
|
||||||
|
|
||||||
|
<!-- Errors -->
|
||||||
|
<string name="error_generic">Error</string>
|
||||||
|
<string name="error_loading">Loading</string>
|
||||||
|
<string name="error_no_projects">No projects found</string>
|
||||||
|
<string name="error_no_members">No members found</string>
|
||||||
|
<string name="error_no_bills">No bills found</string>
|
||||||
|
<string name="error_no_member">At least one member required</string>
|
||||||
|
<string name="error_maintenance_mode">Server is in maintenance mode</string>
|
||||||
|
<string name="error_400">400 Bad request</string>
|
||||||
|
<string name="error_401">401 Unauthorized</string>
|
||||||
|
<string name="error_403">403 Forbidden</string>
|
||||||
|
<string name="error_404">404 Not Found</string>
|
||||||
|
<string name="error_sync">Sync failed: %1$s</string>
|
||||||
|
<string name="error_invalid_login">Invalid login: %1$s</string>
|
||||||
|
<string name="error_auth">Wrong username or password</string>
|
||||||
|
<string name="error_json">Invalid server response</string>
|
||||||
|
<string name="error_req_failed">Request failed</string>
|
||||||
|
<string name="error_invalid_email">Invalid e-mail</string>
|
||||||
|
<string name="error_invalid_project_id">Invalid project ID</string>
|
||||||
|
<string name="error_invalid_project_name">Invalid project title</string>
|
||||||
|
<string name="error_invalid_bill_name">Invalid bill name</string>
|
||||||
|
<string name="error_invalid_bill_date">Invalid bill date</string>
|
||||||
|
<string name="error_invalid_bill_payer">Payer required</string>
|
||||||
|
<string name="error_invalid_bill_owers">Owers required</string>
|
||||||
|
<string name="error_no_network">No network connection</string>
|
||||||
|
<string name="error_server">Server error</string>
|
||||||
|
<string name="error_io">Server connection broken</string>
|
||||||
|
<string name="error_share_impossible">Cannot share this project</string>
|
||||||
|
|
||||||
|
<!-- Drawer / Common UI -->
|
||||||
|
<string name="drawer_no_account">Connect to Nextcloud account</string>
|
||||||
|
<string name="drawer_last_sync">Last sync: %1$02d:%2$02d</string>
|
||||||
|
<string name="simple_cancel">Cancel</string>
|
||||||
|
<string name="simple_ok" tools:ignore="ButtonCase,Typos">Ok</string>
|
||||||
|
<string name="simple_yes">Yes</string>
|
||||||
|
<string name="simple_no">No</string>
|
||||||
|
<string name="simple_close">Close</string>
|
||||||
|
|
||||||
|
<!-- Settings -->
|
||||||
|
<string name="settings_appearance">Appearance</string>
|
||||||
|
<string name="settings_network">Network</string>
|
||||||
|
<string name="settings_other">Other</string>
|
||||||
|
<string name="settings_night_mode">Theme</string>
|
||||||
|
<string name="settings_offline_mode">Offline mode</string>
|
||||||
|
<string name="settings_offline_mode_summary">Only sync manually.</string>
|
||||||
|
<string name="settings_color_custom">Custom color</string>
|
||||||
|
<string name="settings_color_mode">Color Selection</string>
|
||||||
|
<string name="settings_show_archived">Show archived projects</string>
|
||||||
|
<string name="settings_beta_features">Beta Features</string>
|
||||||
|
<string name="settings_beta_features_summary">Enable experimental features. Use at your own risk.</string>
|
||||||
|
<string name="settings_fill_new_bill_from_last">Auto-fill from last bill</string>
|
||||||
|
<string name="settings_fill_new_bill_from_last_summary">Pre-fill payer, category, mode and owers from the last bill created in the project.</string>
|
||||||
|
<string name="settings_auto_sync_on_open">Sync interval</string>
|
||||||
|
<string name="settings_auto_sync_on_open_summary">How often to refresh the account and all projects when opening the app.</string>
|
||||||
|
<string name="pref_value_sync_1m">1 minute</string>
|
||||||
|
<string name="pref_value_sync_10m">10 minutes</string>
|
||||||
|
<string name="pref_value_sync_1h">1 hour</string>
|
||||||
|
<string name="pref_value_sync_1d">1 day</string>
|
||||||
|
<string name="settings_url_warn_http">WARNING: "http" is unsafe. Use "https".</string>
|
||||||
|
<string name="settings_colorpicker_title">Choose Color</string>
|
||||||
|
|
||||||
|
<string name="pref_value_color_system">System</string>
|
||||||
|
<string name="pref_value_color_manual">Manual</string>
|
||||||
|
<string name="pref_value_theme_light">Light</string>
|
||||||
|
<string name="pref_value_theme_dark">Dark</string>
|
||||||
|
<string name="pref_value_theme_system">Follow system</string>
|
||||||
|
|
||||||
|
<!-- Enums and Lists -->
|
||||||
|
<string name="repeat_no">No repeat</string>
|
||||||
|
<string name="repeat_day">Daily</string>
|
||||||
|
<string name="repeat_week">Weekly</string>
|
||||||
|
<string name="repeat_fortnight">Fortnightly</string>
|
||||||
|
<string name="repeat_month">Monthly</string>
|
||||||
|
<string name="repeat_year">Yearly</string>
|
||||||
|
|
||||||
|
<string name="payment_mode_none">None</string>
|
||||||
|
<string name="payment_mode_all">All</string>
|
||||||
|
<string name="payment_mode_credit_card">Credit card</string>
|
||||||
|
<string name="payment_mode_cash">Cash</string>
|
||||||
|
<string name="payment_mode_check">Check</string>
|
||||||
|
<string name="payment_mode_online">Online</string>
|
||||||
|
<string name="payment_mode_transfer">Transfer</string>
|
||||||
|
|
||||||
|
<string name="category_none">None</string>
|
||||||
|
<string name="category_all">All</string>
|
||||||
|
<string name="category_all_except_reimbursement">All except reimbursement</string>
|
||||||
|
<string name="category_groceries">Grocery</string>
|
||||||
|
<string name="category_leisure">Bar/Party</string>
|
||||||
|
<string name="category_rent">Rent</string>
|
||||||
|
<string name="category_bills">Bill</string>
|
||||||
|
<string name="category_excursion">Excursion/Culture</string>
|
||||||
|
<string name="category_health">Health</string>
|
||||||
|
<string name="category_shopping">Shopping</string>
|
||||||
|
<string name="category_reimbursement">Reimbursement</string>
|
||||||
|
<string name="category_restaurant">Restaurant</string>
|
||||||
|
<string name="category_accomodation">Accommodation</string>
|
||||||
|
<string name="category_transport">Transport</string>
|
||||||
|
<string name="category_sport">Sport</string>
|
||||||
|
|
||||||
|
<!-- Project specific -->
|
||||||
|
<string name="new_project_action">What</string>
|
||||||
|
<string name="new_project_where">Where</string>
|
||||||
|
<string name="where_local">Local only</string>
|
||||||
|
<string name="todo_join">Join existing project</string>
|
||||||
|
<string name="todo_create">Create new project</string>
|
||||||
|
<string name="import_tooltip">Import from file</string>
|
||||||
|
<string name="choose_project_management_action">Project</string>
|
||||||
|
<string name="project_added_success">Project added successfully.</string>
|
||||||
|
<string name="no_projects_text">You have no projects yet.</string>
|
||||||
|
<string name="configure_account_choice">Configure Nextcloud account</string>
|
||||||
|
<string name="add_project_choice">Add project manually</string>
|
||||||
|
<string name="no_members_text">No members in this project.</string>
|
||||||
|
<string name="no_bills_text">No bills found.</string>
|
||||||
|
<string name="member_already_exists">Member already exists.</string>
|
||||||
|
<string name="activity_dialog_title">Project: %1$s</string>
|
||||||
|
<string name="remove_project_confirmation">Project %1$s removed.</string>
|
||||||
|
<string name="file_saved_success">File saved: %1$s</string>
|
||||||
|
<string name="import_error_header">Import failed at row %d</string>
|
||||||
|
<string name="import_error_date">Invalid date format at row %d</string>
|
||||||
|
<string name="import_error_owers">Invalid owers at row %d</string>
|
||||||
|
<string name="add_member_dialog_title">Add Member</string>
|
||||||
|
<string name="edit_member_dialog_title">Edit Member</string>
|
||||||
|
<string name="member_edit_delete">Delete</string>
|
||||||
|
<string name="project_edition_no_change">No changes to save.</string>
|
||||||
|
|
||||||
|
<!-- Settlement -->
|
||||||
|
<string name="center_none">None (Optimal)</string>
|
||||||
|
<string name="settle_who">Who pays</string>
|
||||||
|
<string name="settle_to_whom">To whom</string>
|
||||||
|
<string name="settle_how_much">Amount</string>
|
||||||
|
<string name="simple_settle_share">Share</string>
|
||||||
|
<string name="simple_create_bills">Create bills</string>
|
||||||
|
<string name="settle_bill_what">Settlement</string>
|
||||||
|
|
||||||
|
<!-- Currencies -->
|
||||||
|
<string name="currency_dialog_title">Choose Currency (%s)</string>
|
||||||
|
<string name="setting_none">None</string>
|
||||||
|
<string name="setting_all">All</string>
|
||||||
|
<string name="currency_saved_success">Currency settings saved.</string>
|
||||||
|
<string name="main_currency">Main Currency</string>
|
||||||
|
|
||||||
|
<!-- Statistics -->
|
||||||
|
<string name="label_bills_suggested">Suggested Categories</string>
|
||||||
|
<string name="label_bills_skip">Skip</string>
|
||||||
|
<string name="stats_date_min">From</string>
|
||||||
|
<string name="stats_date_max">To</string>
|
||||||
|
<string name="stats_who">Member</string>
|
||||||
|
<string name="stats_paid">Paid</string>
|
||||||
|
<string name="stats_spent">Spent</string>
|
||||||
|
<string name="stats_balance">Balance</string>
|
||||||
|
<string name="total">Total: %1$s</string>
|
||||||
|
|
||||||
|
<!-- Errors Extra -->
|
||||||
|
<string name="error_project_connect_check">Connection failed: %1$s</string>
|
||||||
|
<string name="error_create_remote_project_helper">Creation failed: %1$s</string>
|
||||||
|
<string name="error_edit_remote_project_helper">Error updating remote project: %1$s</string>
|
||||||
|
<string name="remote_project_operation_no_network">Network unavailable for remote operation.</string>
|
||||||
|
<string name="error_scanning_bill_qr_code">Failed to parse QR code.</string>
|
||||||
|
<string name="error_token_mismatch">Authentication token mismatch. Please log in again.</string>
|
||||||
|
<string name="insufficient_access_level">You don\'t have permission to perform this action.</string>
|
||||||
|
<string name="delete_label_confirmation_title">Delete Label</string>
|
||||||
|
<string name="delete_label_confirmation_message">Are you sure you want to delete this label?</string>
|
||||||
|
|
||||||
|
<!-- About -->
|
||||||
|
<string name="about_version">Version %1$s</string>
|
||||||
|
<string name="about_maintainer_title">Maintainer</string>
|
||||||
|
<string name="about_license_title">License</string>
|
||||||
|
<string name="about_source_title">Source code</string>
|
||||||
|
|
||||||
|
<!-- New constants for backward compatibility or shared use -->
|
||||||
|
<string name="share_intent_title">Project %1$s</string>
|
||||||
|
<string name="share_chooser_title">Share %1$s</string>
|
||||||
|
|
||||||
|
</resources>
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
<string name="app_name">Cowspent</string>
|
<string name="app_name" translatable="false">Cowspent</string>
|
||||||
|
|
||||||
<!-- Actions -->
|
<!-- Actions -->
|
||||||
<string name="action_new_bill">New bill</string>
|
<string name="action_new_bill">New bill</string>
|
||||||
@@ -10,7 +10,11 @@
|
|||||||
<string name="action_edit">Edit</string>
|
<string name="action_edit">Edit</string>
|
||||||
<string name="action_share">Share</string>
|
<string name="action_share">Share</string>
|
||||||
<string name="action_search">Search</string>
|
<string name="action_search">Search</string>
|
||||||
|
<string name="action_open_menu">Open menu</string>
|
||||||
|
<string name="action_close_search">Close search</string>
|
||||||
|
<string name="action_clear_search">Clear search</string>
|
||||||
<string name="action_delete">Delete</string>
|
<string name="action_delete">Delete</string>
|
||||||
|
<string name="simple_back">Back</string>
|
||||||
<string name="action_archive">Archive</string>
|
<string name="action_archive">Archive</string>
|
||||||
<string name="action_unarchive">Unarchive</string>
|
<string name="action_unarchive">Unarchive</string>
|
||||||
<string name="action_export">Export</string>
|
<string name="action_export">Export</string>
|
||||||
@@ -35,6 +39,8 @@
|
|||||||
<string name="title_settle">Settle Project</string>
|
<string name="title_settle">Settle Project</string>
|
||||||
<string name="title_share">Share Project</string>
|
<string name="title_share">Share Project</string>
|
||||||
<string name="title_add_project">Add Project</string>
|
<string name="title_add_project">Add Project</string>
|
||||||
|
<string name="title_add_category">Add Category</string>
|
||||||
|
<string name="title_add_payment_mode">Add Payment Mode</string>
|
||||||
<string name="title_account">Nextcloud Account</string>
|
<string name="title_account">Nextcloud Account</string>
|
||||||
<string name="title_share_web">Web link</string>
|
<string name="title_share_web">Web link</string>
|
||||||
<string name="title_share_qr">Cowspent link</string>
|
<string name="title_share_qr">Cowspent link</string>
|
||||||
@@ -133,11 +139,22 @@
|
|||||||
<string name="settings_color_custom">Custom color</string>
|
<string name="settings_color_custom">Custom color</string>
|
||||||
<string name="settings_color_mode">Color Selection</string>
|
<string name="settings_color_mode">Color Selection</string>
|
||||||
<string name="settings_show_archived">Show archived projects</string>
|
<string name="settings_show_archived">Show archived projects</string>
|
||||||
|
<string name="settings_beta_features">Beta Features</string>
|
||||||
|
<string name="settings_beta_features_summary">Enable experimental features. Use at your own risk.</string>
|
||||||
|
<string name="settings_fill_new_bill_from_last">Auto-fill from last bill</string>
|
||||||
|
<string name="settings_fill_new_bill_from_last_summary">Pre-fill payer, category, mode and owers from the last bill created in the project.</string>
|
||||||
|
<string name="settings_stats_include_deactivated">Include deactivated members in stats</string>
|
||||||
|
<string name="settings_auto_sync_on_open">Sync interval</string>
|
||||||
|
<string name="settings_auto_sync_on_open_summary">How often to refresh the account and all projects when opening the app.</string>
|
||||||
|
<string name="pref_value_sync_1m">1 minute</string>
|
||||||
|
<string name="pref_value_sync_10m">10 minutes</string>
|
||||||
|
<string name="pref_value_sync_1h">1 hour</string>
|
||||||
|
<string name="pref_value_sync_1d">1 day</string>
|
||||||
<string name="settings_url_warn_http">WARNING: "http" is unsafe. Use "https".</string>
|
<string name="settings_url_warn_http">WARNING: "http" is unsafe. Use "https".</string>
|
||||||
<string name="settings_colorpicker_title">Choose Color</string>
|
<string name="settings_colorpicker_title">Choose Color</string>
|
||||||
|
|
||||||
<string name="pref_value_color_system">System</string>
|
<string name="pref_value_color_system">System</string>
|
||||||
<string name="pref_value_color_server">Nextcloud</string>
|
<string name="pref_value_color_server" translatable="false">Nextcloud</string>
|
||||||
<string name="pref_value_color_manual">Manual</string>
|
<string name="pref_value_color_manual">Manual</string>
|
||||||
<string name="pref_value_theme_light">Light</string>
|
<string name="pref_value_theme_light">Light</string>
|
||||||
<string name="pref_value_theme_dark">Dark</string>
|
<string name="pref_value_theme_dark">Dark</string>
|
||||||
@@ -153,6 +170,11 @@
|
|||||||
<string name="pref_key_color_mode" translatable="false">colorMode</string>
|
<string name="pref_key_color_mode" translatable="false">colorMode</string>
|
||||||
<string name="pref_key_offline_mode" translatable="false">offlineMode</string>
|
<string name="pref_key_offline_mode" translatable="false">offlineMode</string>
|
||||||
<string name="pref_key_show_archived" translatable="false">showArchived</string>
|
<string name="pref_key_show_archived" translatable="false">showArchived</string>
|
||||||
|
<string name="pref_key_beta_features" translatable="false">betaFeatures</string>
|
||||||
|
<string name="pref_key_stats_include_deactivated" translatable="false">statsIncludeDeactivated</string>
|
||||||
|
<string name="pref_key_auto_sync_on_open" translatable="false">autoSyncOnOpen</string>
|
||||||
|
<string name="pref_key_last_account_sync_timestamp" translatable="false">lastAccountSyncTimestamp</string>
|
||||||
|
<string name="pref_key_fill_new_bill_from_last" translatable="false">fillNewBillFromLast</string>
|
||||||
<string name="pref_value_night_mode_no" translatable="false">1</string>
|
<string name="pref_value_night_mode_no" translatable="false">1</string>
|
||||||
<string name="pref_value_night_mode_yes" translatable="false">2</string>
|
<string name="pref_value_night_mode_yes" translatable="false">2</string>
|
||||||
<string name="pref_value_night_mode_system" translatable="false">-1</string>
|
<string name="pref_value_night_mode_system" translatable="false">-1</string>
|
||||||
@@ -193,13 +215,11 @@
|
|||||||
<string name="new_project_action">What</string>
|
<string name="new_project_action">What</string>
|
||||||
<string name="new_project_where">Where</string>
|
<string name="new_project_where">Where</string>
|
||||||
<string name="where_local">Local only</string>
|
<string name="where_local">Local only</string>
|
||||||
<string name="where_cospend">Cospend</string>
|
<string name="where_cospend" translatable="false">Cospend</string>
|
||||||
<string name="where_ihatemoney">IHateMoney</string>
|
<string name="where_ihatemoney" translatable="false">IHateMoney</string>
|
||||||
<string name="todo_join">Join existing project</string>
|
<string name="todo_join">Join existing project</string>
|
||||||
<string name="todo_create">Create new project</string>
|
<string name="todo_create">Create new project</string>
|
||||||
<string name="import_tooltip">Import from file</string>
|
<string name="import_tooltip">Import from file</string>
|
||||||
<string name="choose_account_project_dialog_title">Choose project</string>
|
|
||||||
<string name="choose_account_project_dialog_impossible">No projects found on this account.</string>
|
|
||||||
<string name="choose_project_management_action">Project</string>
|
<string name="choose_project_management_action">Project</string>
|
||||||
<string name="project_added_success">Project added successfully.</string>
|
<string name="project_added_success">Project added successfully.</string>
|
||||||
<string name="no_projects_text">You have no projects yet.</string>
|
<string name="no_projects_text">You have no projects yet.</string>
|
||||||
@@ -229,7 +249,7 @@
|
|||||||
<string name="settle_bill_what">Settlement</string>
|
<string name="settle_bill_what">Settlement</string>
|
||||||
|
|
||||||
<!-- Currencies -->
|
<!-- Currencies -->
|
||||||
<string name="currency_dialog_title">Choose Currency</string>
|
<string name="currency_dialog_title">Choose Currency (%s)</string>
|
||||||
<string name="setting_none">None</string>
|
<string name="setting_none">None</string>
|
||||||
<string name="setting_all">All</string>
|
<string name="setting_all">All</string>
|
||||||
<string name="currency_saved_success">Currency settings saved.</string>
|
<string name="currency_saved_success">Currency settings saved.</string>
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
package net.helcel.cowspent
|
||||||
|
|
||||||
|
import androidx.compose.ui.ExperimentalComposeUiApi
|
||||||
|
import androidx.compose.ui.InternalComposeUiApi
|
||||||
|
import androidx.compose.ui.platform.InfiniteAnimationPolicy
|
||||||
|
import androidx.compose.ui.platform.WindowRecomposerFactory
|
||||||
|
import androidx.compose.ui.platform.WindowRecomposerPolicy
|
||||||
|
import androidx.compose.ui.platform.createLifecycleAwareWindowRecomposer
|
||||||
|
import kotlinx.coroutines.CancellationException
|
||||||
|
import org.junit.rules.TestWatcher
|
||||||
|
import org.junit.runner.Description
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Robolectric's paused looper only goes idle once nothing is left to run, but a Compose infinite
|
||||||
|
* animation (the pull-to-refresh spinner, for instance) keeps requesting frames forever. Any test
|
||||||
|
* that launches an activity whose UI shows one then burns minutes of CPU inside
|
||||||
|
* ActivityScenario.launch() before it gives up.
|
||||||
|
*
|
||||||
|
* ComposeTestRule solves this by installing an InfiniteAnimationPolicy that cancels those
|
||||||
|
* animations; this rule does the same for tests driving an activity directly.
|
||||||
|
*/
|
||||||
|
@OptIn(ExperimentalComposeUiApi::class, InternalComposeUiApi::class)
|
||||||
|
class NoInfiniteAnimationsRule : TestWatcher() {
|
||||||
|
|
||||||
|
private object CancelInfiniteAnimations : InfiniteAnimationPolicy {
|
||||||
|
override suspend fun <R> onInfiniteOperation(block: suspend () -> R): R =
|
||||||
|
throw CancellationException("Infinite animations are disabled in unit tests")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun starting(description: Description) {
|
||||||
|
WindowRecomposerPolicy.setFactory { view ->
|
||||||
|
view.createLifecycleAwareWindowRecomposer(CancelInfiniteAnimations)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun finished(description: Description) {
|
||||||
|
WindowRecomposerPolicy.setFactory(WindowRecomposerFactory.LifecycleAware)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
package net.helcel.cowspent.android
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.test.junit4.createComposeRule
|
||||||
|
import androidx.compose.ui.test.*
|
||||||
|
import net.helcel.cowspent.NoInfiniteAnimationsRule
|
||||||
|
import org.junit.Rule
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.robolectric.RobolectricTestRunner
|
||||||
|
import org.robolectric.annotation.Config
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Every `@Preview` in the app, rendered once.
|
||||||
|
*
|
||||||
|
* Previews are compiled into the release APK and are the only caller of some composables with
|
||||||
|
* awkward argument shapes, so a preview that throws is a real compile-time-clean runtime break that
|
||||||
|
* nothing else would catch. This is a smoke test: it asserts the tree composed, not what it looks
|
||||||
|
* like — the behaviour of each screen is covered by that screen's own tests.
|
||||||
|
*/
|
||||||
|
@RunWith(RobolectricTestRunner::class)
|
||||||
|
@Config(sdk = [34], qualifiers = "w1080dp-h2400dp")
|
||||||
|
class PreviewsTest {
|
||||||
|
|
||||||
|
@get:Rule
|
||||||
|
val composeTestRule = createComposeRule()
|
||||||
|
|
||||||
|
@get:Rule
|
||||||
|
val noInfiniteAnimations = NoInfiniteAnimationsRule()
|
||||||
|
|
||||||
|
private fun renders(preview: @Composable () -> Unit) {
|
||||||
|
composeTestRule.setContent { preview() }
|
||||||
|
composeTestRule.waitForIdle()
|
||||||
|
composeTestRule.onRoot().assertExists()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test fun testBillItemRow() = renders { net.helcel.cowspent.android.main.BillItemRowPreview() }
|
||||||
|
@Test fun testSectionHeader() = renders { net.helcel.cowspent.android.main.SectionHeaderPreview() }
|
||||||
|
@Test fun testEmptyProjectsState() = renders { net.helcel.cowspent.android.main.EmptyProjectsStatePreview() }
|
||||||
|
@Test fun testEmptyMembersState() = renders { net.helcel.cowspent.android.main.EmptyMembersStatePreview() }
|
||||||
|
@Test fun testEmptyBillsState() = renders { net.helcel.cowspent.android.main.EmptyBillsStatePreview() }
|
||||||
|
|
||||||
|
@Test fun testEditBillScreen() = renders { net.helcel.cowspent.android.bill_edit.EditBillScreenPreview() }
|
||||||
|
@Test fun testEditBillScreenWeighted() = renders { net.helcel.cowspent.android.bill_edit.EditBillScreenWeightedPreview() }
|
||||||
|
@Test fun testEditBillScreenCustom() = renders { net.helcel.cowspent.android.bill_edit.EditBillScreenCustomPreview() }
|
||||||
|
@Test fun testEditBillScreenPercent() = renders { net.helcel.cowspent.android.bill_edit.EditBillScreenPercentPreview() }
|
||||||
|
|
||||||
|
@Test fun testUserAvatar() = renders { net.helcel.cowspent.android.helper.UserAvatarPreview() }
|
||||||
|
@Test fun testUserAvatarCustomColor() = renders { net.helcel.cowspent.android.helper.UserAvatarCustomColorPreview() }
|
||||||
|
@Test fun testUserAvatarDisabled() = renders { net.helcel.cowspent.android.helper.UserAvatarDisabledPreview() }
|
||||||
|
|
||||||
|
@Test fun testProjectSettlementUI() = renders { net.helcel.cowspent.android.project.settle.ProjectSettlementUIPreview() }
|
||||||
|
@Test fun testProjectSettlementUIBalanced() = renders { net.helcel.cowspent.android.project.settle.ProjectSettlementUIBalancedPreview() }
|
||||||
|
|
||||||
|
@Test fun testLabelManagementCategories() = renders { net.helcel.cowspent.android.label.LabelManagementCategoriesPreview() }
|
||||||
|
@Test fun testLabelManagementPaymentModes() = renders { net.helcel.cowspent.android.label.LabelManagementPaymentModesPreview() }
|
||||||
|
|
||||||
|
@Test fun testDrawerItem() = renders { net.helcel.cowspent.android.drawer.DrawerItemPreview() }
|
||||||
|
@Test fun testDrawer() = renders { net.helcel.cowspent.android.drawer.DrawerPreview() }
|
||||||
|
|
||||||
|
@Test fun testCurrencyRow() = renders { net.helcel.cowspent.android.currencies.CurrencyRowPreview() }
|
||||||
|
@Test fun testManageCurrenciesScreen() = renders { net.helcel.cowspent.android.currencies.ManageCurrenciesScreenPreview() }
|
||||||
|
|
||||||
|
@Test fun testProjectStatisticsTable() = renders { net.helcel.cowspent.android.statistics.ProjectStatisticsTablePreview() }
|
||||||
|
@Test fun testProjectSpendingGraph() = renders { net.helcel.cowspent.android.statistics.ProjectSpendingGraphPreview() }
|
||||||
|
@Test fun testProjectSankeyDiagram() = renders { net.helcel.cowspent.android.statistics.ProjectSankeyDiagramPreview() }
|
||||||
|
|
||||||
|
@Test fun testProjectShareDialogContent() = renders { net.helcel.cowspent.android.project.ProjectShareDialogContentPreview() }
|
||||||
|
@Test fun testMemberManagementScreen() = renders { net.helcel.cowspent.android.project.member.MemberManagementScreenPreview() }
|
||||||
|
@Test fun testMemberEditDialogContent() = renders { net.helcel.cowspent.android.project.member.MemberEditDialogContentPreview() }
|
||||||
|
@Test fun testMemberAddDialogContent() = renders { net.helcel.cowspent.android.project.member.MemberAddDialogContentPreview() }
|
||||||
|
@Test fun testEditProjectScreen() = renders { net.helcel.cowspent.android.project.edit.EditProjectScreenPreview() }
|
||||||
|
@Test fun testNewProjectScreen() = renders { net.helcel.cowspent.android.project.create.NewProjectScreenPreview() }
|
||||||
|
|
||||||
|
@Test fun testColorPicker() = renders { net.helcel.cowspent.android.helper.ColorPickerPreview() }
|
||||||
|
@Test fun testLabelBillsScreen() = renders { net.helcel.cowspent.android.bill_label.LabelBillsScreenPreview() }
|
||||||
|
@Test fun testAccountScreen() = renders { net.helcel.cowspent.android.account.AccountScreenPreview() }
|
||||||
|
@Test fun testAboutScreen() = renders { net.helcel.cowspent.android.about.AboutScreenPreview() }
|
||||||
|
|
||||||
|
@Test fun testSimpleAlertDialog() = renders { net.helcel.cowspent.android.helper.SimpleAlertDialogPreview() }
|
||||||
|
@Test fun testConfirmationDialog() = renders { net.helcel.cowspent.android.helper.ConfirmationDialogPreview() }
|
||||||
|
@Test fun testListDialogWithIcons() = renders { net.helcel.cowspent.android.helper.ListDialogWithIconsPreview() }
|
||||||
|
|
||||||
|
/** Opens a real database, so it is the one preview that needs a Robolectric context to exist. */
|
||||||
|
@Test fun testBillsListScreen() = renders { net.helcel.cowspent.android.main.BillsListScreenPreview() }
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
files:
|
||||||
|
- source: /app/src/main/res/values/strings.xml
|
||||||
|
translation: /app/src/main/res/values-%android_code%/strings.xml
|
||||||
+4
-2
@@ -19,10 +19,12 @@ org.gradle.dependency.verification.console=verbose
|
|||||||
# When configured, Gradle will run in incubating parallel mode.
|
# When configured, Gradle will run in incubating parallel mode.
|
||||||
# This option should only be used with decoupled projects. More details, visit
|
# This option should only be used with decoupled projects. More details, visit
|
||||||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
||||||
# org.gradle.parallel=true
|
org.gradle.parallel=true
|
||||||
android.useAndroidX=true
|
android.useAndroidX=true
|
||||||
android.nonTransitiveRClass=false
|
android.nonTransitiveRClass=false
|
||||||
org.gradle.warning.mode=all
|
org.gradle.warning.mode=all
|
||||||
android.uniquePackageNames=false
|
android.uniquePackageNames=false
|
||||||
android.dependency.useConstraints=false
|
android.dependency.useConstraints=false
|
||||||
android.r8.strictFullModeForKeepRules=false
|
android.r8.strictFullModeForKeepRules=false
|
||||||
|
# Enabled parallel sync for Gradle 9.4+
|
||||||
|
org.gradle.tooling.parallel=true
|
||||||
|
|||||||
Vendored
BIN
Binary file not shown.
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.6.1-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-9.7.1-bin.zip
|
||||||
networkTimeout=10000
|
networkTimeout=10000
|
||||||
retries=0
|
retries=0
|
||||||
retryBackOffMs=500
|
retryBackOffMs=500
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
#
|
#
|
||||||
# Copyright © 2015-2021 the original authors.
|
# Copyright © 2015 the original authors.
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
# you may not use this file except in compliance with the License.
|
# you may not use this file except in compliance with the License.
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
#
|
#
|
||||||
# Gradle start up script for POSIX generated by Gradle.
|
# gradlew start up script for POSIX generated by Gradle.
|
||||||
#
|
#
|
||||||
# Important for running:
|
# Important for running:
|
||||||
#
|
#
|
||||||
@@ -29,7 +29,7 @@
|
|||||||
# bash, then to run this script, type that shell name before the whole
|
# bash, then to run this script, type that shell name before the whole
|
||||||
# command line, like:
|
# command line, like:
|
||||||
#
|
#
|
||||||
# ksh Gradle
|
# ksh gradlew
|
||||||
#
|
#
|
||||||
# Busybox and similar reduced shells will NOT work, because this script
|
# Busybox and similar reduced shells will NOT work, because this script
|
||||||
# requires all of these POSIX shell features:
|
# requires all of these POSIX shell features:
|
||||||
@@ -57,7 +57,7 @@
|
|||||||
# Darwin, MinGW, and NonStop.
|
# Darwin, MinGW, and NonStop.
|
||||||
#
|
#
|
||||||
# (3) This script is generated from the Groovy template
|
# (3) This script is generated from the Groovy template
|
||||||
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
# https://github.com/gradle/gradle/blob/3d91ce3b8caaf77ad09f381f43615b715b53f72c/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||||
# within the Gradle project.
|
# within the Gradle project.
|
||||||
#
|
#
|
||||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||||
@@ -114,7 +114,6 @@ case "$( uname )" in #(
|
|||||||
NONSTOP* ) nonstop=true ;;
|
NONSTOP* ) nonstop=true ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
|
||||||
|
|
||||||
|
|
||||||
# Determine the Java command to use to start the JVM.
|
# Determine the Java command to use to start the JVM.
|
||||||
@@ -172,7 +171,6 @@ fi
|
|||||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||||
if "$cygwin" || "$msys" ; then
|
if "$cygwin" || "$msys" ; then
|
||||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
|
||||||
|
|
||||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||||
|
|
||||||
@@ -212,8 +210,7 @@ DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
|||||||
|
|
||||||
set -- \
|
set -- \
|
||||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||||
-classpath "$CLASSPATH" \
|
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
|
||||||
org.gradle.wrapper.GradleWrapperMain \
|
|
||||||
"$@"
|
"$@"
|
||||||
|
|
||||||
# Stop when "xargs" is not available.
|
# Stop when "xargs" is not available.
|
||||||
|
|||||||
Vendored
+12
-24
@@ -19,12 +19,12 @@
|
|||||||
@if "%DEBUG%"=="" @echo off
|
@if "%DEBUG%"=="" @echo off
|
||||||
@rem ##########################################################################
|
@rem ##########################################################################
|
||||||
@rem
|
@rem
|
||||||
@rem Gradle startup script for Windows
|
@rem gradlew startup script for Windows
|
||||||
@rem
|
@rem
|
||||||
@rem ##########################################################################
|
@rem ##########################################################################
|
||||||
|
|
||||||
@rem Set local scope for the variables with windows NT shell
|
@rem Set local scope for the variables, and ensure extensions are enabled
|
||||||
if "%OS%"=="Windows_NT" setlocal
|
setlocal EnableExtensions
|
||||||
|
|
||||||
set DIRNAME=%~dp0
|
set DIRNAME=%~dp0
|
||||||
if "%DIRNAME%"=="" set DIRNAME=.
|
if "%DIRNAME%"=="" set DIRNAME=.
|
||||||
@@ -51,7 +51,7 @@ echo. 1>&2
|
|||||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||||
echo location of your Java installation. 1>&2
|
echo location of your Java installation. 1>&2
|
||||||
|
|
||||||
goto fail
|
"%COMSPEC%" /c exit 1
|
||||||
|
|
||||||
:findJavaFromJavaHome
|
:findJavaFromJavaHome
|
||||||
set JAVA_HOME=%JAVA_HOME:"=%
|
set JAVA_HOME=%JAVA_HOME:"=%
|
||||||
@@ -65,30 +65,18 @@ echo. 1>&2
|
|||||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||||
echo location of your Java installation. 1>&2
|
echo location of your Java installation. 1>&2
|
||||||
|
|
||||||
goto fail
|
"%COMSPEC%" /c exit 1
|
||||||
|
|
||||||
:execute
|
:execute
|
||||||
@rem Setup the command line
|
@rem Setup the command line
|
||||||
|
|
||||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
|
||||||
|
|
||||||
|
|
||||||
@rem Execute Gradle
|
@rem Execute gradlew
|
||||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
@rem endlocal doesn't take effect until after the line is parsed and variables are expanded
|
||||||
|
@rem which allows us to clear the local environment before executing the java command
|
||||||
|
endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel
|
||||||
|
|
||||||
:end
|
:exitWithErrorLevel
|
||||||
@rem End local scope for the variables with windows NT shell
|
@rem Use "%COMSPEC%" /c exit to allow operators to work properly in scripts
|
||||||
if %ERRORLEVEL% equ 0 goto mainEnd
|
"%COMSPEC%" /c exit %ERRORLEVEL%
|
||||||
|
|
||||||
:fail
|
|
||||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
|
||||||
rem the _cmd.exe /c_ return code!
|
|
||||||
set EXIT_CODE=%ERRORLEVEL%
|
|
||||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
|
||||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
|
||||||
exit /b %EXIT_CODE%
|
|
||||||
|
|
||||||
:mainEnd
|
|
||||||
if "%OS%"=="Windows_NT" endlocal
|
|
||||||
|
|
||||||
:omega
|
|
||||||
|
|||||||
@@ -19,8 +19,6 @@ This means you can choose where your data is going and preserve your privacy.
|
|||||||
* Dark theme and customizable main app color
|
* Dark theme and customizable main app color
|
||||||
* Share/import projects with link/QRCode
|
* Share/import projects with link/QRCode
|
||||||
* Connect to a Nextcloud account to automatically add projects
|
* Connect to a Nextcloud account to automatically add projects
|
||||||
* Background sync service with notifications on bills events
|
|
||||||
* Multi-lingual user-interface (translated on Crowdin: https://crowdin.com/project/cowspent)
|
|
||||||
|
|
||||||
# Requirements
|
# Requirements
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://docs.renovatebot.com/renovate-schema.json"
|
||||||
|
}
|
||||||
@@ -6,6 +6,9 @@ pluginManagement {
|
|||||||
maven { url = 'https://jitpack.io' }
|
maven { url = 'https://jitpack.io' }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
plugins {
|
||||||
|
id 'org.gradle.toolchains.foojay-resolver-convention' version '1.0.0'
|
||||||
|
}
|
||||||
dependencyResolutionManagement {
|
dependencyResolutionManagement {
|
||||||
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
|
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
|
||||||
repositories {
|
repositories {
|
||||||
|
|||||||
Reference in New Issue
Block a user