From 880c1bfd4a5a5c2d42ca6a8d9815b25559659134 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 24 May 2026 23:48:29 +0000 Subject: [PATCH] refactor: clear final java.* imports from commons/commonMain Three changes that bring commons/commonMain to zero java.* imports (down from 18 at the start of Phase 2). - EventListMatchingFilter, NoteListMatchingFilter: moved to jvmAndroid. Both use ConcurrentSkipListSet + SortedSet for ordered concurrent iteration, and their only consumer is LocalCache in the Android app. iOS-time we can revisit if a KMP ordered concurrent set is needed. - Note.kt's BigDecimal: switch import from java.math.BigDecimal to quartz's existing expect/actual com.vitorpamplona.quartz.utils.BigDecimal. BigDecimal.ZERO -> BigDecimal(0); BigDecimal.valueOf(longVal) -> BigDecimal(longVal) (the expect class already has the Long constructor). NoteOnchainZapTest gets the same treatment. - Adds two top-level extensions in quartz commonMain (separate BigDecimalOps.kt file to avoid the duplicate-JVM-classname collision with the existing BigDecimal.kt actuals): operator fun BigDecimal.plus(other: BigDecimal) operator fun BigDecimal.minus(other: BigDecimal) Lets += / + / - continue to work on commonMain BigDecimal values. Commons/commonMain is now structurally iOS-ready as far as the java.* import audit can tell. Remaining iOS work: actually flip on the iOS targets, see what UI / dep transitives break, and address. --- .../amethyst/commons/model/Note.kt | 17 ++++++----- .../commons/model/NoteOnchainZapTest.kt | 30 +++++++++---------- .../observables/EventListMatchingFilter.kt | 0 .../observables/NoteListMatchingFilter.kt | 0 .../quartz/utils/BigDecimalOps.kt | 25 ++++++++++++++++ 5 files changed, 49 insertions(+), 23 deletions(-) rename commons/src/{commonMain => jvmAndroid}/kotlin/com/vitorpamplona/amethyst/commons/model/observables/EventListMatchingFilter.kt (100%) rename commons/src/{commonMain => jvmAndroid}/kotlin/com/vitorpamplona/amethyst/commons/model/observables/NoteListMatchingFilter.kt (100%) create mode 100644 quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/BigDecimalOps.kt diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/Note.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/Note.kt index 5e604f97a7..bc131fee37 100644 --- a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/Note.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/Note.kt @@ -64,17 +64,18 @@ import com.vitorpamplona.quartz.nip57Zaps.LnZapRequestEvent import com.vitorpamplona.quartz.nip59Giftwrap.WrappedEvent import com.vitorpamplona.quartz.nip72ModCommunities.approval.CommunityPostApprovalEvent import com.vitorpamplona.quartz.nip72ModCommunities.definition.CommunityDefinitionEvent +import com.vitorpamplona.quartz.utils.BigDecimal import com.vitorpamplona.quartz.utils.TimeUtils import com.vitorpamplona.quartz.utils.anyAsync import com.vitorpamplona.quartz.utils.containsAny import com.vitorpamplona.quartz.utils.launchAndWaitAll +import com.vitorpamplona.quartz.utils.plus import kotlinx.coroutines.CancellationException import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.flatMapLatest -import java.math.BigDecimal import kotlin.concurrent.Volatile interface NotesGatherer { @@ -162,7 +163,7 @@ open class Note( var zaps = mapOf() private set - var zapsAmount: BigDecimal = BigDecimal.ZERO + var zapsAmount: BigDecimal = BigDecimal(0) /** * NIP-BC onchain zaps targeting this note. @@ -357,7 +358,7 @@ open class Note( onchainZaps = mapOf() onchainZapResolved = false zapPayments = mapOf() - zapsAmount = BigDecimal.ZERO + zapsAmount = BigDecimal(0) relays = listOf() if (repliesChanged) flowSet?.replies?.invalidateData() @@ -743,13 +744,13 @@ open class Note( }.flatten() private fun updateZapTotal() { - var sumOfAmounts = BigDecimal.ZERO + var sumOfAmounts = BigDecimal(0) // Regular Zap Receipts zaps.forEach { val noteEvent = it.value?.event if (noteEvent is LnZapEvent) { - sumOfAmounts += noteEvent.amount ?: BigDecimal.ZERO + sumOfAmounts += noteEvent.amount ?: BigDecimal(0) } } @@ -757,7 +758,7 @@ open class Note( // Unverified/pending entries are tracked but excluded from the total per spec. onchainZaps.values.forEach { entry -> if (entry.status == OnchainZapStatus.CONFIRMED) { - sumOfAmounts += BigDecimal.valueOf(entry.verifiedSats) + sumOfAmounts += BigDecimal(entry.verifiedSats) } } @@ -895,7 +896,7 @@ open class Note( pledgeValue != null && it.author == user } - fun pledgedAmountByOthers(): BigDecimal = replies.sumOf { it.event?.addedRewardValue() ?: BigDecimal.ZERO } + fun pledgedAmountByOthers(): BigDecimal = replies.sumOf { it.event?.addedRewardValue() ?: BigDecimal(0) } fun hasAnyReports(): Boolean { val dayAgo = TimeUtils.oneDayAgo() @@ -984,7 +985,7 @@ open class Note( boosts = emptyList() reports = emptyMap() zaps = emptyMap() - zapsAmount = BigDecimal.ZERO + zapsAmount = BigDecimal(0) } fun isHiddenFor(accountChoices: LiveHiddenUsers): Boolean { diff --git a/commons/src/commonTest/kotlin/com/vitorpamplona/amethyst/commons/model/NoteOnchainZapTest.kt b/commons/src/commonTest/kotlin/com/vitorpamplona/amethyst/commons/model/NoteOnchainZapTest.kt index 59064d5512..5bd761e324 100644 --- a/commons/src/commonTest/kotlin/com/vitorpamplona/amethyst/commons/model/NoteOnchainZapTest.kt +++ b/commons/src/commonTest/kotlin/com/vitorpamplona/amethyst/commons/model/NoteOnchainZapTest.kt @@ -21,7 +21,7 @@ package com.vitorpamplona.amethyst.commons.model import com.vitorpamplona.quartz.nip01Core.core.HexKey -import java.math.BigDecimal +import com.vitorpamplona.quartz.utils.BigDecimal import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertFalse @@ -67,7 +67,7 @@ class NoteOnchainZapTest { assertEquals(1000L, entry?.claimedSats) assertEquals(0L, entry?.verifiedSats) assertEquals(OnchainZapStatus.UNVERIFIED, entry?.status) - assertEquals(BigDecimal.ZERO, target.zapsAmount) + assertEquals(BigDecimal(0), target.zapsAmount) } @Test @@ -82,7 +82,7 @@ class NoteOnchainZapTest { assertSame(src, entry?.source) assertEquals(1000L, entry?.verifiedSats) assertEquals(OnchainZapStatus.PENDING, entry?.status) - assertEquals(BigDecimal.ZERO, target.zapsAmount) + assertEquals(BigDecimal(0), target.zapsAmount) } @Test @@ -93,7 +93,7 @@ class NoteOnchainZapTest { target.addOnchainZap(src, "tx1", claimedSats = 5000L, verifiedSats = 5000L, status = OnchainZapStatus.CONFIRMED) assertEquals(OnchainZapStatus.CONFIRMED, target.onchainZaps["tx1"]?.status) - assertEquals(BigDecimal.valueOf(5000L), target.zapsAmount) + assertEquals(BigDecimal(5000L), target.zapsAmount) } @Test @@ -109,7 +109,7 @@ class NoteOnchainZapTest { assertSame(secondSrc, entry?.source) assertEquals(OnchainZapStatus.PENDING, entry?.status) assertEquals(2400L, entry?.verifiedSats) - assertEquals(BigDecimal.ZERO, target.zapsAmount) + assertEquals(BigDecimal(0), target.zapsAmount) } @Test @@ -124,7 +124,7 @@ class NoteOnchainZapTest { val entry = target.onchainZaps["tx1"] assertSame(secondSrc, entry?.source) assertEquals(OnchainZapStatus.CONFIRMED, entry?.status) - assertEquals(BigDecimal.valueOf(2500L), target.zapsAmount) + assertEquals(BigDecimal(2500L), target.zapsAmount) } @Test @@ -139,7 +139,7 @@ class NoteOnchainZapTest { val entry = target.onchainZaps["tx1"] assertSame(firstSrc, entry?.source) assertEquals(OnchainZapStatus.CONFIRMED, entry?.status) - assertEquals(BigDecimal.valueOf(7500L), target.zapsAmount) + assertEquals(BigDecimal(7500L), target.zapsAmount) } @Test @@ -188,7 +188,7 @@ class NoteOnchainZapTest { val entry = target.onchainZaps["tx1"] assertSame(firstSrc, entry?.source) assertEquals(999L, entry?.verifiedSats) - assertEquals(BigDecimal.valueOf(999L), target.zapsAmount) + assertEquals(BigDecimal(999L), target.zapsAmount) } @Test @@ -206,7 +206,7 @@ class NoteOnchainZapTest { val entry = target.onchainZaps["tx1"] assertSame(secondSrc, entry?.source) - assertEquals(BigDecimal.valueOf(1000L), target.zapsAmount) + assertEquals(BigDecimal(1000L), target.zapsAmount) } @Test @@ -224,7 +224,7 @@ class NoteOnchainZapTest { val secondEntry = target.onchainZaps["tx1"] assertSame(firstEntry, secondEntry) - assertEquals(BigDecimal.valueOf(100L), target.zapsAmount) + assertEquals(BigDecimal(100L), target.zapsAmount) } @Test @@ -238,13 +238,13 @@ class NoteOnchainZapTest { target.addOnchainZap(src, "tx1", claimedSats = 4200L, verifiedSats = 4200L, status = OnchainZapStatus.PENDING) // PENDING entries don't contribute to total per spec. - assertEquals(BigDecimal.ZERO, target.zapsAmount) + assertEquals(BigDecimal(0), target.zapsAmount) assertNotNull(target.onchainZaps["tx1"]) target.removeOnchainZapForSource("tx1", srcKey) assertNull(target.onchainZaps["tx1"]) - assertEquals(BigDecimal.ZERO, target.zapsAmount) + assertEquals(BigDecimal(0), target.zapsAmount) } @Test @@ -277,13 +277,13 @@ class NoteOnchainZapTest { val src = sourceNote(srcKey) target.addOnchainZap(src, "tx1", claimedSats = 4200L, verifiedSats = 4200L, status = OnchainZapStatus.CONFIRMED) - assertEquals(BigDecimal.valueOf(4200L), target.zapsAmount) + assertEquals(BigDecimal(4200L), target.zapsAmount) target.removeOnchainZapForSource("tx1", srcKey) assertNotNull(target.onchainZaps["tx1"]) assertEquals(OnchainZapStatus.CONFIRMED, target.onchainZaps["tx1"]?.status) - assertEquals(BigDecimal.valueOf(4200L), target.zapsAmount) + assertEquals(BigDecimal(4200L), target.zapsAmount) } @Test @@ -342,7 +342,7 @@ class NoteOnchainZapTest { target.addOnchainZap(sourceNote("82".repeat(32)), "tx3", claimedSats = 9999L, verifiedSats = 9999L, status = OnchainZapStatus.PENDING) target.addOnchainZap(sourceNote("93".repeat(32)), "tx4", claimedSats = 1234L, verifiedSats = 0L, status = OnchainZapStatus.UNVERIFIED) - assertEquals(BigDecimal.valueOf(3000L), target.zapsAmount) + assertEquals(BigDecimal(3000L), target.zapsAmount) assertEquals(4, target.onchainZaps.size) assertTrue(target.onchainZaps.containsKey("tx3")) assertTrue(target.onchainZaps.containsKey("tx4")) diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/observables/EventListMatchingFilter.kt b/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/model/observables/EventListMatchingFilter.kt similarity index 100% rename from commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/observables/EventListMatchingFilter.kt rename to commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/model/observables/EventListMatchingFilter.kt diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/observables/NoteListMatchingFilter.kt b/commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/model/observables/NoteListMatchingFilter.kt similarity index 100% rename from commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/model/observables/NoteListMatchingFilter.kt rename to commons/src/jvmAndroid/kotlin/com/vitorpamplona/amethyst/commons/model/observables/NoteListMatchingFilter.kt diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/BigDecimalOps.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/BigDecimalOps.kt new file mode 100644 index 0000000000..571f812db1 --- /dev/null +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/utils/BigDecimalOps.kt @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.quartz.utils + +operator fun BigDecimal.plus(other: BigDecimal): BigDecimal = add(other) + +operator fun BigDecimal.minus(other: BigDecimal): BigDecimal = subtract(other)