Author SHA1 Message Date
Renovate Bot 1063f0c319 Update dependency gradle to v9.8.1 2026-10-08 02:01:51 +00:00
sora c2da40ba4d Update .github/workflows/build.yml 2026-10-03 19:38:47 +02:00
sora 6e45507b22 Merge pull request 'Update plugin org.jetbrains.kotlin.plugin.serialization to v2.4.20' (#15) from renovate/org.jetbrains.kotlin.plugin.serialization-2.x into main
Reviewed-on: #15
2026-10-03 19:33:49 +02:00
sora 99d05680c5 Merge pull request 'Update dependency androidx.compose.runtime:runtime to v1.12.1' (#17) from renovate/androidx.compose.runtime-runtime-1.x into main
Reviewed-on: #17
2026-10-03 19:33:35 +02:00
Renovate Bot d89d99ceff Update plugin org.jetbrains.kotlin.plugin.serialization to v2.4.20 2026-10-01 02:01:46 +00:00
Renovate Bot 40be1b79f2 Update dependency androidx.compose.runtime:runtime to v1.12.1 2026-10-01 02:01:44 +00:00
sora e807d6fa66 Merge pull request 'Update dependency androidx.work:work-runtime-ktx to v2.12.0' (#20) from renovate/androidx.work-work-runtime-ktx-2.x into main
Reviewed-on: #20
2026-09-30 23:03:02 +02:00
sora 8ae8df6ef8 Merge pull request 'Update dependency org.robolectric:robolectric to v4.17' (#19) from renovate/org.robolectric-robolectric-4.x into main
Reviewed-on: #19
2026-09-30 23:02:53 +02:00
sora 791f3572b6 Merge pull request 'Update dependency androidx.compose:compose-bom to v2026.09.00' (#18) from renovate/androidx.compose-compose-bom-2026.x into main
Reviewed-on: #18
2026-09-30 23:02:34 +02:00
sora ce8053ff2c Merge pull request 'Update dependency androidx.compose.foundation:foundation to v1.12.1' (#16) from renovate/androidx.compose.foundation-foundation-1.x into main
Reviewed-on: #16
2026-09-30 23:02:15 +02:00
sora f5f4c083f0 Merge pull request 'Update plugin org.jetbrains.kotlin.plugin.compose to v2.4.20' (#14) from renovate/org.jetbrains.kotlin.plugin.compose-2.x into main
Reviewed-on: #14
2026-09-30 23:01:39 +02:00
sora 6800fc6c41 Direct Settlement 2026-09-30 22:51:10 +02:00
Renovate Bot 1f56757d30 Update dependency androidx.work:work-runtime-ktx to v2.12.0 2026-09-24 02:02:58 +00:00
Renovate Bot 73dc64a688 Update dependency org.robolectric:robolectric to v4.17 2026-09-11 02:01:48 +00:00
Renovate Bot 3b22037496 Update dependency androidx.compose:compose-bom to v2026.09.00 2026-09-11 02:01:46 +00:00
Renovate Bot 206c756ad7 Update dependency androidx.compose.foundation:foundation to v1.12.1 2026-09-10 02:01:21 +00:00
Renovate Bot a66d046b3f Update plugin org.jetbrains.kotlin.plugin.compose to v2.4.20 2026-09-08 02:01:15 +00:00
10 changed files with 62 additions and 16 deletions
+2 -2
View File
@@ -93,11 +93,11 @@ jobs:
- name: Upload to Google Play
uses: r0adkll/upload-google-play@v1
if: startsWith(github.ref, 'refs/tags/')
# if: startsWith(github.ref, 'refs/tags/')
with:
serviceAccountJsonPlainText: ${{ secrets.SERVICE_ACCOUNT_JSON }}
packageName: net.helcel.cowspent
releaseFiles: app/build/outputs/bundle/signedRelease/app-signedRelease.aab
tracks: ${{ startsWith(github.ref, 'refs/tags/') && 'production' || 'alpha' }}
tracks: ${{ startsWith(github.ref, 'refs/tags/') && 'production' || 'internal' }}
status: completed
whatsNewDirectory: tmp/whatsnew
+8 -8
View File
@@ -1,7 +1,7 @@
plugins {
id 'com.android.application' version '9.3.2'
id 'org.jetbrains.kotlin.plugin.serialization' version '2.4.10'
id 'org.jetbrains.kotlin.plugin.compose' version '2.4.10'
id 'org.jetbrains.kotlin.plugin.serialization' version '2.4.20'
id 'org.jetbrains.kotlin.plugin.compose' version '2.4.20'
id 'jacoco'
}
@@ -118,12 +118,12 @@ android {
}
dependencies {
implementation 'androidx.compose.foundation:foundation:1.12.0'
implementation 'androidx.compose.runtime:runtime:1.12.0'
implementation 'androidx.compose.foundation:foundation:1.12.1'
implementation 'androidx.compose.runtime:runtime:1.12.1'
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.1.5'
implementation 'androidx.preference:preference-ktx:1.2.1'
implementation 'androidx.work:work-runtime-ktx:2.11.2'
implementation 'androidx.work:work-runtime-ktx:2.12.0'
implementation 'com.google.zxing:core:3.5.4'
implementation 'androidx.camera:camera-camera2:1.6.2'
@@ -132,7 +132,7 @@ dependencies {
implementation 'com.github.nextcloud:Android-SingleSignOn:1.3.4'
implementation 'com.opencsv:opencsv:5.12.0'
implementation platform('androidx.compose:compose-bom:2026.08.00')
implementation platform('androidx.compose:compose-bom:2026.09.00')
implementation 'androidx.compose.ui:ui'
implementation 'androidx.compose.material:material'
implementation 'androidx.compose.material:material-icons-extended'
@@ -147,12 +147,12 @@ dependencies {
testImplementation 'junit:junit:4.13.2'
testImplementation 'io.mockk:mockk:1.14.11'
testImplementation 'org.robolectric:robolectric:4.16.1'
testImplementation 'org.robolectric:robolectric:4.17'
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 platform('androidx.compose:compose-bom:2026.09.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'
@@ -48,8 +48,10 @@ import net.helcel.cowspent.model.Transaction
import net.helcel.cowspent.model.UserItem
import net.helcel.cowspent.persistence.CowspentSQLiteOpenHelper
import net.helcel.cowspent.util.SupportUtil
import net.helcel.cowspent.util.SupportUtil.SETTLE_DIRECT
import net.helcel.cowspent.util.SupportUtil.SETTLE_OPTIMAL
import net.helcel.cowspent.util.SupportUtil.settleBills
import net.helcel.cowspent.util.SupportUtil.settleBillsDirect
@Composable
fun ProjectSettlementDialogContent(
@@ -60,10 +62,12 @@ fun ProjectSettlementDialogContent(
onDismiss: () -> Unit
) {
val centerNoneStr = stringResource(R.string.center_none)
val centerDirectStr = stringResource(R.string.center_none_direct)
val memberList = remember(proj.id) { db.getMembersOfProject(proj.id, null) }
val userList = remember(memberList, centerNoneStr) {
val userList = remember(memberList, centerNoneStr, centerDirectStr) {
buildList {
add(UserItem(SETTLE_OPTIMAL, centerNoneStr))
add(UserItem(SETTLE_DIRECT, centerDirectStr))
addAll(memberList.map { UserItem(it.id, it.name) })
}
}
@@ -91,8 +95,12 @@ fun ProjectSettlementDialogContent(
}
val transactions = remember(selectedMemberId, membersBalance, membersSortedByName) {
if (selectedMemberId == SETTLE_DIRECT) {
settleBillsDirect(membersSortedByName, db.getBillsOfProject(proj.id))
} else {
settleBills(membersSortedByName, membersBalance, selectedMemberId)
}
}
ProjectSettlementUI(
transactions = transactions,
@@ -167,6 +167,39 @@ object SupportUtil {
}
const val SETTLE_OPTIMAL: Long = 0
const val SETTLE_DIRECT: Long = -1
@JvmStatic
fun settleBillsDirect(members: List<DBMember>, bills: List<DBBill>): List<Transaction> {
val membersWeight = members.associate { it.id to it.weight }
// owed[debtor][creditor] = total the debtor owes the creditor over all bills
val owed = HashMap<Long, HashMap<Long, Double>>()
for (b in bills) {
if (b.state == DBBill.STATE_DELETED) continue
val nbOwerShares = b.billOwers.sumOf { membersWeight[it.memberId] ?: 0.0 }
if (nbOwerShares <= 0.0) continue
for (bo in b.billOwers) {
if (bo.memberId == b.payerId) continue
val share = b.amount / nbOwerShares * (membersWeight[bo.memberId] ?: 0.0)
val row = owed.getOrPut(bo.memberId) { HashMap() }
row[b.payerId] = (row[b.payerId] ?: 0.0) + share
}
}
val results: MutableList<Transaction> = ArrayList()
for (debtor in members) {
for (creditor in members) {
if (debtor.id == creditor.id) continue
val net = (owed[debtor.id]?.get(creditor.id) ?: 0.0) -
(owed[creditor.id]?.get(debtor.id) ?: 0.0)
if (round2(net) > 0.0) {
results.add(Transaction(debtor.id, creditor.id, round2(net)))
}
}
}
return results
}
@JvmStatic
fun settleBills(
@@ -209,6 +209,7 @@
<!-- Settlement -->
<string name="center_none">Keine (optimal)</string>
<string name="center_none_direct">Keine (direkt)</string>
<string name="settle_who">Wer zahlt</string>
<string name="settle_to_whom">An wen</string>
<string name="settle_how_much">Betrag</string>
@@ -210,6 +210,7 @@
<!-- Settlement -->
<string name="center_none">Ninguno (óptimo)</string>
<string name="center_none_direct">Ninguno (directo)</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>
@@ -213,6 +213,7 @@
<!-- Settlement -->
<string name="center_none">Aucun (optimal)</string>
<string name="center_none_direct">Aucun (direct)</string>
<string name="settle_who">Qui paie</string>
<string name="settle_to_whom">À qui</string>
<string name="settle_how_much">Montant</string>
@@ -209,6 +209,7 @@
<!-- Settlement -->
<string name="center_none">Нет (оптимально)</string>
<string name="center_none_direct">Нет (напрямую)</string>
<string name="settle_who">Кто платит</string>
<string name="settle_to_whom">Кому</string>
<string name="settle_how_much">Сумма</string>
+1
View File
@@ -247,6 +247,7 @@
<!-- Settlement -->
<string name="center_none">None (Optimal)</string>
<string name="center_none_direct">None (Direct)</string>
<string name="settle_who">Who pays</string>
<string name="settle_to_whom">To whom</string>
<string name="settle_how_much">Amount</string>
+1 -1
View File
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-9.7.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-9.8.1-bin.zip
networkTimeout=10000
retries=0
retryBackOffMs=500