From c2b242e89f07c13ae547bf071d7d2878f51e738d Mon Sep 17 00:00:00 2001 From: Brandon McAnsh Date: Fri, 23 Oct 2026 15:09:24 -0400 Subject: [PATCH 01/50] build(kmp): declare shared targets in flipcash.kmp.library All 14 KMP library modules repeated the same android compileSdk/minSdk block and the same five Apple targets, and only text-format applied the convention plugin. The plugin now declares those targets, and every module applies it and keeps only its namespace and test opt-ins. shared-core attaches its SharedCore framework to each native target via targets.withType() instead of a local target list. discrete-curve hard-coded compileSdk = 37; it now picks up the catalog's 37 with minor API level 2 like the other modules. --- .../main/kotlin/KmpLibraryConventionPlugin.kt | 43 ++++++++++++++++++- kmp/shared-core/build.gradle.kts | 18 +++----- libs/analytics-events/build.gradle.kts | 15 +------ libs/codes/kikcode/build.gradle.kts | 15 +------ .../discrete-curve/build.gradle.kts | 11 +---- libs/encryption/base58/build.gradle.kts | 15 +------ libs/encryption/chat-cipher/build.gradle.kts | 15 +------ libs/encryption/ed25519/build.gradle.kts | 15 +------ libs/encryption/hmac/build.gradle.kts | 15 +------ libs/encryption/mnemonic/build.gradle.kts | 15 +------ libs/encryption/sha256/build.gradle.kts | 15 +------ libs/encryption/sha512/build.gradle.kts | 15 +------ libs/encryption/utils/build.gradle.kts | 15 +------ libs/reporting/build.gradle.kts | 15 +------ libs/text-format/build.gradle.kts | 12 ------ 15 files changed, 59 insertions(+), 190 deletions(-) diff --git a/build-logic/convention/src/main/kotlin/KmpLibraryConventionPlugin.kt b/build-logic/convention/src/main/kotlin/KmpLibraryConventionPlugin.kt index 4d394bce85..38b4d3f11b 100644 --- a/build-logic/convention/src/main/kotlin/KmpLibraryConventionPlugin.kt +++ b/build-logic/convention/src/main/kotlin/KmpLibraryConventionPlugin.kt @@ -1,5 +1,11 @@ +import com.android.build.api.dsl.KotlinMultiplatformAndroidLibraryTarget import org.gradle.api.Plugin import org.gradle.api.Project +import org.gradle.api.artifacts.VersionCatalogsExtension +import org.gradle.api.plugins.ExtensionAware +import org.gradle.kotlin.dsl.configure +import org.gradle.kotlin.dsl.getByType +import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension /** * Convention plugin for KMP library modules. @@ -8,14 +14,25 @@ import org.gradle.api.Project * - `org.jetbrains.kotlin.multiplatform` * - `com.android.kotlin.multiplatform.library` * - * After applying this plugin the `kotlin {}` DSL block is available for configuring targets, - * source sets, and dependencies. + * and declares the targets every shared library builds for: + * - `android` -- compileSdk and minSdk from the version catalog + * - `iosArm64`, `iosSimulatorArm64`, `iosX64`, `macosArm64`, `macosX64` -- the Kotlin/Native + * slices of the `SharedCore` framework iOS consumes + * + * A module still sets its own `namespace`, and opts into host/device tests, inside `kotlin { android {} }`. * * Usage in a module's `build.gradle.kts`: * ``` * plugins { * alias(libs.plugins.flipcash.kmp.library) * } + * + * kotlin { + * android { + * namespace = "com.example" + * withHostTest {} + * } + * } * ``` */ class KmpLibraryConventionPlugin : Plugin { @@ -25,6 +42,28 @@ class KmpLibraryConventionPlugin : Plugin { apply("org.jetbrains.kotlin.multiplatform") apply("com.android.kotlin.multiplatform.library") } + + val libs = extensions.getByType().named("libs") + val compileSdkVersion = libs.findVersion("android-compileSdk").get().requiredVersion.toInt() + val compileSdkMinorVersion = libs.findVersion("android-compileSdkMinor").get().requiredVersion.toInt() + val minSdkVersion = libs.findVersion("android-minSdk").get().requiredVersion.toInt() + + extensions.configure { + (this as ExtensionAware).extensions.configure { + compileSdk { + version = release(compileSdkVersion) { + minorApiLevel = compileSdkMinorVersion + } + } + minSdk = minSdkVersion + } + + iosArm64() + iosSimulatorArm64() + iosX64() + macosArm64() + macosX64() + } } } } diff --git a/kmp/shared-core/build.gradle.kts b/kmp/shared-core/build.gradle.kts index a9bfafc66e..3bf85b67e9 100644 --- a/kmp/shared-core/build.gradle.kts +++ b/kmp/shared-core/build.gradle.kts @@ -1,9 +1,9 @@ import co.touchlab.kmmbridge.KmmBridgeExtension import org.gradle.api.tasks.bundling.Zip +import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget plugins { - kotlin("multiplatform") - id("com.android.kotlin.multiplatform.library") + alias(libs.plugins.flipcash.kmp.library) id("co.touchlab.kmmbridge.github") version "1.2.1" `maven-publish` } @@ -24,17 +24,11 @@ val spmPackageDir = findProperty("spmRepoDir") as String? kotlin { android { namespace = "com.flipcash.shared" - compileSdk { - version = release(libs.versions.android.compileSdk.get().toInt()) { - minorApiLevel = libs.versions.android.compileSdkMinor.get().toInt() - } - } - minSdk = 29 } - - val appleTargets = listOf(iosArm64(), iosSimulatorArm64(), iosX64(), macosArm64(), macosX64()) - appleTargets.forEach { - it.binaries.framework { + + // The Apple targets come from `flipcash.kmp.library`; each one ships a `SharedCore` slice. + targets.withType().configureEach { + binaries.framework { baseName = "SharedCore" isStatic = true export(project(":libs:codes:kikcode")) diff --git a/libs/analytics-events/build.gradle.kts b/libs/analytics-events/build.gradle.kts index 194f8071e1..48eae940ca 100644 --- a/libs/analytics-events/build.gradle.kts +++ b/libs/analytics-events/build.gradle.kts @@ -1,6 +1,5 @@ plugins { - kotlin("multiplatform") - id("com.android.kotlin.multiplatform.library") + alias(libs.plugins.flipcash.kmp.library) // Generates the builders and value enums from events.toml into commonMain. alias(libs.plugins.flipcash.analytics.catalogue) } @@ -8,21 +7,9 @@ plugins { kotlin { android { namespace = "com.flipcash.analytics" - compileSdk { - version = release(libs.versions.android.compileSdk.get().toInt()) { - minorApiLevel = libs.versions.android.compileSdkMinor.get().toInt() - } - } - minSdk = 29 withHostTest {} } - iosArm64() - iosSimulatorArm64() - iosX64() - macosArm64() - macosX64() - sourceSets { commonMain { // Pure Kotlin -- no external dependencies needed. diff --git a/libs/codes/kikcode/build.gradle.kts b/libs/codes/kikcode/build.gradle.kts index b2d926844a..fafb2aaca7 100644 --- a/libs/codes/kikcode/build.gradle.kts +++ b/libs/codes/kikcode/build.gradle.kts @@ -1,6 +1,5 @@ plugins { - kotlin("multiplatform") - id("com.android.kotlin.multiplatform.library") + alias(libs.plugins.flipcash.kmp.library) alias(libs.plugins.flipcash.kmp.test.fixtures) } @@ -13,21 +12,9 @@ testFixtures { kotlin { android { namespace = "com.getcode.codes.kikcode" - compileSdk { - version = release(libs.versions.android.compileSdk.get().toInt()) { - minorApiLevel = libs.versions.android.compileSdkMinor.get().toInt() - } - } - minSdk = 29 withHostTest {} } - iosArm64() - iosSimulatorArm64() - iosX64() - macosArm64() - macosX64() - sourceSets { commonMain { // Pure Kotlin -- geometry + string building, no platform APIs. diff --git a/libs/currency-math/discrete-curve/build.gradle.kts b/libs/currency-math/discrete-curve/build.gradle.kts index 6ba6a5cf34..5cdde2fe86 100644 --- a/libs/currency-math/discrete-curve/build.gradle.kts +++ b/libs/currency-math/discrete-curve/build.gradle.kts @@ -1,6 +1,5 @@ plugins { - kotlin("multiplatform") - id("com.android.kotlin.multiplatform.library") + alias(libs.plugins.flipcash.kmp.library) alias(libs.plugins.flipcash.kmp.test.fixtures) } @@ -13,8 +12,6 @@ testFixtures { kotlin { android { namespace = "com.flipcash.libs.currency.math.curve" - compileSdk = 37 - minSdk = 29 withHostTest {} // `flipcash.kmp.test.fixtures` compiles this module's fixtures -- @@ -31,12 +28,6 @@ kotlin { } } - iosArm64() - iosSimulatorArm64() - iosX64() - macosArm64() - macosX64() - sourceSets { commonMain { dependencies { diff --git a/libs/encryption/base58/build.gradle.kts b/libs/encryption/base58/build.gradle.kts index 143d07f8f0..a4ca3469bc 100644 --- a/libs/encryption/base58/build.gradle.kts +++ b/libs/encryption/base58/build.gradle.kts @@ -1,6 +1,5 @@ plugins { - kotlin("multiplatform") - id("com.android.kotlin.multiplatform.library") + alias(libs.plugins.flipcash.kmp.library) alias(libs.plugins.flipcash.kmp.test.fixtures) } @@ -13,21 +12,9 @@ testFixtures { kotlin { android { namespace = "com.getcode.encryption.base58" - compileSdk { - version = release(libs.versions.android.compileSdk.get().toInt()) { - minorApiLevel = libs.versions.android.compileSdkMinor.get().toInt() - } - } - minSdk = 29 withHostTest {} } - iosArm64() - iosSimulatorArm64() - iosX64() - macosArm64() - macosX64() - sourceSets { commonMain { // Pure Kotlin -- no external dependencies needed. diff --git a/libs/encryption/chat-cipher/build.gradle.kts b/libs/encryption/chat-cipher/build.gradle.kts index 3491f546a8..d61bc38456 100644 --- a/libs/encryption/chat-cipher/build.gradle.kts +++ b/libs/encryption/chat-cipher/build.gradle.kts @@ -1,8 +1,7 @@ import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSetTree plugins { - kotlin("multiplatform") - id("com.android.kotlin.multiplatform.library") + alias(libs.plugins.flipcash.kmp.library) alias(libs.plugins.flipcash.kmp.test.fixtures) } @@ -15,12 +14,6 @@ testFixtures { kotlin { android { namespace = "com.getcode.encryption.chatcipher" - compileSdk { - version = release(libs.versions.android.compileSdk.get().toInt()) { - minorApiLevel = libs.versions.android.compileSdkMinor.get().toInt() - } - } - minSdk = 29 // No host test: libsodium's Android binding loads its .so from the APK and the Ed25519 // actual is JNI, so neither loads on a JVM host. The device test runs commonTest instead, // and the Apple targets run it natively. @@ -31,12 +24,6 @@ kotlin { } } - iosArm64() - iosSimulatorArm64() - iosX64() - macosArm64() - macosX64() - sourceSets { commonMain { dependencies { diff --git a/libs/encryption/ed25519/build.gradle.kts b/libs/encryption/ed25519/build.gradle.kts index b77ecbce3f..911b4bf760 100644 --- a/libs/encryption/ed25519/build.gradle.kts +++ b/libs/encryption/ed25519/build.gradle.kts @@ -1,8 +1,7 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget plugins { - kotlin("multiplatform") - id("com.android.kotlin.multiplatform.library") + alias(libs.plugins.flipcash.kmp.library) alias(libs.plugins.flipcash.kmp.test.fixtures) } @@ -79,21 +78,9 @@ appleTargetDefs.forEach { target -> kotlin { android { namespace = "com.getcode.encryption.ed25519" - compileSdk { - version = release(libs.versions.android.compileSdk.get().toInt()) { - minorApiLevel = libs.versions.android.compileSdkMinor.get().toInt() - } - } - minSdk = 29 withHostTest {} } - iosArm64() - iosSimulatorArm64() - iosX64() - macosArm64() - macosX64() - // ── Cinterop + linker wiring for each Apple target ──────────────────────── targets.withType().configureEach { val targetDef = appleTargetDefs.first { it.kotlinName == name } diff --git a/libs/encryption/hmac/build.gradle.kts b/libs/encryption/hmac/build.gradle.kts index 258a914a10..93776d856c 100644 --- a/libs/encryption/hmac/build.gradle.kts +++ b/libs/encryption/hmac/build.gradle.kts @@ -1,26 +1,13 @@ plugins { - kotlin("multiplatform") - id("com.android.kotlin.multiplatform.library") + alias(libs.plugins.flipcash.kmp.library) } kotlin { android { namespace = "com.getcode.encryption.hmac" - compileSdk { - version = release(libs.versions.android.compileSdk.get().toInt()) { - minorApiLevel = libs.versions.android.compileSdkMinor.get().toInt() - } - } - minSdk = 29 withHostTest {} } - iosArm64() - iosSimulatorArm64() - iosX64() - macosArm64() - macosX64() - sourceSets { commonMain { dependencies { diff --git a/libs/encryption/mnemonic/build.gradle.kts b/libs/encryption/mnemonic/build.gradle.kts index fa0c0dd626..6752d8968c 100644 --- a/libs/encryption/mnemonic/build.gradle.kts +++ b/libs/encryption/mnemonic/build.gradle.kts @@ -1,6 +1,5 @@ plugins { - kotlin("multiplatform") - id("com.android.kotlin.multiplatform.library") + alias(libs.plugins.flipcash.kmp.library) alias(libs.plugins.flipcash.kmp.test.fixtures) } @@ -13,22 +12,10 @@ testFixtures { kotlin { android { namespace = "com.getcode.encryption.mnemonic" - compileSdk { - version = release(libs.versions.android.compileSdk.get().toInt()) { - minorApiLevel = libs.versions.android.compileSdkMinor.get().toInt() - } - } - minSdk = 29 withHostTest {} withDeviceTest {} } - iosArm64() - iosSimulatorArm64() - iosX64() - macosArm64() - macosX64() - sourceSets { commonMain { dependencies { diff --git a/libs/encryption/sha256/build.gradle.kts b/libs/encryption/sha256/build.gradle.kts index adfcd4938f..b2dc650c44 100644 --- a/libs/encryption/sha256/build.gradle.kts +++ b/libs/encryption/sha256/build.gradle.kts @@ -1,26 +1,13 @@ plugins { - kotlin("multiplatform") - id("com.android.kotlin.multiplatform.library") + alias(libs.plugins.flipcash.kmp.library) } kotlin { android { namespace = "com.getcode.encryption.sha256" - compileSdk { - version = release(libs.versions.android.compileSdk.get().toInt()) { - minorApiLevel = libs.versions.android.compileSdkMinor.get().toInt() - } - } - minSdk = 29 withHostTest {} } - iosArm64() - iosSimulatorArm64() - iosX64() - macosArm64() - macosX64() - sourceSets { commonMain { dependencies { diff --git a/libs/encryption/sha512/build.gradle.kts b/libs/encryption/sha512/build.gradle.kts index 038470ad6b..e8557c31cc 100644 --- a/libs/encryption/sha512/build.gradle.kts +++ b/libs/encryption/sha512/build.gradle.kts @@ -1,26 +1,13 @@ plugins { - kotlin("multiplatform") - id("com.android.kotlin.multiplatform.library") + alias(libs.plugins.flipcash.kmp.library) } kotlin { android { namespace = "com.getcode.encryption.sha512" - compileSdk { - version = release(libs.versions.android.compileSdk.get().toInt()) { - minorApiLevel = libs.versions.android.compileSdkMinor.get().toInt() - } - } - minSdk = 29 withHostTest {} } - iosArm64() - iosSimulatorArm64() - iosX64() - macosArm64() - macosX64() - sourceSets { commonMain { dependencies { diff --git a/libs/encryption/utils/build.gradle.kts b/libs/encryption/utils/build.gradle.kts index 6b5bc632f3..79e57d881d 100644 --- a/libs/encryption/utils/build.gradle.kts +++ b/libs/encryption/utils/build.gradle.kts @@ -1,26 +1,13 @@ plugins { - kotlin("multiplatform") - id("com.android.kotlin.multiplatform.library") + alias(libs.plugins.flipcash.kmp.library) } kotlin { android { namespace = "com.getcode.encryption.utils" - compileSdk { - version = release(libs.versions.android.compileSdk.get().toInt()) { - minorApiLevel = libs.versions.android.compileSdkMinor.get().toInt() - } - } - minSdk = 29 withHostTest {} } - iosArm64() - iosSimulatorArm64() - iosX64() - macosArm64() - macosX64() - sourceSets { commonMain { dependencies { diff --git a/libs/reporting/build.gradle.kts b/libs/reporting/build.gradle.kts index a03de2ded7..70b77cc4e6 100644 --- a/libs/reporting/build.gradle.kts +++ b/libs/reporting/build.gradle.kts @@ -1,26 +1,13 @@ plugins { - kotlin("multiplatform") - id("com.android.kotlin.multiplatform.library") + alias(libs.plugins.flipcash.kmp.library) } kotlin { android { namespace = "com.flipcash.reporting" - compileSdk { - version = release(libs.versions.android.compileSdk.get().toInt()) { - minorApiLevel = libs.versions.android.compileSdkMinor.get().toInt() - } - } - minSdk = 29 withHostTest {} } - iosArm64() - iosSimulatorArm64() - iosX64() - macosArm64() - macosX64() - sourceSets { commonMain { // Pure Kotlin -- no external dependencies needed. diff --git a/libs/text-format/build.gradle.kts b/libs/text-format/build.gradle.kts index 16de7b7f18..bf08b14d1a 100644 --- a/libs/text-format/build.gradle.kts +++ b/libs/text-format/build.gradle.kts @@ -12,21 +12,9 @@ testFixtures { kotlin { android { namespace = "com.flipcash.libs.textformat" - compileSdk { - version = release(libs.versions.android.compileSdk.get().toInt()) { - minorApiLevel = libs.versions.android.compileSdkMinor.get().toInt() - } - } - minSdk = 29 withHostTest {} } - iosArm64() - iosSimulatorArm64() - iosX64() - macosArm64() - macosX64() - sourceSets { commonMain { // Pure Kotlin -- no external dependencies needed. From f2508cac172386657997a554fe0702b484dfe9df Mon Sep 17 00:00:00 2001 From: Brandon McAnsh Date: Fri, 23 Oct 2026 15:09:25 -0400 Subject: [PATCH 02/50] feat(kmp): add a jvm() target to the shared libraries First step of the desktop client: the KMP libraries need a JVM target before Compose Desktop modules can depend on them. flipcash.kmp.library now declares jvm() with jvmTarget from the android-java catalog version. Two expect declarations needed JVM actuals: - sha512 derivePlatform: the JDK ships PBKDF2WithHmacSHA512, so the actual is the Android JCA one with the same ASCII-only guard. - Ed25519Kmp: pure Java on net.i2p.crypto:eddsa, which already backs the test-utils shadow. The 64-byte private key is eddsa's clamped hash `h`, the same orlp layout the JNI and cinterop actuals return, so keys move between platforms unchanged. The RFC 8032 vectors in ed25519.json pass on jvmTest, so no native library is loaded on desktop. sign.c includes sha3.h, but that header declares the sha512_* functions and sha3.c is libtom's SHA-512 (it carries the 0x428a2f98d728ae22 round constant). It's a misnamed file, not SHA-3, which is why standard SHA-512 on the JVM reproduces the native signatures. --- .../main/kotlin/KmpLibraryConventionPlugin.kt | 9 +++ libs/encryption/ed25519/build.gradle.kts | 6 ++ .../com/getcode/ed25519kmp/Ed25519Kmp.jvm.kt | 61 +++++++++++++++++++ .../com/getcode/crypt/PBKDF2SHA512.jvm.kt | 27 ++++++++ 4 files changed, 103 insertions(+) create mode 100644 libs/encryption/ed25519/src/jvmMain/kotlin/com/getcode/ed25519kmp/Ed25519Kmp.jvm.kt create mode 100644 libs/encryption/sha512/src/jvmMain/kotlin/com/getcode/crypt/PBKDF2SHA512.jvm.kt diff --git a/build-logic/convention/src/main/kotlin/KmpLibraryConventionPlugin.kt b/build-logic/convention/src/main/kotlin/KmpLibraryConventionPlugin.kt index 38b4d3f11b..94efac5553 100644 --- a/build-logic/convention/src/main/kotlin/KmpLibraryConventionPlugin.kt +++ b/build-logic/convention/src/main/kotlin/KmpLibraryConventionPlugin.kt @@ -5,6 +5,7 @@ import org.gradle.api.artifacts.VersionCatalogsExtension import org.gradle.api.plugins.ExtensionAware import org.gradle.kotlin.dsl.configure import org.gradle.kotlin.dsl.getByType +import org.jetbrains.kotlin.gradle.dsl.JvmTarget import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension /** @@ -18,6 +19,7 @@ import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension * - `android` -- compileSdk and minSdk from the version catalog * - `iosArm64`, `iosSimulatorArm64`, `iosX64`, `macosArm64`, `macosX64` -- the Kotlin/Native * slices of the `SharedCore` framework iOS consumes + * - `jvm` -- the desktop client * * A module still sets its own `namespace`, and opts into host/device tests, inside `kotlin { android {} }`. * @@ -47,6 +49,7 @@ class KmpLibraryConventionPlugin : Plugin { val compileSdkVersion = libs.findVersion("android-compileSdk").get().requiredVersion.toInt() val compileSdkMinorVersion = libs.findVersion("android-compileSdkMinor").get().requiredVersion.toInt() val minSdkVersion = libs.findVersion("android-minSdk").get().requiredVersion.toInt() + val javaVersion = libs.findVersion("android-java").get().requiredVersion extensions.configure { (this as ExtensionAware).extensions.configure { @@ -63,6 +66,12 @@ class KmpLibraryConventionPlugin : Plugin { iosX64() macosArm64() macosX64() + + jvm { + compilerOptions { + jvmTarget.set(JvmTarget.fromTarget(javaVersion)) + } + } } } } diff --git a/libs/encryption/ed25519/build.gradle.kts b/libs/encryption/ed25519/build.gradle.kts index 911b4bf760..28dac3e0e8 100644 --- a/libs/encryption/ed25519/build.gradle.kts +++ b/libs/encryption/ed25519/build.gradle.kts @@ -125,6 +125,12 @@ kotlin { api(project(":libs:encryption:ed25519-native")) } } + jvmMain { + dependencies { + // Pure-Java Ed25519 for desktop -- no per-OS native library to build or ship. + implementation(libs.eddsa) + } + } commonTest { dependencies { implementation(kotlin("test")) diff --git a/libs/encryption/ed25519/src/jvmMain/kotlin/com/getcode/ed25519kmp/Ed25519Kmp.jvm.kt b/libs/encryption/ed25519/src/jvmMain/kotlin/com/getcode/ed25519kmp/Ed25519Kmp.jvm.kt new file mode 100644 index 0000000000..2b7ddbbad5 --- /dev/null +++ b/libs/encryption/ed25519/src/jvmMain/kotlin/com/getcode/ed25519kmp/Ed25519Kmp.jvm.kt @@ -0,0 +1,61 @@ +package com.getcode.ed25519kmp + +import net.i2p.crypto.eddsa.EdDSAEngine +import net.i2p.crypto.eddsa.EdDSAPrivateKey +import net.i2p.crypto.eddsa.EdDSAPublicKey +import net.i2p.crypto.eddsa.math.GroupElement +import net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable +import net.i2p.crypto.eddsa.spec.EdDSAPrivateKeySpec +import net.i2p.crypto.eddsa.spec.EdDSAPublicKeySpec +import java.security.MessageDigest + +/** + * JVM (desktop) actual: pure Java, on `net.i2p.crypto:eddsa`, so there is no native library to + * ship per OS. + * + * The 64-byte private key keeps the orlp layout the Android and Apple actuals produce: the clamped + * SHA-512 expansion of the seed (`a || prefix`). eddsa calls that same value `h`, and accepts it + * directly through [EdDSAPrivateKeySpec]'s `(spec, h)` constructor, so a key created on any + * platform signs identically here. The JDK's own Ed25519 provider can't do this: its private key + * spec only takes the 32-byte seed, which the orlp key doesn't contain. + */ +actual object Ed25519Kmp { + + private val spec = EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.ED_25519) + + actual fun createKeyPair(seed: ByteArray): KeyPair { + val privateKey = EdDSAPrivateKey(EdDSAPrivateKeySpec(seed, spec)) + return KeyPair(publicKey = privateKey.abyte, privateKey = privateKey.h) + } + + actual fun sign( + message: ByteArray, + publicKey: ByteArray, + privateKey: ByteArray, + ): ByteArray { + val key = EdDSAPrivateKey(EdDSAPrivateKeySpec(spec, privateKey)) + return EdDSAEngine(MessageDigest.getInstance(spec.hashAlgorithm)).run { + initSign(key) + update(message) + sign() + } + } + + actual fun verify( + signature: ByteArray, + message: ByteArray, + publicKey: ByteArray, + ): Boolean = runCatching { + val key = EdDSAPublicKey(EdDSAPublicKeySpec(publicKey, spec)) + EdDSAEngine(MessageDigest.getInstance(spec.hashAlgorithm)).run { + initVerify(key) + update(message) + verify(signature) + } + }.getOrDefault(false) + + actual fun onCurve(publicKey: ByteArray): Boolean = runCatching { + GroupElement(spec.curve, publicKey) + true + }.getOrDefault(false) +} diff --git a/libs/encryption/sha512/src/jvmMain/kotlin/com/getcode/crypt/PBKDF2SHA512.jvm.kt b/libs/encryption/sha512/src/jvmMain/kotlin/com/getcode/crypt/PBKDF2SHA512.jvm.kt new file mode 100644 index 0000000000..eb2a0f2aa5 --- /dev/null +++ b/libs/encryption/sha512/src/jvmMain/kotlin/com/getcode/crypt/PBKDF2SHA512.jvm.kt @@ -0,0 +1,27 @@ +package com.getcode.crypt + +import javax.crypto.SecretKeyFactory +import javax.crypto.spec.PBEKeySpec + +private const val ALGORITHM = "PBKDF2WithHmacSHA512" + +/** + * The JDK's SunJCE provider implements PBKDF2WithHmacSHA512, so the desktop JVM takes the same JCA + * route as Android (Conscrypt there). Same ASCII-only restriction and fallback as the Android + * actual -- see `PBKDF2SHA512.android.kt` for why: providers disagree about encoding a non-ASCII + * `char[]` password, and ASCII is where every encoding coincides. + */ +internal actual fun derivePlatform(P: String, S: String, c: Int, dkLen: Int): ByteArray? { + if (!P.isAscii()) return null + + return runCatching { + val spec = PBEKeySpec(P.toCharArray(), S.encodeToByteArray(), c, dkLen * 8) + try { + SecretKeyFactory.getInstance(ALGORITHM).generateSecret(spec).encoded + } finally { + spec.clearPassword() + } + }.getOrNull() +} + +private fun String.isAscii(): Boolean = all { it.code < 0x80 } From 1d367b543c94f367436e7a6562e3d471e17fd1bc Mon Sep 17 00:00:00 2001 From: Brandon McAnsh Date: Fri, 23 Oct 2026 15:29:13 -0400 Subject: [PATCH 03/50] build(kmp): add flipcash.kmp.app.library for android+jvm modules Hilt's Gradle plugin rejects the AGP KMP android target, so KMP modules run the Hilt KSP processors through kspAndroid without the plugin. Only the app and notifications use @AndroidEntryPoint, which is what the plugin's bytecode rewrite exists for. libs:coroutines moves onto the plugin, and its test fixtures become a :libs:coroutines:test-fixtures module, since the KMP android target has no testFixtures. shared:funding moves its sources to androidMain as the first Hilt-bearing module on the KMP plugin. --- .../features/messenger/build.gradle.kts | 2 +- .../shared/appupdates/build.gradle.kts | 2 +- .../shared/authentication/build.gradle.kts | 2 +- apps/flipcash/shared/funding/build.gradle.kts | 46 +++++-- .../app/funding/PurchaseMethodStateTest.kt | 0 .../flipcash/app/funding/PurchaseMethod.kt | 0 .../app/funding/PurchaseMethodController.kt | 0 .../app/funding/PurchaseMethodState.kt | 0 .../flipcash/app/funding/internal/Buttons.kt | 0 .../InternalPurchaseMethodController.kt | 0 apps/flipcash/shared/invite/build.gradle.kts | 2 +- apps/flipcash/shared/session/build.gradle.kts | 2 +- build-logic/convention/build.gradle.kts | 4 + .../kotlin/KmpAppLibraryConventionPlugin.kt | 129 ++++++++++++++++++ gradle/libs.versions.toml | 1 + libs/coroutines/build.gradle.kts | 14 +- .../libs/coroutines/DispatcherProvider.kt | 0 .../coroutines/test-fixtures/build.gradle.kts | 16 +++ .../libs/coroutines/TestDispatcherProvider.kt | 0 settings.gradle.kts | 1 + 20 files changed, 197 insertions(+), 24 deletions(-) rename apps/flipcash/shared/funding/src/{test => androidHostTest}/kotlin/com/flipcash/app/funding/PurchaseMethodStateTest.kt (100%) rename apps/flipcash/shared/funding/src/{main => androidMain}/kotlin/com/flipcash/app/funding/PurchaseMethod.kt (100%) rename apps/flipcash/shared/funding/src/{main => androidMain}/kotlin/com/flipcash/app/funding/PurchaseMethodController.kt (100%) rename apps/flipcash/shared/funding/src/{main => androidMain}/kotlin/com/flipcash/app/funding/PurchaseMethodState.kt (100%) rename apps/flipcash/shared/funding/src/{main => androidMain}/kotlin/com/flipcash/app/funding/internal/Buttons.kt (100%) rename apps/flipcash/shared/funding/src/{main => androidMain}/kotlin/com/flipcash/app/funding/internal/InternalPurchaseMethodController.kt (100%) create mode 100644 build-logic/convention/src/main/kotlin/KmpAppLibraryConventionPlugin.kt rename libs/coroutines/src/{main => commonMain}/kotlin/com/flipcash/libs/coroutines/DispatcherProvider.kt (100%) create mode 100644 libs/coroutines/test-fixtures/build.gradle.kts rename libs/coroutines/{src/testFixtures => test-fixtures/src/commonMain}/kotlin/com/flipcash/libs/coroutines/TestDispatcherProvider.kt (100%) diff --git a/apps/flipcash/features/messenger/build.gradle.kts b/apps/flipcash/features/messenger/build.gradle.kts index 1c21aec922..db75e306bb 100644 --- a/apps/flipcash/features/messenger/build.gradle.kts +++ b/apps/flipcash/features/messenger/build.gradle.kts @@ -9,7 +9,7 @@ android { dependencies { implementation(project(":apps:flipcash:shared:analytics")) testImplementation(testFixtures(project(":apps:flipcash:shared:analytics"))) - testImplementation(testFixtures(project(":libs:coroutines"))) + testImplementation(project(":libs:coroutines:test-fixtures")) implementation(project(":apps:flipcash:shared:blob")) implementation(project(":apps:flipcash:shared:bills")) implementation(project(":apps:flipcash:shared:blocklist")) diff --git a/apps/flipcash/shared/appupdates/build.gradle.kts b/apps/flipcash/shared/appupdates/build.gradle.kts index c6677cd406..0c30c7d864 100644 --- a/apps/flipcash/shared/appupdates/build.gradle.kts +++ b/apps/flipcash/shared/appupdates/build.gradle.kts @@ -20,5 +20,5 @@ dependencies { testImplementation(kotlin("test")) testImplementation(libs.bundles.unit.testing) testImplementation(libs.robolectric) - testImplementation(testFixtures(project(":libs:coroutines"))) + testImplementation(project(":libs:coroutines:test-fixtures")) } diff --git a/apps/flipcash/shared/authentication/build.gradle.kts b/apps/flipcash/shared/authentication/build.gradle.kts index d0da4fab23..76ffc14e35 100644 --- a/apps/flipcash/shared/authentication/build.gradle.kts +++ b/apps/flipcash/shared/authentication/build.gradle.kts @@ -26,5 +26,5 @@ dependencies { testImplementation(kotlin("test")) testImplementation(libs.bundles.unit.testing) testImplementation(libs.robolectric) - testImplementation(testFixtures(project(":libs:coroutines"))) + testImplementation(project(":libs:coroutines:test-fixtures")) } diff --git a/apps/flipcash/shared/funding/build.gradle.kts b/apps/flipcash/shared/funding/build.gradle.kts index 178401e7f9..03fc03ffca 100644 --- a/apps/flipcash/shared/funding/build.gradle.kts +++ b/apps/flipcash/shared/funding/build.gradle.kts @@ -1,16 +1,44 @@ plugins { - alias(libs.plugins.flipcash.android.feature) + alias(libs.plugins.flipcash.kmp.library) + alias(libs.plugins.compose.compiler) + alias(libs.plugins.kotlin.ksp) } -android { - namespace = "${Gradle.flipcashNamespace}.shared.funding" +kotlin { + android { + namespace = "${Gradle.flipcashNamespace}.shared.funding" + withHostTest {} + androidResources { enable = true } + } + sourceSets { + androidMain.dependencies { + implementation(project.dependencies.platform(libs.compose.bom)) + implementation(libs.bundles.compose) + implementation(libs.bundles.hilt) + implementation(project(":libs:coroutines")) + implementation(project(":libs:logging")) + implementation(project(":ui:core")) + implementation(project(":ui:components")) + implementation(project(":ui:navigation")) + implementation(project(":ui:resources")) + implementation(project(":ui:theme")) + implementation(project(":apps:flipcash:core")) + implementation(project(":apps:flipcash:core-ui")) + implementation(project(":apps:flipcash:shared:analytics")) + implementation(project(":apps:flipcash:shared:featureflags")) + implementation(project(":apps:flipcash:shared:tokens:core")) + implementation(project(":apps:flipcash:shared:userflags")) + implementation(project(":libs:messaging")) + implementation(project(":services:flipcash")) + } + getByName("androidHostTest").dependencies { + implementation(kotlin("test")) + implementation(libs.bundles.unit.testing) + } + } } dependencies { - implementation(project(":apps:flipcash:shared:analytics")) - implementation(project(":apps:flipcash:shared:featureflags")) - implementation(project(":apps:flipcash:shared:tokens:core")) - implementation(project(":apps:flipcash:shared:userflags")) - implementation(project(":libs:messaging")) - implementation(project(":services:flipcash")) + add("kspAndroid", libs.hilt.android.compiler) + add("kspAndroid", libs.hilt.compiler) } diff --git a/apps/flipcash/shared/funding/src/test/kotlin/com/flipcash/app/funding/PurchaseMethodStateTest.kt b/apps/flipcash/shared/funding/src/androidHostTest/kotlin/com/flipcash/app/funding/PurchaseMethodStateTest.kt similarity index 100% rename from apps/flipcash/shared/funding/src/test/kotlin/com/flipcash/app/funding/PurchaseMethodStateTest.kt rename to apps/flipcash/shared/funding/src/androidHostTest/kotlin/com/flipcash/app/funding/PurchaseMethodStateTest.kt diff --git a/apps/flipcash/shared/funding/src/main/kotlin/com/flipcash/app/funding/PurchaseMethod.kt b/apps/flipcash/shared/funding/src/androidMain/kotlin/com/flipcash/app/funding/PurchaseMethod.kt similarity index 100% rename from apps/flipcash/shared/funding/src/main/kotlin/com/flipcash/app/funding/PurchaseMethod.kt rename to apps/flipcash/shared/funding/src/androidMain/kotlin/com/flipcash/app/funding/PurchaseMethod.kt diff --git a/apps/flipcash/shared/funding/src/main/kotlin/com/flipcash/app/funding/PurchaseMethodController.kt b/apps/flipcash/shared/funding/src/androidMain/kotlin/com/flipcash/app/funding/PurchaseMethodController.kt similarity index 100% rename from apps/flipcash/shared/funding/src/main/kotlin/com/flipcash/app/funding/PurchaseMethodController.kt rename to apps/flipcash/shared/funding/src/androidMain/kotlin/com/flipcash/app/funding/PurchaseMethodController.kt diff --git a/apps/flipcash/shared/funding/src/main/kotlin/com/flipcash/app/funding/PurchaseMethodState.kt b/apps/flipcash/shared/funding/src/androidMain/kotlin/com/flipcash/app/funding/PurchaseMethodState.kt similarity index 100% rename from apps/flipcash/shared/funding/src/main/kotlin/com/flipcash/app/funding/PurchaseMethodState.kt rename to apps/flipcash/shared/funding/src/androidMain/kotlin/com/flipcash/app/funding/PurchaseMethodState.kt diff --git a/apps/flipcash/shared/funding/src/main/kotlin/com/flipcash/app/funding/internal/Buttons.kt b/apps/flipcash/shared/funding/src/androidMain/kotlin/com/flipcash/app/funding/internal/Buttons.kt similarity index 100% rename from apps/flipcash/shared/funding/src/main/kotlin/com/flipcash/app/funding/internal/Buttons.kt rename to apps/flipcash/shared/funding/src/androidMain/kotlin/com/flipcash/app/funding/internal/Buttons.kt diff --git a/apps/flipcash/shared/funding/src/main/kotlin/com/flipcash/app/funding/internal/InternalPurchaseMethodController.kt b/apps/flipcash/shared/funding/src/androidMain/kotlin/com/flipcash/app/funding/internal/InternalPurchaseMethodController.kt similarity index 100% rename from apps/flipcash/shared/funding/src/main/kotlin/com/flipcash/app/funding/internal/InternalPurchaseMethodController.kt rename to apps/flipcash/shared/funding/src/androidMain/kotlin/com/flipcash/app/funding/internal/InternalPurchaseMethodController.kt diff --git a/apps/flipcash/shared/invite/build.gradle.kts b/apps/flipcash/shared/invite/build.gradle.kts index ab06609168..0a43002570 100644 --- a/apps/flipcash/shared/invite/build.gradle.kts +++ b/apps/flipcash/shared/invite/build.gradle.kts @@ -12,5 +12,5 @@ dependencies { testImplementation(kotlin("test")) testImplementation(libs.bundles.unit.testing) testImplementation(libs.robolectric) - testImplementation(testFixtures(project(":libs:coroutines"))) + testImplementation(project(":libs:coroutines:test-fixtures")) } diff --git a/apps/flipcash/shared/session/build.gradle.kts b/apps/flipcash/shared/session/build.gradle.kts index cbd954cd22..d89ecb4b3d 100644 --- a/apps/flipcash/shared/session/build.gradle.kts +++ b/apps/flipcash/shared/session/build.gradle.kts @@ -9,7 +9,7 @@ android { dependencies { testImplementation(kotlin("test")) testImplementation(libs.bundles.unit.testing) - testImplementation(testFixtures(project(":libs:coroutines"))) + testImplementation(project(":libs:coroutines:test-fixtures")) testImplementation(testFixtures(project(":ui:resources"))) implementation(project(":apps:flipcash:shared:blob")) diff --git a/build-logic/convention/build.gradle.kts b/build-logic/convention/build.gradle.kts index 256dd56494..2d16a1a8e8 100644 --- a/build-logic/convention/build.gradle.kts +++ b/build-logic/convention/build.gradle.kts @@ -49,6 +49,10 @@ gradlePlugin { id = "flipcash.kmp.library" implementationClass = "KmpLibraryConventionPlugin" } + register("kmpAppLibrary") { + id = "flipcash.kmp.app.library" + implementationClass = "KmpAppLibraryConventionPlugin" + } register("kmpTestFixtures") { id = "flipcash.kmp.test.fixtures" implementationClass = "KmpTestFixturesConventionPlugin" diff --git a/build-logic/convention/src/main/kotlin/KmpAppLibraryConventionPlugin.kt b/build-logic/convention/src/main/kotlin/KmpAppLibraryConventionPlugin.kt new file mode 100644 index 0000000000..dd47da8950 --- /dev/null +++ b/build-logic/convention/src/main/kotlin/KmpAppLibraryConventionPlugin.kt @@ -0,0 +1,129 @@ +import com.android.build.api.dsl.KotlinMultiplatformAndroidLibraryTarget +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.api.artifacts.VersionCatalogsExtension +import org.gradle.api.plugins.ExtensionAware +import org.gradle.api.tasks.testing.Test +import org.gradle.jvm.toolchain.JavaLanguageVersion +import org.gradle.kotlin.dsl.configure +import org.gradle.kotlin.dsl.getByType +import org.gradle.kotlin.dsl.withType +import org.jetbrains.kotlin.gradle.dsl.JvmTarget +import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension + +/** + * Convention plugin for app-layer KMP modules that build for Android and the desktop JVM only. + * + * Unlike `flipcash.kmp.library` it declares no Kotlin/Native targets: these modules sit on Android + * and JVM libraries (gRPC, Room, DataStore, OkHttp) with no native counterpart. Because every target + * is a JVM, `commonMain` sees the JDK, so code that only needs `java.*` moves there unchanged and + * only `android.*` uses need an `expect`/`actual` or an interface. + * + * Applies: + * - `org.jetbrains.kotlin.multiplatform` + * - `com.android.kotlin.multiplatform.library` + * - `org.jetbrains.kotlin.plugin.serialization` + * + * and declares: + * - `android` -- compileSdk and minSdk from the version catalog, host tests enabled with the same + * options `flipcash.android.library` sets on unit tests + * - `jvm` -- the desktop client + * + * The AGP KMP library target is single-variant: it has no `buildTypes` and no `BuildConfig`, so a + * value that differed between debug and release must come from the app at runtime. + * + * Usage in a module's `build.gradle.kts`: + * ``` + * plugins { + * alias(libs.plugins.flipcash.kmp.app.library) + * } + * + * kotlin { + * android { + * namespace = "com.example" + * } + * } + * ``` + */ +class KmpAppLibraryConventionPlugin : Plugin { + override fun apply(target: Project) { + with(target) { + with(pluginManager) { + apply("org.jetbrains.kotlin.multiplatform") + apply("com.android.kotlin.multiplatform.library") + apply("org.jetbrains.kotlin.plugin.serialization") + } + + val libs = extensions.getByType().named("libs") + val compileSdkVersion = libs.findVersion("android-compileSdk").get().requiredVersion.toInt() + val compileSdkMinorVersion = libs.findVersion("android-compileSdkMinor").get().requiredVersion.toInt() + val minSdkVersion = libs.findVersion("android-minSdk").get().requiredVersion.toInt() + val javaVersion = libs.findVersion("android-java").get().requiredVersion + + extensions.configure { + jvmToolchain { + languageVersion.set(JavaLanguageVersion.of(javaVersion)) + } + + (this as ExtensionAware).extensions.configure { + compileSdk { + version = release(compileSdkVersion) { + minorApiLevel = compileSdkMinorVersion + } + } + minSdk = minSdkVersion + withHostTestBuilder {}.configure { + isReturnDefaultValues = true + isIncludeAndroidResources = true + } + compilerOptions { + jvmTarget.set(JvmTarget.fromTarget(javaVersion)) + } + } + + jvm { + compilerOptions { + jvmTarget.set(JvmTarget.fromTarget(javaVersion)) + } + } + + compilerOptions { + optIn.addAll( + "kotlin.time.ExperimentalTime", + "kotlin.ExperimentalUnsignedTypes", + "kotlin.RequiresOptIn" + ) + freeCompilerArgs.add("-Xexpect-actual-classes") + } + + sourceSets.named("commonMain") { + dependencies { + implementation(libs.findLibrary("kotlinx-coroutines-core").get()) + } + } + sourceSets.named("androidMain") { + dependencies { + implementation(libs.findLibrary("timber").get()) + } + } + sourceSets.named("androidHostTest") { + dependencies { + implementation(libs.findLibrary("kotlin-test-junit").get()) + // Provides robolectric.properties, which pins the Robolectric SDK level. + implementation(project(":libs:test-utils")) + } + } + sourceSets.named("jvmTest") { + dependencies { + implementation(libs.findLibrary("kotlin-test-junit").get()) + } + } + } + + tasks.withType { + failOnNoDiscoveredTests.set(false) + maxHeapSize = "2g" + } + } + } +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ff83cf456c..55493d0055 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -349,6 +349,7 @@ flipcash-android-library-compose = { id = "flipcash.android.library.compose" } flipcash-android-feature = { id = "flipcash.android.feature" } flipcash-android-ed25519-shadow = { id = "flipcash.android.ed25519.shadow" } flipcash-kmp-library = { id = "flipcash.kmp.library" } +flipcash-kmp-app-library = { id = "flipcash.kmp.app.library" } flipcash-kmp-test-fixtures = { id = "flipcash.kmp.test.fixtures" } flipcash-analytics-catalogue = { id = "flipcash.analytics.catalogue" } android-application = { id = "com.android.application", version.ref = "agp" } diff --git a/libs/coroutines/build.gradle.kts b/libs/coroutines/build.gradle.kts index 0be0cc0f8c..3d32a19f24 100644 --- a/libs/coroutines/build.gradle.kts +++ b/libs/coroutines/build.gradle.kts @@ -1,15 +1,9 @@ plugins { - alias(libs.plugins.flipcash.android.library) - id("org.jetbrains.kotlin.plugin.parcelize") + alias(libs.plugins.flipcash.kmp.app.library) } -android { - namespace = "${Gradle.codeNamespace}.libs.coroutines" - testFixtures { - enable = true +kotlin { + android { + namespace = "${Gradle.codeNamespace}.libs.coroutines" } } - -dependencies { - testFixturesImplementation(libs.kotlinx.coroutines.test) -} diff --git a/libs/coroutines/src/main/kotlin/com/flipcash/libs/coroutines/DispatcherProvider.kt b/libs/coroutines/src/commonMain/kotlin/com/flipcash/libs/coroutines/DispatcherProvider.kt similarity index 100% rename from libs/coroutines/src/main/kotlin/com/flipcash/libs/coroutines/DispatcherProvider.kt rename to libs/coroutines/src/commonMain/kotlin/com/flipcash/libs/coroutines/DispatcherProvider.kt diff --git a/libs/coroutines/test-fixtures/build.gradle.kts b/libs/coroutines/test-fixtures/build.gradle.kts new file mode 100644 index 0000000000..bdc3f43d24 --- /dev/null +++ b/libs/coroutines/test-fixtures/build.gradle.kts @@ -0,0 +1,16 @@ +plugins { + alias(libs.plugins.flipcash.kmp.app.library) +} + +kotlin { + android { + namespace = "${Gradle.codeNamespace}.libs.coroutines.testfixtures" + } + + sourceSets { + commonMain.dependencies { + api(project(":libs:coroutines")) + implementation(libs.kotlinx.coroutines.test) + } + } +} diff --git a/libs/coroutines/src/testFixtures/kotlin/com/flipcash/libs/coroutines/TestDispatcherProvider.kt b/libs/coroutines/test-fixtures/src/commonMain/kotlin/com/flipcash/libs/coroutines/TestDispatcherProvider.kt similarity index 100% rename from libs/coroutines/src/testFixtures/kotlin/com/flipcash/libs/coroutines/TestDispatcherProvider.kt rename to libs/coroutines/test-fixtures/src/commonMain/kotlin/com/flipcash/libs/coroutines/TestDispatcherProvider.kt diff --git a/settings.gradle.kts b/settings.gradle.kts index 1a7f302c17..ce47d2b015 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -200,6 +200,7 @@ include( ":libs:code-detection", ":libs:codes:kikcode", ":libs:coroutines", + ":libs:coroutines:test-fixtures", ":libs:crypto:kin", ":libs:crypto:solana", ":libs:currency", From 46b4b59ddf21186d4706822b06d4de780f1d5161 Mon Sep 17 00:00:00 2001 From: Brandon McAnsh Date: Fri, 23 Oct 2026 15:42:10 -0400 Subject: [PATCH 04/50] build(kmp): move the leaf libraries to android+jvm Converts network:jwt, currency-math, encryption:keys, datetime and messaging onto flipcash.kmp.app.library and gives encryption:utils a jvmShared source set for its java.*/protobuf helpers. Adds :libs:parcelable, a common Parcelable/@Parcelize stand-in that typealiases android.os.Parcelable on Android, so parcelable models can live in commonMain. currency-math's test fixtures become :libs:currency-math:test-fixtures, and the desktop build reads the curve tables from the classpath. --- .../DiscreteBondingCurveInitializer.kt | 1 + apps/flipcash/shared/tokens/build.gradle.kts | 2 +- .../kotlin/KmpAppLibraryConventionPlugin.kt | 12 +++- gradle/libs.versions.toml | 10 +++ libs/currency-math/build.gradle.kts | 58 +++++++++++------- .../assets/curve.json | 0 .../assets/curve_fractional.json | 0 .../curves/DiscreteBondingCurveVectorTest.kt | 0 .../math/ContinuousBondingCurveTests.kt | 0 .../math/DiscreteBondingCurveTests.kt | 0 .../libs/currency/math/EstimationTests.kt | 0 .../math/EstimatorValueExchangeTests.kt | 0 .../flipcash/libs/currency/math/Expects.kt | 0 .../math/loader/ClasspathTableLoader.kt | 0 .../assets/discrete_cumulative_table.bin | Bin .../assets/discrete_pricing_table.bin | Bin .../libs/currency/math/Curves.android.kt | 6 ++ .../internal/loader/AndroidTableLoader.kt | 4 -- .../com/flipcash/libs/currency/math/Curves.kt | 14 +++-- .../flipcash/libs/currency/math/Estimator.kt | 0 .../com/flipcash/libs/currency/math/Units.kt | 0 .../libs/currency/math/internal/BigDecimal.kt | 0 .../libs/currency/math/internal/Constants.kt | 0 .../internal/curves/ContinuousBondingCurve.kt | 2 - .../internal/curves/DiscreteBondingCurve.kt | 0 .../math/internal}/loader/FileTableLoader.kt | 7 +-- .../math/internal/loader/TableByteLoader.kt | 5 ++ .../flipcash/libs/currency/math/Curves.jvm.kt | 6 ++ .../internal/loader/ClasspathTableLoader.kt | 12 ++++ .../currency/math/CurveTestInitializer.kt | 11 ---- .../test-fixtures/build.gradle.kts | 15 +++++ .../currency/math/CurveTestInitializer.kt | 9 +++ libs/datetime/build.gradle.kts | 28 ++++++--- .../kotlin/com/getcode/util/DateUtilsTest.kt | 0 .../com/getcode/util/InstantExtensionsTest.kt | 0 .../kotlin/com/getcode/util/DateUtils.kt | 0 .../kotlin/com/getcode/util/Instant.kt | 0 libs/encryption/keys/build.gradle.kts | 36 ++++++----- .../getcode/solana/keys/AccountMetaTest.kt | 0 .../getcode/solana/keys/KeyInitOrderTest.kt | 0 .../kotlin/com/getcode/solana/keys/KeyTest.kt | 0 .../com/getcode/solana/keys/MintTest.kt | 0 .../com/getcode/solana/keys/PublicKeyTest.kt | 0 .../utils/serializer/SerializerTest.kt | 0 .../com/getcode/solana/keys/AccountMeta.kt | 0 .../kotlin/com/getcode/solana/keys/Key.kt | 0 .../com/getcode/solana/keys/MerkleProof.kt | 0 .../kotlin/com/getcode/solana/keys/Mint.kt | 9 +-- .../com/getcode/solana/keys/PublicKey.kt | 11 ++-- .../kotlin/com/getcode/solana/keys/Types.kt | 0 .../utils/serializer/ByteListSerializer.kt | 7 ++- .../utils/serializer/MintSerializer.kt | 0 .../utils/serializer/PublicKeySerializer.kt | 0 libs/encryption/utils/build.gradle.kts | 19 +++++- .../com/getcode/utils/Base64.android.kt | 11 ++++ .../utils/Ed25519Extensions.android.kt | 6 ++ .../com/getcode/utils/Extensions.android.kt | 48 --------------- .../kotlin/com/getcode/utils/Base64.jvm.kt | 10 +++ .../com/getcode/utils/Extensions.jvmShared.kt | 44 +++++++++++++ libs/messaging/build.gradle.kts | 24 +++++--- .../com/getcode/manager/BottomBarManager.kt | 0 .../com/getcode/manager/TopBarManager.kt | 0 libs/network/jwt/build.gradle.kts | 8 ++- .../com/getcode/network/jwt/JwtProvider.kt | 0 .../getcode/network/jwt/JwtSecuredEndpoint.kt | 0 libs/parcelable/build.gradle.kts | 9 +++ .../getcode/libs/parcelable/ParcelizeTest.kt | 15 +++++ .../libs/parcelable/Parcelable.android.kt | 15 +++++ .../com/getcode/libs/parcelable/Parcelable.kt | 39 ++++++++++++ .../getcode/libs/parcelable/Parcelable.jvm.kt | 13 ++++ services/opencode/build.gradle.kts | 2 +- settings.gradle.kts | 2 + 72 files changed, 378 insertions(+), 152 deletions(-) rename libs/currency-math/src/{androidTest => androidDeviceTest}/assets/curve.json (100%) rename libs/currency-math/src/{androidTest => androidDeviceTest}/assets/curve_fractional.json (100%) rename libs/currency-math/src/{androidTest/java => androidDeviceTest/kotlin}/com/flipcash/libs/currency/math/internal/curves/DiscreteBondingCurveVectorTest.kt (100%) rename libs/currency-math/src/{test/java => androidHostTest/kotlin}/com/flipcash/libs/currency/math/ContinuousBondingCurveTests.kt (100%) rename libs/currency-math/src/{test/java => androidHostTest/kotlin}/com/flipcash/libs/currency/math/DiscreteBondingCurveTests.kt (100%) rename libs/currency-math/src/{test/java => androidHostTest/kotlin}/com/flipcash/libs/currency/math/EstimationTests.kt (100%) rename libs/currency-math/src/{test/java => androidHostTest/kotlin}/com/flipcash/libs/currency/math/EstimatorValueExchangeTests.kt (100%) rename libs/currency-math/src/{test/java => androidHostTest/kotlin}/com/flipcash/libs/currency/math/Expects.kt (100%) rename libs/currency-math/src/{test/java => androidHostTest/kotlin}/com/flipcash/libs/currency/math/loader/ClasspathTableLoader.kt (100%) rename libs/currency-math/src/{main => androidMain}/assets/discrete_cumulative_table.bin (100%) rename libs/currency-math/src/{main => androidMain}/assets/discrete_pricing_table.bin (100%) create mode 100644 libs/currency-math/src/androidMain/kotlin/com/flipcash/libs/currency/math/Curves.android.kt rename libs/currency-math/src/{main => androidMain}/kotlin/com/flipcash/libs/currency/math/internal/loader/AndroidTableLoader.kt (89%) rename libs/currency-math/src/{main => commonMain}/kotlin/com/flipcash/libs/currency/math/Curves.kt (71%) rename libs/currency-math/src/{main => commonMain}/kotlin/com/flipcash/libs/currency/math/Estimator.kt (100%) rename libs/currency-math/src/{main => commonMain}/kotlin/com/flipcash/libs/currency/math/Units.kt (100%) rename libs/currency-math/src/{main => commonMain}/kotlin/com/flipcash/libs/currency/math/internal/BigDecimal.kt (100%) rename libs/currency-math/src/{main => commonMain}/kotlin/com/flipcash/libs/currency/math/internal/Constants.kt (100%) rename libs/currency-math/src/{main => commonMain}/kotlin/com/flipcash/libs/currency/math/internal/curves/ContinuousBondingCurve.kt (99%) rename libs/currency-math/src/{main => commonMain}/kotlin/com/flipcash/libs/currency/math/internal/curves/DiscreteBondingCurve.kt (100%) rename libs/currency-math/src/{testFixtures/kotlin/com/flipcash/libs/currency/math => commonMain/kotlin/com/flipcash/libs/currency/math/internal}/loader/FileTableLoader.kt (81%) create mode 100644 libs/currency-math/src/commonMain/kotlin/com/flipcash/libs/currency/math/internal/loader/TableByteLoader.kt create mode 100644 libs/currency-math/src/jvmMain/kotlin/com/flipcash/libs/currency/math/Curves.jvm.kt create mode 100644 libs/currency-math/src/jvmMain/kotlin/com/flipcash/libs/currency/math/internal/loader/ClasspathTableLoader.kt delete mode 100644 libs/currency-math/src/testFixtures/kotlin/com/flipcash/libs/currency/math/CurveTestInitializer.kt create mode 100644 libs/currency-math/test-fixtures/build.gradle.kts create mode 100644 libs/currency-math/test-fixtures/src/commonMain/kotlin/com/flipcash/libs/currency/math/CurveTestInitializer.kt rename libs/datetime/src/{test => androidHostTest}/kotlin/com/getcode/util/DateUtilsTest.kt (100%) rename libs/datetime/src/{test => androidHostTest}/kotlin/com/getcode/util/InstantExtensionsTest.kt (100%) rename libs/datetime/src/{main => androidMain}/kotlin/com/getcode/util/DateUtils.kt (100%) rename libs/datetime/src/{main => commonMain}/kotlin/com/getcode/util/Instant.kt (100%) rename libs/encryption/keys/src/{test => androidHostTest}/kotlin/com/getcode/solana/keys/AccountMetaTest.kt (100%) rename libs/encryption/keys/src/{test => androidHostTest}/kotlin/com/getcode/solana/keys/KeyInitOrderTest.kt (100%) rename libs/encryption/keys/src/{test => androidHostTest}/kotlin/com/getcode/solana/keys/KeyTest.kt (100%) rename libs/encryption/keys/src/{test => androidHostTest}/kotlin/com/getcode/solana/keys/MintTest.kt (100%) rename libs/encryption/keys/src/{test => androidHostTest}/kotlin/com/getcode/solana/keys/PublicKeyTest.kt (100%) rename libs/encryption/keys/src/{test => androidHostTest}/kotlin/com/getcode/utils/serializer/SerializerTest.kt (100%) rename libs/encryption/keys/src/{main => commonMain}/kotlin/com/getcode/solana/keys/AccountMeta.kt (100%) rename libs/encryption/keys/src/{main => commonMain}/kotlin/com/getcode/solana/keys/Key.kt (100%) rename libs/encryption/keys/src/{main => commonMain}/kotlin/com/getcode/solana/keys/MerkleProof.kt (100%) rename libs/encryption/keys/src/{main => commonMain}/kotlin/com/getcode/solana/keys/Mint.kt (63%) rename libs/encryption/keys/src/{main => commonMain}/kotlin/com/getcode/solana/keys/PublicKey.kt (83%) rename libs/encryption/keys/src/{main => commonMain}/kotlin/com/getcode/solana/keys/Types.kt (100%) rename libs/encryption/keys/src/{main => commonMain}/kotlin/com/getcode/utils/serializer/ByteListSerializer.kt (76%) rename libs/encryption/keys/src/{main => commonMain}/kotlin/com/getcode/utils/serializer/MintSerializer.kt (100%) rename libs/encryption/keys/src/{main => commonMain}/kotlin/com/getcode/utils/serializer/PublicKeySerializer.kt (100%) create mode 100644 libs/encryption/utils/src/androidMain/kotlin/com/getcode/utils/Base64.android.kt create mode 100644 libs/encryption/utils/src/androidMain/kotlin/com/getcode/utils/Ed25519Extensions.android.kt delete mode 100644 libs/encryption/utils/src/androidMain/kotlin/com/getcode/utils/Extensions.android.kt create mode 100644 libs/encryption/utils/src/jvmMain/kotlin/com/getcode/utils/Base64.jvm.kt create mode 100644 libs/encryption/utils/src/jvmSharedMain/kotlin/com/getcode/utils/Extensions.jvmShared.kt rename libs/messaging/src/{main => androidMain}/kotlin/com/getcode/manager/BottomBarManager.kt (100%) rename libs/messaging/src/{main => commonMain}/kotlin/com/getcode/manager/TopBarManager.kt (100%) rename libs/network/jwt/src/{main => commonMain}/kotlin/com/getcode/network/jwt/JwtProvider.kt (100%) rename libs/network/jwt/src/{main => commonMain}/kotlin/com/getcode/network/jwt/JwtSecuredEndpoint.kt (100%) create mode 100644 libs/parcelable/build.gradle.kts create mode 100644 libs/parcelable/src/androidHostTest/kotlin/com/getcode/libs/parcelable/ParcelizeTest.kt create mode 100644 libs/parcelable/src/androidMain/kotlin/com/getcode/libs/parcelable/Parcelable.android.kt create mode 100644 libs/parcelable/src/commonMain/kotlin/com/getcode/libs/parcelable/Parcelable.kt create mode 100644 libs/parcelable/src/jvmMain/kotlin/com/getcode/libs/parcelable/Parcelable.jvm.kt diff --git a/apps/flipcash/app/src/main/kotlin/com/flipcash/app/internal/startup/DiscreteBondingCurveInitializer.kt b/apps/flipcash/app/src/main/kotlin/com/flipcash/app/internal/startup/DiscreteBondingCurveInitializer.kt index f030a36544..a7dbe4dc64 100644 --- a/apps/flipcash/app/src/main/kotlin/com/flipcash/app/internal/startup/DiscreteBondingCurveInitializer.kt +++ b/apps/flipcash/app/src/main/kotlin/com/flipcash/app/internal/startup/DiscreteBondingCurveInitializer.kt @@ -3,6 +3,7 @@ package com.flipcash.app.internal.startup import android.content.Context import androidx.startup.Initializer import com.flipcash.libs.currency.math.Curves +import com.flipcash.libs.currency.math.initialize /** * Preloads the discrete bonding curve tables. diff --git a/apps/flipcash/shared/tokens/build.gradle.kts b/apps/flipcash/shared/tokens/build.gradle.kts index 9f65fd8f5f..0c9906a86b 100644 --- a/apps/flipcash/shared/tokens/build.gradle.kts +++ b/apps/flipcash/shared/tokens/build.gradle.kts @@ -10,7 +10,7 @@ dependencies { testImplementation(kotlin("test")) testImplementation(libs.bundles.unit.testing) testImplementation(testFixtures(project(":ui:resources"))) - testImplementation(testFixtures(project(":libs:currency-math"))) + testImplementation(project(":libs:currency-math:test-fixtures")) testImplementation(libs.mockito.kotlin) api(project(":apps:flipcash:shared:tokens:core")) diff --git a/build-logic/convention/src/main/kotlin/KmpAppLibraryConventionPlugin.kt b/build-logic/convention/src/main/kotlin/KmpAppLibraryConventionPlugin.kt index dd47da8950..f73a5d2110 100644 --- a/build-logic/convention/src/main/kotlin/KmpAppLibraryConventionPlugin.kt +++ b/build-logic/convention/src/main/kotlin/KmpAppLibraryConventionPlugin.kt @@ -23,6 +23,8 @@ import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension * - `org.jetbrains.kotlin.multiplatform` * - `com.android.kotlin.multiplatform.library` * - `org.jetbrains.kotlin.plugin.serialization` + * - `org.jetbrains.kotlin.plugin.parcelize` -- generates Android parcel code for classes marked + * with `com.getcode.libs.parcelable.Parcelize`, the common stand-in in `:libs:parcelable` * * and declares: * - `android` -- compileSdk and minSdk from the version catalog, host tests enabled with the same @@ -52,6 +54,7 @@ class KmpAppLibraryConventionPlugin : Plugin { apply("org.jetbrains.kotlin.multiplatform") apply("com.android.kotlin.multiplatform.library") apply("org.jetbrains.kotlin.plugin.serialization") + apply("org.jetbrains.kotlin.plugin.parcelize") } val libs = extensions.getByType().named("libs") @@ -91,9 +94,14 @@ class KmpAppLibraryConventionPlugin : Plugin { optIn.addAll( "kotlin.time.ExperimentalTime", "kotlin.ExperimentalUnsignedTypes", - "kotlin.RequiresOptIn" + "kotlin.RequiresOptIn", + "kotlin.ExperimentalMultiplatform" + ) + freeCompilerArgs.addAll( + "-Xexpect-actual-classes", + "-P", + "plugin:org.jetbrains.kotlin.parcelize:additionalAnnotation=com.getcode.libs.parcelable.Parcelize" ) - freeCompilerArgs.add("-Xexpect-actual-classes") } sourceSets.named("commonMain") { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 55493d0055..1b6dc7816c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -45,6 +45,7 @@ compose-coil = "3.6.3" hilt = "2.59.2" hilt-jetpack = "1.4.0" +compose-multiplatform = "1.12.1" okhttp = "5.5.0" retrofit = "3.0.0" kin-sdk = "2.1.2" @@ -170,6 +171,9 @@ coil3-network = { module = "io.coil-kt.coil3:coil-network-okhttp", version.ref = # Hilt hilt-android = { module = "com.google.dagger:hilt-android", version.ref = "hilt" } +# Plain JVM jars: @Module/@Provides/@Binds and @InstallIn/SingletonComponent compile in a KMP commonMain. +dagger = { module = "com.google.dagger:dagger", version.ref = "hilt" } +hilt-core = { module = "com.google.dagger:hilt-core", version.ref = "hilt" } hilt-worker = { module = "androidx.hilt:hilt-work", version.ref = "hilt-jetpack" } hilt-android-compiler = { module = "com.google.dagger:hilt-android-compiler", version.ref = "hilt" } hilt-compiler = { module = "androidx.hilt:hilt-compiler", version.ref = "hilt-jetpack" } @@ -330,10 +334,16 @@ androidx-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-toolin androidx-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling", version.ref = "uiTooling" } androidx-foundation-layout = { group = "androidx.compose.foundation", name = "foundation-layout", version.ref = "foundationLayout" } +jetbrains-compose-runtime = { module = "org.jetbrains.compose.runtime:runtime", version.ref = "compose-multiplatform" } +# On Android these resolve to the androidx artifacts at the version the Compose BOM pins. +jetbrains-compose-foundation = { module = "org.jetbrains.compose.foundation:foundation", version.ref = "compose-multiplatform" } +jetbrains-compose-ui = { module = "org.jetbrains.compose.ui:ui", version.ref = "compose-multiplatform" } + [bundles] compose = ["compose-ui", "compose-foundation", "compose-material", "compose-material-icons-extended", "compose-animation", "compose-activities"] hilt = ["hilt-android", "javax-inject"] hilt-compiler = ["hilt-android-compiler", "hilt-compiler"] +hilt-common = ["javax-inject", "dagger", "hilt-core"] haze = ["haze", "haze-blur", "haze-materials"] room = ["androidx-room-runtime", "androidx-room-ktx", "androidx-room-paging"] firebase = ["firebase-messaging", "firebase-installations"] diff --git a/libs/currency-math/build.gradle.kts b/libs/currency-math/build.gradle.kts index 83886bf25b..89c2dc44ea 100644 --- a/libs/currency-math/build.gradle.kts +++ b/libs/currency-math/build.gradle.kts @@ -1,32 +1,45 @@ plugins { - alias(libs.plugins.flipcash.android.library) - id("com.google.devtools.ksp") - id("org.jetbrains.kotlin.plugin.parcelize") + alias(libs.plugins.flipcash.kmp.app.library) } -android { - namespace = "${Gradle.codeNamespace}.libs.currency.math" - testFixtures { - enable = true +kotlin { + android { + namespace = "${Gradle.codeNamespace}.libs.currency.math" + withDeviceTestBuilder {}.configure { + instrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + } } -} - -dependencies { - androidTestImplementation(libs.androidx.junit) - androidTestImplementation(libs.junit) - androidTestImplementation(libs.androidx.test.runner) - - implementation(libs.bundles.hilt) - implementation(project(":libs:currency-math:discrete-curve")) - testFixturesImplementation(libs.kotlinx.coroutines.core) - - testImplementation(kotlin("test")) + sourceSets { + commonMain.dependencies { + implementation(libs.javax.inject) + implementation(project(":libs:currency-math:discrete-curve")) + } + androidMain.dependencies { + implementation(libs.bundles.hilt) + } + // The desktop build ships the same table files Android packs as assets. + jvmMain { + resources.srcDir("src/androidMain/assets") + } + getByName("androidHostTest").dependencies { + implementation(kotlin("test")) + implementation(project(":libs:currency-math:test-fixtures")) + } + getByName("androidDeviceTest").dependencies { + implementation(libs.androidx.junit) + implementation(libs.junit) + implementation(libs.androidx.test.runner) + } + jvmTest.dependencies { + implementation(kotlin("test")) + } + } } val generateCurveTables by tasks.registering(GenerateCurveTables::class) { rustTableUrl.set("https://raw.githubusercontent.com/code-payments/flipcash-program/refs/heads/main/api/src/table.rs") - outputDir.set(layout.projectDirectory.dir("src/main/assets")) + outputDir.set(layout.projectDirectory.dir("src/androidMain/assets")) forceViaGradleProperty.set(providers.gradleProperty("forceCurveTables").map { true }.orElse(false)) // Always regenerate (useful for CI or development) @@ -34,7 +47,8 @@ val generateCurveTables by tasks.registering(GenerateCurveTables::class) { // forceRegenerate.set(true) } -// Make sure tables are generated before assets are merged -tasks.named("preBuild") { +// Make sure tables are generated before either platform packs them. The KMP android target has no +// preBuild task, so hook the compilations instead. +tasks.matching { it.name == "compileAndroidMain" || it.name == "jvmProcessResources" }.configureEach { dependsOn(generateCurveTables) } diff --git a/libs/currency-math/src/androidTest/assets/curve.json b/libs/currency-math/src/androidDeviceTest/assets/curve.json similarity index 100% rename from libs/currency-math/src/androidTest/assets/curve.json rename to libs/currency-math/src/androidDeviceTest/assets/curve.json diff --git a/libs/currency-math/src/androidTest/assets/curve_fractional.json b/libs/currency-math/src/androidDeviceTest/assets/curve_fractional.json similarity index 100% rename from libs/currency-math/src/androidTest/assets/curve_fractional.json rename to libs/currency-math/src/androidDeviceTest/assets/curve_fractional.json diff --git a/libs/currency-math/src/androidTest/java/com/flipcash/libs/currency/math/internal/curves/DiscreteBondingCurveVectorTest.kt b/libs/currency-math/src/androidDeviceTest/kotlin/com/flipcash/libs/currency/math/internal/curves/DiscreteBondingCurveVectorTest.kt similarity index 100% rename from libs/currency-math/src/androidTest/java/com/flipcash/libs/currency/math/internal/curves/DiscreteBondingCurveVectorTest.kt rename to libs/currency-math/src/androidDeviceTest/kotlin/com/flipcash/libs/currency/math/internal/curves/DiscreteBondingCurveVectorTest.kt diff --git a/libs/currency-math/src/test/java/com/flipcash/libs/currency/math/ContinuousBondingCurveTests.kt b/libs/currency-math/src/androidHostTest/kotlin/com/flipcash/libs/currency/math/ContinuousBondingCurveTests.kt similarity index 100% rename from libs/currency-math/src/test/java/com/flipcash/libs/currency/math/ContinuousBondingCurveTests.kt rename to libs/currency-math/src/androidHostTest/kotlin/com/flipcash/libs/currency/math/ContinuousBondingCurveTests.kt diff --git a/libs/currency-math/src/test/java/com/flipcash/libs/currency/math/DiscreteBondingCurveTests.kt b/libs/currency-math/src/androidHostTest/kotlin/com/flipcash/libs/currency/math/DiscreteBondingCurveTests.kt similarity index 100% rename from libs/currency-math/src/test/java/com/flipcash/libs/currency/math/DiscreteBondingCurveTests.kt rename to libs/currency-math/src/androidHostTest/kotlin/com/flipcash/libs/currency/math/DiscreteBondingCurveTests.kt diff --git a/libs/currency-math/src/test/java/com/flipcash/libs/currency/math/EstimationTests.kt b/libs/currency-math/src/androidHostTest/kotlin/com/flipcash/libs/currency/math/EstimationTests.kt similarity index 100% rename from libs/currency-math/src/test/java/com/flipcash/libs/currency/math/EstimationTests.kt rename to libs/currency-math/src/androidHostTest/kotlin/com/flipcash/libs/currency/math/EstimationTests.kt diff --git a/libs/currency-math/src/test/java/com/flipcash/libs/currency/math/EstimatorValueExchangeTests.kt b/libs/currency-math/src/androidHostTest/kotlin/com/flipcash/libs/currency/math/EstimatorValueExchangeTests.kt similarity index 100% rename from libs/currency-math/src/test/java/com/flipcash/libs/currency/math/EstimatorValueExchangeTests.kt rename to libs/currency-math/src/androidHostTest/kotlin/com/flipcash/libs/currency/math/EstimatorValueExchangeTests.kt diff --git a/libs/currency-math/src/test/java/com/flipcash/libs/currency/math/Expects.kt b/libs/currency-math/src/androidHostTest/kotlin/com/flipcash/libs/currency/math/Expects.kt similarity index 100% rename from libs/currency-math/src/test/java/com/flipcash/libs/currency/math/Expects.kt rename to libs/currency-math/src/androidHostTest/kotlin/com/flipcash/libs/currency/math/Expects.kt diff --git a/libs/currency-math/src/test/java/com/flipcash/libs/currency/math/loader/ClasspathTableLoader.kt b/libs/currency-math/src/androidHostTest/kotlin/com/flipcash/libs/currency/math/loader/ClasspathTableLoader.kt similarity index 100% rename from libs/currency-math/src/test/java/com/flipcash/libs/currency/math/loader/ClasspathTableLoader.kt rename to libs/currency-math/src/androidHostTest/kotlin/com/flipcash/libs/currency/math/loader/ClasspathTableLoader.kt diff --git a/libs/currency-math/src/main/assets/discrete_cumulative_table.bin b/libs/currency-math/src/androidMain/assets/discrete_cumulative_table.bin similarity index 100% rename from libs/currency-math/src/main/assets/discrete_cumulative_table.bin rename to libs/currency-math/src/androidMain/assets/discrete_cumulative_table.bin diff --git a/libs/currency-math/src/main/assets/discrete_pricing_table.bin b/libs/currency-math/src/androidMain/assets/discrete_pricing_table.bin similarity index 100% rename from libs/currency-math/src/main/assets/discrete_pricing_table.bin rename to libs/currency-math/src/androidMain/assets/discrete_pricing_table.bin diff --git a/libs/currency-math/src/androidMain/kotlin/com/flipcash/libs/currency/math/Curves.android.kt b/libs/currency-math/src/androidMain/kotlin/com/flipcash/libs/currency/math/Curves.android.kt new file mode 100644 index 0000000000..2315d289b2 --- /dev/null +++ b/libs/currency-math/src/androidMain/kotlin/com/flipcash/libs/currency/math/Curves.android.kt @@ -0,0 +1,6 @@ +package com.flipcash.libs.currency.math + +import android.content.Context +import com.flipcash.libs.currency.math.internal.loader.AndroidTableLoader + +suspend fun Curves.initialize(context: Context) = initialize(AndroidTableLoader(context)) diff --git a/libs/currency-math/src/main/kotlin/com/flipcash/libs/currency/math/internal/loader/AndroidTableLoader.kt b/libs/currency-math/src/androidMain/kotlin/com/flipcash/libs/currency/math/internal/loader/AndroidTableLoader.kt similarity index 89% rename from libs/currency-math/src/main/kotlin/com/flipcash/libs/currency/math/internal/loader/AndroidTableLoader.kt rename to libs/currency-math/src/androidMain/kotlin/com/flipcash/libs/currency/math/internal/loader/AndroidTableLoader.kt index 008ed618dd..cf1f4665fb 100644 --- a/libs/currency-math/src/main/kotlin/com/flipcash/libs/currency/math/internal/loader/AndroidTableLoader.kt +++ b/libs/currency-math/src/androidMain/kotlin/com/flipcash/libs/currency/math/internal/loader/AndroidTableLoader.kt @@ -10,10 +10,6 @@ import kotlinx.coroutines.withContext * [AndroidTableLoader]) so the JVM-only unit test suite -- which has no Android [Context] -- can * satisfy the same initialization path via `FileTableLoader`/`ClasspathTableLoader`. */ -internal interface TableByteLoader { - suspend fun loadTableBytes(name: String): ByteArray -} - internal class AndroidTableLoader(private val context: Context) : TableByteLoader { override suspend fun loadTableBytes(name: String): ByteArray = withContext(Dispatchers.IO) { context.assets.open("$name.bin").use { it.readBytes() } diff --git a/libs/currency-math/src/main/kotlin/com/flipcash/libs/currency/math/Curves.kt b/libs/currency-math/src/commonMain/kotlin/com/flipcash/libs/currency/math/Curves.kt similarity index 71% rename from libs/currency-math/src/main/kotlin/com/flipcash/libs/currency/math/Curves.kt rename to libs/currency-math/src/commonMain/kotlin/com/flipcash/libs/currency/math/Curves.kt index 725543ff15..a95bdcc871 100644 --- a/libs/currency-math/src/main/kotlin/com/flipcash/libs/currency/math/Curves.kt +++ b/libs/currency-math/src/commonMain/kotlin/com/flipcash/libs/currency/math/Curves.kt @@ -1,9 +1,9 @@ package com.flipcash.libs.currency.math -import android.content.Context import com.flipcash.libs.currency.math.internal.DefaultMintMaxTokenSupply import com.flipcash.libs.currency.math.internal.curves.DiscreteBondingCurve -import com.flipcash.libs.currency.math.internal.loader.AndroidTableLoader +import com.flipcash.libs.currency.math.internal.loader.FileTableLoader +import com.flipcash.libs.currency.math.internal.loader.TableByteLoader import java.math.BigDecimal import java.math.MathContext import java.math.RoundingMode @@ -40,10 +40,16 @@ interface BondingCurve { fun formattedTable(): String } +/** + * Loads the discrete curve's tables. Each platform adds its own `initialize` overload that picks the + * table source: the APK's assets on Android, the classpath on the desktop JVM. + */ object Curves { - suspend fun initialize(context: Context) { + internal suspend fun initialize(tableLoader: TableByteLoader) { // only discrete needs to be initialized - val tableLoader = AndroidTableLoader(context) DiscreteBondingCurve.initialize(tableLoader) } + + /** For host tests: reads the tables from this repo's source tree, found by walking up from the working directory. */ + suspend fun initializeFromSourceTree() = initialize(FileTableLoader()) } \ No newline at end of file diff --git a/libs/currency-math/src/main/kotlin/com/flipcash/libs/currency/math/Estimator.kt b/libs/currency-math/src/commonMain/kotlin/com/flipcash/libs/currency/math/Estimator.kt similarity index 100% rename from libs/currency-math/src/main/kotlin/com/flipcash/libs/currency/math/Estimator.kt rename to libs/currency-math/src/commonMain/kotlin/com/flipcash/libs/currency/math/Estimator.kt diff --git a/libs/currency-math/src/main/kotlin/com/flipcash/libs/currency/math/Units.kt b/libs/currency-math/src/commonMain/kotlin/com/flipcash/libs/currency/math/Units.kt similarity index 100% rename from libs/currency-math/src/main/kotlin/com/flipcash/libs/currency/math/Units.kt rename to libs/currency-math/src/commonMain/kotlin/com/flipcash/libs/currency/math/Units.kt diff --git a/libs/currency-math/src/main/kotlin/com/flipcash/libs/currency/math/internal/BigDecimal.kt b/libs/currency-math/src/commonMain/kotlin/com/flipcash/libs/currency/math/internal/BigDecimal.kt similarity index 100% rename from libs/currency-math/src/main/kotlin/com/flipcash/libs/currency/math/internal/BigDecimal.kt rename to libs/currency-math/src/commonMain/kotlin/com/flipcash/libs/currency/math/internal/BigDecimal.kt diff --git a/libs/currency-math/src/main/kotlin/com/flipcash/libs/currency/math/internal/Constants.kt b/libs/currency-math/src/commonMain/kotlin/com/flipcash/libs/currency/math/internal/Constants.kt similarity index 100% rename from libs/currency-math/src/main/kotlin/com/flipcash/libs/currency/math/internal/Constants.kt rename to libs/currency-math/src/commonMain/kotlin/com/flipcash/libs/currency/math/internal/Constants.kt diff --git a/libs/currency-math/src/main/kotlin/com/flipcash/libs/currency/math/internal/curves/ContinuousBondingCurve.kt b/libs/currency-math/src/commonMain/kotlin/com/flipcash/libs/currency/math/internal/curves/ContinuousBondingCurve.kt similarity index 99% rename from libs/currency-math/src/main/kotlin/com/flipcash/libs/currency/math/internal/curves/ContinuousBondingCurve.kt rename to libs/currency-math/src/commonMain/kotlin/com/flipcash/libs/currency/math/internal/curves/ContinuousBondingCurve.kt index f6f1b81754..75cd85dce0 100644 --- a/libs/currency-math/src/main/kotlin/com/flipcash/libs/currency/math/internal/curves/ContinuousBondingCurve.kt +++ b/libs/currency-math/src/commonMain/kotlin/com/flipcash/libs/currency/math/internal/curves/ContinuousBondingCurve.kt @@ -1,6 +1,5 @@ package com.flipcash.libs.currency.math.internal.curves -import android.annotation.SuppressLint import com.flipcash.libs.currency.math.BondingCurve import com.flipcash.libs.currency.math.Valuation import com.flipcash.libs.currency.math.formatter @@ -14,7 +13,6 @@ private val CURVE_A = BigDecimal("11400.230149967394933471") private val CURVE_B = BigDecimal("0.000000877175273521") private val CURVE_C = CURVE_B -@SuppressLint("VisibleForTests") internal class ContinuousBondingCurve( val a: BigDecimal, val b: BigDecimal, diff --git a/libs/currency-math/src/main/kotlin/com/flipcash/libs/currency/math/internal/curves/DiscreteBondingCurve.kt b/libs/currency-math/src/commonMain/kotlin/com/flipcash/libs/currency/math/internal/curves/DiscreteBondingCurve.kt similarity index 100% rename from libs/currency-math/src/main/kotlin/com/flipcash/libs/currency/math/internal/curves/DiscreteBondingCurve.kt rename to libs/currency-math/src/commonMain/kotlin/com/flipcash/libs/currency/math/internal/curves/DiscreteBondingCurve.kt diff --git a/libs/currency-math/src/testFixtures/kotlin/com/flipcash/libs/currency/math/loader/FileTableLoader.kt b/libs/currency-math/src/commonMain/kotlin/com/flipcash/libs/currency/math/internal/loader/FileTableLoader.kt similarity index 81% rename from libs/currency-math/src/testFixtures/kotlin/com/flipcash/libs/currency/math/loader/FileTableLoader.kt rename to libs/currency-math/src/commonMain/kotlin/com/flipcash/libs/currency/math/internal/loader/FileTableLoader.kt index c62f05d9c6..7d27d8cbef 100644 --- a/libs/currency-math/src/testFixtures/kotlin/com/flipcash/libs/currency/math/loader/FileTableLoader.kt +++ b/libs/currency-math/src/commonMain/kotlin/com/flipcash/libs/currency/math/internal/loader/FileTableLoader.kt @@ -1,16 +1,15 @@ -package com.flipcash.libs.currency.math.loader +package com.flipcash.libs.currency.math.internal.loader -import com.flipcash.libs.currency.math.internal.loader.TableByteLoader import java.io.File -class FileTableLoader(private val assetsDir: File) : TableByteLoader { +internal class FileTableLoader(private val assetsDir: File) : TableByteLoader { constructor() : this(resolveAssetsDir()) companion object { private fun resolveAssetsDir(): File { val projectRoot = findProjectRoot() - return File(projectRoot, "libs/currency-math/src/main/assets") + return File(projectRoot, "libs/currency-math/src/androidMain/assets") } private fun findProjectRoot(): File { diff --git a/libs/currency-math/src/commonMain/kotlin/com/flipcash/libs/currency/math/internal/loader/TableByteLoader.kt b/libs/currency-math/src/commonMain/kotlin/com/flipcash/libs/currency/math/internal/loader/TableByteLoader.kt new file mode 100644 index 0000000000..16e1c043e1 --- /dev/null +++ b/libs/currency-math/src/commonMain/kotlin/com/flipcash/libs/currency/math/internal/loader/TableByteLoader.kt @@ -0,0 +1,5 @@ +package com.flipcash.libs.currency.math.internal.loader + +internal interface TableByteLoader { + suspend fun loadTableBytes(name: String): ByteArray +} diff --git a/libs/currency-math/src/jvmMain/kotlin/com/flipcash/libs/currency/math/Curves.jvm.kt b/libs/currency-math/src/jvmMain/kotlin/com/flipcash/libs/currency/math/Curves.jvm.kt new file mode 100644 index 0000000000..4fb1c18631 --- /dev/null +++ b/libs/currency-math/src/jvmMain/kotlin/com/flipcash/libs/currency/math/Curves.jvm.kt @@ -0,0 +1,6 @@ +package com.flipcash.libs.currency.math + +import com.flipcash.libs.currency.math.internal.loader.ClasspathTableLoader + +/** Reads the tables the desktop build packs as JVM resources (the same files Android ships as assets). */ +suspend fun Curves.initialize() = initialize(ClasspathTableLoader()) diff --git a/libs/currency-math/src/jvmMain/kotlin/com/flipcash/libs/currency/math/internal/loader/ClasspathTableLoader.kt b/libs/currency-math/src/jvmMain/kotlin/com/flipcash/libs/currency/math/internal/loader/ClasspathTableLoader.kt new file mode 100644 index 0000000000..7c18f3f1ad --- /dev/null +++ b/libs/currency-math/src/jvmMain/kotlin/com/flipcash/libs/currency/math/internal/loader/ClasspathTableLoader.kt @@ -0,0 +1,12 @@ +package com.flipcash.libs.currency.math.internal.loader + +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext + +internal class ClasspathTableLoader : TableByteLoader { + override suspend fun loadTableBytes(name: String): ByteArray = withContext(Dispatchers.IO) { + val stream = ClasspathTableLoader::class.java.getResourceAsStream("/$name.bin") + ?: error("Missing curve table $name.bin on the classpath") + stream.use { it.readBytes() } + } +} diff --git a/libs/currency-math/src/testFixtures/kotlin/com/flipcash/libs/currency/math/CurveTestInitializer.kt b/libs/currency-math/src/testFixtures/kotlin/com/flipcash/libs/currency/math/CurveTestInitializer.kt deleted file mode 100644 index 6a23027ed6..0000000000 --- a/libs/currency-math/src/testFixtures/kotlin/com/flipcash/libs/currency/math/CurveTestInitializer.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.flipcash.libs.currency.math - -import com.flipcash.libs.currency.math.internal.curves.DiscreteBondingCurve -import com.flipcash.libs.currency.math.loader.FileTableLoader -import kotlinx.coroutines.runBlocking - -object CurveTestInitializer { - fun initialize() { - runBlocking { DiscreteBondingCurve.initialize(FileTableLoader()) } - } -} diff --git a/libs/currency-math/test-fixtures/build.gradle.kts b/libs/currency-math/test-fixtures/build.gradle.kts new file mode 100644 index 0000000000..ba32e5c763 --- /dev/null +++ b/libs/currency-math/test-fixtures/build.gradle.kts @@ -0,0 +1,15 @@ +plugins { + alias(libs.plugins.flipcash.kmp.app.library) +} + +kotlin { + android { + namespace = "${Gradle.codeNamespace}.libs.currency.math.testfixtures" + } + + sourceSets { + commonMain.dependencies { + api(project(":libs:currency-math")) + } + } +} diff --git a/libs/currency-math/test-fixtures/src/commonMain/kotlin/com/flipcash/libs/currency/math/CurveTestInitializer.kt b/libs/currency-math/test-fixtures/src/commonMain/kotlin/com/flipcash/libs/currency/math/CurveTestInitializer.kt new file mode 100644 index 0000000000..1a64c18ef3 --- /dev/null +++ b/libs/currency-math/test-fixtures/src/commonMain/kotlin/com/flipcash/libs/currency/math/CurveTestInitializer.kt @@ -0,0 +1,9 @@ +package com.flipcash.libs.currency.math + +import kotlinx.coroutines.runBlocking + +object CurveTestInitializer { + fun initialize() { + runBlocking { Curves.initializeFromSourceTree() } + } +} diff --git a/libs/datetime/build.gradle.kts b/libs/datetime/build.gradle.kts index b5b2253720..74235dd8d5 100644 --- a/libs/datetime/build.gradle.kts +++ b/libs/datetime/build.gradle.kts @@ -1,14 +1,24 @@ plugins { - alias(libs.plugins.flipcash.android.library.compose) + alias(libs.plugins.flipcash.kmp.app.library) + alias(libs.plugins.compose.compiler) } -android { - namespace = "${Gradle.codeNamespace}.util.datetime" -} - -dependencies { - api(libs.kotlinx.datetime) +kotlin { + android { + namespace = "${Gradle.codeNamespace}.util.datetime" + } - testImplementation(kotlin("test")) - testImplementation(libs.robolectric) + sourceSets { + commonMain.dependencies { + api(libs.kotlinx.datetime) + implementation(libs.jetbrains.compose.runtime) + } + androidMain.dependencies { + implementation(libs.jetbrains.compose.ui) + } + getByName("androidHostTest").dependencies { + implementation(kotlin("test")) + implementation(libs.robolectric) + } + } } diff --git a/libs/datetime/src/test/kotlin/com/getcode/util/DateUtilsTest.kt b/libs/datetime/src/androidHostTest/kotlin/com/getcode/util/DateUtilsTest.kt similarity index 100% rename from libs/datetime/src/test/kotlin/com/getcode/util/DateUtilsTest.kt rename to libs/datetime/src/androidHostTest/kotlin/com/getcode/util/DateUtilsTest.kt diff --git a/libs/datetime/src/test/kotlin/com/getcode/util/InstantExtensionsTest.kt b/libs/datetime/src/androidHostTest/kotlin/com/getcode/util/InstantExtensionsTest.kt similarity index 100% rename from libs/datetime/src/test/kotlin/com/getcode/util/InstantExtensionsTest.kt rename to libs/datetime/src/androidHostTest/kotlin/com/getcode/util/InstantExtensionsTest.kt diff --git a/libs/datetime/src/main/kotlin/com/getcode/util/DateUtils.kt b/libs/datetime/src/androidMain/kotlin/com/getcode/util/DateUtils.kt similarity index 100% rename from libs/datetime/src/main/kotlin/com/getcode/util/DateUtils.kt rename to libs/datetime/src/androidMain/kotlin/com/getcode/util/DateUtils.kt diff --git a/libs/datetime/src/main/kotlin/com/getcode/util/Instant.kt b/libs/datetime/src/commonMain/kotlin/com/getcode/util/Instant.kt similarity index 100% rename from libs/datetime/src/main/kotlin/com/getcode/util/Instant.kt rename to libs/datetime/src/commonMain/kotlin/com/getcode/util/Instant.kt diff --git a/libs/encryption/keys/build.gradle.kts b/libs/encryption/keys/build.gradle.kts index 4e4c81f68c..a45f13b8e3 100644 --- a/libs/encryption/keys/build.gradle.kts +++ b/libs/encryption/keys/build.gradle.kts @@ -1,21 +1,27 @@ plugins { - alias(libs.plugins.flipcash.android.library) + alias(libs.plugins.flipcash.kmp.app.library) } -android { - namespace = "${Gradle.codeNamespace}.encryption.keys" -} - -dependencies { - implementation(project(":libs:encryption:base58")) - implementation(project(":libs:encryption:sha256")) - implementation(project(":libs:encryption:utils")) +kotlin { + android { + namespace = "${Gradle.codeNamespace}.encryption.keys" + } - implementation(libs.protobuf.kotlin.lite) - implementation(libs.grpc.okhttp) - implementation(libs.grpc.kotlin) - implementation(libs.bundles.kotlinx.serialization) + sourceSets { + commonMain.dependencies { + implementation(project(":libs:encryption:base58")) + implementation(project(":libs:encryption:sha256")) + implementation(project(":libs:encryption:utils")) + implementation(project(":libs:parcelable")) - testImplementation(kotlin("test")) - testImplementation(libs.robolectric) + implementation(libs.protobuf.kotlin.lite) + implementation(libs.grpc.okhttp) + implementation(libs.grpc.kotlin) + implementation(libs.bundles.kotlinx.serialization) + } + getByName("androidHostTest").dependencies { + implementation(kotlin("test")) + implementation(libs.robolectric) + } + } } diff --git a/libs/encryption/keys/src/test/kotlin/com/getcode/solana/keys/AccountMetaTest.kt b/libs/encryption/keys/src/androidHostTest/kotlin/com/getcode/solana/keys/AccountMetaTest.kt similarity index 100% rename from libs/encryption/keys/src/test/kotlin/com/getcode/solana/keys/AccountMetaTest.kt rename to libs/encryption/keys/src/androidHostTest/kotlin/com/getcode/solana/keys/AccountMetaTest.kt diff --git a/libs/encryption/keys/src/test/kotlin/com/getcode/solana/keys/KeyInitOrderTest.kt b/libs/encryption/keys/src/androidHostTest/kotlin/com/getcode/solana/keys/KeyInitOrderTest.kt similarity index 100% rename from libs/encryption/keys/src/test/kotlin/com/getcode/solana/keys/KeyInitOrderTest.kt rename to libs/encryption/keys/src/androidHostTest/kotlin/com/getcode/solana/keys/KeyInitOrderTest.kt diff --git a/libs/encryption/keys/src/test/kotlin/com/getcode/solana/keys/KeyTest.kt b/libs/encryption/keys/src/androidHostTest/kotlin/com/getcode/solana/keys/KeyTest.kt similarity index 100% rename from libs/encryption/keys/src/test/kotlin/com/getcode/solana/keys/KeyTest.kt rename to libs/encryption/keys/src/androidHostTest/kotlin/com/getcode/solana/keys/KeyTest.kt diff --git a/libs/encryption/keys/src/test/kotlin/com/getcode/solana/keys/MintTest.kt b/libs/encryption/keys/src/androidHostTest/kotlin/com/getcode/solana/keys/MintTest.kt similarity index 100% rename from libs/encryption/keys/src/test/kotlin/com/getcode/solana/keys/MintTest.kt rename to libs/encryption/keys/src/androidHostTest/kotlin/com/getcode/solana/keys/MintTest.kt diff --git a/libs/encryption/keys/src/test/kotlin/com/getcode/solana/keys/PublicKeyTest.kt b/libs/encryption/keys/src/androidHostTest/kotlin/com/getcode/solana/keys/PublicKeyTest.kt similarity index 100% rename from libs/encryption/keys/src/test/kotlin/com/getcode/solana/keys/PublicKeyTest.kt rename to libs/encryption/keys/src/androidHostTest/kotlin/com/getcode/solana/keys/PublicKeyTest.kt diff --git a/libs/encryption/keys/src/test/kotlin/com/getcode/utils/serializer/SerializerTest.kt b/libs/encryption/keys/src/androidHostTest/kotlin/com/getcode/utils/serializer/SerializerTest.kt similarity index 100% rename from libs/encryption/keys/src/test/kotlin/com/getcode/utils/serializer/SerializerTest.kt rename to libs/encryption/keys/src/androidHostTest/kotlin/com/getcode/utils/serializer/SerializerTest.kt diff --git a/libs/encryption/keys/src/main/kotlin/com/getcode/solana/keys/AccountMeta.kt b/libs/encryption/keys/src/commonMain/kotlin/com/getcode/solana/keys/AccountMeta.kt similarity index 100% rename from libs/encryption/keys/src/main/kotlin/com/getcode/solana/keys/AccountMeta.kt rename to libs/encryption/keys/src/commonMain/kotlin/com/getcode/solana/keys/AccountMeta.kt diff --git a/libs/encryption/keys/src/main/kotlin/com/getcode/solana/keys/Key.kt b/libs/encryption/keys/src/commonMain/kotlin/com/getcode/solana/keys/Key.kt similarity index 100% rename from libs/encryption/keys/src/main/kotlin/com/getcode/solana/keys/Key.kt rename to libs/encryption/keys/src/commonMain/kotlin/com/getcode/solana/keys/Key.kt diff --git a/libs/encryption/keys/src/main/kotlin/com/getcode/solana/keys/MerkleProof.kt b/libs/encryption/keys/src/commonMain/kotlin/com/getcode/solana/keys/MerkleProof.kt similarity index 100% rename from libs/encryption/keys/src/main/kotlin/com/getcode/solana/keys/MerkleProof.kt rename to libs/encryption/keys/src/commonMain/kotlin/com/getcode/solana/keys/MerkleProof.kt diff --git a/libs/encryption/keys/src/main/kotlin/com/getcode/solana/keys/Mint.kt b/libs/encryption/keys/src/commonMain/kotlin/com/getcode/solana/keys/Mint.kt similarity index 63% rename from libs/encryption/keys/src/main/kotlin/com/getcode/solana/keys/Mint.kt rename to libs/encryption/keys/src/commonMain/kotlin/com/getcode/solana/keys/Mint.kt index 5a4ee3532a..b28294443e 100644 --- a/libs/encryption/keys/src/main/kotlin/com/getcode/solana/keys/Mint.kt +++ b/libs/encryption/keys/src/commonMain/kotlin/com/getcode/solana/keys/Mint.kt @@ -1,7 +1,6 @@ package com.getcode.solana.keys -import android.os.Parcel -import android.os.Parcelable +import com.getcode.libs.parcelable.parcelableCreator import com.getcode.utils.serializer.MintAsStringSerializer import com.getcode.vendor.Base58 import kotlinx.serialization.Serializable @@ -12,11 +11,7 @@ class Mint(bytes: List): PublicKey(bytes) { companion object { @JvmField - val CREATOR: Parcelable.Creator = - object : Parcelable.Creator { - override fun createFromParcel(parcel: Parcel) = Mint(parcel.readString().orEmpty()) - override fun newArray(size: Int) = arrayOfNulls(size) - } + val CREATOR: Any = parcelableCreator({ arrayOfNulls(it) }) { parcel -> Mint(parcel.readString().orEmpty()) } val usdc: Mint get() = Mint("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v") diff --git a/libs/encryption/keys/src/main/kotlin/com/getcode/solana/keys/PublicKey.kt b/libs/encryption/keys/src/commonMain/kotlin/com/getcode/solana/keys/PublicKey.kt similarity index 83% rename from libs/encryption/keys/src/main/kotlin/com/getcode/solana/keys/PublicKey.kt rename to libs/encryption/keys/src/commonMain/kotlin/com/getcode/solana/keys/PublicKey.kt index 8668741349..4aa214734d 100644 --- a/libs/encryption/keys/src/main/kotlin/com/getcode/solana/keys/PublicKey.kt +++ b/libs/encryption/keys/src/commonMain/kotlin/com/getcode/solana/keys/PublicKey.kt @@ -1,7 +1,8 @@ package com.getcode.solana.keys -import android.os.Parcel -import android.os.Parcelable +import com.getcode.libs.parcelable.Parcel +import com.getcode.libs.parcelable.Parcelable +import com.getcode.libs.parcelable.parcelableCreator import com.getcode.utils.serializer.PublicKeyAsStringSerializer import com.getcode.vendor.Base58 import com.google.protobuf.ByteString @@ -33,11 +34,7 @@ open class PublicKey(bytes: List) : Key32(bytes), Parcelable { val ZERO: PublicKey = PublicKey(ByteArray(LENGTH_32).toList()) @JvmField - val CREATOR: Parcelable.Creator = - object : Parcelable.Creator { - override fun createFromParcel(parcel: Parcel) = PublicKey(parcel) - override fun newArray(size: Int) = arrayOfNulls(size) - } + val CREATOR: Any = parcelableCreator({ arrayOfNulls(it) }) { parcel -> PublicKey(parcel) } } override fun equals(other: Any?): Boolean { diff --git a/libs/encryption/keys/src/main/kotlin/com/getcode/solana/keys/Types.kt b/libs/encryption/keys/src/commonMain/kotlin/com/getcode/solana/keys/Types.kt similarity index 100% rename from libs/encryption/keys/src/main/kotlin/com/getcode/solana/keys/Types.kt rename to libs/encryption/keys/src/commonMain/kotlin/com/getcode/solana/keys/Types.kt diff --git a/libs/encryption/keys/src/main/kotlin/com/getcode/utils/serializer/ByteListSerializer.kt b/libs/encryption/keys/src/commonMain/kotlin/com/getcode/utils/serializer/ByteListSerializer.kt similarity index 76% rename from libs/encryption/keys/src/main/kotlin/com/getcode/utils/serializer/ByteListSerializer.kt rename to libs/encryption/keys/src/commonMain/kotlin/com/getcode/utils/serializer/ByteListSerializer.kt index cca7ba75e3..ebd71a94b9 100644 --- a/libs/encryption/keys/src/main/kotlin/com/getcode/utils/serializer/ByteListSerializer.kt +++ b/libs/encryption/keys/src/commonMain/kotlin/com/getcode/utils/serializer/ByteListSerializer.kt @@ -1,6 +1,7 @@ package com.getcode.utils.serializer -import android.util.Base64 +import com.getcode.utils.decodeBase64 +import com.getcode.utils.encodeBase64 import kotlinx.serialization.KSerializer import kotlinx.serialization.descriptors.PrimitiveKind import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor @@ -12,10 +13,10 @@ object ByteListAsBase64Serializer : KSerializer> { override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("ByteList", PrimitiveKind.STRING) override fun serialize(encoder: Encoder, value: List) { - encoder.encodeString(Base64.encodeToString(value.toByteArray(), Base64.NO_WRAP)) + encoder.encodeString(value.toByteArray().encodeBase64()) } override fun deserialize(decoder: Decoder): List { - return Base64.decode(decoder.decodeString(), Base64.NO_WRAP).toList() + return decoder.decodeString().decodeBase64().toList() } } diff --git a/libs/encryption/keys/src/main/kotlin/com/getcode/utils/serializer/MintSerializer.kt b/libs/encryption/keys/src/commonMain/kotlin/com/getcode/utils/serializer/MintSerializer.kt similarity index 100% rename from libs/encryption/keys/src/main/kotlin/com/getcode/utils/serializer/MintSerializer.kt rename to libs/encryption/keys/src/commonMain/kotlin/com/getcode/utils/serializer/MintSerializer.kt diff --git a/libs/encryption/keys/src/main/kotlin/com/getcode/utils/serializer/PublicKeySerializer.kt b/libs/encryption/keys/src/commonMain/kotlin/com/getcode/utils/serializer/PublicKeySerializer.kt similarity index 100% rename from libs/encryption/keys/src/main/kotlin/com/getcode/utils/serializer/PublicKeySerializer.kt rename to libs/encryption/keys/src/commonMain/kotlin/com/getcode/utils/serializer/PublicKeySerializer.kt diff --git a/libs/encryption/utils/build.gradle.kts b/libs/encryption/utils/build.gradle.kts index 79e57d881d..41a6ca18d0 100644 --- a/libs/encryption/utils/build.gradle.kts +++ b/libs/encryption/utils/build.gradle.kts @@ -1,8 +1,21 @@ +import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType + plugins { alias(libs.plugins.flipcash.kmp.library) } +@OptIn(org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi::class) kotlin { + // jvmShared: code for both JVM targets (Android and desktop) that needs java.* or protobuf. + applyDefaultHierarchyTemplate { + common { + group("jvmShared") { + withJvm() + withCompilations { it.platformType == KotlinPlatformType.androidJvm } + } + } + } + android { namespace = "com.getcode.encryption.utils" withHostTest {} @@ -14,10 +27,14 @@ kotlin { implementation(project(":libs:encryption:base58")) } } + getByName("jvmSharedMain") { + dependencies { + implementation(libs.protobuf.kotlin.lite) + } + } androidMain { dependencies { implementation(project(":libs:encryption:ed25519")) - implementation(libs.protobuf.kotlin.lite) implementation(libs.bundles.kotlinx.serialization) implementation(libs.timber) } diff --git a/libs/encryption/utils/src/androidMain/kotlin/com/getcode/utils/Base64.android.kt b/libs/encryption/utils/src/androidMain/kotlin/com/getcode/utils/Base64.android.kt new file mode 100644 index 0000000000..790debf0d3 --- /dev/null +++ b/libs/encryption/utils/src/androidMain/kotlin/com/getcode/utils/Base64.android.kt @@ -0,0 +1,11 @@ +package com.getcode.utils + +import android.util.Base64 + +internal actual fun base64Encode(bytes: ByteArray, urlSafe: Boolean): ByteArray = + Base64.encode(bytes, flags(urlSafe)) + +internal actual fun base64Decode(bytes: ByteArray, urlSafe: Boolean): ByteArray = + Base64.decode(bytes, flags(urlSafe)) + +private fun flags(urlSafe: Boolean) = if (urlSafe) Base64.NO_WRAP or Base64.URL_SAFE else Base64.NO_WRAP diff --git a/libs/encryption/utils/src/androidMain/kotlin/com/getcode/utils/Ed25519Extensions.android.kt b/libs/encryption/utils/src/androidMain/kotlin/com/getcode/utils/Ed25519Extensions.android.kt new file mode 100644 index 0000000000..c5edb257bf --- /dev/null +++ b/libs/encryption/utils/src/androidMain/kotlin/com/getcode/utils/Ed25519Extensions.android.kt @@ -0,0 +1,6 @@ +package com.getcode.utils + +import com.getcode.ed25519.Ed25519 +import com.getcode.vendor.Base58 + +fun Ed25519.KeyPair.getPublicKeyBase58(): String = Base58.encode(publicKeyBytes) diff --git a/libs/encryption/utils/src/androidMain/kotlin/com/getcode/utils/Extensions.android.kt b/libs/encryption/utils/src/androidMain/kotlin/com/getcode/utils/Extensions.android.kt deleted file mode 100644 index 6bbbd55e96..0000000000 --- a/libs/encryption/utils/src/androidMain/kotlin/com/getcode/utils/Extensions.android.kt +++ /dev/null @@ -1,48 +0,0 @@ -package com.getcode.utils - -import android.util.Base64 -import com.getcode.ed25519.Ed25519 -import com.getcode.vendor.Base58 -import com.google.protobuf.ByteString -import java.net.URLDecoder -import java.net.URLEncoder -import java.security.MessageDigest -import java.security.NoSuchAlgorithmException - -fun List.toByteString(): ByteString = ByteString.copyFrom(this.toByteArray()) -fun ByteArray.toByteString(): ByteString = ByteString.copyFrom(this) - -val List.base64: String - get() = Base64.encodeToString(toByteArray(), Base64.NO_WRAP) - -fun String.decodeBase64(): ByteArray = Base64.decode(this, Base64.NO_WRAP) - -fun String.decodeBase64UrlSafe(): ByteArray = Base64.decode(this, Base64.NO_WRAP or Base64.URL_SAFE) - -fun ByteArray.decodeBase64(): ByteArray = Base64.decode(this, Base64.NO_WRAP) - -val ByteArray.base64: String - get() = Base64.encodeToString(this, Base64.NO_WRAP) - -fun ByteArray.encodeBase64(urlSafe: Boolean = false): String { - val flags = if (urlSafe) Base64.NO_WRAP or Base64.URL_SAFE else Base64.NO_WRAP - return Base64.encodeToString(this, flags) -} - -fun ByteArray.encodeBase64ToArray(): ByteArray = Base64.encode(this, Base64.NO_WRAP) - -fun ByteArray.sha512(): ByteArray { - return try { - MessageDigest.getInstance("SHA-512") - .apply { update(this@sha512) } - .digest() - } catch (e: NoSuchAlgorithmException) { - throw RuntimeException("SHA-512 not implemented") - } -} - -fun String.urlEncode(): String = URLEncoder.encode(this, "UTF-8") - -fun String.urlDecode(): String = URLDecoder.decode(this, "UTF-8") - -fun Ed25519.KeyPair.getPublicKeyBase58(): String = Base58.encode(publicKeyBytes) diff --git a/libs/encryption/utils/src/jvmMain/kotlin/com/getcode/utils/Base64.jvm.kt b/libs/encryption/utils/src/jvmMain/kotlin/com/getcode/utils/Base64.jvm.kt new file mode 100644 index 0000000000..37539363e2 --- /dev/null +++ b/libs/encryption/utils/src/jvmMain/kotlin/com/getcode/utils/Base64.jvm.kt @@ -0,0 +1,10 @@ +package com.getcode.utils + +import java.util.Base64 + +// android.util.Base64.decode tolerates missing padding; java.util.Base64's decoder does too. +internal actual fun base64Encode(bytes: ByteArray, urlSafe: Boolean): ByteArray = + (if (urlSafe) Base64.getUrlEncoder() else Base64.getEncoder()).encode(bytes) + +internal actual fun base64Decode(bytes: ByteArray, urlSafe: Boolean): ByteArray = + (if (urlSafe) Base64.getUrlDecoder() else Base64.getDecoder()).decode(bytes) diff --git a/libs/encryption/utils/src/jvmSharedMain/kotlin/com/getcode/utils/Extensions.jvmShared.kt b/libs/encryption/utils/src/jvmSharedMain/kotlin/com/getcode/utils/Extensions.jvmShared.kt new file mode 100644 index 0000000000..47efb02dc2 --- /dev/null +++ b/libs/encryption/utils/src/jvmSharedMain/kotlin/com/getcode/utils/Extensions.jvmShared.kt @@ -0,0 +1,44 @@ +package com.getcode.utils + +import com.google.protobuf.ByteString +import java.net.URLDecoder +import java.net.URLEncoder +import java.security.MessageDigest +import java.security.NoSuchAlgorithmException + +fun List.toByteString(): ByteString = ByteString.copyFrom(this.toByteArray()) +fun ByteArray.toByteString(): ByteString = ByteString.copyFrom(this) + +// Base64 goes through the platform: android.util.Base64 on Android (unchanged), java.util.Base64 on the desktop JVM. +internal expect fun base64Encode(bytes: ByteArray, urlSafe: Boolean): ByteArray +internal expect fun base64Decode(bytes: ByteArray, urlSafe: Boolean): ByteArray + +val List.base64: String + get() = toByteArray().base64 + +fun String.decodeBase64(): ByteArray = base64Decode(toByteArray(), urlSafe = false) + +fun String.decodeBase64UrlSafe(): ByteArray = base64Decode(toByteArray(), urlSafe = true) + +fun ByteArray.decodeBase64(): ByteArray = base64Decode(this, urlSafe = false) + +val ByteArray.base64: String + get() = encodeBase64() + +fun ByteArray.encodeBase64(urlSafe: Boolean = false): String = String(base64Encode(this, urlSafe), Charsets.US_ASCII) + +fun ByteArray.encodeBase64ToArray(): ByteArray = base64Encode(this, urlSafe = false) + +fun ByteArray.sha512(): ByteArray { + return try { + MessageDigest.getInstance("SHA-512") + .apply { update(this@sha512) } + .digest() + } catch (e: NoSuchAlgorithmException) { + throw RuntimeException("SHA-512 not implemented") + } +} + +fun String.urlEncode(): String = URLEncoder.encode(this, "UTF-8") + +fun String.urlDecode(): String = URLDecoder.decode(this, "UTF-8") diff --git a/libs/messaging/build.gradle.kts b/libs/messaging/build.gradle.kts index 133be35447..f791759ead 100644 --- a/libs/messaging/build.gradle.kts +++ b/libs/messaging/build.gradle.kts @@ -1,13 +1,21 @@ plugins { - alias(libs.plugins.flipcash.android.library.compose) + alias(libs.plugins.flipcash.kmp.app.library) + alias(libs.plugins.compose.compiler) } -android { - namespace = "${Gradle.codeNamespace}.libs.messaging" -} +kotlin { + android { + namespace = "${Gradle.codeNamespace}.libs.messaging" + } -dependencies { - api(libs.kotlin.stdlib) - api(libs.kotlinx.coroutines.core) - api(libs.timber) + sourceSets { + commonMain.dependencies { + api(libs.kotlin.stdlib) + api(libs.kotlinx.coroutines.core) + implementation(libs.jetbrains.compose.foundation) + } + androidMain.dependencies { + api(libs.timber) + } + } } diff --git a/libs/messaging/src/main/kotlin/com/getcode/manager/BottomBarManager.kt b/libs/messaging/src/androidMain/kotlin/com/getcode/manager/BottomBarManager.kt similarity index 100% rename from libs/messaging/src/main/kotlin/com/getcode/manager/BottomBarManager.kt rename to libs/messaging/src/androidMain/kotlin/com/getcode/manager/BottomBarManager.kt diff --git a/libs/messaging/src/main/kotlin/com/getcode/manager/TopBarManager.kt b/libs/messaging/src/commonMain/kotlin/com/getcode/manager/TopBarManager.kt similarity index 100% rename from libs/messaging/src/main/kotlin/com/getcode/manager/TopBarManager.kt rename to libs/messaging/src/commonMain/kotlin/com/getcode/manager/TopBarManager.kt diff --git a/libs/network/jwt/build.gradle.kts b/libs/network/jwt/build.gradle.kts index 4ae483c8bd..907929211b 100644 --- a/libs/network/jwt/build.gradle.kts +++ b/libs/network/jwt/build.gradle.kts @@ -1,7 +1,9 @@ plugins { - alias(libs.plugins.flipcash.android.library) + alias(libs.plugins.flipcash.kmp.app.library) } -android { - namespace = "${Gradle.codeNamespace}.libs.network.jwt" +kotlin { + android { + namespace = "${Gradle.codeNamespace}.libs.network.jwt" + } } diff --git a/libs/network/jwt/src/main/kotlin/com/getcode/network/jwt/JwtProvider.kt b/libs/network/jwt/src/commonMain/kotlin/com/getcode/network/jwt/JwtProvider.kt similarity index 100% rename from libs/network/jwt/src/main/kotlin/com/getcode/network/jwt/JwtProvider.kt rename to libs/network/jwt/src/commonMain/kotlin/com/getcode/network/jwt/JwtProvider.kt diff --git a/libs/network/jwt/src/main/kotlin/com/getcode/network/jwt/JwtSecuredEndpoint.kt b/libs/network/jwt/src/commonMain/kotlin/com/getcode/network/jwt/JwtSecuredEndpoint.kt similarity index 100% rename from libs/network/jwt/src/main/kotlin/com/getcode/network/jwt/JwtSecuredEndpoint.kt rename to libs/network/jwt/src/commonMain/kotlin/com/getcode/network/jwt/JwtSecuredEndpoint.kt diff --git a/libs/parcelable/build.gradle.kts b/libs/parcelable/build.gradle.kts new file mode 100644 index 0000000000..e06a9d2d4b --- /dev/null +++ b/libs/parcelable/build.gradle.kts @@ -0,0 +1,9 @@ +plugins { + alias(libs.plugins.flipcash.kmp.app.library) +} + +kotlin { + android { + namespace = "${Gradle.codeNamespace}.libs.parcelable" + } +} diff --git a/libs/parcelable/src/androidHostTest/kotlin/com/getcode/libs/parcelable/ParcelizeTest.kt b/libs/parcelable/src/androidHostTest/kotlin/com/getcode/libs/parcelable/ParcelizeTest.kt new file mode 100644 index 0000000000..de1cca403b --- /dev/null +++ b/libs/parcelable/src/androidHostTest/kotlin/com/getcode/libs/parcelable/ParcelizeTest.kt @@ -0,0 +1,15 @@ +package com.getcode.libs.parcelable + +import kotlin.test.Test +import kotlin.test.assertNotNull + +@Parcelize +data class Sample(val name: String) : Parcelable + +class ParcelizeTest { + @Test + fun `common Parcelize annotation generates a CREATOR`() { + // The parcelize plugin only adds the field when it treats the common annotation as its own. + assertNotNull(Sample::class.java.getField("CREATOR").get(null) as? android.os.Parcelable.Creator<*>) + } +} diff --git a/libs/parcelable/src/androidMain/kotlin/com/getcode/libs/parcelable/Parcelable.android.kt b/libs/parcelable/src/androidMain/kotlin/com/getcode/libs/parcelable/Parcelable.android.kt new file mode 100644 index 0000000000..a8b89a1439 --- /dev/null +++ b/libs/parcelable/src/androidMain/kotlin/com/getcode/libs/parcelable/Parcelable.android.kt @@ -0,0 +1,15 @@ +package com.getcode.libs.parcelable + +actual typealias Parcelable = android.os.Parcelable + +actual typealias Parcel = android.os.Parcel + +actual fun parcelableCreator(newArray: (Int) -> Array, create: (Parcel) -> T): Any = + object : android.os.Parcelable.Creator { + override fun createFromParcel(source: Parcel): T = create(source) + override fun newArray(size: Int): Array = newArray(size) + } + +actual typealias Parcelize = kotlinx.parcelize.Parcelize + +actual typealias IgnoredOnParcel = kotlinx.parcelize.IgnoredOnParcel diff --git a/libs/parcelable/src/commonMain/kotlin/com/getcode/libs/parcelable/Parcelable.kt b/libs/parcelable/src/commonMain/kotlin/com/getcode/libs/parcelable/Parcelable.kt new file mode 100644 index 0000000000..fe69aed7b3 --- /dev/null +++ b/libs/parcelable/src/commonMain/kotlin/com/getcode/libs/parcelable/Parcelable.kt @@ -0,0 +1,39 @@ +package com.getcode.libs.parcelable + +/** + * `android.os.Parcelable` on Android; on the desktop JVM a plain interface nothing reads. + * + * The two members are declared so a class can hand-write its parcel format in common code. + * Classes that use [Parcelize] implement neither. + */ +expect interface Parcelable { + fun describeContents(): Int + fun writeToParcel(dest: Parcel, flags: Int) +} + +/** `android.os.Parcel` on Android. The desktop JVM never creates one. */ +expect class Parcel { + fun writeString(value: String?) + fun readString(): String? +} + +/** + * Builds the `CREATOR` a hand-written [Parcelable] needs on Android. Android finds the field by + * reflection and casts it, so the declared type can stay [Any] in common code. + */ +expect fun parcelableCreator(newArray: (Int) -> Array, create: (Parcel) -> T): Any + +/** + * Common stand-in for `kotlinx.parcelize.Parcelize`. The parcelize compiler plugin is told to + * treat it as its own (`additionalAnnotation`), so it generates the Android implementation. + */ +@OptionalExpectation +@Target(AnnotationTarget.CLASS) +@Retention(AnnotationRetention.BINARY) +expect annotation class Parcelize() + +/** Common stand-in for `kotlinx.parcelize.IgnoredOnParcel`. */ +@OptionalExpectation +@Target(AnnotationTarget.PROPERTY) +@Retention(AnnotationRetention.SOURCE) +expect annotation class IgnoredOnParcel() diff --git a/libs/parcelable/src/jvmMain/kotlin/com/getcode/libs/parcelable/Parcelable.jvm.kt b/libs/parcelable/src/jvmMain/kotlin/com/getcode/libs/parcelable/Parcelable.jvm.kt new file mode 100644 index 0000000000..f8b472d1e6 --- /dev/null +++ b/libs/parcelable/src/jvmMain/kotlin/com/getcode/libs/parcelable/Parcelable.jvm.kt @@ -0,0 +1,13 @@ +package com.getcode.libs.parcelable + +actual interface Parcelable { + actual fun describeContents(): Int + actual fun writeToParcel(dest: Parcel, flags: Int) +} + +actual class Parcel private constructor() { + actual fun writeString(value: String?): Unit = throw UnsupportedOperationException() + actual fun readString(): String? = throw UnsupportedOperationException() +} + +actual fun parcelableCreator(newArray: (Int) -> Array, create: (Parcel) -> T): Any = Unit diff --git a/services/opencode/build.gradle.kts b/services/opencode/build.gradle.kts index a7f5334f2d..67b88e1945 100644 --- a/services/opencode/build.gradle.kts +++ b/services/opencode/build.gradle.kts @@ -92,5 +92,5 @@ dependencies { testImplementation(kotlin("test")) testImplementation(libs.bundles.unit.testing) - testImplementation(testFixtures(project(":libs:currency-math"))) + testImplementation(project(":libs:currency-math:test-fixtures")) } diff --git a/settings.gradle.kts b/settings.gradle.kts index ce47d2b015..4ad45e5ae7 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -201,6 +201,8 @@ include( ":libs:codes:kikcode", ":libs:coroutines", ":libs:coroutines:test-fixtures", + ":libs:parcelable", + ":libs:currency-math:test-fixtures", ":libs:crypto:kin", ":libs:crypto:solana", ":libs:currency", From 5d41abf248b5d9ea7a4e7753a1477f9a30b6f4a2 Mon Sep 17 00:00:00 2001 From: Brandon McAnsh Date: Fri, 23 Oct 2026 15:44:34 -0400 Subject: [PATCH 05/50] build(parcelable): split hand-written parcel members into ManualParcelable A common @Parcelize class implemented the JVM Parcelable's abstract members on Android only, so it failed to compile for jvm. Parcelable is now a member-free marker; PublicKey, which writes its own parcel format, implements ManualParcelable. --- libs/encryption/keys/build.gradle.kts | 2 +- .../kotlin/com/getcode/solana/keys/PublicKey.kt | 4 ++-- .../kotlin/com/getcode/utils/ErrorUtilsTest.kt | 0 .../kotlin/com/getcode/utils/FileTreeTest.kt | 0 .../com/getcode/utils/MetadataBuilderTest.kt | 0 .../com/getcode/utils/PiiMaskingPluginTest.kt | 0 .../kotlin/com/getcode/utils/TraceManagerTest.kt | 0 .../kotlin/com/getcode/utils/FileTree.kt | 0 .../kotlin/com/getcode/utils/BreadcrumbSink.kt | 0 .../kotlin/com/getcode/utils/CodeServerError.kt | 0 .../com/getcode/utils/ConditionallyNotifiable.kt | 0 .../kotlin/com/getcode/utils/ErrorReporter.kt | 0 .../kotlin/com/getcode/utils/ErrorUtils.kt | 0 .../kotlin/com/getcode/utils/Logging.kt | 0 .../kotlin/com/getcode/utils/NotifiableError.kt | 0 .../kotlin/com/getcode/utils/PiiMaskingPlugin.kt | 0 .../com/getcode/utils/RpcBodyFilterPlugin.kt | 0 .../kotlin/com/getcode/utils/TraceLogPlugin.kt | 0 .../kotlin/com/getcode/utils/UnreportedError.kt | 0 .../getcode/libs/parcelable/Parcelable.android.kt | 5 +++++ .../com/getcode/libs/parcelable/Parcelable.kt | 14 ++++++++++---- .../com/getcode/libs/parcelable/ParcelizeProbe.kt | 4 ++++ .../com/getcode/libs/parcelable/Parcelable.jvm.kt | 4 +++- 23 files changed, 25 insertions(+), 8 deletions(-) rename libs/logging/src/{test => androidHostTest}/kotlin/com/getcode/utils/ErrorUtilsTest.kt (100%) rename libs/logging/src/{test => androidHostTest}/kotlin/com/getcode/utils/FileTreeTest.kt (100%) rename libs/logging/src/{test => androidHostTest}/kotlin/com/getcode/utils/MetadataBuilderTest.kt (100%) rename libs/logging/src/{test => androidHostTest}/kotlin/com/getcode/utils/PiiMaskingPluginTest.kt (100%) rename libs/logging/src/{test => androidHostTest}/kotlin/com/getcode/utils/TraceManagerTest.kt (100%) rename libs/logging/src/{main => androidMain}/kotlin/com/getcode/utils/FileTree.kt (100%) rename libs/logging/src/{main => commonMain}/kotlin/com/getcode/utils/BreadcrumbSink.kt (100%) rename libs/logging/src/{main => commonMain}/kotlin/com/getcode/utils/CodeServerError.kt (100%) rename libs/logging/src/{main => commonMain}/kotlin/com/getcode/utils/ConditionallyNotifiable.kt (100%) rename libs/logging/src/{main => commonMain}/kotlin/com/getcode/utils/ErrorReporter.kt (100%) rename libs/logging/src/{main => commonMain}/kotlin/com/getcode/utils/ErrorUtils.kt (100%) rename libs/logging/src/{main => commonMain}/kotlin/com/getcode/utils/Logging.kt (100%) rename libs/logging/src/{main => commonMain}/kotlin/com/getcode/utils/NotifiableError.kt (100%) rename libs/logging/src/{main => commonMain}/kotlin/com/getcode/utils/PiiMaskingPlugin.kt (100%) rename libs/logging/src/{main => commonMain}/kotlin/com/getcode/utils/RpcBodyFilterPlugin.kt (100%) rename libs/logging/src/{main => commonMain}/kotlin/com/getcode/utils/TraceLogPlugin.kt (100%) rename libs/logging/src/{main => commonMain}/kotlin/com/getcode/utils/UnreportedError.kt (100%) create mode 100644 libs/parcelable/src/commonTest/kotlin/com/getcode/libs/parcelable/ParcelizeProbe.kt diff --git a/libs/encryption/keys/build.gradle.kts b/libs/encryption/keys/build.gradle.kts index a45f13b8e3..14c70fec7a 100644 --- a/libs/encryption/keys/build.gradle.kts +++ b/libs/encryption/keys/build.gradle.kts @@ -12,7 +12,7 @@ kotlin { implementation(project(":libs:encryption:base58")) implementation(project(":libs:encryption:sha256")) implementation(project(":libs:encryption:utils")) - implementation(project(":libs:parcelable")) + api(project(":libs:parcelable")) implementation(libs.protobuf.kotlin.lite) implementation(libs.grpc.okhttp) diff --git a/libs/encryption/keys/src/commonMain/kotlin/com/getcode/solana/keys/PublicKey.kt b/libs/encryption/keys/src/commonMain/kotlin/com/getcode/solana/keys/PublicKey.kt index 4aa214734d..fbdb8bf627 100644 --- a/libs/encryption/keys/src/commonMain/kotlin/com/getcode/solana/keys/PublicKey.kt +++ b/libs/encryption/keys/src/commonMain/kotlin/com/getcode/solana/keys/PublicKey.kt @@ -1,7 +1,7 @@ package com.getcode.solana.keys import com.getcode.libs.parcelable.Parcel -import com.getcode.libs.parcelable.Parcelable +import com.getcode.libs.parcelable.ManualParcelable import com.getcode.libs.parcelable.parcelableCreator import com.getcode.utils.serializer.PublicKeyAsStringSerializer import com.getcode.vendor.Base58 @@ -9,7 +9,7 @@ import com.google.protobuf.ByteString import kotlinx.serialization.Serializable @Serializable(with = PublicKeyAsStringSerializer::class) -open class PublicKey(bytes: List) : Key32(bytes), Parcelable { +open class PublicKey(bytes: List) : Key32(bytes), ManualParcelable { constructor(base58: String): this(Base58.decode(base58).toList()) diff --git a/libs/logging/src/test/kotlin/com/getcode/utils/ErrorUtilsTest.kt b/libs/logging/src/androidHostTest/kotlin/com/getcode/utils/ErrorUtilsTest.kt similarity index 100% rename from libs/logging/src/test/kotlin/com/getcode/utils/ErrorUtilsTest.kt rename to libs/logging/src/androidHostTest/kotlin/com/getcode/utils/ErrorUtilsTest.kt diff --git a/libs/logging/src/test/kotlin/com/getcode/utils/FileTreeTest.kt b/libs/logging/src/androidHostTest/kotlin/com/getcode/utils/FileTreeTest.kt similarity index 100% rename from libs/logging/src/test/kotlin/com/getcode/utils/FileTreeTest.kt rename to libs/logging/src/androidHostTest/kotlin/com/getcode/utils/FileTreeTest.kt diff --git a/libs/logging/src/test/kotlin/com/getcode/utils/MetadataBuilderTest.kt b/libs/logging/src/androidHostTest/kotlin/com/getcode/utils/MetadataBuilderTest.kt similarity index 100% rename from libs/logging/src/test/kotlin/com/getcode/utils/MetadataBuilderTest.kt rename to libs/logging/src/androidHostTest/kotlin/com/getcode/utils/MetadataBuilderTest.kt diff --git a/libs/logging/src/test/kotlin/com/getcode/utils/PiiMaskingPluginTest.kt b/libs/logging/src/androidHostTest/kotlin/com/getcode/utils/PiiMaskingPluginTest.kt similarity index 100% rename from libs/logging/src/test/kotlin/com/getcode/utils/PiiMaskingPluginTest.kt rename to libs/logging/src/androidHostTest/kotlin/com/getcode/utils/PiiMaskingPluginTest.kt diff --git a/libs/logging/src/test/kotlin/com/getcode/utils/TraceManagerTest.kt b/libs/logging/src/androidHostTest/kotlin/com/getcode/utils/TraceManagerTest.kt similarity index 100% rename from libs/logging/src/test/kotlin/com/getcode/utils/TraceManagerTest.kt rename to libs/logging/src/androidHostTest/kotlin/com/getcode/utils/TraceManagerTest.kt diff --git a/libs/logging/src/main/kotlin/com/getcode/utils/FileTree.kt b/libs/logging/src/androidMain/kotlin/com/getcode/utils/FileTree.kt similarity index 100% rename from libs/logging/src/main/kotlin/com/getcode/utils/FileTree.kt rename to libs/logging/src/androidMain/kotlin/com/getcode/utils/FileTree.kt diff --git a/libs/logging/src/main/kotlin/com/getcode/utils/BreadcrumbSink.kt b/libs/logging/src/commonMain/kotlin/com/getcode/utils/BreadcrumbSink.kt similarity index 100% rename from libs/logging/src/main/kotlin/com/getcode/utils/BreadcrumbSink.kt rename to libs/logging/src/commonMain/kotlin/com/getcode/utils/BreadcrumbSink.kt diff --git a/libs/logging/src/main/kotlin/com/getcode/utils/CodeServerError.kt b/libs/logging/src/commonMain/kotlin/com/getcode/utils/CodeServerError.kt similarity index 100% rename from libs/logging/src/main/kotlin/com/getcode/utils/CodeServerError.kt rename to libs/logging/src/commonMain/kotlin/com/getcode/utils/CodeServerError.kt diff --git a/libs/logging/src/main/kotlin/com/getcode/utils/ConditionallyNotifiable.kt b/libs/logging/src/commonMain/kotlin/com/getcode/utils/ConditionallyNotifiable.kt similarity index 100% rename from libs/logging/src/main/kotlin/com/getcode/utils/ConditionallyNotifiable.kt rename to libs/logging/src/commonMain/kotlin/com/getcode/utils/ConditionallyNotifiable.kt diff --git a/libs/logging/src/main/kotlin/com/getcode/utils/ErrorReporter.kt b/libs/logging/src/commonMain/kotlin/com/getcode/utils/ErrorReporter.kt similarity index 100% rename from libs/logging/src/main/kotlin/com/getcode/utils/ErrorReporter.kt rename to libs/logging/src/commonMain/kotlin/com/getcode/utils/ErrorReporter.kt diff --git a/libs/logging/src/main/kotlin/com/getcode/utils/ErrorUtils.kt b/libs/logging/src/commonMain/kotlin/com/getcode/utils/ErrorUtils.kt similarity index 100% rename from libs/logging/src/main/kotlin/com/getcode/utils/ErrorUtils.kt rename to libs/logging/src/commonMain/kotlin/com/getcode/utils/ErrorUtils.kt diff --git a/libs/logging/src/main/kotlin/com/getcode/utils/Logging.kt b/libs/logging/src/commonMain/kotlin/com/getcode/utils/Logging.kt similarity index 100% rename from libs/logging/src/main/kotlin/com/getcode/utils/Logging.kt rename to libs/logging/src/commonMain/kotlin/com/getcode/utils/Logging.kt diff --git a/libs/logging/src/main/kotlin/com/getcode/utils/NotifiableError.kt b/libs/logging/src/commonMain/kotlin/com/getcode/utils/NotifiableError.kt similarity index 100% rename from libs/logging/src/main/kotlin/com/getcode/utils/NotifiableError.kt rename to libs/logging/src/commonMain/kotlin/com/getcode/utils/NotifiableError.kt diff --git a/libs/logging/src/main/kotlin/com/getcode/utils/PiiMaskingPlugin.kt b/libs/logging/src/commonMain/kotlin/com/getcode/utils/PiiMaskingPlugin.kt similarity index 100% rename from libs/logging/src/main/kotlin/com/getcode/utils/PiiMaskingPlugin.kt rename to libs/logging/src/commonMain/kotlin/com/getcode/utils/PiiMaskingPlugin.kt diff --git a/libs/logging/src/main/kotlin/com/getcode/utils/RpcBodyFilterPlugin.kt b/libs/logging/src/commonMain/kotlin/com/getcode/utils/RpcBodyFilterPlugin.kt similarity index 100% rename from libs/logging/src/main/kotlin/com/getcode/utils/RpcBodyFilterPlugin.kt rename to libs/logging/src/commonMain/kotlin/com/getcode/utils/RpcBodyFilterPlugin.kt diff --git a/libs/logging/src/main/kotlin/com/getcode/utils/TraceLogPlugin.kt b/libs/logging/src/commonMain/kotlin/com/getcode/utils/TraceLogPlugin.kt similarity index 100% rename from libs/logging/src/main/kotlin/com/getcode/utils/TraceLogPlugin.kt rename to libs/logging/src/commonMain/kotlin/com/getcode/utils/TraceLogPlugin.kt diff --git a/libs/logging/src/main/kotlin/com/getcode/utils/UnreportedError.kt b/libs/logging/src/commonMain/kotlin/com/getcode/utils/UnreportedError.kt similarity index 100% rename from libs/logging/src/main/kotlin/com/getcode/utils/UnreportedError.kt rename to libs/logging/src/commonMain/kotlin/com/getcode/utils/UnreportedError.kt diff --git a/libs/parcelable/src/androidMain/kotlin/com/getcode/libs/parcelable/Parcelable.android.kt b/libs/parcelable/src/androidMain/kotlin/com/getcode/libs/parcelable/Parcelable.android.kt index a8b89a1439..f06cb51e54 100644 --- a/libs/parcelable/src/androidMain/kotlin/com/getcode/libs/parcelable/Parcelable.android.kt +++ b/libs/parcelable/src/androidMain/kotlin/com/getcode/libs/parcelable/Parcelable.android.kt @@ -2,6 +2,11 @@ package com.getcode.libs.parcelable actual typealias Parcelable = android.os.Parcelable +actual interface ManualParcelable : Parcelable { + actual override fun describeContents(): Int + actual override fun writeToParcel(dest: Parcel, flags: Int) +} + actual typealias Parcel = android.os.Parcel actual fun parcelableCreator(newArray: (Int) -> Array, create: (Parcel) -> T): Any = diff --git a/libs/parcelable/src/commonMain/kotlin/com/getcode/libs/parcelable/Parcelable.kt b/libs/parcelable/src/commonMain/kotlin/com/getcode/libs/parcelable/Parcelable.kt index fe69aed7b3..c36000ae8c 100644 --- a/libs/parcelable/src/commonMain/kotlin/com/getcode/libs/parcelable/Parcelable.kt +++ b/libs/parcelable/src/commonMain/kotlin/com/getcode/libs/parcelable/Parcelable.kt @@ -1,12 +1,18 @@ package com.getcode.libs.parcelable /** - * `android.os.Parcelable` on Android; on the desktop JVM a plain interface nothing reads. + * `android.os.Parcelable` on Android; on the desktop JVM a marker interface nothing reads. * - * The two members are declared so a class can hand-write its parcel format in common code. - * Classes that use [Parcelize] implement neither. + * Common code sees no members, so a [Parcelize] class compiles on both targets. A class that + * writes its own parcel format implements [ManualParcelable] instead. */ -expect interface Parcelable { +expect interface Parcelable + +/** + * A sub-interface of `android.os.Parcelable` on Android, with the two members declared so a class can + * hand-write its parcel format in common code. + */ +expect interface ManualParcelable : Parcelable { fun describeContents(): Int fun writeToParcel(dest: Parcel, flags: Int) } diff --git a/libs/parcelable/src/commonTest/kotlin/com/getcode/libs/parcelable/ParcelizeProbe.kt b/libs/parcelable/src/commonTest/kotlin/com/getcode/libs/parcelable/ParcelizeProbe.kt new file mode 100644 index 0000000000..7631dbe02f --- /dev/null +++ b/libs/parcelable/src/commonTest/kotlin/com/getcode/libs/parcelable/ParcelizeProbe.kt @@ -0,0 +1,4 @@ +package com.getcode.libs.parcelable + +@Parcelize +data class ParcelizeProbe(val name: String, val count: Int) : Parcelable diff --git a/libs/parcelable/src/jvmMain/kotlin/com/getcode/libs/parcelable/Parcelable.jvm.kt b/libs/parcelable/src/jvmMain/kotlin/com/getcode/libs/parcelable/Parcelable.jvm.kt index f8b472d1e6..4e8741c5c6 100644 --- a/libs/parcelable/src/jvmMain/kotlin/com/getcode/libs/parcelable/Parcelable.jvm.kt +++ b/libs/parcelable/src/jvmMain/kotlin/com/getcode/libs/parcelable/Parcelable.jvm.kt @@ -1,6 +1,8 @@ package com.getcode.libs.parcelable -actual interface Parcelable { +actual interface Parcelable + +actual interface ManualParcelable : Parcelable { actual fun describeContents(): Int actual fun writeToParcel(dest: Parcel, flags: Int) } From 0ddf461c880bbbe7fd71e1c3228f1a72e1f3b40d Mon Sep 17 00:00:00 2001 From: Brandon McAnsh Date: Fri, 23 Oct 2026 15:51:10 -0400 Subject: [PATCH 06/50] build(logging): move libs:logging to android+jvm Timber, SystemClock and android.database.SQLException move behind PlatformLog actuals; FileTree stays in androidMain and plugs in through LogFileStore. The library had debug and release values for NOTIFY_ERRORS, which a single-variant KMP target can't carry, so the app now sets BuildFlags from its own BuildConfig at startup. --- apps/flipcash/app/build.gradle.kts | 6 ++ .../app/internal/startup/TraceInitializer.kt | 4 ++ libs/logging/build.gradle.kts | 47 ++++++--------- .../kotlin/com/getcode/utils/FileTree.kt | 12 ++-- .../com/getcode/utils/PlatformLog.android.kt | 32 +++++++++++ .../kotlin/com/getcode/utils/BuildFlags.kt | 18 ++++++ .../kotlin/com/getcode/utils/ErrorUtils.kt | 9 +-- .../kotlin/com/getcode/utils/Logging.kt | 57 +++++++++---------- .../kotlin/com/getcode/utils/PlatformLog.kt | 34 +++++++++++ .../com/getcode/utils/PlatformLog.jvm.kt | 24 ++++++++ 10 files changed, 173 insertions(+), 70 deletions(-) create mode 100644 libs/logging/src/androidMain/kotlin/com/getcode/utils/PlatformLog.android.kt create mode 100644 libs/logging/src/commonMain/kotlin/com/getcode/utils/BuildFlags.kt create mode 100644 libs/logging/src/commonMain/kotlin/com/getcode/utils/PlatformLog.kt create mode 100644 libs/logging/src/jvmMain/kotlin/com/getcode/utils/PlatformLog.jvm.kt diff --git a/apps/flipcash/app/build.gradle.kts b/apps/flipcash/app/build.gradle.kts index 42b2d1e676..8c621ee69d 100644 --- a/apps/flipcash/app/build.gradle.kts +++ b/apps/flipcash/app/build.gradle.kts @@ -86,12 +86,18 @@ android { buildTypes { getByName("release") { resValue("string", "applicationId", appNamespace) + buildConfigField("Boolean", "NOTIFY_ERRORS", "true") isMinifyEnabled = !skipExpensiveReleaseTasks isShrinkResources = !skipExpensiveReleaseTasks proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro") } getByName("debug") { resValue("string", "applicationId", appNamespace) + buildConfigField( + "Boolean", + "NOTIFY_ERRORS", + tryReadProperty(rootProject.rootDir, "NOTIFY_ERRORS", "false") + ) signingConfig = signingConfigs.getByName("contributors") val debugMinifyEnabled = tryReadProperty(rootProject.rootDir, "DEBUG_MINIFY", "false").toBooleanStrictOrNull() ?: false diff --git a/apps/flipcash/app/src/main/kotlin/com/flipcash/app/internal/startup/TraceInitializer.kt b/apps/flipcash/app/src/main/kotlin/com/flipcash/app/internal/startup/TraceInitializer.kt index 57831c3500..667f244df9 100644 --- a/apps/flipcash/app/src/main/kotlin/com/flipcash/app/internal/startup/TraceInitializer.kt +++ b/apps/flipcash/app/src/main/kotlin/com/flipcash/app/internal/startup/TraceInitializer.kt @@ -11,8 +11,10 @@ import com.flipcash.app.internal.debug.TestLab import com.flipcash.app.internal.debug.bugsnagReleaseStage import com.flipcash.app.updates.ReleaseStage import com.flipcash.app.updates.ReleaseStageProvider +import com.getcode.utils.BuildFlags import com.getcode.utils.ErrorUtils import com.getcode.utils.TraceManager +import com.getcode.utils.initialize import dagger.hilt.EntryPoint import dagger.hilt.InstallIn import dagger.hilt.android.EntryPointAccessors @@ -28,6 +30,8 @@ class TraceInitializer: Initializer { } override fun create(context: Context) { + BuildFlags.isDebug = BuildConfig.DEBUG + BuildFlags.notifyErrors = BuildConfig.NOTIFY_ERRORS TraceManager.initialize(context) if (BuildConfig.DEBUG) { diff --git a/libs/logging/build.gradle.kts b/libs/logging/build.gradle.kts index 6baf81d2b1..91d7fd6e48 100644 --- a/libs/logging/build.gradle.kts +++ b/libs/logging/build.gradle.kts @@ -1,37 +1,26 @@ plugins { - alias(libs.plugins.flipcash.android.library) + alias(libs.plugins.flipcash.kmp.app.library) } -android { - namespace = "${Gradle.codeNamespace}.libs.logging" +kotlin { + android { + namespace = "${Gradle.codeNamespace}.libs.logging" + } - buildTypes { - getByName("release") { - buildConfigField("Boolean", "NOTIFY_ERRORS", "true") + sourceSets { + commonMain.dependencies { + implementation(libs.androidx.annotation) + implementation(libs.grpc.kotlin) + implementation(project(":libs:messaging")) + implementation(libs.ocp.client.protocol) + implementation(libs.flipcash2.client.protocol) } - getByName("debug") { - buildConfigField( - "Boolean", - "NOTIFY_ERRORS", - tryReadProperty(rootProject.rootDir, "NOTIFY_ERRORS", "false") - ) + androidMain.dependencies { + api(libs.timber) + } + getByName("androidHostTest").dependencies { + implementation(kotlin("test")) + implementation(libs.robolectric) } } - - buildFeatures { - buildConfig = true - } -} - -dependencies { - testImplementation(kotlin("test")) - testImplementation(libs.robolectric) - - api(libs.timber) - implementation(libs.androidx.annotation) - implementation(libs.grpc.kotlin) - implementation(project(":libs:messaging")) - - implementation(libs.ocp.client.protocol) - implementation(libs.flipcash2.client.protocol) } diff --git a/libs/logging/src/androidMain/kotlin/com/getcode/utils/FileTree.kt b/libs/logging/src/androidMain/kotlin/com/getcode/utils/FileTree.kt index 19f9437eec..e7405364a6 100644 --- a/libs/logging/src/androidMain/kotlin/com/getcode/utils/FileTree.kt +++ b/libs/logging/src/androidMain/kotlin/com/getcode/utils/FileTree.kt @@ -24,7 +24,7 @@ import java.util.TimeZone class FileTree( context: Context, private val plugins: () -> List, -) : Timber.Tree() { +) : Timber.Tree(), LogFileStore { private val traceDir = File(context.filesDir, "traces").apply { mkdirs() } private val logFile = File(traceDir, "trace.log") @@ -46,7 +46,7 @@ class FileTree( * immediately receive the most recent [LOG_STREAM_BUFFER_CAPACITY] lines * via replay cache, so the in-app viewer opens already populated. */ - val logStream: SharedFlow = logFlow.asSharedFlow() + override val logStream: SharedFlow = logFlow.asSharedFlow() init { // Clear previous session logs on cold launch @@ -95,7 +95,7 @@ class FileTree( logFlow.tryEmit(processed!!) } - fun getLogFile(includeHeader: Boolean = true): File? { + override fun getLogFile(includeHeader: Boolean): File? { if (!logFile.exists() || logFile.length() == 0L) return null synchronized(lock) { exportFile.delete() @@ -112,7 +112,7 @@ class FileTree( } @OptIn(ExperimentalCoroutinesApi::class) - fun clearLogs() { + override fun clearLogs() { synchronized(lock) { logFile.delete() exportFile.delete() @@ -121,6 +121,10 @@ class FileTree( logFlow.resetReplayCache() } + override fun close() { + Timber.uproot(this) + } + companion object { /** Max number of log lines retained in the live stream's replay cache. */ const val LOG_STREAM_BUFFER_CAPACITY = 1000 diff --git a/libs/logging/src/androidMain/kotlin/com/getcode/utils/PlatformLog.android.kt b/libs/logging/src/androidMain/kotlin/com/getcode/utils/PlatformLog.android.kt new file mode 100644 index 0000000000..bb9eab709a --- /dev/null +++ b/libs/logging/src/androidMain/kotlin/com/getcode/utils/PlatformLog.android.kt @@ -0,0 +1,32 @@ +package com.getcode.utils + +import android.content.Context +import android.database.SQLException +import android.os.SystemClock +import timber.log.Timber + +internal actual object PlatformLog { + actual fun log(priority: Int, tag: String?, message: String) { + val tree = if (tag == null) Timber else Timber.tag(tag) + tree.log(priority, message) + } + + actual fun error(throwable: Throwable) { + Timber.e(throwable) + } +} + +internal actual fun isPlatformSqlException(throwable: Throwable): Boolean = throwable is SQLException + +internal actual fun elapsedRealtimeMillis(): Long = SystemClock.elapsedRealtime() + +/** + * Plants a [FileTree] and initializes [TraceManager] with it. Safe to call multiple times; + * subsequent calls are no-ops. + */ +fun TraceManager.initialize(context: Context) { + if (initialized) return + val tree = FileTree(context, plugins = { plugins }) + Timber.plant(tree) + initialize(tree) +} diff --git a/libs/logging/src/commonMain/kotlin/com/getcode/utils/BuildFlags.kt b/libs/logging/src/commonMain/kotlin/com/getcode/utils/BuildFlags.kt new file mode 100644 index 0000000000..92a82a0118 --- /dev/null +++ b/libs/logging/src/commonMain/kotlin/com/getcode/utils/BuildFlags.kt @@ -0,0 +1,18 @@ +package com.getcode.utils + +/** + * Build-type flags the app sets at startup. + * + * KMP library modules have a single variant and no `BuildConfig`, so a value that used to differ + * between a library's debug and release builds is read here instead. Both default to the release + * value until the app sets them. + */ +object BuildFlags { + /** What a library's `BuildConfig.DEBUG` used to report. */ + @Volatile + var isDebug: Boolean = false + + /** Whether [ErrorUtils] forwards errors to its reporters. */ + @Volatile + var notifyErrors: Boolean = true +} diff --git a/libs/logging/src/commonMain/kotlin/com/getcode/utils/ErrorUtils.kt b/libs/logging/src/commonMain/kotlin/com/getcode/utils/ErrorUtils.kt index 5fa512d292..01a3d10e75 100644 --- a/libs/logging/src/commonMain/kotlin/com/getcode/utils/ErrorUtils.kt +++ b/libs/logging/src/commonMain/kotlin/com/getcode/utils/ErrorUtils.kt @@ -1,14 +1,11 @@ package com.getcode.utils -import android.database.SQLException -import com.getcode.libs.logging.BuildConfig import com.getcode.manager.TopBarManager import io.grpc.Status import io.grpc.StatusException import io.grpc.StatusRuntimeException import kotlinx.coroutines.CancellationException import kotlinx.coroutines.TimeoutCancellationException -import timber.log.Timber import java.net.ConnectException import java.net.SocketException import java.net.UnknownHostException @@ -48,7 +45,7 @@ object ErrorUtils { if (isIgnoredGrpcStatus(throwableCause)) return - Timber.e(throwable) + PlatformLog.error(throwable) if (isRuntimeError(throwable)) return @@ -61,7 +58,7 @@ object ErrorUtils { ) } - if (BuildConfig.NOTIFY_ERRORS && shouldReport(throwable, throwableCause)) { + if (BuildFlags.notifyErrors && shouldReport(throwable, throwableCause)) { val isNotifiable = when { throwable is ConditionallyNotifiable -> throwable.isNotifiable throwableCause is ConditionallyNotifiable -> throwableCause.isNotifiable @@ -146,7 +143,7 @@ object ErrorUtils { throwable.cause is StatusException private fun isSuppressibleError(throwable: Throwable): Boolean = - throwable is SQLException || throwable is SuppressibleException || throwable is TimeoutCancellationException + isPlatformSqlException(throwable) || throwable is SuppressibleException || throwable is TimeoutCancellationException } fun Throwable.isNetworkError(): Boolean = diff --git a/libs/logging/src/commonMain/kotlin/com/getcode/utils/Logging.kt b/libs/logging/src/commonMain/kotlin/com/getcode/utils/Logging.kt index 636d9e5681..e4e39fe8b2 100644 --- a/libs/logging/src/commonMain/kotlin/com/getcode/utils/Logging.kt +++ b/libs/logging/src/commonMain/kotlin/com/getcode/utils/Logging.kt @@ -1,13 +1,9 @@ package com.getcode.utils -import android.annotation.SuppressLint -import android.content.Context -import android.os.SystemClock import kotlinx.coroutines.channels.BufferOverflow import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.asSharedFlow -import timber.log.Timber import java.io.File import kotlin.time.Duration import kotlin.time.TimeSource @@ -57,7 +53,7 @@ sealed interface TraceType { * - [BreadcrumbSink]s — forward structured breadcrumbs to external services (e.g. Bugsnag). */ object TraceManager { - private var fileTree: FileTree? = null + private var logFile: LogFileStore? = null /** `true` after [initialize] has been called. [trace] is a no-op until then. */ var initialized: Boolean = false @@ -100,13 +96,13 @@ object TraceManager { fun recordClockDrift(driftMillis: Long, source: ClockSource) { clockDriftMillis = driftMillis clockDriftSource = source - clockDriftSyncElapsedRealtime = SystemClock.elapsedRealtime() + clockDriftSyncElapsedRealtime = elapsedRealtimeMillis() } /** Latest clock-drift measurement, or `null` if no server time has been observed yet. */ fun clockDriftSnapshot(): ClockDriftSnapshot? { val drift = clockDriftMillis ?: return null - val ageMillis = clockDriftSyncElapsedRealtime?.let { SystemClock.elapsedRealtime() - it } + val ageMillis = clockDriftSyncElapsedRealtime?.let { elapsedRealtimeMillis() - it } return ClockDriftSnapshot( driftMillis = drift, source = clockDriftSource, @@ -127,22 +123,22 @@ object TraceManager { fun sinks(): List = breadcrumbSinks /** - * Bootstraps Timber with a [FileTree], plants default plugins - * ([PiiMaskingPlugin], [RpcBodyFilterPlugin]), and marks the manager - * as [initialized]. Safe to call multiple times; subsequent calls are no-ops. + * Plants default plugins ([PiiMaskingPlugin], [RpcBodyFilterPlugin]), keeps [logFile] for + * [getLogFile], [logStream] and [clearLogs], and marks the manager as [initialized]. Safe to + * call multiple times; subsequent calls are no-ops. + * + * Android calls this through `TraceManager.initialize(context)`, which supplies a FileTree. */ - fun initialize(context: Context) { + fun initialize(logFile: LogFileStore? = null) { if (initialized) return - val tree = FileTree(context, plugins = { plugins }) - fileTree = tree + this.logFile = logFile addPlugin(PiiMaskingPlugin()) addPlugin(RpcBodyFilterPlugin()) - Timber.plant(tree) initialized = true } /** Returns the current log file, or `null` if not yet initialized. */ - fun getLogFile(includeHeader: Boolean = true): File? = fileTree?.getLogFile(includeHeader) + fun getLogFile(includeHeader: Boolean = true): File? = logFile?.getLogFile(includeHeader) /** * Hot stream of processed log lines for live in-app viewers. Emits only @@ -150,7 +146,7 @@ object TraceManager { * empty [SharedFlow] that will never emit. */ val logStream: SharedFlow - get() = fileTree?.logStream ?: EmptyLogStream + get() = logFile?.logStream ?: EmptyLogStream private val EmptyLogStream: SharedFlow = MutableSharedFlow( replay = 0, @@ -159,14 +155,14 @@ object TraceManager { ).asSharedFlow() fun clearLogs() { - fileTree?.clearLogs() + logFile?.clearLogs() } /** Tears down all state. Intended for tests only. */ @androidx.annotation.VisibleForTesting internal fun reset() { - fileTree?.let { Timber.uproot(it) } - fileTree = null + logFile?.close() + logFile = null initialized = false plugins.clear() breadcrumbSinks.clear() @@ -194,7 +190,7 @@ enum class ClockSource { } /** - * Primary logging entry point. Writes [message] to Timber and forwards a + * Primary logging entry point. Writes [message] to the platform log (Timber on Android) and forwards a * breadcrumb to every registered [BreadcrumbSink]. * * No-op if [TraceManager] has not been [initialized][TraceManager.initialize], @@ -206,7 +202,6 @@ enum class ClockSource { * @param error If non-null, forwarded to [ErrorUtils.handleError] after logging. * @param type Categorization that determines the Timber log level. */ -@SuppressLint("TimberExceptionLogging") fun trace( message: String, tag: String? = null, @@ -217,7 +212,6 @@ fun trace( if (!TraceManager.initialized) return val tagBlock = tag?.let { "[$it] " } - val tree = if (tagBlock == null) Timber else Timber.tag(tagBlock) val metadataMap = metadata { metadata() } @@ -228,16 +222,17 @@ fun trace( message } - when (type) { - TraceType.Error -> tree.e(logMessage) - TraceType.Log -> tree.d(logMessage) - TraceType.Navigation -> tree.d(logMessage) - TraceType.Network -> tree.i(logMessage) - TraceType.Process -> tree.d(logMessage) - TraceType.Silent -> tree.d(logMessage) - TraceType.StateChange -> tree.d(logMessage) - TraceType.User -> tree.d(logMessage) + val priority = when (type) { + TraceType.Error -> LogPriority.ERROR + TraceType.Log -> LogPriority.DEBUG + TraceType.Navigation -> LogPriority.DEBUG + TraceType.Network -> LogPriority.INFO + TraceType.Process -> LogPriority.DEBUG + TraceType.Silent -> LogPriority.DEBUG + TraceType.StateChange -> LogPriority.DEBUG + TraceType.User -> LogPriority.DEBUG } + PlatformLog.log(priority, tagBlock, logMessage) val rawBreadcrumb = if (tag != null) "$tagBlock $message" else message val sinks = TraceManager.sinks() diff --git a/libs/logging/src/commonMain/kotlin/com/getcode/utils/PlatformLog.kt b/libs/logging/src/commonMain/kotlin/com/getcode/utils/PlatformLog.kt new file mode 100644 index 0000000000..aa2588a5bf --- /dev/null +++ b/libs/logging/src/commonMain/kotlin/com/getcode/utils/PlatformLog.kt @@ -0,0 +1,34 @@ +package com.getcode.utils + +import kotlinx.coroutines.flow.SharedFlow +import java.io.File + +/** Log levels, numbered as `android.util.Log` numbers them so Android passes them straight through. */ +object LogPriority { + const val VERBOSE = 2 + const val DEBUG = 3 + const val INFO = 4 + const val WARN = 5 + const val ERROR = 6 +} + +/** Where [trace] and [ErrorUtils] write: Timber on Android, standard error on the desktop JVM. */ +internal expect object PlatformLog { + fun log(priority: Int, tag: String?, message: String) + fun error(throwable: Throwable) +} + +/** The platform's `SQLException`, which [ErrorUtils] treats as suppressible. */ +internal expect fun isPlatformSqlException(throwable: Throwable): Boolean + +/** Milliseconds on a clock that keeps running while the device sleeps. */ +internal expect fun elapsedRealtimeMillis(): Long + +/** The on-disk log behind [TraceManager.getLogFile], [TraceManager.logStream] and [TraceManager.clearLogs]. */ +interface LogFileStore { + val logStream: SharedFlow + fun getLogFile(includeHeader: Boolean = true): File? + fun clearLogs() + /** Stops writing to the log. Called when [TraceManager] is reset. */ + fun close() +} diff --git a/libs/logging/src/jvmMain/kotlin/com/getcode/utils/PlatformLog.jvm.kt b/libs/logging/src/jvmMain/kotlin/com/getcode/utils/PlatformLog.jvm.kt new file mode 100644 index 0000000000..f91e3777b3 --- /dev/null +++ b/libs/logging/src/jvmMain/kotlin/com/getcode/utils/PlatformLog.jvm.kt @@ -0,0 +1,24 @@ +package com.getcode.utils + +import java.sql.SQLException + +internal actual object PlatformLog { + actual fun log(priority: Int, tag: String?, message: String) { + val level = when (priority) { + LogPriority.VERBOSE -> "V" + LogPriority.DEBUG -> "D" + LogPriority.INFO -> "I" + LogPriority.WARN -> "W" + else -> "E" + } + System.err.println("$level ${tag.orEmpty()}$message") + } + + actual fun error(throwable: Throwable) { + throwable.printStackTrace() + } +} + +internal actual fun isPlatformSqlException(throwable: Throwable): Boolean = throwable is SQLException + +internal actual fun elapsedRealtimeMillis(): Long = System.nanoTime() / 1_000_000 From 6e5146a71365fc5c66d48285be2ca59f3f1b9ac7 Mon Sep 17 00:00:00 2001 From: Brandon McAnsh Date: Fri, 23 Oct 2026 15:57:53 -0400 Subject: [PATCH 07/50] build(resources): move ui:resources to android + jvm ResourceHelper keeps the members that return plain types in commonMain. The four that return Drawable, Typeface, DisplayMetrics and File move to AndroidResourceHelper, which only the access-key screens use; the app binds both. FakeResourceHelper moves from testFixtures to :ui:resources:test-fixtures, since the KMP library target has no testFixtures. --- .../com/flipcash/app/inject/AppModule.kt | 10 ++++- .../internal/BackupKeyScreenViewModel.kt | 4 +- apps/flipcash/features/cash/build.gradle.kts | 2 +- .../contact-verification/build.gradle.kts | 2 +- apps/flipcash/features/login/build.gradle.kts | 2 +- .../login/internal/LoginAccessKeyViewModel.kt | 4 +- apps/flipcash/features/menu/build.gradle.kts | 2 +- .../features/myaccount/build.gradle.kts | 2 +- .../features/tipping/build.gradle.kts | 2 +- .../features/transactions/build.gradle.kts | 2 +- .../features/user-profile/build.gradle.kts | 2 +- .../features/withdrawal/build.gradle.kts | 2 +- .../app/accesskey/BaseAccessKeyViewModel.kt | 4 +- apps/flipcash/shared/session/build.gradle.kts | 2 +- .../shared/shareable/build.gradle.kts | 2 +- apps/flipcash/shared/tokens/build.gradle.kts | 2 +- .../transaction-history/build.gradle.kts | 2 +- settings.gradle.kts | 1 + ui/resources/build.gradle.kts | 39 +++++++++++------- .../util/resources/AndroidResourceHelper.kt | 19 +++++++++ .../util/resources/AndroidResources.kt | 2 +- .../util/resources/AndroidSettingsHelper.kt | 0 .../getcode/util/resources/ContentReader.kt | 0 .../res/drawable-nodpi/ic_bill_globe.webp | Bin .../res/drawable-nodpi/ic_bill_grid.webp | Bin .../res/drawable-nodpi/ic_bill_hexagons.webp | Bin .../ic_bill_security_strip.webp | Bin .../res/drawable-nodpi/ic_bill_waves.webp | Bin .../res/drawable-nodpi/ic_flag_ad.webp | Bin .../res/drawable-nodpi/ic_flag_ae.webp | Bin .../res/drawable-nodpi/ic_flag_af.webp | Bin .../res/drawable-nodpi/ic_flag_ag.webp | Bin .../res/drawable-nodpi/ic_flag_ai.webp | Bin .../res/drawable-nodpi/ic_flag_al.webp | Bin .../res/drawable-nodpi/ic_flag_am.webp | Bin .../res/drawable-nodpi/ic_flag_an.webp | Bin .../res/drawable-nodpi/ic_flag_ao.webp | Bin .../res/drawable-nodpi/ic_flag_aq.webp | Bin .../res/drawable-nodpi/ic_flag_ar.webp | Bin .../res/drawable-nodpi/ic_flag_as.webp | Bin .../res/drawable-nodpi/ic_flag_at.webp | Bin .../res/drawable-nodpi/ic_flag_au.webp | Bin .../res/drawable-nodpi/ic_flag_aw.webp | Bin .../res/drawable-nodpi/ic_flag_ax.webp | Bin .../res/drawable-nodpi/ic_flag_az.webp | Bin .../res/drawable-nodpi/ic_flag_ba.webp | Bin .../res/drawable-nodpi/ic_flag_bb.webp | Bin .../res/drawable-nodpi/ic_flag_bd.webp | Bin .../res/drawable-nodpi/ic_flag_be.webp | Bin .../res/drawable-nodpi/ic_flag_bf.webp | Bin .../res/drawable-nodpi/ic_flag_bg.webp | Bin .../res/drawable-nodpi/ic_flag_bh.webp | Bin .../res/drawable-nodpi/ic_flag_bi.webp | Bin .../res/drawable-nodpi/ic_flag_bj.webp | Bin .../res/drawable-nodpi/ic_flag_bl.webp | Bin .../res/drawable-nodpi/ic_flag_bm.webp | Bin .../res/drawable-nodpi/ic_flag_bn.webp | Bin .../res/drawable-nodpi/ic_flag_bo.webp | Bin .../res/drawable-nodpi/ic_flag_bq.webp | Bin .../res/drawable-nodpi/ic_flag_br.webp | Bin .../res/drawable-nodpi/ic_flag_bs.webp | Bin .../res/drawable-nodpi/ic_flag_bt.webp | Bin .../res/drawable-nodpi/ic_flag_bv.webp | Bin .../res/drawable-nodpi/ic_flag_bw.webp | Bin .../res/drawable-nodpi/ic_flag_by.webp | Bin .../res/drawable-nodpi/ic_flag_bz.webp | Bin .../res/drawable-nodpi/ic_flag_ca.webp | Bin .../res/drawable-nodpi/ic_flag_cc.webp | Bin .../res/drawable-nodpi/ic_flag_cd.webp | Bin .../res/drawable-nodpi/ic_flag_cf.webp | Bin .../res/drawable-nodpi/ic_flag_cg.webp | Bin .../res/drawable-nodpi/ic_flag_ch.webp | Bin .../res/drawable-nodpi/ic_flag_ci.webp | Bin .../res/drawable-nodpi/ic_flag_ck.webp | Bin .../res/drawable-nodpi/ic_flag_cl.webp | Bin .../res/drawable-nodpi/ic_flag_cm.webp | Bin .../res/drawable-nodpi/ic_flag_cn.webp | Bin .../res/drawable-nodpi/ic_flag_co.webp | Bin .../res/drawable-nodpi/ic_flag_cr.webp | Bin .../res/drawable-nodpi/ic_flag_cu.webp | Bin .../res/drawable-nodpi/ic_flag_cv.webp | Bin .../res/drawable-nodpi/ic_flag_cw.webp | Bin .../res/drawable-nodpi/ic_flag_cx.webp | Bin .../res/drawable-nodpi/ic_flag_cy.webp | Bin .../res/drawable-nodpi/ic_flag_cz.webp | Bin .../res/drawable-nodpi/ic_flag_de.webp | Bin .../res/drawable-nodpi/ic_flag_dj.webp | Bin .../res/drawable-nodpi/ic_flag_dk.webp | Bin .../res/drawable-nodpi/ic_flag_dm.webp | Bin .../res/drawable-nodpi/ic_flag_do.webp | Bin .../res/drawable-nodpi/ic_flag_dz.webp | Bin .../res/drawable-nodpi/ic_flag_ec.webp | Bin .../res/drawable-nodpi/ic_flag_ee.webp | Bin .../res/drawable-nodpi/ic_flag_eg.webp | Bin .../res/drawable-nodpi/ic_flag_eh.webp | Bin .../res/drawable-nodpi/ic_flag_eo.webp | Bin .../res/drawable-nodpi/ic_flag_er.webp | Bin .../res/drawable-nodpi/ic_flag_es.webp | Bin .../res/drawable-nodpi/ic_flag_et.webp | Bin .../res/drawable-nodpi/ic_flag_eu.webp | Bin .../res/drawable-nodpi/ic_flag_fi.webp | Bin .../res/drawable-nodpi/ic_flag_fj.webp | Bin .../res/drawable-nodpi/ic_flag_fk.webp | Bin .../res/drawable-nodpi/ic_flag_fm.webp | Bin .../res/drawable-nodpi/ic_flag_fo.webp | Bin .../res/drawable-nodpi/ic_flag_fr.webp | Bin .../res/drawable-nodpi/ic_flag_ga.webp | Bin .../res/drawable-nodpi/ic_flag_gb.webp | Bin .../res/drawable-nodpi/ic_flag_gd.webp | Bin .../res/drawable-nodpi/ic_flag_ge.webp | Bin .../res/drawable-nodpi/ic_flag_gf.webp | Bin .../res/drawable-nodpi/ic_flag_gg.webp | Bin .../res/drawable-nodpi/ic_flag_gh.webp | Bin .../res/drawable-nodpi/ic_flag_gi.webp | Bin .../res/drawable-nodpi/ic_flag_gl.webp | Bin .../res/drawable-nodpi/ic_flag_gm.webp | Bin .../res/drawable-nodpi/ic_flag_gn.webp | Bin .../res/drawable-nodpi/ic_flag_gp.webp | Bin .../res/drawable-nodpi/ic_flag_gq.webp | Bin .../res/drawable-nodpi/ic_flag_gr.webp | Bin .../res/drawable-nodpi/ic_flag_gs.webp | Bin .../res/drawable-nodpi/ic_flag_gt.webp | Bin .../res/drawable-nodpi/ic_flag_gu.webp | Bin .../res/drawable-nodpi/ic_flag_gw.webp | Bin .../res/drawable-nodpi/ic_flag_gy.webp | Bin .../res/drawable-nodpi/ic_flag_hk.webp | Bin .../res/drawable-nodpi/ic_flag_hm.webp | Bin .../res/drawable-nodpi/ic_flag_hn.webp | Bin .../res/drawable-nodpi/ic_flag_hr.webp | Bin .../res/drawable-nodpi/ic_flag_ht.webp | Bin .../res/drawable-nodpi/ic_flag_hu.webp | Bin .../res/drawable-nodpi/ic_flag_id.webp | Bin .../res/drawable-nodpi/ic_flag_ie.webp | Bin .../res/drawable-nodpi/ic_flag_il.webp | Bin .../res/drawable-nodpi/ic_flag_im.webp | Bin .../res/drawable-nodpi/ic_flag_in.webp | Bin .../res/drawable-nodpi/ic_flag_io.webp | Bin .../res/drawable-nodpi/ic_flag_iq.webp | Bin .../res/drawable-nodpi/ic_flag_ir.webp | Bin .../res/drawable-nodpi/ic_flag_is.webp | Bin .../res/drawable-nodpi/ic_flag_it.webp | Bin .../res/drawable-nodpi/ic_flag_je.webp | Bin .../res/drawable-nodpi/ic_flag_jm.webp | Bin .../res/drawable-nodpi/ic_flag_jo.webp | Bin .../res/drawable-nodpi/ic_flag_jp.webp | Bin .../res/drawable-nodpi/ic_flag_ke.webp | Bin .../res/drawable-nodpi/ic_flag_kg.webp | Bin .../res/drawable-nodpi/ic_flag_kh.webp | Bin .../res/drawable-nodpi/ic_flag_ki.webp | Bin .../res/drawable-nodpi/ic_flag_km.webp | Bin .../res/drawable-nodpi/ic_flag_kn.webp | Bin .../res/drawable-nodpi/ic_flag_kp.webp | Bin .../res/drawable-nodpi/ic_flag_kr.webp | Bin .../res/drawable-nodpi/ic_flag_kw.webp | Bin .../res/drawable-nodpi/ic_flag_ky.webp | Bin .../res/drawable-nodpi/ic_flag_kz.webp | Bin .../res/drawable-nodpi/ic_flag_la.webp | Bin .../res/drawable-nodpi/ic_flag_lb.webp | Bin .../res/drawable-nodpi/ic_flag_lc.webp | Bin .../res/drawable-nodpi/ic_flag_li.webp | Bin .../res/drawable-nodpi/ic_flag_lk.webp | Bin .../res/drawable-nodpi/ic_flag_lr.webp | Bin .../res/drawable-nodpi/ic_flag_ls.webp | Bin .../res/drawable-nodpi/ic_flag_lt.webp | Bin .../res/drawable-nodpi/ic_flag_lu.webp | Bin .../res/drawable-nodpi/ic_flag_lv.webp | Bin .../res/drawable-nodpi/ic_flag_ly.webp | Bin .../res/drawable-nodpi/ic_flag_ma.webp | Bin .../res/drawable-nodpi/ic_flag_mc.webp | Bin .../res/drawable-nodpi/ic_flag_md.webp | Bin .../res/drawable-nodpi/ic_flag_me.webp | Bin .../res/drawable-nodpi/ic_flag_mf.webp | Bin .../res/drawable-nodpi/ic_flag_mg.webp | Bin .../res/drawable-nodpi/ic_flag_mh.webp | Bin .../res/drawable-nodpi/ic_flag_mk.webp | Bin .../res/drawable-nodpi/ic_flag_ml.webp | Bin .../res/drawable-nodpi/ic_flag_mm.webp | Bin .../res/drawable-nodpi/ic_flag_mn.webp | Bin .../res/drawable-nodpi/ic_flag_mo.webp | Bin .../res/drawable-nodpi/ic_flag_mp.webp | Bin .../res/drawable-nodpi/ic_flag_mq.webp | Bin .../res/drawable-nodpi/ic_flag_mr.webp | Bin .../res/drawable-nodpi/ic_flag_ms.webp | Bin .../res/drawable-nodpi/ic_flag_mt.webp | Bin .../res/drawable-nodpi/ic_flag_mu.webp | Bin .../res/drawable-nodpi/ic_flag_mv.webp | Bin .../res/drawable-nodpi/ic_flag_mw.webp | Bin .../res/drawable-nodpi/ic_flag_mx.webp | Bin .../res/drawable-nodpi/ic_flag_my.webp | Bin .../res/drawable-nodpi/ic_flag_mz.webp | Bin .../res/drawable-nodpi/ic_flag_na.webp | Bin .../res/drawable-nodpi/ic_flag_nc.webp | Bin .../res/drawable-nodpi/ic_flag_ne.webp | Bin .../res/drawable-nodpi/ic_flag_nf.webp | Bin .../res/drawable-nodpi/ic_flag_ng.webp | Bin .../res/drawable-nodpi/ic_flag_ni.webp | Bin .../res/drawable-nodpi/ic_flag_nl.webp | Bin .../res/drawable-nodpi/ic_flag_no.webp | Bin .../res/drawable-nodpi/ic_flag_np.webp | Bin .../res/drawable-nodpi/ic_flag_nr.webp | Bin .../res/drawable-nodpi/ic_flag_nu.webp | Bin .../res/drawable-nodpi/ic_flag_nz.webp | Bin .../res/drawable-nodpi/ic_flag_om.webp | Bin .../res/drawable-nodpi/ic_flag_pa.webp | Bin .../res/drawable-nodpi/ic_flag_pe.webp | Bin .../res/drawable-nodpi/ic_flag_pf.webp | Bin .../res/drawable-nodpi/ic_flag_pg.webp | Bin .../res/drawable-nodpi/ic_flag_ph.webp | Bin .../res/drawable-nodpi/ic_flag_pk.webp | Bin .../res/drawable-nodpi/ic_flag_pl.webp | Bin .../res/drawable-nodpi/ic_flag_pm.webp | Bin .../res/drawable-nodpi/ic_flag_pn.webp | Bin .../res/drawable-nodpi/ic_flag_pr.webp | Bin .../res/drawable-nodpi/ic_flag_ps.webp | Bin .../res/drawable-nodpi/ic_flag_pt.webp | Bin .../res/drawable-nodpi/ic_flag_pw.webp | Bin .../res/drawable-nodpi/ic_flag_py.webp | Bin .../res/drawable-nodpi/ic_flag_qa.webp | Bin .../res/drawable-nodpi/ic_flag_re.webp | Bin .../res/drawable-nodpi/ic_flag_ro.webp | Bin .../res/drawable-nodpi/ic_flag_rs.webp | Bin .../res/drawable-nodpi/ic_flag_ru.webp | Bin .../res/drawable-nodpi/ic_flag_rw.webp | Bin .../res/drawable-nodpi/ic_flag_sa.webp | Bin .../res/drawable-nodpi/ic_flag_sb.webp | Bin .../res/drawable-nodpi/ic_flag_sc.webp | Bin .../res/drawable-nodpi/ic_flag_sd.webp | Bin .../res/drawable-nodpi/ic_flag_se.webp | Bin .../res/drawable-nodpi/ic_flag_sg.webp | Bin .../res/drawable-nodpi/ic_flag_sh.webp | Bin .../res/drawable-nodpi/ic_flag_si.webp | Bin .../res/drawable-nodpi/ic_flag_sj.webp | Bin .../res/drawable-nodpi/ic_flag_sk.webp | Bin .../res/drawable-nodpi/ic_flag_sl.webp | Bin .../res/drawable-nodpi/ic_flag_sm.webp | Bin .../res/drawable-nodpi/ic_flag_sn.webp | Bin .../res/drawable-nodpi/ic_flag_so.webp | Bin .../res/drawable-nodpi/ic_flag_sr.webp | Bin .../res/drawable-nodpi/ic_flag_ss.webp | Bin .../res/drawable-nodpi/ic_flag_st.webp | Bin .../res/drawable-nodpi/ic_flag_sv.webp | Bin .../res/drawable-nodpi/ic_flag_sx.webp | Bin .../res/drawable-nodpi/ic_flag_sy.webp | Bin .../res/drawable-nodpi/ic_flag_sz.webp | Bin .../res/drawable-nodpi/ic_flag_tc.webp | Bin .../res/drawable-nodpi/ic_flag_td.webp | Bin .../res/drawable-nodpi/ic_flag_tf.webp | Bin .../res/drawable-nodpi/ic_flag_tg.webp | Bin .../res/drawable-nodpi/ic_flag_th.webp | Bin .../res/drawable-nodpi/ic_flag_tj.webp | Bin .../res/drawable-nodpi/ic_flag_tk.webp | Bin .../res/drawable-nodpi/ic_flag_tl.webp | Bin .../res/drawable-nodpi/ic_flag_tm.webp | Bin .../res/drawable-nodpi/ic_flag_tn.webp | Bin .../res/drawable-nodpi/ic_flag_to.webp | Bin .../res/drawable-nodpi/ic_flag_tr.webp | Bin .../res/drawable-nodpi/ic_flag_tt.webp | Bin .../res/drawable-nodpi/ic_flag_tv.webp | Bin .../res/drawable-nodpi/ic_flag_tw.webp | Bin .../res/drawable-nodpi/ic_flag_tz.webp | Bin .../res/drawable-nodpi/ic_flag_ua.webp | Bin .../res/drawable-nodpi/ic_flag_ug.webp | Bin .../res/drawable-nodpi/ic_flag_um.webp | Bin .../res/drawable-nodpi/ic_flag_us.webp | Bin .../res/drawable-nodpi/ic_flag_uy.webp | Bin .../res/drawable-nodpi/ic_flag_uz.webp | Bin .../res/drawable-nodpi/ic_flag_va.webp | Bin .../res/drawable-nodpi/ic_flag_vc.webp | Bin .../res/drawable-nodpi/ic_flag_ve.webp | Bin .../res/drawable-nodpi/ic_flag_vg.webp | Bin .../res/drawable-nodpi/ic_flag_vi.webp | Bin .../res/drawable-nodpi/ic_flag_vn.webp | Bin .../res/drawable-nodpi/ic_flag_vu.webp | Bin .../res/drawable-nodpi/ic_flag_wf.webp | Bin .../res/drawable-nodpi/ic_flag_ws.webp | Bin .../res/drawable-nodpi/ic_flag_ye.webp | Bin .../res/drawable-nodpi/ic_flag_yt.webp | Bin .../res/drawable-nodpi/ic_flag_za.webp | Bin .../res/drawable-nodpi/ic_flag_zm.webp | Bin .../res/drawable-nodpi/ic_flag_zw.webp | Bin .../res/drawable-nodpi/ic_flag_zz.webp | Bin .../drawable-nodpi/ic_placeholder_user.webp | Bin .../res/drawable-nodpi/video_sell_kin_2x.webp | Bin .../res/drawable-xhdpi/ic_bill_grid.webp | Bin .../res/drawable-xhdpi/ic_bill_hexagons.webp | Bin .../res/drawable-xxhdpi/ic_bill_grid.webp | Bin .../res/drawable-xxhdpi/ic_bill_hexagons.webp | Bin .../res/drawable-xxxhdpi/ic_bill_grid.webp | Bin .../drawable-xxxhdpi/ic_bill_hexagons.webp | Bin .../res/drawable/ic_android_icon.xml | 0 .../res/drawable/ic_apple_icon.xml | 0 .../res/drawable/ic_arrow_back.xml | 0 .../res/drawable/ic_bezier_curve.xml | 0 .../res/drawable/ic_bill_close.xml | 0 .../res/drawable/ic_chain_link.xml | 0 .../res/drawable/ic_chat.xml | 0 .../res/drawable/ic_check.xml | 0 .../res/drawable/ic_check_circle.xml | 0 .../res/drawable/ic_check_white.xml | 0 .../res/drawable/ic_checked_blue.xml | 0 .../res/drawable/ic_checked_green.xml | 0 .../res/drawable/ic_chevron_left.xml | 0 .../res/drawable/ic_chevron_right.xml | 0 .../res/drawable/ic_copy.xml | 0 .../res/drawable/ic_crown.xml | 0 .../res/drawable/ic_delete.xml | 0 .../res/drawable/ic_dropdown.xml | 0 .../drawable/ic_exclamation_octagon_fill.xml | 0 .../res/drawable/ic_file_bend.xml | 0 .../res/drawable/ic_file_download.xml | 0 .../res/drawable/ic_kin_brand.xml | 0 .../res/drawable/ic_kin_red.xml | 0 .../res/drawable/ic_kin_white.xml | 0 .../res/drawable/ic_kin_white_outline.xml | 0 .../res/drawable/ic_kin_white_small.xml | 0 .../res/drawable/ic_remote_send.xml | 0 .../res/drawable/ic_settings_outline.xml | 0 .../res/drawable/ic_share_os.xml | 0 .../res/drawable/ic_twitter_x.xml | 0 .../res/drawable/ic_unchecked.xml | 0 .../res/drawable/ic_wifi_slash.xml | 0 .../res/drawable/ic_x_octagon_fill.xml | 0 .../res/drawable/ic_xmark_red.xml | 0 .../res/values/strings-localized.xml | 0 .../res/values/strings.xml | 0 .../getcode/util/resources/ResourceHelper.kt | 30 +++----------- .../getcode/util/resources/SettingsHelper.kt | 0 .../getcode/util/resources/icons/Delete.kt | 0 .../util/resources/icons/ImageVector.kt | 0 .../util/resources/icons/MessageCircle.kt | 0 ui/resources/test-fixtures/build.gradle.kts | 13 ++++++ .../util/resources/FakeResourceHelper.kt | 2 +- 332 files changed, 91 insertions(+), 63 deletions(-) create mode 100644 ui/resources/src/androidMain/kotlin/com/getcode/util/resources/AndroidResourceHelper.kt rename ui/resources/src/{main/java => androidMain/kotlin}/com/getcode/util/resources/AndroidResources.kt (99%) rename ui/resources/src/{main/java => androidMain/kotlin}/com/getcode/util/resources/AndroidSettingsHelper.kt (100%) rename ui/resources/src/{main/java => androidMain/kotlin}/com/getcode/util/resources/ContentReader.kt (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_bill_globe.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_bill_grid.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_bill_hexagons.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_bill_security_strip.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_bill_waves.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_ad.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_ae.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_af.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_ag.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_ai.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_al.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_am.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_an.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_ao.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_aq.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_ar.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_as.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_at.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_au.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_aw.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_ax.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_az.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_ba.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_bb.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_bd.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_be.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_bf.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_bg.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_bh.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_bi.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_bj.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_bl.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_bm.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_bn.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_bo.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_bq.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_br.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_bs.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_bt.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_bv.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_bw.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_by.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_bz.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_ca.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_cc.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_cd.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_cf.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_cg.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_ch.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_ci.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_ck.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_cl.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_cm.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_cn.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_co.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_cr.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_cu.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_cv.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_cw.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_cx.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_cy.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_cz.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_de.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_dj.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_dk.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_dm.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_do.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_dz.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_ec.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_ee.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_eg.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_eh.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_eo.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_er.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_es.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_et.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_eu.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_fi.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_fj.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_fk.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_fm.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_fo.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_fr.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_ga.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_gb.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_gd.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_ge.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_gf.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_gg.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_gh.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_gi.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_gl.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_gm.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_gn.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_gp.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_gq.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_gr.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_gs.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_gt.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_gu.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_gw.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_gy.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_hk.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_hm.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_hn.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_hr.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_ht.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_hu.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_id.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_ie.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_il.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_im.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_in.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_io.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_iq.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_ir.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_is.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_it.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_je.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_jm.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_jo.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_jp.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_ke.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_kg.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_kh.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_ki.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_km.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_kn.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_kp.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_kr.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_kw.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_ky.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_kz.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_la.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_lb.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_lc.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_li.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_lk.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_lr.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_ls.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_lt.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_lu.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_lv.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_ly.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_ma.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_mc.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_md.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_me.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_mf.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_mg.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_mh.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_mk.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_ml.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_mm.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_mn.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_mo.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_mp.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_mq.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_mr.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_ms.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_mt.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_mu.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_mv.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_mw.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_mx.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_my.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_mz.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_na.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_nc.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_ne.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_nf.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_ng.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_ni.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_nl.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_no.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_np.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_nr.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_nu.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_nz.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_om.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_pa.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_pe.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_pf.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_pg.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_ph.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_pk.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_pl.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_pm.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_pn.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_pr.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_ps.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_pt.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_pw.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_py.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_qa.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_re.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_ro.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_rs.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_ru.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_rw.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_sa.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_sb.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_sc.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_sd.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_se.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_sg.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_sh.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_si.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_sj.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_sk.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_sl.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_sm.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_sn.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_so.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_sr.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_ss.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_st.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_sv.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_sx.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_sy.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_sz.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_tc.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_td.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_tf.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_tg.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_th.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_tj.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_tk.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_tl.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_tm.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_tn.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_to.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_tr.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_tt.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_tv.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_tw.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_tz.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_ua.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_ug.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_um.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_us.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_uy.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_uz.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_va.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_vc.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_ve.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_vg.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_vi.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_vn.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_vu.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_wf.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_ws.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_ye.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_yt.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_za.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_zm.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_zw.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_flag_zz.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/ic_placeholder_user.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-nodpi/video_sell_kin_2x.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-xhdpi/ic_bill_grid.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-xhdpi/ic_bill_hexagons.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-xxhdpi/ic_bill_grid.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-xxhdpi/ic_bill_hexagons.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-xxxhdpi/ic_bill_grid.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable-xxxhdpi/ic_bill_hexagons.webp (100%) rename ui/resources/src/{main => androidMain}/res/drawable/ic_android_icon.xml (100%) rename ui/resources/src/{main => androidMain}/res/drawable/ic_apple_icon.xml (100%) rename ui/resources/src/{main => androidMain}/res/drawable/ic_arrow_back.xml (100%) rename ui/resources/src/{main => androidMain}/res/drawable/ic_bezier_curve.xml (100%) rename ui/resources/src/{main => androidMain}/res/drawable/ic_bill_close.xml (100%) rename ui/resources/src/{main => androidMain}/res/drawable/ic_chain_link.xml (100%) rename ui/resources/src/{main => androidMain}/res/drawable/ic_chat.xml (100%) rename ui/resources/src/{main => androidMain}/res/drawable/ic_check.xml (100%) rename ui/resources/src/{main => androidMain}/res/drawable/ic_check_circle.xml (100%) rename ui/resources/src/{main => androidMain}/res/drawable/ic_check_white.xml (100%) rename ui/resources/src/{main => androidMain}/res/drawable/ic_checked_blue.xml (100%) rename ui/resources/src/{main => androidMain}/res/drawable/ic_checked_green.xml (100%) rename ui/resources/src/{main => androidMain}/res/drawable/ic_chevron_left.xml (100%) rename ui/resources/src/{main => androidMain}/res/drawable/ic_chevron_right.xml (100%) rename ui/resources/src/{main => androidMain}/res/drawable/ic_copy.xml (100%) rename ui/resources/src/{main => androidMain}/res/drawable/ic_crown.xml (100%) rename ui/resources/src/{main => androidMain}/res/drawable/ic_delete.xml (100%) rename ui/resources/src/{main => androidMain}/res/drawable/ic_dropdown.xml (100%) rename ui/resources/src/{main => androidMain}/res/drawable/ic_exclamation_octagon_fill.xml (100%) rename ui/resources/src/{main => androidMain}/res/drawable/ic_file_bend.xml (100%) rename ui/resources/src/{main => androidMain}/res/drawable/ic_file_download.xml (100%) rename ui/resources/src/{main => androidMain}/res/drawable/ic_kin_brand.xml (100%) rename ui/resources/src/{main => androidMain}/res/drawable/ic_kin_red.xml (100%) rename ui/resources/src/{main => androidMain}/res/drawable/ic_kin_white.xml (100%) rename ui/resources/src/{main => androidMain}/res/drawable/ic_kin_white_outline.xml (100%) rename ui/resources/src/{main => androidMain}/res/drawable/ic_kin_white_small.xml (100%) rename ui/resources/src/{main => androidMain}/res/drawable/ic_remote_send.xml (100%) rename ui/resources/src/{main => androidMain}/res/drawable/ic_settings_outline.xml (100%) rename ui/resources/src/{main => androidMain}/res/drawable/ic_share_os.xml (100%) rename ui/resources/src/{main => androidMain}/res/drawable/ic_twitter_x.xml (100%) rename ui/resources/src/{main => androidMain}/res/drawable/ic_unchecked.xml (100%) rename ui/resources/src/{main => androidMain}/res/drawable/ic_wifi_slash.xml (100%) rename ui/resources/src/{main => androidMain}/res/drawable/ic_x_octagon_fill.xml (100%) rename ui/resources/src/{main => androidMain}/res/drawable/ic_xmark_red.xml (100%) rename ui/resources/src/{main => androidMain}/res/values/strings-localized.xml (100%) rename ui/resources/src/{main => androidMain}/res/values/strings.xml (100%) rename ui/resources/src/{main/java => commonMain/kotlin}/com/getcode/util/resources/ResourceHelper.kt (72%) rename ui/resources/src/{main/java => commonMain/kotlin}/com/getcode/util/resources/SettingsHelper.kt (100%) rename ui/resources/src/{main/java => commonMain/kotlin}/com/getcode/util/resources/icons/Delete.kt (100%) rename ui/resources/src/{main/java => commonMain/kotlin}/com/getcode/util/resources/icons/ImageVector.kt (100%) rename ui/resources/src/{main/java => commonMain/kotlin}/com/getcode/util/resources/icons/MessageCircle.kt (100%) create mode 100644 ui/resources/test-fixtures/build.gradle.kts rename ui/resources/{src/testFixtures => test-fixtures/src/main}/kotlin/com/getcode/util/resources/FakeResourceHelper.kt (98%) diff --git a/apps/flipcash/app/src/main/kotlin/com/flipcash/app/inject/AppModule.kt b/apps/flipcash/app/src/main/kotlin/com/flipcash/app/inject/AppModule.kt index cbc65b893a..1c03924035 100644 --- a/apps/flipcash/app/src/main/kotlin/com/flipcash/app/inject/AppModule.kt +++ b/apps/flipcash/app/src/main/kotlin/com/flipcash/app/inject/AppModule.kt @@ -13,6 +13,7 @@ import com.getcode.util.resources.AndroidContentReader import com.getcode.util.resources.AndroidResources import com.getcode.util.resources.AndroidSettingsHelper import com.getcode.util.resources.ContentReader +import com.getcode.util.resources.AndroidResourceHelper import com.getcode.util.resources.ResourceHelper import com.getcode.util.resources.SettingsHelper import dagger.Module @@ -43,9 +44,14 @@ object AppModule { ): ContentReader = AndroidContentReader(context) @Provides - fun providesResourceHelper( + fun providesAndroidResourceHelper( @ApplicationContext context: Context, - ): ResourceHelper = AndroidResources(context) + ): AndroidResourceHelper = AndroidResources(context) + + @Provides + fun providesResourceHelper( + resources: AndroidResourceHelper, + ): ResourceHelper = resources @Provides fun providesSettingsHelper( diff --git a/apps/flipcash/features/backupkey/src/main/kotlin/com/flipcash/app/backupkey/internal/BackupKeyScreenViewModel.kt b/apps/flipcash/features/backupkey/src/main/kotlin/com/flipcash/app/backupkey/internal/BackupKeyScreenViewModel.kt index 082361df7d..ca5c97d98c 100644 --- a/apps/flipcash/features/backupkey/src/main/kotlin/com/flipcash/app/backupkey/internal/BackupKeyScreenViewModel.kt +++ b/apps/flipcash/features/backupkey/src/main/kotlin/com/flipcash/app/backupkey/internal/BackupKeyScreenViewModel.kt @@ -6,7 +6,7 @@ import com.flipcash.libs.coroutines.DispatcherProvider import com.flipcash.services.user.UserManager import com.getcode.libs.qr.QRCodeGenerator import com.getcode.opencode.managers.MnemonicManager -import com.getcode.util.resources.ResourceHelper +import com.getcode.util.resources.AndroidResourceHelper import com.getcode.view.LoadingSuccessState import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.delay @@ -16,7 +16,7 @@ import kotlin.time.Duration.Companion.seconds @HiltViewModel internal class BackupKeyScreenViewModel @Inject constructor( - resources: ResourceHelper, + resources: AndroidResourceHelper, mnemonicManager: MnemonicManager, mediaSaver: MediaSaver, userManager: UserManager, diff --git a/apps/flipcash/features/cash/build.gradle.kts b/apps/flipcash/features/cash/build.gradle.kts index 750d1d06ee..748344538f 100644 --- a/apps/flipcash/features/cash/build.gradle.kts +++ b/apps/flipcash/features/cash/build.gradle.kts @@ -9,7 +9,7 @@ android { dependencies { testImplementation(kotlin("test")) testImplementation(libs.bundles.unit.testing) - testImplementation(testFixtures(project(":ui:resources"))) + testImplementation(project(":ui:resources:test-fixtures")) testImplementation(libs.mockito.kotlin) testImplementation(libs.robolectric) diff --git a/apps/flipcash/features/contact-verification/build.gradle.kts b/apps/flipcash/features/contact-verification/build.gradle.kts index 3f36620e35..38cbfb9c12 100644 --- a/apps/flipcash/features/contact-verification/build.gradle.kts +++ b/apps/flipcash/features/contact-verification/build.gradle.kts @@ -9,7 +9,7 @@ android { dependencies { testImplementation(kotlin("test")) testImplementation(libs.bundles.unit.testing) - testImplementation(testFixtures(project(":ui:resources"))) + testImplementation(project(":ui:resources:test-fixtures")) testImplementation(libs.mockito.kotlin) implementation(libs.bundles.kotlinx.serialization) diff --git a/apps/flipcash/features/login/build.gradle.kts b/apps/flipcash/features/login/build.gradle.kts index 8b4a065713..fdc0140b53 100644 --- a/apps/flipcash/features/login/build.gradle.kts +++ b/apps/flipcash/features/login/build.gradle.kts @@ -9,7 +9,7 @@ android { dependencies { testImplementation(kotlin("test")) testImplementation(libs.bundles.unit.testing) - testImplementation(testFixtures(project(":ui:resources"))) + testImplementation(project(":ui:resources:test-fixtures")) testImplementation(libs.mockito.kotlin) testImplementation(libs.bundles.compose.ui.testing) diff --git a/apps/flipcash/features/login/src/main/kotlin/com/flipcash/app/login/internal/LoginAccessKeyViewModel.kt b/apps/flipcash/features/login/src/main/kotlin/com/flipcash/app/login/internal/LoginAccessKeyViewModel.kt index 8da7981d8e..9c7cd604ed 100644 --- a/apps/flipcash/features/login/src/main/kotlin/com/flipcash/app/login/internal/LoginAccessKeyViewModel.kt +++ b/apps/flipcash/features/login/src/main/kotlin/com/flipcash/app/login/internal/LoginAccessKeyViewModel.kt @@ -15,7 +15,7 @@ import com.flipcash.services.user.UserManager import com.getcode.libs.qr.QRCodeGenerator import com.getcode.manager.BottomBarManager import com.getcode.opencode.managers.MnemonicManager -import com.getcode.util.resources.ResourceHelper +import com.getcode.util.resources.AndroidResourceHelper import com.getcode.view.LoadingSuccessState import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.delay @@ -24,7 +24,7 @@ import javax.inject.Inject @HiltViewModel internal class LoginAccessKeyViewModel @Inject constructor( - private val resources: ResourceHelper, + private val resources: AndroidResourceHelper, mnemonicManager: MnemonicManager, qrCodeGenerator: QRCodeGenerator, mediaSaver: MediaSaver, diff --git a/apps/flipcash/features/menu/build.gradle.kts b/apps/flipcash/features/menu/build.gradle.kts index 3d8bf2d322..c4858b7a56 100644 --- a/apps/flipcash/features/menu/build.gradle.kts +++ b/apps/flipcash/features/menu/build.gradle.kts @@ -11,7 +11,7 @@ dependencies { testImplementation(libs.kotlinx.coroutines.test) testImplementation(libs.robolectric) testImplementation(libs.bundles.unit.testing) - testImplementation(testFixtures(project(":ui:resources"))) + testImplementation(project(":ui:resources:test-fixtures")) implementation(libs.bundles.haze) diff --git a/apps/flipcash/features/myaccount/build.gradle.kts b/apps/flipcash/features/myaccount/build.gradle.kts index 3362ff2d55..781f5d7348 100644 --- a/apps/flipcash/features/myaccount/build.gradle.kts +++ b/apps/flipcash/features/myaccount/build.gradle.kts @@ -10,7 +10,7 @@ dependencies { testImplementation(kotlin("test")) testImplementation(libs.bundles.unit.testing) testImplementation(libs.bundles.compose.ui.testing) - testImplementation(testFixtures(project(":ui:resources"))) + testImplementation(project(":ui:resources:test-fixtures")) implementation(libs.bundles.haze) implementation(libs.compose.paging) diff --git a/apps/flipcash/features/tipping/build.gradle.kts b/apps/flipcash/features/tipping/build.gradle.kts index db2603d881..2c4f4a7910 100644 --- a/apps/flipcash/features/tipping/build.gradle.kts +++ b/apps/flipcash/features/tipping/build.gradle.kts @@ -9,7 +9,7 @@ android { dependencies { testImplementation(kotlin("test")) testImplementation(libs.bundles.unit.testing) - testImplementation(testFixtures(project(":ui:resources"))) + testImplementation(project(":ui:resources:test-fixtures")) testImplementation(testFixtures(project(":apps:flipcash:shared:analytics"))) testImplementation(libs.robolectric) diff --git a/apps/flipcash/features/transactions/build.gradle.kts b/apps/flipcash/features/transactions/build.gradle.kts index bc4506aa2f..777a85f700 100644 --- a/apps/flipcash/features/transactions/build.gradle.kts +++ b/apps/flipcash/features/transactions/build.gradle.kts @@ -9,7 +9,7 @@ android { dependencies { testImplementation(kotlin("test")) testImplementation(libs.bundles.unit.testing) - testImplementation(testFixtures(project(":ui:resources"))) + testImplementation(project(":ui:resources:test-fixtures")) testImplementation(libs.mockito.kotlin) implementation(libs.compose.paging) diff --git a/apps/flipcash/features/user-profile/build.gradle.kts b/apps/flipcash/features/user-profile/build.gradle.kts index 07815031be..e82b55b0a1 100644 --- a/apps/flipcash/features/user-profile/build.gradle.kts +++ b/apps/flipcash/features/user-profile/build.gradle.kts @@ -9,7 +9,7 @@ android { dependencies { testImplementation(kotlin("test")) testImplementation(libs.bundles.unit.testing) - testImplementation(testFixtures(project(":ui:resources"))) + testImplementation(project(":ui:resources:test-fixtures")) testImplementation(libs.mockito.kotlin) implementation(libs.bundles.kotlinx.serialization) diff --git a/apps/flipcash/features/withdrawal/build.gradle.kts b/apps/flipcash/features/withdrawal/build.gradle.kts index a2a6ac1bfc..2d2fb40188 100644 --- a/apps/flipcash/features/withdrawal/build.gradle.kts +++ b/apps/flipcash/features/withdrawal/build.gradle.kts @@ -9,7 +9,7 @@ android { dependencies { testImplementation(kotlin("test")) testImplementation(libs.bundles.unit.testing) - testImplementation(testFixtures(project(":ui:resources"))) + testImplementation(project(":ui:resources:test-fixtures")) testImplementation(libs.bundles.compose.ui.testing) implementation(project(":apps:flipcash:shared:amount-entry")) diff --git a/apps/flipcash/shared/accesskey/src/main/kotlin/com/flipcash/app/accesskey/BaseAccessKeyViewModel.kt b/apps/flipcash/shared/accesskey/src/main/kotlin/com/flipcash/app/accesskey/BaseAccessKeyViewModel.kt index a8886ef6c9..33ef7b3f6a 100644 --- a/apps/flipcash/shared/accesskey/src/main/kotlin/com/flipcash/app/accesskey/BaseAccessKeyViewModel.kt +++ b/apps/flipcash/shared/accesskey/src/main/kotlin/com/flipcash/app/accesskey/BaseAccessKeyViewModel.kt @@ -24,7 +24,7 @@ import com.getcode.theme.Alert import com.getcode.theme.GradientSpec import com.getcode.theme.White import com.getcode.ui.utils.toAGColor -import com.getcode.util.resources.ResourceHelper +import com.getcode.util.resources.AndroidResourceHelper import com.getcode.utils.TraceType import com.getcode.utils.decodeBase64 import com.getcode.utils.trace @@ -59,7 +59,7 @@ data class AccessKeyUiModel( ) abstract class BaseAccessKeyViewModel( - private val resources: ResourceHelper, + private val resources: AndroidResourceHelper, private val mnemonicManager: MnemonicManager, private val mediaSaver: MediaSaver, userManager: UserManager, diff --git a/apps/flipcash/shared/session/build.gradle.kts b/apps/flipcash/shared/session/build.gradle.kts index d89ecb4b3d..9fb357fa99 100644 --- a/apps/flipcash/shared/session/build.gradle.kts +++ b/apps/flipcash/shared/session/build.gradle.kts @@ -10,7 +10,7 @@ dependencies { testImplementation(kotlin("test")) testImplementation(libs.bundles.unit.testing) testImplementation(project(":libs:coroutines:test-fixtures")) - testImplementation(testFixtures(project(":ui:resources"))) + testImplementation(project(":ui:resources:test-fixtures")) implementation(project(":apps:flipcash:shared:blob")) implementation(project(":apps:flipcash:shared:blocklist")) diff --git a/apps/flipcash/shared/shareable/build.gradle.kts b/apps/flipcash/shared/shareable/build.gradle.kts index 574501ca49..52a8a2b5df 100644 --- a/apps/flipcash/shared/shareable/build.gradle.kts +++ b/apps/flipcash/shared/shareable/build.gradle.kts @@ -10,7 +10,7 @@ dependencies { testImplementation(kotlin("test")) testImplementation(libs.bundles.unit.testing) testImplementation(libs.robolectric) - testImplementation(testFixtures(project(":ui:resources"))) + testImplementation(project(":ui:resources:test-fixtures")) implementation(libs.bundles.kotlinx.serialization) diff --git a/apps/flipcash/shared/tokens/build.gradle.kts b/apps/flipcash/shared/tokens/build.gradle.kts index 0c9906a86b..e7825e9269 100644 --- a/apps/flipcash/shared/tokens/build.gradle.kts +++ b/apps/flipcash/shared/tokens/build.gradle.kts @@ -9,7 +9,7 @@ android { dependencies { testImplementation(kotlin("test")) testImplementation(libs.bundles.unit.testing) - testImplementation(testFixtures(project(":ui:resources"))) + testImplementation(project(":ui:resources:test-fixtures")) testImplementation(project(":libs:currency-math:test-fixtures")) testImplementation(libs.mockito.kotlin) diff --git a/apps/flipcash/shared/transaction-history/build.gradle.kts b/apps/flipcash/shared/transaction-history/build.gradle.kts index e79a443160..ee44a7fbf1 100644 --- a/apps/flipcash/shared/transaction-history/build.gradle.kts +++ b/apps/flipcash/shared/transaction-history/build.gradle.kts @@ -22,7 +22,7 @@ dependencies { testImplementation(libs.bundles.unit.testing) testImplementation(libs.robolectric) - testImplementation(testFixtures(project(":ui:resources"))) + testImplementation(project(":ui:resources:test-fixtures")) // Screenshot renders only: FlipcashPreview for the theme, ExchangeStub for the currency flag // LocalExchange would otherwise resolve to ExchangeNull. testImplementation(project(":apps:flipcash:shared:theme")) diff --git a/settings.gradle.kts b/settings.gradle.kts index 4ad45e5ae7..9db5357f60 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -262,6 +262,7 @@ include( ":ui:components", ":ui:navigation", ":ui:resources", + ":ui:resources:test-fixtures", ":ui:scanner", ":ui:testing", ":ui:theme", diff --git a/ui/resources/build.gradle.kts b/ui/resources/build.gradle.kts index cd0dc3c181..47fa09cfd2 100644 --- a/ui/resources/build.gradle.kts +++ b/ui/resources/build.gradle.kts @@ -1,22 +1,29 @@ plugins { - alias(libs.plugins.flipcash.android.library.compose) + alias(libs.plugins.flipcash.kmp.app.library) + alias(libs.plugins.compose.compiler) } -android { - namespace = "${Gradle.codeNamespace}.util.resources" - testFixtures { - enable = true +kotlin { + android { + namespace = "${Gradle.codeNamespace}.util.resources" + androidResources { + enable = true + } } -} - -dependencies { - testFixturesImplementation(platform(libs.compose.bom)) - testFixturesImplementation(libs.compose.ui) - api(libs.androidx.annotation) - api(libs.androidx.appcompat) - api(libs.androidx.core) - implementation(libs.androidx.exifinterface) - api(libs.kotlin.stdlib) - api(libs.kotlinx.coroutines.core) + sourceSets { + commonMain.dependencies { + api(libs.androidx.annotation) + api(libs.kotlin.stdlib) + api(libs.kotlinx.coroutines.core) + api(libs.jetbrains.compose.runtime) + api(libs.jetbrains.compose.ui) + } + androidMain.dependencies { + api(libs.androidx.appcompat) + api(libs.androidx.core) + implementation(libs.androidx.exifinterface) + implementation(libs.timber) + } + } } diff --git a/ui/resources/src/androidMain/kotlin/com/getcode/util/resources/AndroidResourceHelper.kt b/ui/resources/src/androidMain/kotlin/com/getcode/util/resources/AndroidResourceHelper.kt new file mode 100644 index 0000000000..8018d3268a --- /dev/null +++ b/ui/resources/src/androidMain/kotlin/com/getcode/util/resources/AndroidResourceHelper.kt @@ -0,0 +1,19 @@ +package com.getcode.util.resources + +import android.graphics.Typeface +import android.graphics.drawable.Drawable +import android.util.DisplayMetrics +import androidx.annotation.DrawableRes +import androidx.annotation.FontRes +import java.io.File + +/** The [ResourceHelper] members that return Android types. */ +interface AndroidResourceHelper : ResourceHelper { + fun getDir(name: String, mode: Int): File? + + val displayMetrics: DisplayMetrics + + fun getDrawable(@DrawableRes drawableResId: Int): Drawable? + + fun getFont(@FontRes fontResId: Int): Typeface? +} diff --git a/ui/resources/src/main/java/com/getcode/util/resources/AndroidResources.kt b/ui/resources/src/androidMain/kotlin/com/getcode/util/resources/AndroidResources.kt similarity index 99% rename from ui/resources/src/main/java/com/getcode/util/resources/AndroidResources.kt rename to ui/resources/src/androidMain/kotlin/com/getcode/util/resources/AndroidResources.kt index a2fc26c4f4..db84bf05b6 100644 --- a/ui/resources/src/main/java/com/getcode/util/resources/AndroidResources.kt +++ b/ui/resources/src/androidMain/kotlin/com/getcode/util/resources/AndroidResources.kt @@ -15,7 +15,7 @@ import java.io.File class AndroidResources( private val context: Context, -) : ResourceHelper { +) : AndroidResourceHelper { override fun getString(@StringRes resourceId: Int): String { return context.getString(resourceId) diff --git a/ui/resources/src/main/java/com/getcode/util/resources/AndroidSettingsHelper.kt b/ui/resources/src/androidMain/kotlin/com/getcode/util/resources/AndroidSettingsHelper.kt similarity index 100% rename from ui/resources/src/main/java/com/getcode/util/resources/AndroidSettingsHelper.kt rename to ui/resources/src/androidMain/kotlin/com/getcode/util/resources/AndroidSettingsHelper.kt diff --git a/ui/resources/src/main/java/com/getcode/util/resources/ContentReader.kt b/ui/resources/src/androidMain/kotlin/com/getcode/util/resources/ContentReader.kt similarity index 100% rename from ui/resources/src/main/java/com/getcode/util/resources/ContentReader.kt rename to ui/resources/src/androidMain/kotlin/com/getcode/util/resources/ContentReader.kt diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_bill_globe.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_bill_globe.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_bill_globe.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_bill_globe.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_bill_grid.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_bill_grid.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_bill_grid.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_bill_grid.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_bill_hexagons.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_bill_hexagons.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_bill_hexagons.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_bill_hexagons.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_bill_security_strip.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_bill_security_strip.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_bill_security_strip.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_bill_security_strip.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_bill_waves.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_bill_waves.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_bill_waves.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_bill_waves.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_ad.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ad.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_ad.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ad.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_ae.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ae.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_ae.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ae.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_af.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_af.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_af.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_af.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_ag.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ag.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_ag.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ag.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_ai.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ai.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_ai.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ai.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_al.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_al.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_al.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_al.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_am.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_am.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_am.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_am.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_an.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_an.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_an.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_an.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_ao.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ao.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_ao.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ao.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_aq.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_aq.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_aq.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_aq.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_ar.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ar.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_ar.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ar.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_as.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_as.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_as.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_as.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_at.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_at.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_at.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_at.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_au.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_au.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_au.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_au.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_aw.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_aw.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_aw.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_aw.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_ax.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ax.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_ax.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ax.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_az.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_az.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_az.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_az.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_ba.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ba.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_ba.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ba.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_bb.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_bb.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_bb.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_bb.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_bd.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_bd.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_bd.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_bd.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_be.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_be.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_be.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_be.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_bf.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_bf.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_bf.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_bf.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_bg.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_bg.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_bg.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_bg.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_bh.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_bh.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_bh.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_bh.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_bi.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_bi.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_bi.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_bi.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_bj.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_bj.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_bj.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_bj.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_bl.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_bl.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_bl.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_bl.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_bm.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_bm.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_bm.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_bm.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_bn.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_bn.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_bn.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_bn.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_bo.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_bo.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_bo.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_bo.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_bq.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_bq.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_bq.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_bq.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_br.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_br.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_br.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_br.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_bs.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_bs.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_bs.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_bs.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_bt.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_bt.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_bt.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_bt.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_bv.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_bv.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_bv.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_bv.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_bw.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_bw.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_bw.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_bw.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_by.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_by.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_by.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_by.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_bz.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_bz.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_bz.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_bz.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_ca.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ca.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_ca.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ca.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_cc.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_cc.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_cc.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_cc.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_cd.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_cd.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_cd.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_cd.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_cf.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_cf.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_cf.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_cf.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_cg.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_cg.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_cg.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_cg.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_ch.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ch.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_ch.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ch.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_ci.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ci.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_ci.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ci.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_ck.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ck.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_ck.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ck.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_cl.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_cl.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_cl.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_cl.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_cm.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_cm.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_cm.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_cm.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_cn.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_cn.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_cn.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_cn.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_co.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_co.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_co.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_co.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_cr.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_cr.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_cr.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_cr.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_cu.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_cu.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_cu.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_cu.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_cv.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_cv.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_cv.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_cv.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_cw.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_cw.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_cw.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_cw.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_cx.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_cx.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_cx.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_cx.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_cy.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_cy.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_cy.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_cy.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_cz.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_cz.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_cz.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_cz.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_de.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_de.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_de.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_de.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_dj.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_dj.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_dj.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_dj.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_dk.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_dk.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_dk.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_dk.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_dm.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_dm.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_dm.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_dm.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_do.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_do.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_do.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_do.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_dz.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_dz.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_dz.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_dz.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_ec.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ec.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_ec.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ec.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_ee.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ee.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_ee.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ee.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_eg.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_eg.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_eg.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_eg.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_eh.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_eh.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_eh.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_eh.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_eo.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_eo.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_eo.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_eo.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_er.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_er.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_er.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_er.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_es.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_es.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_es.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_es.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_et.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_et.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_et.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_et.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_eu.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_eu.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_eu.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_eu.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_fi.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_fi.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_fi.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_fi.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_fj.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_fj.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_fj.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_fj.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_fk.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_fk.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_fk.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_fk.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_fm.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_fm.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_fm.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_fm.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_fo.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_fo.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_fo.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_fo.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_fr.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_fr.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_fr.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_fr.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_ga.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ga.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_ga.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ga.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_gb.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_gb.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_gb.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_gb.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_gd.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_gd.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_gd.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_gd.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_ge.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ge.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_ge.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ge.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_gf.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_gf.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_gf.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_gf.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_gg.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_gg.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_gg.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_gg.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_gh.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_gh.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_gh.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_gh.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_gi.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_gi.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_gi.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_gi.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_gl.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_gl.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_gl.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_gl.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_gm.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_gm.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_gm.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_gm.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_gn.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_gn.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_gn.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_gn.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_gp.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_gp.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_gp.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_gp.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_gq.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_gq.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_gq.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_gq.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_gr.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_gr.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_gr.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_gr.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_gs.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_gs.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_gs.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_gs.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_gt.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_gt.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_gt.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_gt.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_gu.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_gu.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_gu.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_gu.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_gw.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_gw.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_gw.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_gw.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_gy.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_gy.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_gy.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_gy.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_hk.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_hk.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_hk.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_hk.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_hm.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_hm.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_hm.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_hm.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_hn.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_hn.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_hn.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_hn.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_hr.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_hr.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_hr.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_hr.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_ht.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ht.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_ht.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ht.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_hu.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_hu.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_hu.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_hu.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_id.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_id.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_id.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_id.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_ie.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ie.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_ie.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ie.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_il.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_il.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_il.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_il.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_im.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_im.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_im.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_im.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_in.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_in.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_in.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_in.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_io.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_io.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_io.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_io.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_iq.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_iq.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_iq.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_iq.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_ir.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ir.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_ir.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ir.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_is.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_is.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_is.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_is.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_it.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_it.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_it.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_it.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_je.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_je.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_je.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_je.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_jm.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_jm.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_jm.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_jm.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_jo.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_jo.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_jo.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_jo.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_jp.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_jp.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_jp.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_jp.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_ke.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ke.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_ke.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ke.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_kg.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_kg.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_kg.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_kg.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_kh.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_kh.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_kh.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_kh.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_ki.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ki.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_ki.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ki.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_km.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_km.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_km.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_km.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_kn.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_kn.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_kn.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_kn.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_kp.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_kp.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_kp.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_kp.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_kr.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_kr.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_kr.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_kr.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_kw.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_kw.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_kw.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_kw.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_ky.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ky.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_ky.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ky.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_kz.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_kz.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_kz.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_kz.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_la.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_la.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_la.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_la.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_lb.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_lb.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_lb.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_lb.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_lc.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_lc.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_lc.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_lc.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_li.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_li.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_li.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_li.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_lk.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_lk.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_lk.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_lk.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_lr.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_lr.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_lr.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_lr.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_ls.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ls.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_ls.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ls.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_lt.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_lt.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_lt.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_lt.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_lu.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_lu.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_lu.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_lu.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_lv.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_lv.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_lv.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_lv.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_ly.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ly.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_ly.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ly.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_ma.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ma.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_ma.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ma.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_mc.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_mc.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_mc.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_mc.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_md.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_md.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_md.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_md.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_me.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_me.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_me.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_me.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_mf.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_mf.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_mf.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_mf.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_mg.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_mg.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_mg.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_mg.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_mh.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_mh.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_mh.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_mh.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_mk.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_mk.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_mk.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_mk.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_ml.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ml.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_ml.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ml.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_mm.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_mm.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_mm.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_mm.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_mn.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_mn.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_mn.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_mn.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_mo.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_mo.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_mo.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_mo.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_mp.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_mp.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_mp.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_mp.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_mq.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_mq.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_mq.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_mq.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_mr.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_mr.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_mr.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_mr.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_ms.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ms.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_ms.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ms.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_mt.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_mt.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_mt.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_mt.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_mu.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_mu.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_mu.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_mu.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_mv.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_mv.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_mv.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_mv.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_mw.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_mw.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_mw.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_mw.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_mx.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_mx.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_mx.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_mx.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_my.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_my.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_my.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_my.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_mz.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_mz.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_mz.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_mz.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_na.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_na.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_na.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_na.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_nc.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_nc.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_nc.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_nc.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_ne.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ne.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_ne.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ne.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_nf.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_nf.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_nf.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_nf.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_ng.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ng.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_ng.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ng.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_ni.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ni.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_ni.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ni.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_nl.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_nl.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_nl.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_nl.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_no.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_no.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_no.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_no.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_np.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_np.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_np.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_np.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_nr.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_nr.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_nr.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_nr.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_nu.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_nu.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_nu.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_nu.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_nz.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_nz.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_nz.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_nz.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_om.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_om.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_om.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_om.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_pa.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_pa.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_pa.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_pa.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_pe.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_pe.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_pe.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_pe.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_pf.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_pf.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_pf.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_pf.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_pg.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_pg.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_pg.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_pg.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_ph.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ph.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_ph.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ph.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_pk.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_pk.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_pk.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_pk.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_pl.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_pl.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_pl.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_pl.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_pm.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_pm.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_pm.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_pm.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_pn.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_pn.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_pn.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_pn.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_pr.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_pr.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_pr.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_pr.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_ps.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ps.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_ps.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ps.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_pt.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_pt.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_pt.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_pt.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_pw.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_pw.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_pw.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_pw.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_py.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_py.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_py.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_py.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_qa.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_qa.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_qa.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_qa.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_re.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_re.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_re.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_re.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_ro.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ro.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_ro.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ro.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_rs.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_rs.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_rs.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_rs.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_ru.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ru.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_ru.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ru.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_rw.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_rw.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_rw.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_rw.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_sa.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_sa.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_sa.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_sa.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_sb.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_sb.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_sb.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_sb.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_sc.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_sc.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_sc.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_sc.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_sd.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_sd.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_sd.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_sd.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_se.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_se.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_se.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_se.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_sg.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_sg.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_sg.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_sg.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_sh.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_sh.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_sh.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_sh.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_si.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_si.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_si.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_si.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_sj.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_sj.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_sj.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_sj.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_sk.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_sk.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_sk.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_sk.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_sl.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_sl.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_sl.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_sl.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_sm.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_sm.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_sm.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_sm.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_sn.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_sn.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_sn.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_sn.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_so.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_so.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_so.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_so.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_sr.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_sr.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_sr.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_sr.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_ss.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ss.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_ss.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ss.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_st.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_st.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_st.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_st.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_sv.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_sv.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_sv.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_sv.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_sx.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_sx.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_sx.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_sx.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_sy.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_sy.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_sy.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_sy.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_sz.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_sz.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_sz.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_sz.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_tc.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_tc.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_tc.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_tc.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_td.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_td.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_td.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_td.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_tf.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_tf.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_tf.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_tf.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_tg.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_tg.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_tg.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_tg.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_th.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_th.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_th.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_th.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_tj.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_tj.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_tj.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_tj.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_tk.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_tk.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_tk.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_tk.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_tl.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_tl.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_tl.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_tl.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_tm.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_tm.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_tm.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_tm.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_tn.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_tn.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_tn.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_tn.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_to.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_to.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_to.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_to.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_tr.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_tr.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_tr.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_tr.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_tt.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_tt.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_tt.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_tt.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_tv.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_tv.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_tv.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_tv.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_tw.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_tw.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_tw.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_tw.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_tz.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_tz.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_tz.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_tz.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_ua.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ua.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_ua.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ua.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_ug.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ug.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_ug.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ug.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_um.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_um.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_um.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_um.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_us.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_us.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_us.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_us.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_uy.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_uy.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_uy.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_uy.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_uz.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_uz.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_uz.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_uz.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_va.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_va.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_va.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_va.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_vc.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_vc.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_vc.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_vc.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_ve.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ve.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_ve.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ve.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_vg.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_vg.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_vg.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_vg.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_vi.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_vi.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_vi.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_vi.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_vn.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_vn.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_vn.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_vn.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_vu.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_vu.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_vu.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_vu.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_wf.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_wf.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_wf.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_wf.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_ws.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ws.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_ws.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ws.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_ye.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ye.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_ye.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_ye.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_yt.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_yt.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_yt.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_yt.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_za.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_za.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_za.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_za.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_zm.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_zm.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_zm.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_zm.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_zw.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_zw.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_zw.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_zw.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_flag_zz.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_zz.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_flag_zz.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_flag_zz.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/ic_placeholder_user.webp b/ui/resources/src/androidMain/res/drawable-nodpi/ic_placeholder_user.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/ic_placeholder_user.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/ic_placeholder_user.webp diff --git a/ui/resources/src/main/res/drawable-nodpi/video_sell_kin_2x.webp b/ui/resources/src/androidMain/res/drawable-nodpi/video_sell_kin_2x.webp similarity index 100% rename from ui/resources/src/main/res/drawable-nodpi/video_sell_kin_2x.webp rename to ui/resources/src/androidMain/res/drawable-nodpi/video_sell_kin_2x.webp diff --git a/ui/resources/src/main/res/drawable-xhdpi/ic_bill_grid.webp b/ui/resources/src/androidMain/res/drawable-xhdpi/ic_bill_grid.webp similarity index 100% rename from ui/resources/src/main/res/drawable-xhdpi/ic_bill_grid.webp rename to ui/resources/src/androidMain/res/drawable-xhdpi/ic_bill_grid.webp diff --git a/ui/resources/src/main/res/drawable-xhdpi/ic_bill_hexagons.webp b/ui/resources/src/androidMain/res/drawable-xhdpi/ic_bill_hexagons.webp similarity index 100% rename from ui/resources/src/main/res/drawable-xhdpi/ic_bill_hexagons.webp rename to ui/resources/src/androidMain/res/drawable-xhdpi/ic_bill_hexagons.webp diff --git a/ui/resources/src/main/res/drawable-xxhdpi/ic_bill_grid.webp b/ui/resources/src/androidMain/res/drawable-xxhdpi/ic_bill_grid.webp similarity index 100% rename from ui/resources/src/main/res/drawable-xxhdpi/ic_bill_grid.webp rename to ui/resources/src/androidMain/res/drawable-xxhdpi/ic_bill_grid.webp diff --git a/ui/resources/src/main/res/drawable-xxhdpi/ic_bill_hexagons.webp b/ui/resources/src/androidMain/res/drawable-xxhdpi/ic_bill_hexagons.webp similarity index 100% rename from ui/resources/src/main/res/drawable-xxhdpi/ic_bill_hexagons.webp rename to ui/resources/src/androidMain/res/drawable-xxhdpi/ic_bill_hexagons.webp diff --git a/ui/resources/src/main/res/drawable-xxxhdpi/ic_bill_grid.webp b/ui/resources/src/androidMain/res/drawable-xxxhdpi/ic_bill_grid.webp similarity index 100% rename from ui/resources/src/main/res/drawable-xxxhdpi/ic_bill_grid.webp rename to ui/resources/src/androidMain/res/drawable-xxxhdpi/ic_bill_grid.webp diff --git a/ui/resources/src/main/res/drawable-xxxhdpi/ic_bill_hexagons.webp b/ui/resources/src/androidMain/res/drawable-xxxhdpi/ic_bill_hexagons.webp similarity index 100% rename from ui/resources/src/main/res/drawable-xxxhdpi/ic_bill_hexagons.webp rename to ui/resources/src/androidMain/res/drawable-xxxhdpi/ic_bill_hexagons.webp diff --git a/ui/resources/src/main/res/drawable/ic_android_icon.xml b/ui/resources/src/androidMain/res/drawable/ic_android_icon.xml similarity index 100% rename from ui/resources/src/main/res/drawable/ic_android_icon.xml rename to ui/resources/src/androidMain/res/drawable/ic_android_icon.xml diff --git a/ui/resources/src/main/res/drawable/ic_apple_icon.xml b/ui/resources/src/androidMain/res/drawable/ic_apple_icon.xml similarity index 100% rename from ui/resources/src/main/res/drawable/ic_apple_icon.xml rename to ui/resources/src/androidMain/res/drawable/ic_apple_icon.xml diff --git a/ui/resources/src/main/res/drawable/ic_arrow_back.xml b/ui/resources/src/androidMain/res/drawable/ic_arrow_back.xml similarity index 100% rename from ui/resources/src/main/res/drawable/ic_arrow_back.xml rename to ui/resources/src/androidMain/res/drawable/ic_arrow_back.xml diff --git a/ui/resources/src/main/res/drawable/ic_bezier_curve.xml b/ui/resources/src/androidMain/res/drawable/ic_bezier_curve.xml similarity index 100% rename from ui/resources/src/main/res/drawable/ic_bezier_curve.xml rename to ui/resources/src/androidMain/res/drawable/ic_bezier_curve.xml diff --git a/ui/resources/src/main/res/drawable/ic_bill_close.xml b/ui/resources/src/androidMain/res/drawable/ic_bill_close.xml similarity index 100% rename from ui/resources/src/main/res/drawable/ic_bill_close.xml rename to ui/resources/src/androidMain/res/drawable/ic_bill_close.xml diff --git a/ui/resources/src/main/res/drawable/ic_chain_link.xml b/ui/resources/src/androidMain/res/drawable/ic_chain_link.xml similarity index 100% rename from ui/resources/src/main/res/drawable/ic_chain_link.xml rename to ui/resources/src/androidMain/res/drawable/ic_chain_link.xml diff --git a/ui/resources/src/main/res/drawable/ic_chat.xml b/ui/resources/src/androidMain/res/drawable/ic_chat.xml similarity index 100% rename from ui/resources/src/main/res/drawable/ic_chat.xml rename to ui/resources/src/androidMain/res/drawable/ic_chat.xml diff --git a/ui/resources/src/main/res/drawable/ic_check.xml b/ui/resources/src/androidMain/res/drawable/ic_check.xml similarity index 100% rename from ui/resources/src/main/res/drawable/ic_check.xml rename to ui/resources/src/androidMain/res/drawable/ic_check.xml diff --git a/ui/resources/src/main/res/drawable/ic_check_circle.xml b/ui/resources/src/androidMain/res/drawable/ic_check_circle.xml similarity index 100% rename from ui/resources/src/main/res/drawable/ic_check_circle.xml rename to ui/resources/src/androidMain/res/drawable/ic_check_circle.xml diff --git a/ui/resources/src/main/res/drawable/ic_check_white.xml b/ui/resources/src/androidMain/res/drawable/ic_check_white.xml similarity index 100% rename from ui/resources/src/main/res/drawable/ic_check_white.xml rename to ui/resources/src/androidMain/res/drawable/ic_check_white.xml diff --git a/ui/resources/src/main/res/drawable/ic_checked_blue.xml b/ui/resources/src/androidMain/res/drawable/ic_checked_blue.xml similarity index 100% rename from ui/resources/src/main/res/drawable/ic_checked_blue.xml rename to ui/resources/src/androidMain/res/drawable/ic_checked_blue.xml diff --git a/ui/resources/src/main/res/drawable/ic_checked_green.xml b/ui/resources/src/androidMain/res/drawable/ic_checked_green.xml similarity index 100% rename from ui/resources/src/main/res/drawable/ic_checked_green.xml rename to ui/resources/src/androidMain/res/drawable/ic_checked_green.xml diff --git a/ui/resources/src/main/res/drawable/ic_chevron_left.xml b/ui/resources/src/androidMain/res/drawable/ic_chevron_left.xml similarity index 100% rename from ui/resources/src/main/res/drawable/ic_chevron_left.xml rename to ui/resources/src/androidMain/res/drawable/ic_chevron_left.xml diff --git a/ui/resources/src/main/res/drawable/ic_chevron_right.xml b/ui/resources/src/androidMain/res/drawable/ic_chevron_right.xml similarity index 100% rename from ui/resources/src/main/res/drawable/ic_chevron_right.xml rename to ui/resources/src/androidMain/res/drawable/ic_chevron_right.xml diff --git a/ui/resources/src/main/res/drawable/ic_copy.xml b/ui/resources/src/androidMain/res/drawable/ic_copy.xml similarity index 100% rename from ui/resources/src/main/res/drawable/ic_copy.xml rename to ui/resources/src/androidMain/res/drawable/ic_copy.xml diff --git a/ui/resources/src/main/res/drawable/ic_crown.xml b/ui/resources/src/androidMain/res/drawable/ic_crown.xml similarity index 100% rename from ui/resources/src/main/res/drawable/ic_crown.xml rename to ui/resources/src/androidMain/res/drawable/ic_crown.xml diff --git a/ui/resources/src/main/res/drawable/ic_delete.xml b/ui/resources/src/androidMain/res/drawable/ic_delete.xml similarity index 100% rename from ui/resources/src/main/res/drawable/ic_delete.xml rename to ui/resources/src/androidMain/res/drawable/ic_delete.xml diff --git a/ui/resources/src/main/res/drawable/ic_dropdown.xml b/ui/resources/src/androidMain/res/drawable/ic_dropdown.xml similarity index 100% rename from ui/resources/src/main/res/drawable/ic_dropdown.xml rename to ui/resources/src/androidMain/res/drawable/ic_dropdown.xml diff --git a/ui/resources/src/main/res/drawable/ic_exclamation_octagon_fill.xml b/ui/resources/src/androidMain/res/drawable/ic_exclamation_octagon_fill.xml similarity index 100% rename from ui/resources/src/main/res/drawable/ic_exclamation_octagon_fill.xml rename to ui/resources/src/androidMain/res/drawable/ic_exclamation_octagon_fill.xml diff --git a/ui/resources/src/main/res/drawable/ic_file_bend.xml b/ui/resources/src/androidMain/res/drawable/ic_file_bend.xml similarity index 100% rename from ui/resources/src/main/res/drawable/ic_file_bend.xml rename to ui/resources/src/androidMain/res/drawable/ic_file_bend.xml diff --git a/ui/resources/src/main/res/drawable/ic_file_download.xml b/ui/resources/src/androidMain/res/drawable/ic_file_download.xml similarity index 100% rename from ui/resources/src/main/res/drawable/ic_file_download.xml rename to ui/resources/src/androidMain/res/drawable/ic_file_download.xml diff --git a/ui/resources/src/main/res/drawable/ic_kin_brand.xml b/ui/resources/src/androidMain/res/drawable/ic_kin_brand.xml similarity index 100% rename from ui/resources/src/main/res/drawable/ic_kin_brand.xml rename to ui/resources/src/androidMain/res/drawable/ic_kin_brand.xml diff --git a/ui/resources/src/main/res/drawable/ic_kin_red.xml b/ui/resources/src/androidMain/res/drawable/ic_kin_red.xml similarity index 100% rename from ui/resources/src/main/res/drawable/ic_kin_red.xml rename to ui/resources/src/androidMain/res/drawable/ic_kin_red.xml diff --git a/ui/resources/src/main/res/drawable/ic_kin_white.xml b/ui/resources/src/androidMain/res/drawable/ic_kin_white.xml similarity index 100% rename from ui/resources/src/main/res/drawable/ic_kin_white.xml rename to ui/resources/src/androidMain/res/drawable/ic_kin_white.xml diff --git a/ui/resources/src/main/res/drawable/ic_kin_white_outline.xml b/ui/resources/src/androidMain/res/drawable/ic_kin_white_outline.xml similarity index 100% rename from ui/resources/src/main/res/drawable/ic_kin_white_outline.xml rename to ui/resources/src/androidMain/res/drawable/ic_kin_white_outline.xml diff --git a/ui/resources/src/main/res/drawable/ic_kin_white_small.xml b/ui/resources/src/androidMain/res/drawable/ic_kin_white_small.xml similarity index 100% rename from ui/resources/src/main/res/drawable/ic_kin_white_small.xml rename to ui/resources/src/androidMain/res/drawable/ic_kin_white_small.xml diff --git a/ui/resources/src/main/res/drawable/ic_remote_send.xml b/ui/resources/src/androidMain/res/drawable/ic_remote_send.xml similarity index 100% rename from ui/resources/src/main/res/drawable/ic_remote_send.xml rename to ui/resources/src/androidMain/res/drawable/ic_remote_send.xml diff --git a/ui/resources/src/main/res/drawable/ic_settings_outline.xml b/ui/resources/src/androidMain/res/drawable/ic_settings_outline.xml similarity index 100% rename from ui/resources/src/main/res/drawable/ic_settings_outline.xml rename to ui/resources/src/androidMain/res/drawable/ic_settings_outline.xml diff --git a/ui/resources/src/main/res/drawable/ic_share_os.xml b/ui/resources/src/androidMain/res/drawable/ic_share_os.xml similarity index 100% rename from ui/resources/src/main/res/drawable/ic_share_os.xml rename to ui/resources/src/androidMain/res/drawable/ic_share_os.xml diff --git a/ui/resources/src/main/res/drawable/ic_twitter_x.xml b/ui/resources/src/androidMain/res/drawable/ic_twitter_x.xml similarity index 100% rename from ui/resources/src/main/res/drawable/ic_twitter_x.xml rename to ui/resources/src/androidMain/res/drawable/ic_twitter_x.xml diff --git a/ui/resources/src/main/res/drawable/ic_unchecked.xml b/ui/resources/src/androidMain/res/drawable/ic_unchecked.xml similarity index 100% rename from ui/resources/src/main/res/drawable/ic_unchecked.xml rename to ui/resources/src/androidMain/res/drawable/ic_unchecked.xml diff --git a/ui/resources/src/main/res/drawable/ic_wifi_slash.xml b/ui/resources/src/androidMain/res/drawable/ic_wifi_slash.xml similarity index 100% rename from ui/resources/src/main/res/drawable/ic_wifi_slash.xml rename to ui/resources/src/androidMain/res/drawable/ic_wifi_slash.xml diff --git a/ui/resources/src/main/res/drawable/ic_x_octagon_fill.xml b/ui/resources/src/androidMain/res/drawable/ic_x_octagon_fill.xml similarity index 100% rename from ui/resources/src/main/res/drawable/ic_x_octagon_fill.xml rename to ui/resources/src/androidMain/res/drawable/ic_x_octagon_fill.xml diff --git a/ui/resources/src/main/res/drawable/ic_xmark_red.xml b/ui/resources/src/androidMain/res/drawable/ic_xmark_red.xml similarity index 100% rename from ui/resources/src/main/res/drawable/ic_xmark_red.xml rename to ui/resources/src/androidMain/res/drawable/ic_xmark_red.xml diff --git a/ui/resources/src/main/res/values/strings-localized.xml b/ui/resources/src/androidMain/res/values/strings-localized.xml similarity index 100% rename from ui/resources/src/main/res/values/strings-localized.xml rename to ui/resources/src/androidMain/res/values/strings-localized.xml diff --git a/ui/resources/src/main/res/values/strings.xml b/ui/resources/src/androidMain/res/values/strings.xml similarity index 100% rename from ui/resources/src/main/res/values/strings.xml rename to ui/resources/src/androidMain/res/values/strings.xml diff --git a/ui/resources/src/main/java/com/getcode/util/resources/ResourceHelper.kt b/ui/resources/src/commonMain/kotlin/com/getcode/util/resources/ResourceHelper.kt similarity index 72% rename from ui/resources/src/main/java/com/getcode/util/resources/ResourceHelper.kt rename to ui/resources/src/commonMain/kotlin/com/getcode/util/resources/ResourceHelper.kt index f129e1b0ff..fb339aa961 100644 --- a/ui/resources/src/main/java/com/getcode/util/resources/ResourceHelper.kt +++ b/ui/resources/src/commonMain/kotlin/com/getcode/util/resources/ResourceHelper.kt @@ -1,17 +1,17 @@ package com.getcode.util.resources -import android.graphics.Typeface -import android.graphics.drawable.Drawable -import android.util.DisplayMetrics import androidx.annotation.DimenRes -import androidx.annotation.DrawableRes -import androidx.annotation.FontRes import androidx.annotation.PluralsRes import androidx.annotation.RawRes import androidx.annotation.StringRes import androidx.compose.runtime.staticCompositionLocalOf -import java.io.File +/** + * Looks up app resources by their Android resource ID. + * + * Members that return Android types (`Drawable`, `Typeface`, `DisplayMetrics`, `getDir`) live on + * `AndroidResourceHelper` in androidMain. + */ interface ResourceHelper { fun getString(@StringRes resourceId: Int): String @@ -29,15 +29,7 @@ interface ResourceHelper { fun getDimension(@DimenRes dimenId: Int, default: Float = 0f): Float fun getDimensionPixelSize(@DimenRes dimenId: Int, default: Int = 0): Int - fun getDir(name: String, mode: Int): File? - - val displayMetrics: DisplayMetrics - - fun getDrawable(@DrawableRes drawableResId: Int): Drawable? - fun getIdentifier(name: String, type: ResourceType): Int? - - fun getFont(@FontRes fontResId: Int): Typeface? } sealed interface ResourceType { @@ -70,15 +62,5 @@ private object NoOpResources : ResourceHelper { override fun getDimensionPixelSize(dimenId: Int, default: Int): Int = 0 - override fun getDir(name: String, mode: Int): File? = null - - override val displayMetrics: DisplayMetrics - get() = TODO("Not yet implemented") - - override fun getDrawable(drawableResId: Int): Drawable? = null - override fun getIdentifier(name: String, type: ResourceType): Int? = null - - override fun getFont(fontResId: Int): Typeface? = null - } \ No newline at end of file diff --git a/ui/resources/src/main/java/com/getcode/util/resources/SettingsHelper.kt b/ui/resources/src/commonMain/kotlin/com/getcode/util/resources/SettingsHelper.kt similarity index 100% rename from ui/resources/src/main/java/com/getcode/util/resources/SettingsHelper.kt rename to ui/resources/src/commonMain/kotlin/com/getcode/util/resources/SettingsHelper.kt diff --git a/ui/resources/src/main/java/com/getcode/util/resources/icons/Delete.kt b/ui/resources/src/commonMain/kotlin/com/getcode/util/resources/icons/Delete.kt similarity index 100% rename from ui/resources/src/main/java/com/getcode/util/resources/icons/Delete.kt rename to ui/resources/src/commonMain/kotlin/com/getcode/util/resources/icons/Delete.kt diff --git a/ui/resources/src/main/java/com/getcode/util/resources/icons/ImageVector.kt b/ui/resources/src/commonMain/kotlin/com/getcode/util/resources/icons/ImageVector.kt similarity index 100% rename from ui/resources/src/main/java/com/getcode/util/resources/icons/ImageVector.kt rename to ui/resources/src/commonMain/kotlin/com/getcode/util/resources/icons/ImageVector.kt diff --git a/ui/resources/src/main/java/com/getcode/util/resources/icons/MessageCircle.kt b/ui/resources/src/commonMain/kotlin/com/getcode/util/resources/icons/MessageCircle.kt similarity index 100% rename from ui/resources/src/main/java/com/getcode/util/resources/icons/MessageCircle.kt rename to ui/resources/src/commonMain/kotlin/com/getcode/util/resources/icons/MessageCircle.kt diff --git a/ui/resources/test-fixtures/build.gradle.kts b/ui/resources/test-fixtures/build.gradle.kts new file mode 100644 index 0000000000..8e13fc2224 --- /dev/null +++ b/ui/resources/test-fixtures/build.gradle.kts @@ -0,0 +1,13 @@ +plugins { + alias(libs.plugins.flipcash.android.library) +} + +android { + namespace = "${Gradle.codeNamespace}.util.resources.testfixtures" +} + +dependencies { + api(project(":ui:resources")) + implementation(platform(libs.compose.bom)) + implementation(libs.compose.ui) +} diff --git a/ui/resources/src/testFixtures/kotlin/com/getcode/util/resources/FakeResourceHelper.kt b/ui/resources/test-fixtures/src/main/kotlin/com/getcode/util/resources/FakeResourceHelper.kt similarity index 98% rename from ui/resources/src/testFixtures/kotlin/com/getcode/util/resources/FakeResourceHelper.kt rename to ui/resources/test-fixtures/src/main/kotlin/com/getcode/util/resources/FakeResourceHelper.kt index 973ede92b9..e9881b8b62 100644 --- a/ui/resources/src/testFixtures/kotlin/com/getcode/util/resources/FakeResourceHelper.kt +++ b/ui/resources/test-fixtures/src/main/kotlin/com/getcode/util/resources/FakeResourceHelper.kt @@ -8,7 +8,7 @@ import java.net.URL import java.net.URLClassLoader import java.util.jar.JarFile -class FakeResourceHelper(vararg rClasses: Class<*>) : ResourceHelper { +class FakeResourceHelper(vararg rClasses: Class<*>) : AndroidResourceHelper { private val nameMap: Map = if (rClasses.isNotEmpty()) { buildMapFrom(rClasses) From bad06787479520c109e59554c9ea3f79f865c39a Mon Sep 17 00:00:00 2001 From: Brandon McAnsh Date: Fri, 23 Oct 2026 16:02:33 -0400 Subject: [PATCH 08/50] build(kmp): move currency, models, locale and connectivity APIs to android+jvm Currency icons sit behind an expect object (null on desktop), and SocialProfile's file extension lookup gets a JVM copy of the AOSP MimeTypeMap rules. --- libs/currency/build.gradle.kts | 35 ++++---- .../com/getcode/utils/CurrencyFormat.kt | 35 ++++++++ .../getcode/utils/CurrencyIcons.android.kt | 9 ++ .../drawable/ic_currency_dollar_active.xml | 0 .../drawable/ic_currency_dollar_inactive.xml | 0 .../res/drawable/ic_currency_kin.xml | 0 .../res/drawable/ic_currency_xaf.xml | 0 .../res/drawable/ic_currency_xof.xml | 0 .../kotlin/com/getcode/model/Currency.kt | 0 .../kotlin/com/getcode/model/CurrencyCode.kt | 0 .../kotlin/com/getcode/model/Kin.kt | 4 +- .../kotlin/com/getcode/model/Rate.kt | 4 +- .../kotlin/com/getcode/model/RegionCode.kt | 0 .../kotlin/com/getcode/utils/Currency.kt | 49 +++++++++++ .../kotlin/com/getcode/utils/CurrencyIcons.kt | 11 +++ .../kotlin/com/getcode/utils/CurrencyUtils.kt | 10 +-- .../kotlin/com/getcode/utils/FormatUtils.kt | 0 .../getcode/utils/serializer/KinSerializer.kt | 0 .../utils/serializer/RateSerializer.kt | 0 .../com/getcode/utils/CurrencyIcons.jvm.kt | 7 ++ .../main/kotlin/com/getcode/utils/Currency.kt | 82 ------------------- libs/locale/public/build.gradle.kts | 28 ++++--- .../com/getcode/util/locale/LocaleUtils.kt | 0 .../com/getcode/util/locale/LocaleHelper.kt | 0 libs/models/build.gradle.kts | 30 +++---- .../social/user/FileExtension.android.kt | 6 ++ .../kotlin/com/getcode/model/Cursor.kt | 0 .../kotlin/com/getcode/model/EncryptedData.kt | 0 .../kotlin/com/getcode/model/ID.kt | 0 .../kotlin/com/getcode/model/PointerStatus.kt | 0 .../getcode/model/chat/AnnouncementAction.kt | 0 .../com/getcode/model/chat/ChatMessage.kt | 0 .../kotlin/com/getcode/model/chat/ChatType.kt | 0 .../com/getcode/model/chat/MessageContent.kt | 0 .../com/getcode/model/chat/MessageStatus.kt | 0 .../kotlin/com/getcode/model/chat/Platform.kt | 0 .../kotlin/com/getcode/model/chat/Pointer.kt | 0 .../com/getcode/model/chat/Reference.kt | 0 .../kotlin/com/getcode/model/chat/Sender.kt | 4 +- .../kotlin/com/getcode/model/chat/Title.kt | 0 .../kotlin/com/getcode/model/chat/Verb.kt | 0 .../model/social/user/FileExtension.kt | 4 + .../model/social/user/SocialProfile.kt | 3 +- .../serialization/InstantIso8601Serializer.kt | 0 .../kotlin/com/getcode/utils/UUID.kt | 0 .../utils/serializer/UUIDSerializer.kt | 0 .../model/social/user/FileExtension.jvm.kt | 17 ++++ .../connectivity/public/build.gradle.kts | 41 ++++++---- .../utils/network/ConnectionTypeTest.kt | 0 .../getcode/utils/network/PollUntilTest.kt | 0 .../com/getcode/utils/network/RetryTest.kt | 0 .../connectivity/ConnectionStatusProvider.kt | 0 .../network/NetworkConnectionListener.kt | 0 .../com/getcode/utils/network/Polling.kt | 0 .../kotlin/com/getcode/utils/network/Retry.kt | 0 55 files changed, 226 insertions(+), 153 deletions(-) create mode 100644 libs/currency/src/androidMain/kotlin/com/getcode/utils/CurrencyFormat.kt create mode 100644 libs/currency/src/androidMain/kotlin/com/getcode/utils/CurrencyIcons.android.kt rename libs/currency/src/{main => androidMain}/res/drawable/ic_currency_dollar_active.xml (100%) rename libs/currency/src/{main => androidMain}/res/drawable/ic_currency_dollar_inactive.xml (100%) rename libs/currency/src/{main => androidMain}/res/drawable/ic_currency_kin.xml (100%) rename libs/currency/src/{main => androidMain}/res/drawable/ic_currency_xaf.xml (100%) rename libs/currency/src/{main => androidMain}/res/drawable/ic_currency_xof.xml (100%) rename libs/currency/src/{main => commonMain}/kotlin/com/getcode/model/Currency.kt (100%) rename libs/currency/src/{main => commonMain}/kotlin/com/getcode/model/CurrencyCode.kt (100%) rename libs/currency/src/{main => commonMain}/kotlin/com/getcode/model/Kin.kt (96%) rename libs/currency/src/{main => commonMain}/kotlin/com/getcode/model/Rate.kt (78%) rename libs/currency/src/{main => commonMain}/kotlin/com/getcode/model/RegionCode.kt (100%) create mode 100644 libs/currency/src/commonMain/kotlin/com/getcode/utils/Currency.kt create mode 100644 libs/currency/src/commonMain/kotlin/com/getcode/utils/CurrencyIcons.kt rename libs/currency/src/{main => commonMain}/kotlin/com/getcode/utils/CurrencyUtils.kt (92%) rename libs/currency/src/{main => commonMain}/kotlin/com/getcode/utils/FormatUtils.kt (100%) rename libs/currency/src/{main => commonMain}/kotlin/com/getcode/utils/serializer/KinSerializer.kt (100%) rename libs/currency/src/{main => commonMain}/kotlin/com/getcode/utils/serializer/RateSerializer.kt (100%) create mode 100644 libs/currency/src/jvmMain/kotlin/com/getcode/utils/CurrencyIcons.jvm.kt delete mode 100644 libs/currency/src/main/kotlin/com/getcode/utils/Currency.kt rename libs/locale/public/src/{main => androidMain}/kotlin/com/getcode/util/locale/LocaleUtils.kt (100%) rename libs/locale/public/src/{main => commonMain}/kotlin/com/getcode/util/locale/LocaleHelper.kt (100%) create mode 100644 libs/models/src/androidMain/kotlin/com/getcode/model/social/user/FileExtension.android.kt rename libs/models/src/{main => commonMain}/kotlin/com/getcode/model/Cursor.kt (100%) rename libs/models/src/{main => commonMain}/kotlin/com/getcode/model/EncryptedData.kt (100%) rename libs/models/src/{main => commonMain}/kotlin/com/getcode/model/ID.kt (100%) rename libs/models/src/{main => commonMain}/kotlin/com/getcode/model/PointerStatus.kt (100%) rename libs/models/src/{main => commonMain}/kotlin/com/getcode/model/chat/AnnouncementAction.kt (100%) rename libs/models/src/{main => commonMain}/kotlin/com/getcode/model/chat/ChatMessage.kt (100%) rename libs/models/src/{main => commonMain}/kotlin/com/getcode/model/chat/ChatType.kt (100%) rename libs/models/src/{main => commonMain}/kotlin/com/getcode/model/chat/MessageContent.kt (100%) rename libs/models/src/{main => commonMain}/kotlin/com/getcode/model/chat/MessageStatus.kt (100%) rename libs/models/src/{main => commonMain}/kotlin/com/getcode/model/chat/Platform.kt (100%) rename libs/models/src/{main => commonMain}/kotlin/com/getcode/model/chat/Pointer.kt (100%) rename libs/models/src/{main => commonMain}/kotlin/com/getcode/model/chat/Reference.kt (100%) rename libs/models/src/{main => commonMain}/kotlin/com/getcode/model/chat/Sender.kt (96%) rename libs/models/src/{main => commonMain}/kotlin/com/getcode/model/chat/Title.kt (100%) rename libs/models/src/{main => commonMain}/kotlin/com/getcode/model/chat/Verb.kt (100%) create mode 100644 libs/models/src/commonMain/kotlin/com/getcode/model/social/user/FileExtension.kt rename libs/models/src/{main => commonMain}/kotlin/com/getcode/model/social/user/SocialProfile.kt (96%) rename libs/models/src/{main => commonMain}/kotlin/com/getcode/serialization/InstantIso8601Serializer.kt (100%) rename libs/models/src/{main => commonMain}/kotlin/com/getcode/utils/UUID.kt (100%) rename libs/models/src/{main => commonMain}/kotlin/com/getcode/utils/serializer/UUIDSerializer.kt (100%) create mode 100644 libs/models/src/jvmMain/kotlin/com/getcode/model/social/user/FileExtension.jvm.kt rename libs/network/connectivity/public/src/{test => androidHostTest}/kotlin/com/getcode/utils/network/ConnectionTypeTest.kt (100%) rename libs/network/connectivity/public/src/{test => androidHostTest}/kotlin/com/getcode/utils/network/PollUntilTest.kt (100%) rename libs/network/connectivity/public/src/{test => androidHostTest}/kotlin/com/getcode/utils/network/RetryTest.kt (100%) rename libs/network/connectivity/public/src/{main => androidMain}/kotlin/com/getcode/utils/network/connectivity/ConnectionStatusProvider.kt (100%) rename libs/network/connectivity/public/src/{main => commonMain}/kotlin/com/getcode/utils/network/NetworkConnectionListener.kt (100%) rename libs/network/connectivity/public/src/{main => commonMain}/kotlin/com/getcode/utils/network/Polling.kt (100%) rename libs/network/connectivity/public/src/{main => commonMain}/kotlin/com/getcode/utils/network/Retry.kt (100%) diff --git a/libs/currency/build.gradle.kts b/libs/currency/build.gradle.kts index 67ff4a3adb..7aac9e1ab4 100644 --- a/libs/currency/build.gradle.kts +++ b/libs/currency/build.gradle.kts @@ -1,20 +1,27 @@ plugins { - alias(libs.plugins.flipcash.android.library.compose) + alias(libs.plugins.flipcash.kmp.app.library) + alias(libs.plugins.compose.compiler) id("org.jetbrains.kotlin.plugin.parcelize") } -android { - namespace = "${Gradle.codeNamespace}.libs.currency" -} - -dependencies { - implementation(project(":ui:resources")) - - implementation(libs.bundles.kotlinx.serialization) - implementation(libs.kotlinx.datetime) - implementation(libs.bundles.hilt) +kotlin { + android { + namespace = "${Gradle.codeNamespace}.libs.currency" + androidResources { + enable = true + } + } - androidTestImplementation(libs.androidx.junit) - androidTestImplementation(libs.junit) - androidTestImplementation(libs.androidx.test.runner) + sourceSets { + commonMain.dependencies { + api(project(":libs:parcelable")) + implementation(project(":ui:resources")) + implementation(libs.bundles.kotlinx.serialization) + implementation(libs.kotlinx.datetime) + implementation(libs.kotlinx.coroutines.core) + implementation(libs.jetbrains.compose.runtime) + implementation(libs.androidx.annotation) + implementation(libs.javax.inject) + } + } } diff --git a/libs/currency/src/androidMain/kotlin/com/getcode/utils/CurrencyFormat.kt b/libs/currency/src/androidMain/kotlin/com/getcode/utils/CurrencyFormat.kt new file mode 100644 index 0000000000..448b41b74c --- /dev/null +++ b/libs/currency/src/androidMain/kotlin/com/getcode/utils/CurrencyFormat.kt @@ -0,0 +1,35 @@ +package com.getcode.utils + +import com.getcode.model.Currency +import com.getcode.util.resources.ResourceHelper + +fun Currency.format(resources: ResourceHelper, amount: Double): String { + return formatAmountString( + resources, + this, + amount + ) +} + +fun formatAmountString( + resources: ResourceHelper, + currency: Currency, + amount: Double, + kinSuffix: String = resources.getString(com.getcode.util.resources.R.string.core_kin), + suffix: String = resources.getString(com.getcode.util.resources.R.string.core_ofKin) +): String { + val isKin = currency.code == Currency.Kin.code + + return if (isKin) { + "${FormatUtils.formatWholeRoundDown(amount)}${if (kinSuffix.isNotEmpty()) " $kinSuffix" else ""}" + } else { + when { + currency.code == currency.symbol -> { + FormatUtils.format(amount) + if (suffix.isNotEmpty()) " $suffix" else "" + } + else -> { + "${currency.symbol}${FormatUtils.format(amount)}" + if (suffix.isNotEmpty()) " $suffix" else "" + } + } + } +} \ No newline at end of file diff --git a/libs/currency/src/androidMain/kotlin/com/getcode/utils/CurrencyIcons.android.kt b/libs/currency/src/androidMain/kotlin/com/getcode/utils/CurrencyIcons.android.kt new file mode 100644 index 0000000000..d2c437ef80 --- /dev/null +++ b/libs/currency/src/androidMain/kotlin/com/getcode/utils/CurrencyIcons.android.kt @@ -0,0 +1,9 @@ +package com.getcode.utils + +import com.getcode.libs.currency.R + +internal actual object CurrencyIcons { + actual val kin: Int? = R.drawable.ic_currency_kin + actual val xaf: Int? = R.drawable.ic_currency_xaf + actual val xof: Int? = R.drawable.ic_currency_xof +} diff --git a/libs/currency/src/main/res/drawable/ic_currency_dollar_active.xml b/libs/currency/src/androidMain/res/drawable/ic_currency_dollar_active.xml similarity index 100% rename from libs/currency/src/main/res/drawable/ic_currency_dollar_active.xml rename to libs/currency/src/androidMain/res/drawable/ic_currency_dollar_active.xml diff --git a/libs/currency/src/main/res/drawable/ic_currency_dollar_inactive.xml b/libs/currency/src/androidMain/res/drawable/ic_currency_dollar_inactive.xml similarity index 100% rename from libs/currency/src/main/res/drawable/ic_currency_dollar_inactive.xml rename to libs/currency/src/androidMain/res/drawable/ic_currency_dollar_inactive.xml diff --git a/libs/currency/src/main/res/drawable/ic_currency_kin.xml b/libs/currency/src/androidMain/res/drawable/ic_currency_kin.xml similarity index 100% rename from libs/currency/src/main/res/drawable/ic_currency_kin.xml rename to libs/currency/src/androidMain/res/drawable/ic_currency_kin.xml diff --git a/libs/currency/src/main/res/drawable/ic_currency_xaf.xml b/libs/currency/src/androidMain/res/drawable/ic_currency_xaf.xml similarity index 100% rename from libs/currency/src/main/res/drawable/ic_currency_xaf.xml rename to libs/currency/src/androidMain/res/drawable/ic_currency_xaf.xml diff --git a/libs/currency/src/main/res/drawable/ic_currency_xof.xml b/libs/currency/src/androidMain/res/drawable/ic_currency_xof.xml similarity index 100% rename from libs/currency/src/main/res/drawable/ic_currency_xof.xml rename to libs/currency/src/androidMain/res/drawable/ic_currency_xof.xml diff --git a/libs/currency/src/main/kotlin/com/getcode/model/Currency.kt b/libs/currency/src/commonMain/kotlin/com/getcode/model/Currency.kt similarity index 100% rename from libs/currency/src/main/kotlin/com/getcode/model/Currency.kt rename to libs/currency/src/commonMain/kotlin/com/getcode/model/Currency.kt diff --git a/libs/currency/src/main/kotlin/com/getcode/model/CurrencyCode.kt b/libs/currency/src/commonMain/kotlin/com/getcode/model/CurrencyCode.kt similarity index 100% rename from libs/currency/src/main/kotlin/com/getcode/model/CurrencyCode.kt rename to libs/currency/src/commonMain/kotlin/com/getcode/model/CurrencyCode.kt diff --git a/libs/currency/src/main/kotlin/com/getcode/model/Kin.kt b/libs/currency/src/commonMain/kotlin/com/getcode/model/Kin.kt similarity index 96% rename from libs/currency/src/main/kotlin/com/getcode/model/Kin.kt rename to libs/currency/src/commonMain/kotlin/com/getcode/model/Kin.kt index ae4df25d3c..ca6d385115 100644 --- a/libs/currency/src/main/kotlin/com/getcode/model/Kin.kt +++ b/libs/currency/src/commonMain/kotlin/com/getcode/model/Kin.kt @@ -1,7 +1,7 @@ package com.getcode.model -import android.os.Parcelable -import kotlinx.parcelize.Parcelize +import com.getcode.libs.parcelable.Parcelable +import com.getcode.libs.parcelable.Parcelize import java.math.BigDecimal import java.math.RoundingMode import kotlin.math.floor diff --git a/libs/currency/src/main/kotlin/com/getcode/model/Rate.kt b/libs/currency/src/commonMain/kotlin/com/getcode/model/Rate.kt similarity index 78% rename from libs/currency/src/main/kotlin/com/getcode/model/Rate.kt rename to libs/currency/src/commonMain/kotlin/com/getcode/model/Rate.kt index 1fe4ab900c..6cee497078 100644 --- a/libs/currency/src/main/kotlin/com/getcode/model/Rate.kt +++ b/libs/currency/src/commonMain/kotlin/com/getcode/model/Rate.kt @@ -1,7 +1,7 @@ package com.getcode.model -import android.os.Parcelable -import kotlinx.parcelize.Parcelize +import com.getcode.libs.parcelable.Parcelable +import com.getcode.libs.parcelable.Parcelize import kotlinx.serialization.Serializable @Parcelize diff --git a/libs/currency/src/main/kotlin/com/getcode/model/RegionCode.kt b/libs/currency/src/commonMain/kotlin/com/getcode/model/RegionCode.kt similarity index 100% rename from libs/currency/src/main/kotlin/com/getcode/model/RegionCode.kt rename to libs/currency/src/commonMain/kotlin/com/getcode/model/RegionCode.kt diff --git a/libs/currency/src/commonMain/kotlin/com/getcode/utils/Currency.kt b/libs/currency/src/commonMain/kotlin/com/getcode/utils/Currency.kt new file mode 100644 index 0000000000..55574c3fc0 --- /dev/null +++ b/libs/currency/src/commonMain/kotlin/com/getcode/utils/Currency.kt @@ -0,0 +1,49 @@ +package com.getcode.utils + +import androidx.annotation.DrawableRes +import androidx.compose.runtime.Composable +import com.getcode.model.Currency +import com.getcode.model.CurrencyCode +import com.getcode.util.resources.LocalResources +import com.getcode.util.resources.ResourceHelper +import com.getcode.util.resources.ResourceType + +val Currency.Companion.Kin: Currency + get() = Currency(CurrencyCode.KIN.name, "Kin", CurrencyIcons.kin, "K", 1.00,) + +@get:DrawableRes +val CurrencyCode.flagResId: Int? + @Composable get() { + if (this.name == "KIN") return CurrencyIcons.kin + if (this.name == "XAF") return CurrencyIcons.xaf + if (this.name == "XOF") return CurrencyIcons.xof + + return getRegion()?.name?.let { + getFlag(LocalResources.current!!, it) + } + } + +@DrawableRes +fun Currency.flagResId(resourceHelper: ResourceHelper): Int? { + if (code == "KIN") return CurrencyIcons.kin + if (code == "XAF") return CurrencyIcons.xaf + if (code == "XOF") return CurrencyIcons.xof + + return CurrencyCode.tryValueOf(code)?.let { currency -> + currency.getRegion()?.name + }?.let { regionName -> + getFlag(resourceHelper, regionName) + } +} + + +@DrawableRes +@Suppress("DiscouragedApi") +private fun getFlag(resourceHelper: ResourceHelper, countryCode: String): Int? { + if (countryCode.isEmpty()) return null + val resourceName = "ic_flag_${countryCode.lowercase()}" + return resourceHelper.getIdentifier( + resourceName, + ResourceType.Drawable, + ) +} diff --git a/libs/currency/src/commonMain/kotlin/com/getcode/utils/CurrencyIcons.kt b/libs/currency/src/commonMain/kotlin/com/getcode/utils/CurrencyIcons.kt new file mode 100644 index 0000000000..f3cfe6c501 --- /dev/null +++ b/libs/currency/src/commonMain/kotlin/com/getcode/utils/CurrencyIcons.kt @@ -0,0 +1,11 @@ +package com.getcode.utils + +/** + * Drawable resource IDs for the currencies that have no country flag. Android maps them to the + * module's drawables; desktop has no Android resources, so they are null there. + */ +internal expect object CurrencyIcons { + val kin: Int? + val xaf: Int? + val xof: Int? +} diff --git a/libs/currency/src/main/kotlin/com/getcode/utils/CurrencyUtils.kt b/libs/currency/src/commonMain/kotlin/com/getcode/utils/CurrencyUtils.kt similarity index 92% rename from libs/currency/src/main/kotlin/com/getcode/utils/CurrencyUtils.kt rename to libs/currency/src/commonMain/kotlin/com/getcode/utils/CurrencyUtils.kt index 30e8123a62..ad134fbfc3 100644 --- a/libs/currency/src/main/kotlin/com/getcode/utils/CurrencyUtils.kt +++ b/libs/currency/src/commonMain/kotlin/com/getcode/utils/CurrencyUtils.kt @@ -1,9 +1,7 @@ package com.getcode.utils -import android.annotation.SuppressLint import androidx.compose.runtime.ProvidableCompositionLocal import androidx.compose.runtime.staticCompositionLocalOf -import com.getcode.libs.currency.R import com.getcode.model.Currency import com.getcode.model.CurrencyCode import com.getcode.model.Rate @@ -52,9 +50,9 @@ class CurrencyUtils @Inject constructor( fun getFlagByCurrency(currencyCode: String?): Int? { currencyCode ?: return null - if (currencyCode == "KIN") return R.drawable.ic_currency_kin - if (currencyCode == "XAF") return R.drawable.ic_currency_xaf - if (currencyCode == "XOF") return R.drawable.ic_currency_xof + if (currencyCode == "KIN") return CurrencyIcons.kin + if (currencyCode == "XAF") return CurrencyIcons.xaf + if (currencyCode == "XOF") return CurrencyIcons.xof return CurrencyCode.tryValueOf(currencyCode)?.let { currency -> currency.getRegion()?.name @@ -63,7 +61,7 @@ class CurrencyUtils @Inject constructor( } } - @SuppressLint("DiscouragedApi") + @Suppress("DiscouragedApi") fun getFlag(countryCode: String): Int? { if (countryCode.isEmpty()) return null val resourceName = "ic_flag_${countryCode.lowercase()}" diff --git a/libs/currency/src/main/kotlin/com/getcode/utils/FormatUtils.kt b/libs/currency/src/commonMain/kotlin/com/getcode/utils/FormatUtils.kt similarity index 100% rename from libs/currency/src/main/kotlin/com/getcode/utils/FormatUtils.kt rename to libs/currency/src/commonMain/kotlin/com/getcode/utils/FormatUtils.kt diff --git a/libs/currency/src/main/kotlin/com/getcode/utils/serializer/KinSerializer.kt b/libs/currency/src/commonMain/kotlin/com/getcode/utils/serializer/KinSerializer.kt similarity index 100% rename from libs/currency/src/main/kotlin/com/getcode/utils/serializer/KinSerializer.kt rename to libs/currency/src/commonMain/kotlin/com/getcode/utils/serializer/KinSerializer.kt diff --git a/libs/currency/src/main/kotlin/com/getcode/utils/serializer/RateSerializer.kt b/libs/currency/src/commonMain/kotlin/com/getcode/utils/serializer/RateSerializer.kt similarity index 100% rename from libs/currency/src/main/kotlin/com/getcode/utils/serializer/RateSerializer.kt rename to libs/currency/src/commonMain/kotlin/com/getcode/utils/serializer/RateSerializer.kt diff --git a/libs/currency/src/jvmMain/kotlin/com/getcode/utils/CurrencyIcons.jvm.kt b/libs/currency/src/jvmMain/kotlin/com/getcode/utils/CurrencyIcons.jvm.kt new file mode 100644 index 0000000000..a2b87f0a88 --- /dev/null +++ b/libs/currency/src/jvmMain/kotlin/com/getcode/utils/CurrencyIcons.jvm.kt @@ -0,0 +1,7 @@ +package com.getcode.utils + +internal actual object CurrencyIcons { + actual val kin: Int? = null + actual val xaf: Int? = null + actual val xof: Int? = null +} diff --git a/libs/currency/src/main/kotlin/com/getcode/utils/Currency.kt b/libs/currency/src/main/kotlin/com/getcode/utils/Currency.kt deleted file mode 100644 index a735ba2f66..0000000000 --- a/libs/currency/src/main/kotlin/com/getcode/utils/Currency.kt +++ /dev/null @@ -1,82 +0,0 @@ -package com.getcode.utils - -import android.annotation.SuppressLint -import androidx.annotation.DrawableRes -import androidx.compose.runtime.Composable -import com.getcode.libs.currency.R -import com.getcode.model.Currency -import com.getcode.model.CurrencyCode -import com.getcode.util.resources.LocalResources -import com.getcode.util.resources.ResourceHelper -import com.getcode.util.resources.ResourceType - -val Currency.Companion.Kin: Currency - get() = Currency(CurrencyCode.KIN.name, "Kin", R.drawable.ic_currency_kin, "K", 1.00,) - -@get:DrawableRes -val CurrencyCode.flagResId: Int? - @Composable get() { - if (this.name == "KIN") return R.drawable.ic_currency_kin - if (this.name == "XAF") return R.drawable.ic_currency_xaf - if (this.name == "XOF") return R.drawable.ic_currency_xof - - return getRegion()?.name?.let { - getFlag(LocalResources.current!!, it) - } - } - -@DrawableRes -fun Currency.flagResId(resourceHelper: ResourceHelper): Int? { - if (code == "KIN") return R.drawable.ic_currency_kin - if (code == "XAF") return R.drawable.ic_currency_xaf - if (code == "XOF") return R.drawable.ic_currency_xof - - return CurrencyCode.tryValueOf(code)?.let { currency -> - currency.getRegion()?.name - }?.let { regionName -> - getFlag(resourceHelper, regionName) - } -} - - -@DrawableRes -@SuppressLint("DiscouragedApi") -private fun getFlag(resourceHelper: ResourceHelper, countryCode: String): Int? { - if (countryCode.isEmpty()) return null - val resourceName = "ic_flag_${countryCode.lowercase()}" - return resourceHelper.getIdentifier( - resourceName, - ResourceType.Drawable, - ) -} - -fun Currency.format(resources: ResourceHelper, amount: Double): String { - return formatAmountString( - resources, - this, - amount - ) -} - -fun formatAmountString( - resources: ResourceHelper, - currency: Currency, - amount: Double, - kinSuffix: String = resources.getString(com.getcode.util.resources.R.string.core_kin), - suffix: String = resources.getString(com.getcode.util.resources.R.string.core_ofKin) -): String { - val isKin = currency.code == Currency.Kin.code - - return if (isKin) { - "${FormatUtils.formatWholeRoundDown(amount)}${if (kinSuffix.isNotEmpty()) " $kinSuffix" else ""}" - } else { - when { - currency.code == currency.symbol -> { - FormatUtils.format(amount) + if (suffix.isNotEmpty()) " $suffix" else "" - } - else -> { - "${currency.symbol}${FormatUtils.format(amount)}" + if (suffix.isNotEmpty()) " $suffix" else "" - } - } - } -} \ No newline at end of file diff --git a/libs/locale/public/build.gradle.kts b/libs/locale/public/build.gradle.kts index 9c5d3353bf..efd1055d63 100644 --- a/libs/locale/public/build.gradle.kts +++ b/libs/locale/public/build.gradle.kts @@ -1,16 +1,22 @@ plugins { - alias(libs.plugins.flipcash.android.library) + alias(libs.plugins.flipcash.kmp.app.library) } -android { - namespace = "${Gradle.codeNamespace}.util.locale" -} +kotlin { + android { + namespace = "${Gradle.codeNamespace}.util.locale" + } -dependencies { - implementation(project(":libs:datetime")) - implementation(project(":libs:currency")) - implementation(libs.okhttp) - api(libs.androidx.annotation) - api(libs.kotlin.stdlib) - api(libs.kotlinx.coroutines.core) + sourceSets { + commonMain.dependencies { + implementation(project(":libs:datetime")) + implementation(project(":libs:currency")) + api(libs.androidx.annotation) + api(libs.kotlin.stdlib) + api(libs.kotlinx.coroutines.core) + } + androidMain.dependencies { + implementation(libs.okhttp) + } + } } diff --git a/libs/locale/public/src/main/kotlin/com/getcode/util/locale/LocaleUtils.kt b/libs/locale/public/src/androidMain/kotlin/com/getcode/util/locale/LocaleUtils.kt similarity index 100% rename from libs/locale/public/src/main/kotlin/com/getcode/util/locale/LocaleUtils.kt rename to libs/locale/public/src/androidMain/kotlin/com/getcode/util/locale/LocaleUtils.kt diff --git a/libs/locale/public/src/main/kotlin/com/getcode/util/locale/LocaleHelper.kt b/libs/locale/public/src/commonMain/kotlin/com/getcode/util/locale/LocaleHelper.kt similarity index 100% rename from libs/locale/public/src/main/kotlin/com/getcode/util/locale/LocaleHelper.kt rename to libs/locale/public/src/commonMain/kotlin/com/getcode/util/locale/LocaleHelper.kt diff --git a/libs/models/build.gradle.kts b/libs/models/build.gradle.kts index f7d77d5385..f5266c6654 100644 --- a/libs/models/build.gradle.kts +++ b/libs/models/build.gradle.kts @@ -1,20 +1,22 @@ plugins { - alias(libs.plugins.flipcash.android.library) + alias(libs.plugins.flipcash.kmp.app.library) id("org.jetbrains.kotlin.plugin.parcelize") } -android { - namespace = "${Gradle.codeNamespace}.libs.models" -} - -dependencies { - implementation(project(":libs:encryption:base58")) - implementation(project(":libs:encryption:ed25519")) - implementation(project(":libs:encryption:keys")) - implementation(project(":libs:encryption:utils")) - implementation(project(":libs:currency")) - implementation(libs.bundles.kotlinx.serialization) +kotlin { + android { + namespace = "${Gradle.codeNamespace}.libs.models" + } - implementation(libs.androidx.room.runtime) - implementation(libs.androidx.room.ktx) + sourceSets { + commonMain.dependencies { + api(project(":libs:parcelable")) + implementation(project(":libs:encryption:base58")) + implementation(project(":libs:encryption:ed25519")) + implementation(project(":libs:encryption:keys")) + implementation(project(":libs:encryption:utils")) + implementation(project(":libs:currency")) + implementation(libs.bundles.kotlinx.serialization) + } + } } diff --git a/libs/models/src/androidMain/kotlin/com/getcode/model/social/user/FileExtension.android.kt b/libs/models/src/androidMain/kotlin/com/getcode/model/social/user/FileExtension.android.kt new file mode 100644 index 0000000000..af0eda358d --- /dev/null +++ b/libs/models/src/androidMain/kotlin/com/getcode/model/social/user/FileExtension.android.kt @@ -0,0 +1,6 @@ +package com.getcode.model.social.user + +import android.webkit.MimeTypeMap + +internal actual fun fileExtensionFromUrl(url: String): String = + MimeTypeMap.getFileExtensionFromUrl(url) diff --git a/libs/models/src/main/kotlin/com/getcode/model/Cursor.kt b/libs/models/src/commonMain/kotlin/com/getcode/model/Cursor.kt similarity index 100% rename from libs/models/src/main/kotlin/com/getcode/model/Cursor.kt rename to libs/models/src/commonMain/kotlin/com/getcode/model/Cursor.kt diff --git a/libs/models/src/main/kotlin/com/getcode/model/EncryptedData.kt b/libs/models/src/commonMain/kotlin/com/getcode/model/EncryptedData.kt similarity index 100% rename from libs/models/src/main/kotlin/com/getcode/model/EncryptedData.kt rename to libs/models/src/commonMain/kotlin/com/getcode/model/EncryptedData.kt diff --git a/libs/models/src/main/kotlin/com/getcode/model/ID.kt b/libs/models/src/commonMain/kotlin/com/getcode/model/ID.kt similarity index 100% rename from libs/models/src/main/kotlin/com/getcode/model/ID.kt rename to libs/models/src/commonMain/kotlin/com/getcode/model/ID.kt diff --git a/libs/models/src/main/kotlin/com/getcode/model/PointerStatus.kt b/libs/models/src/commonMain/kotlin/com/getcode/model/PointerStatus.kt similarity index 100% rename from libs/models/src/main/kotlin/com/getcode/model/PointerStatus.kt rename to libs/models/src/commonMain/kotlin/com/getcode/model/PointerStatus.kt diff --git a/libs/models/src/main/kotlin/com/getcode/model/chat/AnnouncementAction.kt b/libs/models/src/commonMain/kotlin/com/getcode/model/chat/AnnouncementAction.kt similarity index 100% rename from libs/models/src/main/kotlin/com/getcode/model/chat/AnnouncementAction.kt rename to libs/models/src/commonMain/kotlin/com/getcode/model/chat/AnnouncementAction.kt diff --git a/libs/models/src/main/kotlin/com/getcode/model/chat/ChatMessage.kt b/libs/models/src/commonMain/kotlin/com/getcode/model/chat/ChatMessage.kt similarity index 100% rename from libs/models/src/main/kotlin/com/getcode/model/chat/ChatMessage.kt rename to libs/models/src/commonMain/kotlin/com/getcode/model/chat/ChatMessage.kt diff --git a/libs/models/src/main/kotlin/com/getcode/model/chat/ChatType.kt b/libs/models/src/commonMain/kotlin/com/getcode/model/chat/ChatType.kt similarity index 100% rename from libs/models/src/main/kotlin/com/getcode/model/chat/ChatType.kt rename to libs/models/src/commonMain/kotlin/com/getcode/model/chat/ChatType.kt diff --git a/libs/models/src/main/kotlin/com/getcode/model/chat/MessageContent.kt b/libs/models/src/commonMain/kotlin/com/getcode/model/chat/MessageContent.kt similarity index 100% rename from libs/models/src/main/kotlin/com/getcode/model/chat/MessageContent.kt rename to libs/models/src/commonMain/kotlin/com/getcode/model/chat/MessageContent.kt diff --git a/libs/models/src/main/kotlin/com/getcode/model/chat/MessageStatus.kt b/libs/models/src/commonMain/kotlin/com/getcode/model/chat/MessageStatus.kt similarity index 100% rename from libs/models/src/main/kotlin/com/getcode/model/chat/MessageStatus.kt rename to libs/models/src/commonMain/kotlin/com/getcode/model/chat/MessageStatus.kt diff --git a/libs/models/src/main/kotlin/com/getcode/model/chat/Platform.kt b/libs/models/src/commonMain/kotlin/com/getcode/model/chat/Platform.kt similarity index 100% rename from libs/models/src/main/kotlin/com/getcode/model/chat/Platform.kt rename to libs/models/src/commonMain/kotlin/com/getcode/model/chat/Platform.kt diff --git a/libs/models/src/main/kotlin/com/getcode/model/chat/Pointer.kt b/libs/models/src/commonMain/kotlin/com/getcode/model/chat/Pointer.kt similarity index 100% rename from libs/models/src/main/kotlin/com/getcode/model/chat/Pointer.kt rename to libs/models/src/commonMain/kotlin/com/getcode/model/chat/Pointer.kt diff --git a/libs/models/src/main/kotlin/com/getcode/model/chat/Reference.kt b/libs/models/src/commonMain/kotlin/com/getcode/model/chat/Reference.kt similarity index 100% rename from libs/models/src/main/kotlin/com/getcode/model/chat/Reference.kt rename to libs/models/src/commonMain/kotlin/com/getcode/model/chat/Reference.kt diff --git a/libs/models/src/main/kotlin/com/getcode/model/chat/Sender.kt b/libs/models/src/commonMain/kotlin/com/getcode/model/chat/Sender.kt similarity index 96% rename from libs/models/src/main/kotlin/com/getcode/model/chat/Sender.kt rename to libs/models/src/commonMain/kotlin/com/getcode/model/chat/Sender.kt index 7b95a8915e..ef23584c66 100644 --- a/libs/models/src/main/kotlin/com/getcode/model/chat/Sender.kt +++ b/libs/models/src/commonMain/kotlin/com/getcode/model/chat/Sender.kt @@ -1,9 +1,9 @@ package com.getcode.model.chat -import android.os.Parcelable +import com.getcode.libs.parcelable.Parcelable import com.getcode.model.ID import com.getcode.model.social.user.XExtraData -import kotlinx.parcelize.Parcelize +import com.getcode.libs.parcelable.Parcelize import kotlinx.serialization.json.Json @Parcelize diff --git a/libs/models/src/main/kotlin/com/getcode/model/chat/Title.kt b/libs/models/src/commonMain/kotlin/com/getcode/model/chat/Title.kt similarity index 100% rename from libs/models/src/main/kotlin/com/getcode/model/chat/Title.kt rename to libs/models/src/commonMain/kotlin/com/getcode/model/chat/Title.kt diff --git a/libs/models/src/main/kotlin/com/getcode/model/chat/Verb.kt b/libs/models/src/commonMain/kotlin/com/getcode/model/chat/Verb.kt similarity index 100% rename from libs/models/src/main/kotlin/com/getcode/model/chat/Verb.kt rename to libs/models/src/commonMain/kotlin/com/getcode/model/chat/Verb.kt diff --git a/libs/models/src/commonMain/kotlin/com/getcode/model/social/user/FileExtension.kt b/libs/models/src/commonMain/kotlin/com/getcode/model/social/user/FileExtension.kt new file mode 100644 index 0000000000..7b426d85d6 --- /dev/null +++ b/libs/models/src/commonMain/kotlin/com/getcode/model/social/user/FileExtension.kt @@ -0,0 +1,4 @@ +package com.getcode.model.social.user + +/** The file extension of [url], or an empty string; Android's `MimeTypeMap` rules. */ +internal expect fun fileExtensionFromUrl(url: String): String diff --git a/libs/models/src/main/kotlin/com/getcode/model/social/user/SocialProfile.kt b/libs/models/src/commonMain/kotlin/com/getcode/model/social/user/SocialProfile.kt similarity index 96% rename from libs/models/src/main/kotlin/com/getcode/model/social/user/SocialProfile.kt rename to libs/models/src/commonMain/kotlin/com/getcode/model/social/user/SocialProfile.kt index 2adca2b575..db74cdf709 100644 --- a/libs/models/src/main/kotlin/com/getcode/model/social/user/SocialProfile.kt +++ b/libs/models/src/commonMain/kotlin/com/getcode/model/social/user/SocialProfile.kt @@ -1,6 +1,5 @@ package com.getcode.model.social.user -import android.webkit.MimeTypeMap import com.getcode.model.chat.LinkedSocialProfile import kotlinx.serialization.Serializable import kotlinx.serialization.encodeToString @@ -47,7 +46,7 @@ sealed interface SocialProfile { val profilePicUrl: String? get() { val url = _profilePicUrl ?: return null - val extension = MimeTypeMap.getFileExtensionFromUrl(url) + val extension = fileExtensionFromUrl(url) val urlWithoutExtension = url.removeSuffix(extension) val urlWithoutType = urlWithoutExtension.substringBeforeLast("_") diff --git a/libs/models/src/main/kotlin/com/getcode/serialization/InstantIso8601Serializer.kt b/libs/models/src/commonMain/kotlin/com/getcode/serialization/InstantIso8601Serializer.kt similarity index 100% rename from libs/models/src/main/kotlin/com/getcode/serialization/InstantIso8601Serializer.kt rename to libs/models/src/commonMain/kotlin/com/getcode/serialization/InstantIso8601Serializer.kt diff --git a/libs/models/src/main/kotlin/com/getcode/utils/UUID.kt b/libs/models/src/commonMain/kotlin/com/getcode/utils/UUID.kt similarity index 100% rename from libs/models/src/main/kotlin/com/getcode/utils/UUID.kt rename to libs/models/src/commonMain/kotlin/com/getcode/utils/UUID.kt diff --git a/libs/models/src/main/kotlin/com/getcode/utils/serializer/UUIDSerializer.kt b/libs/models/src/commonMain/kotlin/com/getcode/utils/serializer/UUIDSerializer.kt similarity index 100% rename from libs/models/src/main/kotlin/com/getcode/utils/serializer/UUIDSerializer.kt rename to libs/models/src/commonMain/kotlin/com/getcode/utils/serializer/UUIDSerializer.kt diff --git a/libs/models/src/jvmMain/kotlin/com/getcode/model/social/user/FileExtension.jvm.kt b/libs/models/src/jvmMain/kotlin/com/getcode/model/social/user/FileExtension.jvm.kt new file mode 100644 index 0000000000..a50b072280 --- /dev/null +++ b/libs/models/src/jvmMain/kotlin/com/getcode/model/social/user/FileExtension.jvm.kt @@ -0,0 +1,17 @@ +package com.getcode.model.social.user + +private val FILENAME = Regex("[a-zA-Z_0-9.\\-()%]+") + +/** Same rules as AOSP `MimeTypeMap.getFileExtensionFromUrl`. */ +internal actual fun fileExtensionFromUrl(url: String): String { + if (url.isEmpty()) return "" + var path = url + val fragment = path.lastIndexOf('#') + if (fragment > 0) path = path.substring(0, fragment) + val query = path.lastIndexOf('?') + if (query > 0) path = path.substring(0, query) + val filename = path.substring(path.lastIndexOf('/') + 1) + if (filename.isEmpty() || !FILENAME.matches(filename)) return "" + val dot = filename.lastIndexOf('.') + return if (dot >= 0) filename.substring(dot + 1) else "" +} diff --git a/libs/network/connectivity/public/build.gradle.kts b/libs/network/connectivity/public/build.gradle.kts index 81092157f3..632d3d1477 100644 --- a/libs/network/connectivity/public/build.gradle.kts +++ b/libs/network/connectivity/public/build.gradle.kts @@ -1,23 +1,28 @@ plugins { - alias(libs.plugins.flipcash.android.library.compose) + alias(libs.plugins.flipcash.kmp.app.library) + alias(libs.plugins.compose.compiler) } -android { - namespace = "${Gradle.codeNamespace}.libs.network" -} - -dependencies { - implementation(project(":libs:datetime")) - implementation(project(":libs:logging")) - debugImplementation(libs.compose.ui.tools) - implementation(libs.compose.ui.tools.preview) - implementation(libs.bundles.kotlinx.serialization) - implementation(libs.bundles.hilt) - - testImplementation(kotlin("test")) - testImplementation(libs.kotlinx.coroutines.test) +kotlin { + android { + namespace = "${Gradle.codeNamespace}.libs.network" + } - androidTestImplementation(libs.androidx.junit) - androidTestImplementation(libs.junit) - androidTestImplementation(libs.androidx.test.runner) + sourceSets { + commonMain.dependencies { + implementation(project(":libs:datetime")) + implementation(project(":libs:logging")) + implementation(libs.bundles.kotlinx.serialization) + implementation(libs.jetbrains.compose.runtime) + implementation(libs.javax.inject) + } + androidMain.dependencies { + implementation(project.dependencies.platform(libs.compose.bom)) + implementation(libs.compose.ui.tools.preview) + } + getByName("androidHostTest").dependencies { + implementation(kotlin("test")) + implementation(libs.kotlinx.coroutines.test) + } + } } diff --git a/libs/network/connectivity/public/src/test/kotlin/com/getcode/utils/network/ConnectionTypeTest.kt b/libs/network/connectivity/public/src/androidHostTest/kotlin/com/getcode/utils/network/ConnectionTypeTest.kt similarity index 100% rename from libs/network/connectivity/public/src/test/kotlin/com/getcode/utils/network/ConnectionTypeTest.kt rename to libs/network/connectivity/public/src/androidHostTest/kotlin/com/getcode/utils/network/ConnectionTypeTest.kt diff --git a/libs/network/connectivity/public/src/test/kotlin/com/getcode/utils/network/PollUntilTest.kt b/libs/network/connectivity/public/src/androidHostTest/kotlin/com/getcode/utils/network/PollUntilTest.kt similarity index 100% rename from libs/network/connectivity/public/src/test/kotlin/com/getcode/utils/network/PollUntilTest.kt rename to libs/network/connectivity/public/src/androidHostTest/kotlin/com/getcode/utils/network/PollUntilTest.kt diff --git a/libs/network/connectivity/public/src/test/kotlin/com/getcode/utils/network/RetryTest.kt b/libs/network/connectivity/public/src/androidHostTest/kotlin/com/getcode/utils/network/RetryTest.kt similarity index 100% rename from libs/network/connectivity/public/src/test/kotlin/com/getcode/utils/network/RetryTest.kt rename to libs/network/connectivity/public/src/androidHostTest/kotlin/com/getcode/utils/network/RetryTest.kt diff --git a/libs/network/connectivity/public/src/main/kotlin/com/getcode/utils/network/connectivity/ConnectionStatusProvider.kt b/libs/network/connectivity/public/src/androidMain/kotlin/com/getcode/utils/network/connectivity/ConnectionStatusProvider.kt similarity index 100% rename from libs/network/connectivity/public/src/main/kotlin/com/getcode/utils/network/connectivity/ConnectionStatusProvider.kt rename to libs/network/connectivity/public/src/androidMain/kotlin/com/getcode/utils/network/connectivity/ConnectionStatusProvider.kt diff --git a/libs/network/connectivity/public/src/main/kotlin/com/getcode/utils/network/NetworkConnectionListener.kt b/libs/network/connectivity/public/src/commonMain/kotlin/com/getcode/utils/network/NetworkConnectionListener.kt similarity index 100% rename from libs/network/connectivity/public/src/main/kotlin/com/getcode/utils/network/NetworkConnectionListener.kt rename to libs/network/connectivity/public/src/commonMain/kotlin/com/getcode/utils/network/NetworkConnectionListener.kt diff --git a/libs/network/connectivity/public/src/main/kotlin/com/getcode/utils/network/Polling.kt b/libs/network/connectivity/public/src/commonMain/kotlin/com/getcode/utils/network/Polling.kt similarity index 100% rename from libs/network/connectivity/public/src/main/kotlin/com/getcode/utils/network/Polling.kt rename to libs/network/connectivity/public/src/commonMain/kotlin/com/getcode/utils/network/Polling.kt diff --git a/libs/network/connectivity/public/src/main/kotlin/com/getcode/utils/network/Retry.kt b/libs/network/connectivity/public/src/commonMain/kotlin/com/getcode/utils/network/Retry.kt similarity index 100% rename from libs/network/connectivity/public/src/main/kotlin/com/getcode/utils/network/Retry.kt rename to libs/network/connectivity/public/src/commonMain/kotlin/com/getcode/utils/network/Retry.kt From fa514cbf23f2e15a949aecd08a1c235b5d395159 Mon Sep 17 00:00:00 2001 From: Brandon McAnsh Date: Fri, 23 Oct 2026 16:21:47 -0400 Subject: [PATCH 09/50] build(opencode): move services:opencode to the android+jvm KMP plugin services:opencode now builds for jvm with Hilt wiring left in androidMain. Its keys came from the Java JNI class com.getcode.ed25519.Ed25519, which has no desktop equivalent, so: - ed25519 gains a jvmShared source set with a Kotlin Ed25519 object (same members as the Java class) over Ed25519Kmp. KeyPair keeps the Base64 string fields and its Parcelable form, so stored keys are unchanged. Callers move from com.getcode.ed25519 to com.getcode.ed25519kmp. - mnemonic's DerivedKey, MnemonicPhrase and MnemonicCache, and utils' Ed25519 extensions, move from androidMain to jvmShared. - logging gains a plain Log (Timber on Android) for the two opencode files that logged without trace()'s gating. - toInstantFromMillis moves to datetime's commonMain. - UserManager reads BuildFlags.isDebug instead of opencode's BuildConfig, which a KMP library no longer generates. The KMP Android target now compiles Java (withJava()): Hilt's KSP processors emit hilt_aggregated_deps as Java, and without it the app graph lost every opencode @Module binding. Adds HeadlessBalanceTest (jvmTest), which fetches token balances from the OCP backend over grpc-okhttp with no UI or DI. It reads the phrase from FLIPCASH_TEST_MNEMONIC or flipcash.test.mnemonic in local.properties and skips when neither is set. --- .../startup/MnemonicCacheInitializer.kt | 3 +- .../accounts/AccountProfileFetcher.kt | 2 +- .../PassphraseCredentialManager.kt | 2 +- .../accounts/AccountProfileFetcherTest.kt | 2 +- .../app/shareable/ShareSheetController.kt | 2 +- .../kotlin/KmpAppLibraryConventionPlugin.kt | 3 + .../kotlin/com/getcode/util/DateUtils.kt | 2 - .../kotlin/com/getcode/util/Instant.kt | 4 +- libs/encryption/ed25519/build.gradle.kts | 17 ++ .../getcode/ed25519kmp/RandomSeed.android.kt | 9 + .../com/getcode/ed25519kmp/RandomSeed.jvm.kt | 7 + .../kotlin/com/getcode/ed25519kmp/Ed25519.kt | 87 ++++++++++ libs/encryption/mnemonic/build.gradle.kts | 19 +- .../kotlin/com/getcode/crypt/MnemonicCache.kt | 15 -- .../kotlin/com/getcode/crypt/DerivedKey.kt | 2 +- .../kotlin/com/getcode/crypt/MnemonicCache.kt | 7 + .../com/getcode/crypt/MnemonicPhrase.kt | 2 +- libs/encryption/utils/build.gradle.kts | 2 +- .../com/getcode/utils/Ed25519Extensions.kt} | 2 +- .../com/getcode/utils/PlatformLog.android.kt | 4 + .../kotlin/com/getcode/utils/PlatformLog.kt | 12 ++ .../com/getcode/utils/PlatformLog.jvm.kt | 5 + .../controllers/BlobStorageController.kt | 2 +- .../flipcash/services/extensions/KeyPair.kt | 4 +- .../services/internal/extensions/KeyPair.kt | 2 +- .../internal/network/api/AccountApi.kt | 2 +- .../internal/network/api/ActivityFeedApi.kt | 2 +- .../internal/network/api/BlobStorageApi.kt | 2 +- .../internal/network/api/BlocklistApi.kt | 2 +- .../services/internal/network/api/ChatApi.kt | 2 +- .../internal/network/api/ChatMessagingApi.kt | 2 +- .../internal/network/api/CommunityApi.kt | 2 +- .../internal/network/api/ContactListApi.kt | 2 +- .../network/api/EmailVerificationApi.kt | 2 +- .../internal/network/api/ModerationApi.kt | 2 +- .../network/api/PhoneVerificationApi.kt | 2 +- .../services/internal/network/api/PollApi.kt | 2 +- .../internal/network/api/ProfileApi.kt | 2 +- .../internal/network/api/PurchaseApi.kt | 2 +- .../services/internal/network/api/PushApi.kt | 2 +- .../internal/network/api/ReportingApi.kt | 2 +- .../internal/network/api/ResolverApi.kt | 2 +- .../internal/network/api/SettingsApi.kt | 2 +- .../internal/network/api/ThirdPartyApi.kt | 2 +- .../network/extensions/AuthenticateMessage.kt | 2 +- .../network/extensions/LocalToProtobuf.kt | 2 +- .../network/extensions/SignMessage.kt | 2 +- .../network/services/AccountService.kt | 2 +- .../network/services/ActivityFeedService.kt | 2 +- .../network/services/BlobStorageService.kt | 2 +- .../network/services/BlocklistService.kt | 2 +- .../network/services/ChatMessagingService.kt | 2 +- .../internal/network/services/ChatService.kt | 2 +- .../network/services/CommunityService.kt | 2 +- .../network/services/ContactListService.kt | 2 +- .../services/EmailVerificationService.kt | 2 +- .../network/services/EventStreamingService.kt | 2 +- .../network/services/ModerationService.kt | 2 +- .../services/PhoneVerificationService.kt | 2 +- .../internal/network/services/PollService.kt | 2 +- .../network/services/ProfileService.kt | 2 +- .../network/services/PurchaseService.kt | 2 +- .../internal/network/services/PushService.kt | 2 +- .../network/services/ReportingService.kt | 2 +- .../network/services/ResolverService.kt | 2 +- .../network/services/SettingsService.kt | 2 +- .../network/services/ThirdPartyService.kt | 2 +- .../repositories/InternalAccountRepository.kt | 2 +- .../InternalActivityFeedRepository.kt | 2 +- .../InternalBlobStorageRepository.kt | 2 +- .../InternalBlocklistRepository.kt | 2 +- .../InternalChatMessagingRepository.kt | 2 +- .../repositories/InternalChatRepository.kt | 2 +- .../InternalCommunityRepository.kt | 2 +- .../InternalContactListRepository.kt | 2 +- .../InternalContactVerificationRepository.kt | 2 +- .../InternalEventStreamingRepository.kt | 2 +- .../InternalModerationRepository.kt | 2 +- .../repositories/InternalPollRepository.kt | 2 +- .../repositories/InternalProfileRepository.kt | 2 +- .../InternalPurchaseRepository.kt | 2 +- .../repositories/InternalPushRepository.kt | 2 +- .../InternalReportingRepository.kt | 2 +- .../InternalResolverRepository.kt | 2 +- .../InternalSettingsRepository.kt | 2 +- .../InternalThirdPartyRepository.kt | 2 +- .../services/repository/AccountRepository.kt | 2 +- .../repository/ActivityFeedRepository.kt | 2 +- .../repository/BlobStorageRepository.kt | 2 +- .../repository/BlocklistRepository.kt | 2 +- .../repository/ChatMessagingRepository.kt | 2 +- .../services/repository/ChatRepository.kt | 2 +- .../repository/CommunityRepository.kt | 2 +- .../repository/ContactListRepository.kt | 2 +- .../ContactVerificationRepository.kt | 2 +- .../repository/EventStreamingRepository.kt | 2 +- .../repository/ModerationRepository.kt | 2 +- .../services/repository/PollRepository.kt | 2 +- .../services/repository/ProfileRepository.kt | 2 +- .../services/repository/PurchaseRepository.kt | 2 +- .../services/repository/PushRepository.kt | 2 +- .../repository/ReportingRepository.kt | 2 +- .../services/repository/ResolverRepository.kt | 2 +- .../services/repository/SettingsRepository.kt | 2 +- .../repository/ThirdPartyRepository.kt | 2 +- .../com/flipcash/services/user/UserManager.kt | 4 +- .../BlobStorageControllerChatMediaTest.kt | 2 +- .../controllers/BlobStorageControllerTest.kt | 2 +- .../controllers/ChatControllerTest.kt | 2 +- .../ChatMessagingControllerTest.kt | 2 +- .../EventStreamingControllerTest.kt | 2 +- .../controllers/ProfileControllerTest.kt | 2 +- .../network/api/BlobStorageApiDeadlineTest.kt | 2 +- .../services/PhoneVerificationServiceTest.kt | 2 +- services/opencode/build.gradle.kts | 162 +++++++++--------- services/opencode/consumer-rules.pro | 0 .../model/core/OpenCodePayloadTests.kt | 0 .../getcode/opencode/solana/swap/SwapTests.kt | 0 .../com/getcode/opencode/tests/PublicKey.kt | 0 .../controllers/AccountControllerTest.kt | 2 +- .../TokenControllerFetchTokenBalancesTest.kt | 0 ...sactionControllerPollIntentMetadataTest.kt | 0 .../bidi/OpenBidirectionalStreamTest.kt | 0 .../RealVerifiedFiatCalculatorTest.kt | 0 .../extensions/ByteArrayExtensionsTest.kt | 0 .../extensions/CurrencyCodeExtensionsTest.kt | 0 .../extensions/ResultExtensionsTest.kt | 0 .../extensions/VerifiedStateExtTest.kt | 0 .../manager/VerifiedProtoManagerTest.kt | 0 .../api/intents/IntentMultiTransferTest.kt | 2 +- .../network/pollers/SwapPollerTest.kt | 2 +- .../network/services/CurrencyServiceTest.kt | 2 +- .../internal/proto/ProtoWireFormatTest.kt | 0 .../opencode/internal/solana/ShortVecTest.kt | 0 .../solana/extensions/PdaDerivationTest.kt | 2 +- .../internal/solana/extensions/UInt16Test.kt | 0 .../CoinbaseStablecoinPoolAccountTest.kt | 0 .../CoinbaseStableSwapperProgramTest.kt | 0 .../programs/CurrencyCreatorProgramTest.kt | 0 .../solana/programs/ProgramAddressesTest.kt | 0 .../internal/solana/programs/SysVarTest.kt | 0 .../programs/VirtualMachineProgramTest.kt | 0 .../transactors/ClaimValidationTest.kt | 0 .../transactors/GiveBillTransactorTest.kt | 0 .../transactors/GrabBillTransactorTest.kt | 0 .../ReceiveGiftCardTransactorTest.kt | 0 .../transactors/SendGiftCardTransactorTest.kt | 0 .../model/core/OpenCodePayloadTest.kt | 0 .../model/core/errors/SodiumErrorTest.kt | 0 .../core/errors/SubmitIntentErrorTest.kt | 0 .../model/core/errors/SwapErrorTest.kt | 0 .../model/financial/DistributionTest.kt | 0 .../opencode/model/financial/FeeTest.kt | 0 .../opencode/model/financial/FiatTest.kt | 0 .../opencode/model/financial/FiatTests.kt | 0 .../model/financial/HistoricalMintDataTest.kt | 0 .../model/financial/LaunchpadSellFeeTest.kt | 0 .../opencode/model/financial/LimitsTest.kt | 0 .../opencode/model/financial/LocalFiatTest.kt | 0 .../model/financial/MintMetadataTest.kt | 0 .../opencode/model/financial/RateTest.kt | 0 .../model/transactions/SwapMetadataTest.kt | 0 .../solana/CompactMessageVectorTest.kt | 0 .../solana/InstructionIntegrationTest.kt | 0 .../solana/MultiPaymentIntentVectorTest.kt | 2 +- .../solana/SolanaMessageVectorTest.kt | 0 .../SolanaTransactionLookupTableTest.kt | 0 .../opencode/solana/VersionedMessageV0Test.kt | 0 .../swap/ClientBuiltDepositSwapV2Test.kt | 0 ...oinbaseStablecoinDepositTransactionTest.kt | 0 ...inbaseStablecoinSwapperInstructionsTest.kt | 0 .../solana/swap/ExistingCurrencyBuyFeeTest.kt | 2 +- .../swap/StablecoinSwapVersionRequestTest.kt | 2 +- .../swap/StatelessSwapInstructionsTest.kt | 0 .../com/getcode/opencode/tests/PublicKey.kt | 0 .../opencode/utils/DoubleExtensionsTest.kt | 0 .../com/getcode/opencode/utils/LongTest.kt | 0 .../com/getcode/opencode/utils/MapsTest.kt | 0 .../opencode/utils/StringExtensionsTest.kt | 0 .../opencode/utils/ThrowableExtensionsTest.kt | 0 .../resources/compact_message.json | 0 .../resources/multi_payment_intent.json | 0 .../resources/solana_message.json | 0 .../com/getcode/opencode/ControllerFactory.kt | 0 .../com/getcode/opencode/ExchangeFactory.kt | 0 .../com/getcode/opencode/NetworkFactory.kt | 0 .../com/getcode/opencode/RepositoryFactory.kt | 0 .../getcode/opencode/inject/OpenCodeModule.kt | 0 .../opencode/inject/SessionListenersModule.kt | 0 .../opencode/inject/TransactorModule.kt | 0 .../platform/ProcessLifecycle.android.kt | 25 +++ .../model/core/ScanCodeEncoder.android.kt | 5 + .../drawable/ic_currency_dollar_active.xml | 0 .../drawable/ic_currency_dollar_inactive.xml | 0 .../res/drawable/ic_currency_xaf.xml | 0 .../res/drawable/ic_currency_xof.xml | 0 .../com/getcode/opencode/ManagerFactory.kt | 0 .../com/getcode/opencode/ProtocolConfig.kt | 0 .../opencode/controllers/AccountController.kt | 0 .../opencode/controllers/BalanceController.kt | 0 .../controllers/CurrencyController.kt | 0 .../controllers/MessagingController.kt | 2 +- .../opencode/controllers/TokenController.kt | 0 .../controllers/TransactionController.kt | 2 +- .../controllers/TransactionOperations.kt | 0 .../com/getcode/opencode/events/Events.kt | 0 .../com/getcode/opencode/exchange/Exchange.kt | 0 .../exchange/VerifiedFiatCalculator.kt | 6 +- .../opencode/generators/GiftCardGenerator.kt | 0 .../opencode/generators/MnemonicGenerator.kt | 0 .../annotations/OpenCodeManagedChannel.kt | 0 .../opencode/internal/annotations/Protocol.kt | 0 .../bidi/BidirectionalStreamReference.kt | 0 .../opencode/internal/bidi/OpenStream.kt | 0 .../internal/bidi/OpenStreamForResult.kt | 0 .../domain/mapping/BillCustomizationMapper.kt | 0 .../mapping/HistoricalMintDataMapper.kt | 0 .../domain/mapping/HolderMetricsMapper.kt | 0 .../domain/mapping/LaunchpadMetadataMapper.kt | 0 .../domain/mapping/LiveMintDataMapper.kt | 0 .../domain/mapping/MarketCapMetricsMapper.kt | 0 .../internal/domain/mapping/MessageMapper.kt | 0 .../internal/domain/mapping/MintMapper.kt | 0 .../domain/mapping/OwnerBalanceMapper.kt | 0 .../domain/mapping/SocialLinkMapper.kt | 0 .../domain/mapping/SwapMetadataMapper.kt | 0 .../mapping/TransactionMetadataMapper.kt | 0 .../domain/mapping/VmMetadataMapper.kt | 0 .../repositories/InternalAccountRepository.kt | 2 +- .../repositories/InternalBalanceRepository.kt | 0 .../InternalCurrencyRepository.kt | 2 +- .../repositories/InternalEventRepository.kt | 0 .../InternalMessagingRepository.kt | 2 +- .../repositories/InternalSwapRepository.kt | 2 +- .../InternalTransactionRepository.kt | 2 +- .../internal/exchange/OpenCodeExchange.kt | 29 +--- .../exchange/RealVerifiedFiatCalculator.kt | 1 - .../opencode/internal/extensions/ByteArray.kt | 0 .../opencode/internal/extensions/Currency.kt | 0 .../internal/extensions/CurrencyCode.kt | 0 .../opencode/internal/extensions/Instant.kt | 0 .../opencode/internal/extensions/KeyPair.kt | 2 +- .../opencode/internal/extensions/PublicKey.kt | 0 .../opencode/internal/extensions/Result.kt | 0 .../internal/extensions/VerifiedState.kt | 0 .../opencode/internal/generator/Generator.kt | 0 .../internal/manager/VerifiedProtoManager.kt | 0 .../internal/network/api/AccountApi.kt | 2 +- .../internal/network/api/BalanceApi.kt | 0 .../internal/network/api/CurrencyApi.kt | 2 +- .../internal/network/api/MessagingApi.kt | 4 +- .../internal/network/api/TransactionApi.kt | 2 +- .../api/intents/IntentCreateAccount.kt | 0 .../network/api/intents/IntentDistribution.kt | 0 .../network/api/intents/IntentFundSwap.kt | 0 .../api/intents/IntentMultiTransfer.kt | 0 .../api/intents/IntentRemoteReceive.kt | 0 .../network/api/intents/IntentRemoteSend.kt | 0 .../network/api/intents/IntentStatefulSwap.kt | 0 .../api/intents/IntentStatelessSwap.kt | 0 .../network/api/intents/IntentTransfer.kt | 0 .../network/api/intents/IntentWithdraw.kt | 0 .../api/intents/actions/ActionFeePayment.kt | 2 +- .../api/intents/actions/ActionOpenAccount.kt | 2 +- .../intents/actions/ActionPublicTransfer.kt | 2 +- .../intents/actions/ActionPublicWithdraw.kt | 2 +- .../opencode/internal/network/core/GrpcApi.kt | 24 +++ .../network/executors/IntentExecutor.kt | 6 +- .../network/executors/StatefulSwapExecutor.kt | 4 +- .../executors/StatelessSwapExecutor.kt | 4 +- .../network/extensions/FoldWithSuppression.kt | 0 .../network/extensions/LocalToProtobuf.kt | 2 +- .../network/extensions/ProtobufToLocal.kt | 0 .../network/extensions/SignMessage.kt | 2 +- .../internal/network/funding/SwapFunding.kt | 0 .../internal/network/pollers/SwapPoller.kt | 2 +- .../network/serializer/UUIDSerializer.kt | 0 .../network/services/AccountService.kt | 2 +- .../network/services/BalanceService.kt | 0 .../network/services/CurrencyService.kt | 2 +- .../network/services/MessagingService.kt | 2 +- .../internal/network/services/SwapService.kt | 2 +- .../network/services/TransactionService.kt | 4 +- .../network/streamers/LiveMintDataStreamer.kt | 0 .../internal/platform/ProcessLifecycle.kt | 15 ++ .../opencode/internal/solana/Definitions.kt | 0 .../opencode/internal/solana/ShortVec.kt | 0 .../extensions/AssociatedTokenAccount.kt | 0 .../extensions/ExtractServerParameters.kt | 0 .../internal/solana/extensions/PublicKey.kt | 2 +- .../extensions/TimelockDerivedAccounts.kt | 0 .../internal/solana/extensions/Token.kt | 0 .../internal/solana/extensions/UInt16.kt | 0 .../model/CoinbaseStablecoinPoolAccount.kt | 0 .../solana/model/CoinbaseSwapAccounts.kt | 0 .../solana/model/MessageAddressLookupTable.kt | 0 .../opencode/internal/solana/model/SwapId.kt | 4 +- .../opencode/internal/solana/model/Vault.kt | 0 .../solana/programs/AssociatedTokenProgram.kt | 0 ...AssociatedTokenProgram_CreateIdempotent.kt | 0 .../programs/CoinbaseStableSwapperProgram.kt | 0 .../CoinbaseStableSwapperProgram_SwapV2.kt | 0 .../solana/programs/ComputeBudgetProgram.kt | 0 ...omputeBudgetProgram_SetComputeUnitLimit.kt | 0 ...omputeBudgetProgram_SetComputeUnitPrice.kt | 0 .../solana/programs/CurrencyCreatorProgram.kt | 0 ...rencyCreatorProgram_BuyAndDepositIntoVm.kt | 0 .../CurrencyCreatorProgram_BuyTokens.kt | 0 ...rrencyCreatorProgram_InitializeCurrency.kt | 0 .../CurrencyCreatorProgram_InitializePool.kt | 0 ...encyCreatorProgram_SellAndDepositIntoVm.kt | 0 .../CurrencyCreatorProgram_SellTokens.kt | 0 .../solana/programs/InstructionType.kt | 0 .../internal/solana/programs/MemoProgram.kt | 0 .../solana/programs/MemoProgram_Memo.kt | 0 .../solana/programs/SwapValidatorProgram.kt | 0 .../internal/solana/programs/SysVar.kt | 0 .../internal/solana/programs/SystemProgram.kt | 0 .../programs/SystemProgram_AdvanceNonce.kt | 0 .../solana/programs/TimelockProgram.kt | 0 .../internal/solana/programs/TokenProgram.kt | 0 .../programs/TokenProgram_CloseAccount.kt | 0 .../solana/programs/TokenProgram_Transfer.kt | 0 .../internal/solana/programs/UsdfProgram.kt | 0 .../solana/programs/UsdfProgram_Swap.kt | 0 .../solana/programs/UsdfProgram_Transfer.kt | 0 .../solana/programs/VirtualMachineProgram.kt | 0 ...lMachineProgram_CloseSwapAccountIfEmpty.kt | 0 .../programs/VirtualMachineProgram_InitVm.kt | 0 .../VirtualMachineProgram_TransferForSwap.kt | 0 ...alMachineProgram_TransferForSwapWithFee.kt | 0 .../internal/solana/utils/DataSlice.kt | 0 .../opencode/internal/solana/utils/Differ.kt | 12 +- .../transactors/AccountClusterFactory.kt | 0 .../transactors/BillPresentationData.kt | 0 .../transactors/GiveBillTransactor.kt | 2 +- .../transactors/GrabBillTransactor.kt | 0 .../internal/transactors/PayloadFactory.kt | 2 +- .../transactors/ReceiveGiftCardTransactor.kt | 0 .../transactors/SendGiftCardTransactor.kt | 2 +- .../internal/transactors/Transactor.kt | 0 .../managers/BillTransactionManager.kt | 0 .../opencode/managers/GiftCardManager.kt | 0 .../opencode/managers/MnemonicManager.kt | 2 +- .../com/getcode/opencode/mapper/Mapper.kt | 0 .../opencode/model/accounts/AccountCluster.kt | 2 +- .../opencode/model/accounts/AccountFilter.kt | 0 .../opencode/model/accounts/AccountInfo.kt | 0 .../model/accounts/AccountResponse.kt | 0 .../opencode/model/accounts/AccountType.kt | 0 .../model/accounts/GiftCardAccount.kt | 0 .../opencode/model/accounts/PoolAccount.kt | 2 +- .../opencode/model/core/EncryptedData.kt | 2 +- .../com/getcode/opencode/model/core/ID.kt | 0 .../opencode/model/core/OpenCodePayload.kt | 5 +- .../opencode/model/core/PayloadKind.kt | 0 .../opencode/model/core/PayloadValue.kt | 0 .../opencode/model/core/ScanCodeEncoder.kt | 4 + .../com/getcode/opencode/model/core/UUID.kt | 0 .../opencode/model/core/errors/Errors.kt | 0 .../opencode/model/core/errors/SodiumError.kt | 0 .../model/core/errors/ValidationException.kt | 0 .../opencode/model/financial/Currency.kt | 0 .../opencode/model/financial/CurrencyCode.kt | 0 .../opencode/model/financial/Distribution.kt | 0 .../getcode/opencode/model/financial/Fee.kt | 0 .../getcode/opencode/model/financial/Fiat.kt | 4 +- .../model/financial/HistoricalMintData.kt | 0 .../LaunchpadReserveStateSnapshot.kt | 0 .../model/financial/LaunchpadSellFee.kt | 0 .../opencode/model/financial/Limits.kt | 0 .../opencode/model/financial/LocalFiat.kt | 4 +- .../opencode/model/financial/MintMetadata.kt | 6 +- .../model/financial/MintStreamingData.kt | 0 .../opencode/model/financial/OwnerBalance.kt | 0 .../getcode/opencode/model/financial/Rate.kt | 4 +- .../opencode/model/financial/RegionCode.kt | 0 .../model/financial/TokenCreateRequest.kt | 0 .../opencode/model/financial/TokenResult.kt | 0 .../model/financial/TokenUpdateRequest.kt | 0 .../model/messaging/KeepAliveRequest.kt | 2 +- .../opencode/model/messaging/Message.kt | 0 .../model/moderation/ModerationAttestation.kt | 0 .../model/transactions/AddressLookupTable.kt | 0 .../model/transactions/ExchangeData.kt | 0 .../model/transactions/FundSwapPool.kt | 0 .../model/transactions/LiquidityPool.kt | 0 .../transactions/StartSwapServerParameters.kt | 0 .../model/transactions/StatefulSwapRequest.kt | 2 +- .../StatefulSwapResponseServerParameters.kt | 0 .../model/transactions/StatefulSwapResult.kt | 0 .../transactions/StatelessSwapRequest.kt | 0 .../model/transactions/StatelessSwapResult.kt | 0 .../StatelessSwapServerParameters.kt | 0 .../model/transactions/SwapFundingSource.kt | 0 .../model/transactions/SwapMetadata.kt | 0 .../opencode/model/transactions/SwapRoute.kt | 0 .../model/transactions/TransactionMetadata.kt | 0 .../model/transactions/TransferRequest.kt | 0 .../transactions/WithdrawalAvailability.kt | 0 .../opencode/model/ui/BillCustomization.kt | 4 +- .../opencode/model/ui/DiscoverCategory.kt | 0 .../opencode/model/ui/WindowedRange.kt | 0 .../opencode/providers/SessionListener.kt | 0 .../providers/TokenMetadataProvider.kt | 0 .../repositories/AccountRepository.kt | 2 +- .../repositories/BalanceRepository.kt | 0 .../repositories/CurrencyRepository.kt | 2 +- .../opencode/repositories/EventRepository.kt | 0 .../repositories/MessagingRepository.kt | 2 +- .../opencode/repositories/SwapRepository.kt | 2 +- .../repositories/TransactionRepository.kt | 2 +- .../getcode/opencode/solana/Instruction.kt | 0 .../getcode/opencode/solana/LegacyMessage.kt | 0 .../com/getcode/opencode/solana/Message.kt | 0 .../getcode/opencode/solana/MessageHeader.kt | 0 .../opencode/solana/SolanaTransaction.kt | 2 +- .../opencode/solana/TransactionBuilder.kt | 0 .../opencode/solana/VersionedMessage.kt | 0 .../opencode/solana/intents/ActionGroup.kt | 0 .../opencode/solana/intents/IntentType.kt | 2 +- .../solana/intents/ServerParameter.kt | 0 .../solana/intents/actions/ActionType.kt | 2 +- .../solana/keys/ProgramDerivedAccount.kt | 0 .../solana/keys/TimelockVmSwapAccounts.kt | 0 .../CoinbaseStablecoinSwapperInstructions.kt | 0 .../CrossCurrencyExistingSwapInstructions.kt | 0 .../swap/ExistingCurrencyBuyInstructions.kt | 0 .../solana/swap/NewCurrencyBuyInstructions.kt | 0 .../opencode/solana/swap/SellInstructions.kt | 0 .../solana/swap/UsdcDepositInstructions.kt | 0 .../swap/UsdcDepositSweepInstructions.kt | 0 .../solana/swap/UsdcToUsdfSwapInstructions.kt | 0 .../solana/swap/UsdfDepositInstructions.kt | 0 .../com/getcode/opencode/utils/Double.kt | 0 .../kotlin/com/getcode/opencode/utils/Flow.kt | 6 +- .../com/getcode/opencode/utils/KeyPair.kt | 10 ++ .../kotlin/com/getcode/opencode/utils/Long.kt | 0 .../kotlin/com/getcode/opencode/utils/Maps.kt | 0 .../com/getcode/opencode/utils/Nonce.kt | 0 .../com/getcode/opencode/utils/PublicKey.kt | 2 +- .../com/getcode/opencode/utils/Result.kt | 0 .../com/getcode/opencode/utils/String.kt | 0 .../com/getcode/opencode/utils/Throwable.kt | 0 .../utils/logging/LoggingClientCall.kt | 0 .../logging/LoggingClientCallListener.kt | 0 .../utils/logging/LoggingClientInterceptor.kt | 0 .../internal/platform/ProcessLifecycle.jvm.kt | 14 ++ .../model/core/ScanCodeEncoder.jvm.kt | 4 + .../getcode/opencode/HeadlessBalanceTest.kt | 51 ++++++ .../opencode/internal/network/core/GrpcApi.kt | 39 ----- .../com/getcode/opencode/utils/KeyPair.kt | 10 -- 452 files changed, 602 insertions(+), 364 deletions(-) create mode 100644 libs/encryption/ed25519/src/androidMain/kotlin/com/getcode/ed25519kmp/RandomSeed.android.kt create mode 100644 libs/encryption/ed25519/src/jvmMain/kotlin/com/getcode/ed25519kmp/RandomSeed.jvm.kt create mode 100644 libs/encryption/ed25519/src/jvmSharedMain/kotlin/com/getcode/ed25519kmp/Ed25519.kt delete mode 100644 libs/encryption/mnemonic/src/androidMain/kotlin/com/getcode/crypt/MnemonicCache.kt rename libs/encryption/mnemonic/src/{androidMain => jvmSharedMain}/kotlin/com/getcode/crypt/DerivedKey.kt (95%) create mode 100644 libs/encryption/mnemonic/src/jvmSharedMain/kotlin/com/getcode/crypt/MnemonicCache.kt rename libs/encryption/mnemonic/src/{androidMain => jvmSharedMain}/kotlin/com/getcode/crypt/MnemonicPhrase.kt (98%) rename libs/encryption/utils/src/{androidMain/kotlin/com/getcode/utils/Ed25519Extensions.android.kt => jvmSharedMain/kotlin/com/getcode/utils/Ed25519Extensions.kt} (78%) delete mode 100644 services/opencode/consumer-rules.pro rename services/opencode/src/{androidTest => androidDeviceTest}/kotlin/com/getcode/opencode/model/core/OpenCodePayloadTests.kt (100%) rename services/opencode/src/{androidTest => androidDeviceTest}/kotlin/com/getcode/opencode/solana/swap/SwapTests.kt (100%) rename services/opencode/src/{androidTest => androidDeviceTest}/kotlin/com/getcode/opencode/tests/PublicKey.kt (100%) rename services/opencode/src/{test => androidHostTest}/kotlin/com/getcode/opencode/controllers/AccountControllerTest.kt (99%) rename services/opencode/src/{test => androidHostTest}/kotlin/com/getcode/opencode/controllers/TokenControllerFetchTokenBalancesTest.kt (100%) rename services/opencode/src/{test => androidHostTest}/kotlin/com/getcode/opencode/controllers/TransactionControllerPollIntentMetadataTest.kt (100%) rename services/opencode/src/{test => androidHostTest}/kotlin/com/getcode/opencode/internal/bidi/OpenBidirectionalStreamTest.kt (100%) rename services/opencode/src/{test => androidHostTest}/kotlin/com/getcode/opencode/internal/exchange/RealVerifiedFiatCalculatorTest.kt (100%) rename services/opencode/src/{test => androidHostTest}/kotlin/com/getcode/opencode/internal/extensions/ByteArrayExtensionsTest.kt (100%) rename services/opencode/src/{test => androidHostTest}/kotlin/com/getcode/opencode/internal/extensions/CurrencyCodeExtensionsTest.kt (100%) rename services/opencode/src/{test => androidHostTest}/kotlin/com/getcode/opencode/internal/extensions/ResultExtensionsTest.kt (100%) rename services/opencode/src/{test => androidHostTest}/kotlin/com/getcode/opencode/internal/extensions/VerifiedStateExtTest.kt (100%) rename services/opencode/src/{test => androidHostTest}/kotlin/com/getcode/opencode/internal/manager/VerifiedProtoManagerTest.kt (100%) rename services/opencode/src/{test => androidHostTest}/kotlin/com/getcode/opencode/internal/network/api/intents/IntentMultiTransferTest.kt (99%) rename services/opencode/src/{test => androidHostTest}/kotlin/com/getcode/opencode/internal/network/pollers/SwapPollerTest.kt (99%) rename services/opencode/src/{test => androidHostTest}/kotlin/com/getcode/opencode/internal/network/services/CurrencyServiceTest.kt (99%) rename services/opencode/src/{test => androidHostTest}/kotlin/com/getcode/opencode/internal/proto/ProtoWireFormatTest.kt (100%) rename services/opencode/src/{test => androidHostTest}/kotlin/com/getcode/opencode/internal/solana/ShortVecTest.kt (100%) rename services/opencode/src/{test => androidHostTest}/kotlin/com/getcode/opencode/internal/solana/extensions/PdaDerivationTest.kt (99%) rename services/opencode/src/{test => androidHostTest}/kotlin/com/getcode/opencode/internal/solana/extensions/UInt16Test.kt (100%) rename services/opencode/src/{test => androidHostTest}/kotlin/com/getcode/opencode/internal/solana/model/CoinbaseStablecoinPoolAccountTest.kt (100%) rename services/opencode/src/{test => androidHostTest}/kotlin/com/getcode/opencode/internal/solana/programs/CoinbaseStableSwapperProgramTest.kt (100%) rename services/opencode/src/{test => androidHostTest}/kotlin/com/getcode/opencode/internal/solana/programs/CurrencyCreatorProgramTest.kt (100%) rename services/opencode/src/{test => androidHostTest}/kotlin/com/getcode/opencode/internal/solana/programs/ProgramAddressesTest.kt (100%) rename services/opencode/src/{test => androidHostTest}/kotlin/com/getcode/opencode/internal/solana/programs/SysVarTest.kt (100%) rename services/opencode/src/{test => androidHostTest}/kotlin/com/getcode/opencode/internal/solana/programs/VirtualMachineProgramTest.kt (100%) rename services/opencode/src/{test => androidHostTest}/kotlin/com/getcode/opencode/internal/transactors/ClaimValidationTest.kt (100%) rename services/opencode/src/{test => androidHostTest}/kotlin/com/getcode/opencode/internal/transactors/GiveBillTransactorTest.kt (100%) rename services/opencode/src/{test => androidHostTest}/kotlin/com/getcode/opencode/internal/transactors/GrabBillTransactorTest.kt (100%) rename services/opencode/src/{test => androidHostTest}/kotlin/com/getcode/opencode/internal/transactors/ReceiveGiftCardTransactorTest.kt (100%) rename services/opencode/src/{test => androidHostTest}/kotlin/com/getcode/opencode/internal/transactors/SendGiftCardTransactorTest.kt (100%) rename services/opencode/src/{test => androidHostTest}/kotlin/com/getcode/opencode/model/core/OpenCodePayloadTest.kt (100%) rename services/opencode/src/{test => androidHostTest}/kotlin/com/getcode/opencode/model/core/errors/SodiumErrorTest.kt (100%) rename services/opencode/src/{test => androidHostTest}/kotlin/com/getcode/opencode/model/core/errors/SubmitIntentErrorTest.kt (100%) rename services/opencode/src/{test => androidHostTest}/kotlin/com/getcode/opencode/model/core/errors/SwapErrorTest.kt (100%) rename services/opencode/src/{test => androidHostTest}/kotlin/com/getcode/opencode/model/financial/DistributionTest.kt (100%) rename services/opencode/src/{test => androidHostTest}/kotlin/com/getcode/opencode/model/financial/FeeTest.kt (100%) rename services/opencode/src/{test => androidHostTest}/kotlin/com/getcode/opencode/model/financial/FiatTest.kt (100%) rename services/opencode/src/{test => androidHostTest}/kotlin/com/getcode/opencode/model/financial/FiatTests.kt (100%) rename services/opencode/src/{test => androidHostTest}/kotlin/com/getcode/opencode/model/financial/HistoricalMintDataTest.kt (100%) rename services/opencode/src/{test => androidHostTest}/kotlin/com/getcode/opencode/model/financial/LaunchpadSellFeeTest.kt (100%) rename services/opencode/src/{test => androidHostTest}/kotlin/com/getcode/opencode/model/financial/LimitsTest.kt (100%) rename services/opencode/src/{test => androidHostTest}/kotlin/com/getcode/opencode/model/financial/LocalFiatTest.kt (100%) rename services/opencode/src/{test => androidHostTest}/kotlin/com/getcode/opencode/model/financial/MintMetadataTest.kt (100%) rename services/opencode/src/{test => androidHostTest}/kotlin/com/getcode/opencode/model/financial/RateTest.kt (100%) rename services/opencode/src/{test => androidHostTest}/kotlin/com/getcode/opencode/model/transactions/SwapMetadataTest.kt (100%) rename services/opencode/src/{test => androidHostTest}/kotlin/com/getcode/opencode/solana/CompactMessageVectorTest.kt (100%) rename services/opencode/src/{test => androidHostTest}/kotlin/com/getcode/opencode/solana/InstructionIntegrationTest.kt (100%) rename services/opencode/src/{test => androidHostTest}/kotlin/com/getcode/opencode/solana/MultiPaymentIntentVectorTest.kt (99%) rename services/opencode/src/{test => androidHostTest}/kotlin/com/getcode/opencode/solana/SolanaMessageVectorTest.kt (100%) rename services/opencode/src/{test => androidHostTest}/kotlin/com/getcode/opencode/solana/SolanaTransactionLookupTableTest.kt (100%) rename services/opencode/src/{test => androidHostTest}/kotlin/com/getcode/opencode/solana/VersionedMessageV0Test.kt (100%) rename services/opencode/src/{test => androidHostTest}/kotlin/com/getcode/opencode/solana/swap/ClientBuiltDepositSwapV2Test.kt (100%) rename services/opencode/src/{test => androidHostTest}/kotlin/com/getcode/opencode/solana/swap/CoinbaseStablecoinDepositTransactionTest.kt (100%) rename services/opencode/src/{test => androidHostTest}/kotlin/com/getcode/opencode/solana/swap/CoinbaseStablecoinSwapperInstructionsTest.kt (100%) rename services/opencode/src/{test => androidHostTest}/kotlin/com/getcode/opencode/solana/swap/ExistingCurrencyBuyFeeTest.kt (99%) rename services/opencode/src/{test => androidHostTest}/kotlin/com/getcode/opencode/solana/swap/StablecoinSwapVersionRequestTest.kt (98%) rename services/opencode/src/{test => androidHostTest}/kotlin/com/getcode/opencode/solana/swap/StatelessSwapInstructionsTest.kt (100%) rename services/opencode/src/{test => androidHostTest}/kotlin/com/getcode/opencode/tests/PublicKey.kt (100%) rename services/opencode/src/{test => androidHostTest}/kotlin/com/getcode/opencode/utils/DoubleExtensionsTest.kt (100%) rename services/opencode/src/{test => androidHostTest}/kotlin/com/getcode/opencode/utils/LongTest.kt (100%) rename services/opencode/src/{test => androidHostTest}/kotlin/com/getcode/opencode/utils/MapsTest.kt (100%) rename services/opencode/src/{test => androidHostTest}/kotlin/com/getcode/opencode/utils/StringExtensionsTest.kt (100%) rename services/opencode/src/{test => androidHostTest}/kotlin/com/getcode/opencode/utils/ThrowableExtensionsTest.kt (100%) rename services/opencode/src/{test => androidHostTest}/resources/compact_message.json (100%) rename services/opencode/src/{test => androidHostTest}/resources/multi_payment_intent.json (100%) rename services/opencode/src/{test => androidHostTest}/resources/solana_message.json (100%) rename services/opencode/src/{main => androidMain}/kotlin/com/getcode/opencode/ControllerFactory.kt (100%) rename services/opencode/src/{main => androidMain}/kotlin/com/getcode/opencode/ExchangeFactory.kt (100%) rename services/opencode/src/{main => androidMain}/kotlin/com/getcode/opencode/NetworkFactory.kt (100%) rename services/opencode/src/{main => androidMain}/kotlin/com/getcode/opencode/RepositoryFactory.kt (100%) rename services/opencode/src/{main => androidMain}/kotlin/com/getcode/opencode/inject/OpenCodeModule.kt (100%) rename services/opencode/src/{main => androidMain}/kotlin/com/getcode/opencode/inject/SessionListenersModule.kt (100%) rename services/opencode/src/{main => androidMain}/kotlin/com/getcode/opencode/inject/TransactorModule.kt (100%) create mode 100644 services/opencode/src/androidMain/kotlin/com/getcode/opencode/internal/platform/ProcessLifecycle.android.kt create mode 100644 services/opencode/src/androidMain/kotlin/com/getcode/opencode/model/core/ScanCodeEncoder.android.kt rename services/opencode/src/{main => androidMain}/res/drawable/ic_currency_dollar_active.xml (100%) rename services/opencode/src/{main => androidMain}/res/drawable/ic_currency_dollar_inactive.xml (100%) rename services/opencode/src/{main => androidMain}/res/drawable/ic_currency_xaf.xml (100%) rename services/opencode/src/{main => androidMain}/res/drawable/ic_currency_xof.xml (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/ManagerFactory.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/ProtocolConfig.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/controllers/AccountController.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/controllers/BalanceController.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/controllers/CurrencyController.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/controllers/MessagingController.kt (99%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/controllers/TokenController.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/controllers/TransactionController.kt (99%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/controllers/TransactionOperations.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/events/Events.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/exchange/Exchange.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/exchange/VerifiedFiatCalculator.kt (91%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/generators/GiftCardGenerator.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/generators/MnemonicGenerator.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/annotations/OpenCodeManagedChannel.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/annotations/Protocol.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/bidi/BidirectionalStreamReference.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/bidi/OpenStream.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/bidi/OpenStreamForResult.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/domain/mapping/BillCustomizationMapper.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/domain/mapping/HistoricalMintDataMapper.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/domain/mapping/HolderMetricsMapper.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/domain/mapping/LaunchpadMetadataMapper.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/domain/mapping/LiveMintDataMapper.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/domain/mapping/MarketCapMetricsMapper.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/domain/mapping/MessageMapper.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/domain/mapping/MintMapper.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/domain/mapping/OwnerBalanceMapper.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/domain/mapping/SocialLinkMapper.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/domain/mapping/SwapMetadataMapper.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/domain/mapping/TransactionMetadataMapper.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/domain/mapping/VmMetadataMapper.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/domain/repositories/InternalAccountRepository.kt (98%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/domain/repositories/InternalBalanceRepository.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/domain/repositories/InternalCurrencyRepository.kt (98%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/domain/repositories/InternalEventRepository.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/domain/repositories/InternalMessagingRepository.kt (98%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/domain/repositories/InternalSwapRepository.kt (97%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/domain/repositories/InternalTransactionRepository.kt (99%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/exchange/OpenCodeExchange.kt (89%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/exchange/RealVerifiedFiatCalculator.kt (99%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/extensions/ByteArray.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/extensions/Currency.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/extensions/CurrencyCode.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/extensions/Instant.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/extensions/KeyPair.kt (80%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/extensions/PublicKey.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/extensions/Result.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/extensions/VerifiedState.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/generator/Generator.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/manager/VerifiedProtoManager.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/network/api/AccountApi.kt (98%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/network/api/BalanceApi.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/network/api/CurrencyApi.kt (99%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/network/api/MessagingApi.kt (98%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/network/api/TransactionApi.kt (99%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/network/api/intents/IntentCreateAccount.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/network/api/intents/IntentDistribution.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/network/api/intents/IntentFundSwap.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/network/api/intents/IntentMultiTransfer.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/network/api/intents/IntentRemoteReceive.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/network/api/intents/IntentRemoteSend.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/network/api/intents/IntentStatefulSwap.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/network/api/intents/IntentStatelessSwap.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/network/api/intents/IntentTransfer.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/network/api/intents/IntentWithdraw.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/network/api/intents/actions/ActionFeePayment.kt (98%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/network/api/intents/actions/ActionOpenAccount.kt (98%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/network/api/intents/actions/ActionPublicTransfer.kt (98%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/network/api/intents/actions/ActionPublicWithdraw.kt (98%) create mode 100644 services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/core/GrpcApi.kt rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/network/executors/IntentExecutor.kt (98%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/network/executors/StatefulSwapExecutor.kt (99%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/network/executors/StatelessSwapExecutor.kt (98%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/network/extensions/FoldWithSuppression.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/network/extensions/LocalToProtobuf.kt (99%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/network/extensions/ProtobufToLocal.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/network/extensions/SignMessage.kt (94%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/network/funding/SwapFunding.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/network/pollers/SwapPoller.kt (99%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/network/serializer/UUIDSerializer.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/network/services/AccountService.kt (98%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/network/services/BalanceService.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/network/services/CurrencyService.kt (99%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/network/services/MessagingService.kt (99%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/network/services/SwapService.kt (98%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/network/services/TransactionService.kt (99%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/network/streamers/LiveMintDataStreamer.kt (100%) create mode 100644 services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/platform/ProcessLifecycle.kt rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/solana/Definitions.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/solana/ShortVec.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/solana/extensions/AssociatedTokenAccount.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/solana/extensions/ExtractServerParameters.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/solana/extensions/PublicKey.kt (99%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/solana/extensions/TimelockDerivedAccounts.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/solana/extensions/Token.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/solana/extensions/UInt16.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/solana/model/CoinbaseStablecoinPoolAccount.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/solana/model/CoinbaseSwapAccounts.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/solana/model/MessageAddressLookupTable.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/solana/model/SwapId.kt (90%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/solana/model/Vault.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/solana/programs/AssociatedTokenProgram.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/solana/programs/AssociatedTokenProgram_CreateIdempotent.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/solana/programs/CoinbaseStableSwapperProgram.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/solana/programs/CoinbaseStableSwapperProgram_SwapV2.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/solana/programs/ComputeBudgetProgram.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/solana/programs/ComputeBudgetProgram_SetComputeUnitLimit.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/solana/programs/ComputeBudgetProgram_SetComputeUnitPrice.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/solana/programs/CurrencyCreatorProgram.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/solana/programs/CurrencyCreatorProgram_BuyAndDepositIntoVm.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/solana/programs/CurrencyCreatorProgram_BuyTokens.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/solana/programs/CurrencyCreatorProgram_InitializeCurrency.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/solana/programs/CurrencyCreatorProgram_InitializePool.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/solana/programs/CurrencyCreatorProgram_SellAndDepositIntoVm.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/solana/programs/CurrencyCreatorProgram_SellTokens.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/solana/programs/InstructionType.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/solana/programs/MemoProgram.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/solana/programs/MemoProgram_Memo.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/solana/programs/SwapValidatorProgram.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/solana/programs/SysVar.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/solana/programs/SystemProgram.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/solana/programs/SystemProgram_AdvanceNonce.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/solana/programs/TimelockProgram.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/solana/programs/TokenProgram.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/solana/programs/TokenProgram_CloseAccount.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/solana/programs/TokenProgram_Transfer.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/solana/programs/UsdfProgram.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/solana/programs/UsdfProgram_Swap.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/solana/programs/UsdfProgram_Transfer.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/solana/programs/VirtualMachineProgram.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/solana/programs/VirtualMachineProgram_CloseSwapAccountIfEmpty.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/solana/programs/VirtualMachineProgram_InitVm.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/solana/programs/VirtualMachineProgram_TransferForSwap.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/solana/programs/VirtualMachineProgram_TransferForSwapWithFee.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/solana/utils/DataSlice.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/solana/utils/Differ.kt (75%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/transactors/AccountClusterFactory.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/transactors/BillPresentationData.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/transactors/GiveBillTransactor.kt (99%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/transactors/GrabBillTransactor.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/transactors/PayloadFactory.kt (96%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/transactors/ReceiveGiftCardTransactor.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/transactors/SendGiftCardTransactor.kt (99%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/internal/transactors/Transactor.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/managers/BillTransactionManager.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/managers/GiftCardManager.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/managers/MnemonicManager.kt (96%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/mapper/Mapper.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/model/accounts/AccountCluster.kt (98%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/model/accounts/AccountFilter.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/model/accounts/AccountInfo.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/model/accounts/AccountResponse.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/model/accounts/AccountType.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/model/accounts/GiftCardAccount.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/model/accounts/PoolAccount.kt (95%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/model/core/EncryptedData.kt (89%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/model/core/ID.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/model/core/OpenCodePayload.kt (96%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/model/core/PayloadKind.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/model/core/PayloadValue.kt (100%) create mode 100644 services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/core/ScanCodeEncoder.kt rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/model/core/UUID.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/model/core/errors/Errors.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/model/core/errors/SodiumError.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/model/core/errors/ValidationException.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/model/financial/Currency.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/model/financial/CurrencyCode.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/model/financial/Distribution.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/model/financial/Fee.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/model/financial/Fiat.kt (99%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/model/financial/HistoricalMintData.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/model/financial/LaunchpadReserveStateSnapshot.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/model/financial/LaunchpadSellFee.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/model/financial/Limits.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/model/financial/LocalFiat.kt (98%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/model/financial/MintMetadata.kt (98%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/model/financial/MintStreamingData.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/model/financial/OwnerBalance.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/model/financial/Rate.kt (83%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/model/financial/RegionCode.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/model/financial/TokenCreateRequest.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/model/financial/TokenResult.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/model/financial/TokenUpdateRequest.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/model/messaging/KeepAliveRequest.kt (83%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/model/messaging/Message.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/model/moderation/ModerationAttestation.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/model/transactions/AddressLookupTable.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/model/transactions/ExchangeData.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/model/transactions/FundSwapPool.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/model/transactions/LiquidityPool.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/model/transactions/StartSwapServerParameters.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/model/transactions/StatefulSwapRequest.kt (98%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/model/transactions/StatefulSwapResponseServerParameters.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/model/transactions/StatefulSwapResult.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/model/transactions/StatelessSwapRequest.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/model/transactions/StatelessSwapResult.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/model/transactions/StatelessSwapServerParameters.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/model/transactions/SwapFundingSource.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/model/transactions/SwapMetadata.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/model/transactions/SwapRoute.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/model/transactions/TransactionMetadata.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/model/transactions/TransferRequest.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/model/transactions/WithdrawalAvailability.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/model/ui/BillCustomization.kt (95%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/model/ui/DiscoverCategory.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/model/ui/WindowedRange.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/providers/SessionListener.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/providers/TokenMetadataProvider.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/repositories/AccountRepository.kt (95%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/repositories/BalanceRepository.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/repositories/CurrencyRepository.kt (97%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/repositories/EventRepository.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/repositories/MessagingRepository.kt (96%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/repositories/SwapRepository.kt (94%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/repositories/TransactionRepository.kt (98%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/solana/Instruction.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/solana/LegacyMessage.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/solana/Message.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/solana/MessageHeader.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/solana/SolanaTransaction.kt (99%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/solana/TransactionBuilder.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/solana/VersionedMessage.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/solana/intents/ActionGroup.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/solana/intents/IntentType.kt (98%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/solana/intents/ServerParameter.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/solana/intents/actions/ActionType.kt (98%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/solana/keys/ProgramDerivedAccount.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/solana/keys/TimelockVmSwapAccounts.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/solana/swap/CoinbaseStablecoinSwapperInstructions.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/solana/swap/CrossCurrencyExistingSwapInstructions.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/solana/swap/ExistingCurrencyBuyInstructions.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/solana/swap/NewCurrencyBuyInstructions.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/solana/swap/SellInstructions.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/solana/swap/UsdcDepositInstructions.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/solana/swap/UsdcDepositSweepInstructions.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/solana/swap/UsdcToUsdfSwapInstructions.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/solana/swap/UsdfDepositInstructions.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/utils/Double.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/utils/Flow.kt (97%) create mode 100644 services/opencode/src/commonMain/kotlin/com/getcode/opencode/utils/KeyPair.kt rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/utils/Long.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/utils/Maps.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/utils/Nonce.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/utils/PublicKey.kt (85%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/utils/Result.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/utils/String.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/utils/Throwable.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/utils/logging/LoggingClientCall.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/utils/logging/LoggingClientCallListener.kt (100%) rename services/opencode/src/{main => commonMain}/kotlin/com/getcode/opencode/utils/logging/LoggingClientInterceptor.kt (100%) create mode 100644 services/opencode/src/jvmMain/kotlin/com/getcode/opencode/internal/platform/ProcessLifecycle.jvm.kt create mode 100644 services/opencode/src/jvmMain/kotlin/com/getcode/opencode/model/core/ScanCodeEncoder.jvm.kt create mode 100644 services/opencode/src/jvmTest/kotlin/com/getcode/opencode/HeadlessBalanceTest.kt delete mode 100644 services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/core/GrpcApi.kt delete mode 100644 services/opencode/src/main/kotlin/com/getcode/opencode/utils/KeyPair.kt diff --git a/apps/flipcash/app/src/main/kotlin/com/flipcash/app/internal/startup/MnemonicCacheInitializer.kt b/apps/flipcash/app/src/main/kotlin/com/flipcash/app/internal/startup/MnemonicCacheInitializer.kt index d5aa7f237f..824fc6a836 100644 --- a/apps/flipcash/app/src/main/kotlin/com/flipcash/app/internal/startup/MnemonicCacheInitializer.kt +++ b/apps/flipcash/app/src/main/kotlin/com/flipcash/app/internal/startup/MnemonicCacheInitializer.kt @@ -6,7 +6,8 @@ import com.getcode.crypt.MnemonicCache class MnemonicCacheInitializer: Initializer { override fun create(context: Context) { - MnemonicCache.init(context) + // Touching the cache loads the BIP39 word list at startup rather than on first use. + MnemonicCache.cachedCode } override fun dependencies(): List?>?> { diff --git a/apps/flipcash/shared/authentication/src/main/kotlin/com/flipcash/app/auth/internal/accounts/AccountProfileFetcher.kt b/apps/flipcash/shared/authentication/src/main/kotlin/com/flipcash/app/auth/internal/accounts/AccountProfileFetcher.kt index cc2021b058..65d997bda1 100644 --- a/apps/flipcash/shared/authentication/src/main/kotlin/com/flipcash/app/auth/internal/accounts/AccountProfileFetcher.kt +++ b/apps/flipcash/shared/authentication/src/main/kotlin/com/flipcash/app/auth/internal/accounts/AccountProfileFetcher.kt @@ -4,7 +4,7 @@ import com.flipcash.services.models.GetUserProfileError import com.flipcash.services.models.ProfileIdentifier import com.flipcash.services.repository.AccountRepository import com.flipcash.services.repository.ProfileRepository -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair import com.getcode.opencode.model.core.ID import javax.inject.Inject diff --git a/apps/flipcash/shared/authentication/src/main/kotlin/com/flipcash/app/auth/internal/credentials/PassphraseCredentialManager.kt b/apps/flipcash/shared/authentication/src/main/kotlin/com/flipcash/app/auth/internal/credentials/PassphraseCredentialManager.kt index bfecc0d7cf..26c2f982d3 100644 --- a/apps/flipcash/shared/authentication/src/main/kotlin/com/flipcash/app/auth/internal/credentials/PassphraseCredentialManager.kt +++ b/apps/flipcash/shared/authentication/src/main/kotlin/com/flipcash/app/auth/internal/credentials/PassphraseCredentialManager.kt @@ -13,7 +13,7 @@ import com.flipcash.app.auth.internal.accounts.AccountStoreMigration import com.flipcash.services.controllers.AccountController import com.flipcash.services.user.AuthState import com.flipcash.services.user.UserManager -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.opencode.model.core.ID import com.getcode.utils.base58 import com.getcode.utils.encodeBase64 diff --git a/apps/flipcash/shared/authentication/src/test/kotlin/com/flipcash/app/auth/internal/accounts/AccountProfileFetcherTest.kt b/apps/flipcash/shared/authentication/src/test/kotlin/com/flipcash/app/auth/internal/accounts/AccountProfileFetcherTest.kt index 8900f70124..7eb7c6d3bd 100644 --- a/apps/flipcash/shared/authentication/src/test/kotlin/com/flipcash/app/auth/internal/accounts/AccountProfileFetcherTest.kt +++ b/apps/flipcash/shared/authentication/src/test/kotlin/com/flipcash/app/auth/internal/accounts/AccountProfileFetcherTest.kt @@ -5,7 +5,7 @@ import com.flipcash.services.models.ProfileIdentifier import com.flipcash.services.models.UserProfile import com.flipcash.services.repository.AccountRepository import com.flipcash.services.repository.ProfileRepository -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair import io.mockk.coEvery import io.mockk.coVerify import io.mockk.mockk diff --git a/apps/flipcash/shared/shareable/src/main/kotlin/com/flipcash/app/shareable/ShareSheetController.kt b/apps/flipcash/shared/shareable/src/main/kotlin/com/flipcash/app/shareable/ShareSheetController.kt index 7827617c05..acb935aefc 100644 --- a/apps/flipcash/shared/shareable/src/main/kotlin/com/flipcash/app/shareable/ShareSheetController.kt +++ b/apps/flipcash/shared/shareable/src/main/kotlin/com/flipcash/app/shareable/ShareSheetController.kt @@ -4,7 +4,7 @@ import androidx.compose.runtime.ProvidableCompositionLocal import androidx.compose.runtime.staticCompositionLocalOf import com.flipcash.app.core.share.TipCodeExport import com.flipcash.app.core.share.TipCodePreview -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.opencode.model.accounts.GiftCardAccount import com.getcode.opencode.model.core.ID import com.getcode.opencode.model.financial.LocalFiat diff --git a/build-logic/convention/src/main/kotlin/KmpAppLibraryConventionPlugin.kt b/build-logic/convention/src/main/kotlin/KmpAppLibraryConventionPlugin.kt index f73a5d2110..30e9766e70 100644 --- a/build-logic/convention/src/main/kotlin/KmpAppLibraryConventionPlugin.kt +++ b/build-logic/convention/src/main/kotlin/KmpAppLibraryConventionPlugin.kt @@ -75,6 +75,9 @@ class KmpAppLibraryConventionPlugin : Plugin { } } minSdk = minSdkVersion + // Hilt's KSP processors emit Java (factories, hilt_aggregated_deps), which the + // KMP Android target only compiles when Java compilation is enabled. + withJava() withHostTestBuilder {}.configure { isReturnDefaultValues = true isIncludeAndroidResources = true diff --git a/libs/datetime/src/androidMain/kotlin/com/getcode/util/DateUtils.kt b/libs/datetime/src/androidMain/kotlin/com/getcode/util/DateUtils.kt index fd9c3eaf55..0e0f863d71 100644 --- a/libs/datetime/src/androidMain/kotlin/com/getcode/util/DateUtils.kt +++ b/libs/datetime/src/androidMain/kotlin/com/getcode/util/DateUtils.kt @@ -50,8 +50,6 @@ object DateUtils { private fun isYesterday(millis: Long) = isToday(millis + DateUtils.DAY_IN_MILLIS) } -fun Long.toInstantFromMillis() = Instant.fromEpochMilliseconds(this) - fun Instant.formatDateRelatively(): String { return com.getcode.util.DateUtils.getDateRelatively(toEpochMilliseconds()) } diff --git a/libs/datetime/src/commonMain/kotlin/com/getcode/util/Instant.kt b/libs/datetime/src/commonMain/kotlin/com/getcode/util/Instant.kt index c966ff01bb..7d56a70cb9 100644 --- a/libs/datetime/src/commonMain/kotlin/com/getcode/util/Instant.kt +++ b/libs/datetime/src/commonMain/kotlin/com/getcode/util/Instant.kt @@ -42,4 +42,6 @@ fun Instant.formatLocalized( } else { format(if12Hour, Locale.US) } -} \ No newline at end of file +} + +fun Long.toInstantFromMillis() = kotlin.time.Instant.fromEpochMilliseconds(this) diff --git a/libs/encryption/ed25519/build.gradle.kts b/libs/encryption/ed25519/build.gradle.kts index 28dac3e0e8..7ec3b4596d 100644 --- a/libs/encryption/ed25519/build.gradle.kts +++ b/libs/encryption/ed25519/build.gradle.kts @@ -1,3 +1,4 @@ +import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget plugins { @@ -112,10 +113,26 @@ kotlin { } } + // jvmShared: the string-keyed Ed25519 API for both JVM targets (Android and desktop). + @OptIn(org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi::class) + applyDefaultHierarchyTemplate { + common { + group("jvmShared") { + withJvm() + withCompilations { it.platformType == KotlinPlatformType.androidJvm } + } + } + } + sourceSets { commonMain { // Ed25519Kmp expect object + KeyPair — no external deps. } + getByName("jvmSharedMain") { + dependencies { + api(project(":libs:parcelable")) + } + } androidMain { dependencies { // Delegate to the JNI module for NDK/CMake compilation. `api` (not diff --git a/libs/encryption/ed25519/src/androidMain/kotlin/com/getcode/ed25519kmp/RandomSeed.android.kt b/libs/encryption/ed25519/src/androidMain/kotlin/com/getcode/ed25519kmp/RandomSeed.android.kt new file mode 100644 index 0000000000..7db1155470 --- /dev/null +++ b/libs/encryption/ed25519/src/androidMain/kotlin/com/getcode/ed25519kmp/RandomSeed.android.kt @@ -0,0 +1,9 @@ +package com.getcode.ed25519kmp + +import com.getcode.ed25519.Ed25519 as JniEd25519 + +internal actual fun randomSeed(size: Int): ByteArray = when (size) { + 16 -> JniEd25519.createSeed16() + 32 -> JniEd25519.createSeed32() + else -> error("Unsupported seed size $size") +} diff --git a/libs/encryption/ed25519/src/jvmMain/kotlin/com/getcode/ed25519kmp/RandomSeed.jvm.kt b/libs/encryption/ed25519/src/jvmMain/kotlin/com/getcode/ed25519kmp/RandomSeed.jvm.kt new file mode 100644 index 0000000000..e763d9088a --- /dev/null +++ b/libs/encryption/ed25519/src/jvmMain/kotlin/com/getcode/ed25519kmp/RandomSeed.jvm.kt @@ -0,0 +1,7 @@ +package com.getcode.ed25519kmp + +import java.security.SecureRandom + +private val random = SecureRandom() + +internal actual fun randomSeed(size: Int): ByteArray = ByteArray(size).also(random::nextBytes) diff --git a/libs/encryption/ed25519/src/jvmSharedMain/kotlin/com/getcode/ed25519kmp/Ed25519.kt b/libs/encryption/ed25519/src/jvmSharedMain/kotlin/com/getcode/ed25519kmp/Ed25519.kt new file mode 100644 index 0000000000..e05c9c31ba --- /dev/null +++ b/libs/encryption/ed25519/src/jvmSharedMain/kotlin/com/getcode/ed25519kmp/Ed25519.kt @@ -0,0 +1,87 @@ +package com.getcode.ed25519kmp + +import com.getcode.libs.parcelable.ManualParcelable +import com.getcode.libs.parcelable.Parcel +import com.getcode.libs.parcelable.parcelableCreator +import java.util.Base64 + +/** + * The string-keyed Ed25519 API the app was written against, shared by Android and desktop. + * + * Mirrors the JNI class `com.getcode.ed25519.Ed25519` member for member, so callers only change + * the import. Key strings keep the JNI's format (unwrapped base64), and a seed made from bytes keeps + * the `Base64.DEFAULT` format the JNI class stored, so serialized seeds and parcels are unchanged. + */ +object Ed25519 { + + fun createKeyPair(): KeyPair = createKeyPair(createSeed32()) + + /** [seed] is base64, as produced by [KeyPair.seed]. */ + fun createKeyPair(seed: String): KeyPair { + val pair = Ed25519Kmp.createKeyPair(decode(seed)) + return KeyPair(encode(pair.publicKey), encode(pair.privateKey), seed) + } + + fun createKeyPair(seed: ByteArray): KeyPair { + val pair = Ed25519Kmp.createKeyPair(seed) + return KeyPair(encode(pair.publicKey), encode(pair.privateKey), encodeDefault(seed)) + } + + fun createSeed16(): ByteArray = randomSeed(16) + + fun createSeed32(): ByteArray = randomSeed(32) + + fun sign(message: ByteArray, keyPair: KeyPair): ByteArray = + Ed25519Kmp.sign(message, keyPair.publicKeyBytes, keyPair.privateKeyBytes) + + fun verify(signature: ByteArray, message: ByteArray, publicKey: ByteArray): Boolean = + Ed25519Kmp.verify(signature, message, publicKey) + + fun onCurve(publicKey: ByteArray): Boolean = Ed25519Kmp.onCurve(publicKey) + + class KeyPair( + val publicKey: String, + val privateKey: String, + val seed: String?, + ) : ManualParcelable { + + val publicKeyBytes: ByteArray get() = decode(publicKey) + + val privateKeyBytes: ByteArray get() = decode(privateKey) + + fun sign(message: ByteArray): ByteArray = Ed25519.sign(message, this) + + fun verify(signature: ByteArray, message: ByteArray): Boolean = + Ed25519.verify(signature, message, publicKeyBytes) + + override fun equals(other: Any?): Boolean = + other is KeyPair && publicKey == other.publicKey && privateKey == other.privateKey + + override fun hashCode(): Int = java.util.Objects.hash(publicKey, privateKey) + + override fun describeContents(): Int = 0 + + override fun writeToParcel(dest: Parcel, flags: Int) { + dest.writeString(publicKey) + dest.writeString(privateKey) + dest.writeString(seed) + } + + companion object { + @JvmField + val CREATOR: Any = parcelableCreator({ arrayOfNulls(it) }) { parcel -> + KeyPair(checkNotNull(parcel.readString()), checkNotNull(parcel.readString()), parcel.readString()) + } + } + } +} + +internal expect fun randomSeed(size: Int): ByteArray + +private fun encode(bytes: ByteArray): String = Base64.getEncoder().encodeToString(bytes) + +// android.util.Base64.DEFAULT: 76-character lines, each ending in "\n". +private fun encodeDefault(bytes: ByteArray): String = + Base64.getMimeEncoder(76, byteArrayOf('\n'.code.toByte())).encodeToString(bytes) + "\n" + +private fun decode(base64: String): ByteArray = Base64.getMimeDecoder().decode(base64) diff --git a/libs/encryption/mnemonic/build.gradle.kts b/libs/encryption/mnemonic/build.gradle.kts index 6752d8968c..812aba854b 100644 --- a/libs/encryption/mnemonic/build.gradle.kts +++ b/libs/encryption/mnemonic/build.gradle.kts @@ -1,3 +1,5 @@ +import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType + plugins { alias(libs.plugins.flipcash.kmp.library) alias(libs.plugins.flipcash.kmp.test.fixtures) @@ -9,7 +11,18 @@ testFixtures { packageName = "com.getcode.crypt" } +@OptIn(org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi::class) kotlin { + // jvmShared: key and phrase types for both JVM targets (Android and desktop). + applyDefaultHierarchyTemplate { + common { + group("jvmShared") { + withJvm() + withCompilations { it.platformType == KotlinPlatformType.androidJvm } + } + } + } + android { namespace = "com.getcode.encryption.mnemonic" withHostTest {} @@ -32,10 +45,14 @@ kotlin { implementation(libs.kotlinx.serialization.json) } } - androidMain { + getByName("jvmSharedMain") { dependencies { // Legacy vendored Base58 codec (fromEntropyB58/getBase58EncodedEntropy). implementation(project(":libs:encryption:base58")) + } + } + androidMain { + dependencies { // Domain.kt uses android.net.Uri. implementation(libs.androidx.core) } diff --git a/libs/encryption/mnemonic/src/androidMain/kotlin/com/getcode/crypt/MnemonicCache.kt b/libs/encryption/mnemonic/src/androidMain/kotlin/com/getcode/crypt/MnemonicCache.kt deleted file mode 100644 index 44b068ffd9..0000000000 --- a/libs/encryption/mnemonic/src/androidMain/kotlin/com/getcode/crypt/MnemonicCache.kt +++ /dev/null @@ -1,15 +0,0 @@ -package com.getcode.crypt - -import android.content.Context - -object MnemonicCache { - val cachedCode: MnemonicCode = MnemonicCode - - fun init(context: Context) { - // MnemonicCode no longer needs Android resources -- the wordlist is a compile-time - // constant (see Bip39EnglishWordList). Kept so MnemonicCacheInitializer's startup - // call still compiles. - } - - val cache = mutableMapOf, String>, ByteArray>() -} diff --git a/libs/encryption/mnemonic/src/androidMain/kotlin/com/getcode/crypt/DerivedKey.kt b/libs/encryption/mnemonic/src/jvmSharedMain/kotlin/com/getcode/crypt/DerivedKey.kt similarity index 95% rename from libs/encryption/mnemonic/src/androidMain/kotlin/com/getcode/crypt/DerivedKey.kt rename to libs/encryption/mnemonic/src/jvmSharedMain/kotlin/com/getcode/crypt/DerivedKey.kt index a4536b5429..fc534ecf42 100644 --- a/libs/encryption/mnemonic/src/androidMain/kotlin/com/getcode/crypt/DerivedKey.kt +++ b/libs/encryption/mnemonic/src/jvmSharedMain/kotlin/com/getcode/crypt/DerivedKey.kt @@ -1,6 +1,6 @@ package com.getcode.crypt -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 data class DerivedKey(val path: DerivePath, val keyPair: Ed25519.KeyPair) { diff --git a/libs/encryption/mnemonic/src/jvmSharedMain/kotlin/com/getcode/crypt/MnemonicCache.kt b/libs/encryption/mnemonic/src/jvmSharedMain/kotlin/com/getcode/crypt/MnemonicCache.kt new file mode 100644 index 0000000000..7b152e37f3 --- /dev/null +++ b/libs/encryption/mnemonic/src/jvmSharedMain/kotlin/com/getcode/crypt/MnemonicCache.kt @@ -0,0 +1,7 @@ +package com.getcode.crypt + +object MnemonicCache { + val cachedCode: MnemonicCode = MnemonicCode + + val cache = mutableMapOf, String>, ByteArray>() +} diff --git a/libs/encryption/mnemonic/src/androidMain/kotlin/com/getcode/crypt/MnemonicPhrase.kt b/libs/encryption/mnemonic/src/jvmSharedMain/kotlin/com/getcode/crypt/MnemonicPhrase.kt similarity index 98% rename from libs/encryption/mnemonic/src/androidMain/kotlin/com/getcode/crypt/MnemonicPhrase.kt rename to libs/encryption/mnemonic/src/jvmSharedMain/kotlin/com/getcode/crypt/MnemonicPhrase.kt index c8cd5bd23d..c99013c2a1 100644 --- a/libs/encryption/mnemonic/src/androidMain/kotlin/com/getcode/crypt/MnemonicPhrase.kt +++ b/libs/encryption/mnemonic/src/jvmSharedMain/kotlin/com/getcode/crypt/MnemonicPhrase.kt @@ -1,6 +1,6 @@ package com.getcode.crypt -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.utils.decodeBase64 import com.getcode.utils.encodeBase64 import com.getcode.vendor.Base58 diff --git a/libs/encryption/utils/build.gradle.kts b/libs/encryption/utils/build.gradle.kts index 41a6ca18d0..e8e693884c 100644 --- a/libs/encryption/utils/build.gradle.kts +++ b/libs/encryption/utils/build.gradle.kts @@ -30,11 +30,11 @@ kotlin { getByName("jvmSharedMain") { dependencies { implementation(libs.protobuf.kotlin.lite) + implementation(project(":libs:encryption:ed25519")) } } androidMain { dependencies { - implementation(project(":libs:encryption:ed25519")) implementation(libs.bundles.kotlinx.serialization) implementation(libs.timber) } diff --git a/libs/encryption/utils/src/androidMain/kotlin/com/getcode/utils/Ed25519Extensions.android.kt b/libs/encryption/utils/src/jvmSharedMain/kotlin/com/getcode/utils/Ed25519Extensions.kt similarity index 78% rename from libs/encryption/utils/src/androidMain/kotlin/com/getcode/utils/Ed25519Extensions.android.kt rename to libs/encryption/utils/src/jvmSharedMain/kotlin/com/getcode/utils/Ed25519Extensions.kt index c5edb257bf..fc2be84b77 100644 --- a/libs/encryption/utils/src/androidMain/kotlin/com/getcode/utils/Ed25519Extensions.android.kt +++ b/libs/encryption/utils/src/jvmSharedMain/kotlin/com/getcode/utils/Ed25519Extensions.kt @@ -1,6 +1,6 @@ package com.getcode.utils -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.vendor.Base58 fun Ed25519.KeyPair.getPublicKeyBase58(): String = Base58.encode(publicKeyBytes) diff --git a/libs/logging/src/androidMain/kotlin/com/getcode/utils/PlatformLog.android.kt b/libs/logging/src/androidMain/kotlin/com/getcode/utils/PlatformLog.android.kt index bb9eab709a..2e5b41e2a7 100644 --- a/libs/logging/src/androidMain/kotlin/com/getcode/utils/PlatformLog.android.kt +++ b/libs/logging/src/androidMain/kotlin/com/getcode/utils/PlatformLog.android.kt @@ -14,6 +14,10 @@ internal actual object PlatformLog { actual fun error(throwable: Throwable) { Timber.e(throwable) } + + actual fun error(throwable: Throwable, message: String?) { + Timber.e(throwable, message) + } } internal actual fun isPlatformSqlException(throwable: Throwable): Boolean = throwable is SQLException diff --git a/libs/logging/src/commonMain/kotlin/com/getcode/utils/PlatformLog.kt b/libs/logging/src/commonMain/kotlin/com/getcode/utils/PlatformLog.kt index aa2588a5bf..d92204d232 100644 --- a/libs/logging/src/commonMain/kotlin/com/getcode/utils/PlatformLog.kt +++ b/libs/logging/src/commonMain/kotlin/com/getcode/utils/PlatformLog.kt @@ -16,6 +16,7 @@ object LogPriority { internal expect object PlatformLog { fun log(priority: Int, tag: String?, message: String) fun error(throwable: Throwable) + fun error(throwable: Throwable, message: String?) } /** The platform's `SQLException`, which [ErrorUtils] treats as suppressible. */ @@ -32,3 +33,14 @@ interface LogFileStore { /** Stops writing to the log. Called when [TraceManager] is reset. */ fun close() } + +/** + * Writes straight to the platform log: Timber on Android, standard error on the desktop JVM. + * + * Unlike [trace], it is not gated on [TraceManager] and never reports errors. + */ +object Log { + fun d(message: String) = PlatformLog.log(LogPriority.DEBUG, null, message) + + fun e(throwable: Throwable, message: String?) = PlatformLog.error(throwable, message) +} diff --git a/libs/logging/src/jvmMain/kotlin/com/getcode/utils/PlatformLog.jvm.kt b/libs/logging/src/jvmMain/kotlin/com/getcode/utils/PlatformLog.jvm.kt index f91e3777b3..9ac65d65a6 100644 --- a/libs/logging/src/jvmMain/kotlin/com/getcode/utils/PlatformLog.jvm.kt +++ b/libs/logging/src/jvmMain/kotlin/com/getcode/utils/PlatformLog.jvm.kt @@ -17,6 +17,11 @@ internal actual object PlatformLog { actual fun error(throwable: Throwable) { throwable.printStackTrace() } + + actual fun error(throwable: Throwable, message: String?) { + message?.let { System.err.println("E $it") } + throwable.printStackTrace() + } } internal actual fun isPlatformSqlException(throwable: Throwable): Boolean = throwable is SQLException diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/controllers/BlobStorageController.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/controllers/BlobStorageController.kt index 804a34410b..a4fdb8cffd 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/controllers/BlobStorageController.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/controllers/BlobStorageController.kt @@ -16,7 +16,7 @@ import com.flipcash.services.models.chat.ChatId import com.flipcash.services.models.blob.UploadReservation import com.flipcash.services.repository.BlobStorageRepository import com.flipcash.services.user.UserManager -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.utils.base58 import kotlinx.coroutines.delay import javax.inject.Inject diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/extensions/KeyPair.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/extensions/KeyPair.kt index 445a8833e3..446d1e9c70 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/extensions/KeyPair.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/extensions/KeyPair.kt @@ -3,8 +3,8 @@ package com.flipcash.services.extensions import android.util.Base64 import com.flipcash.services.internal.extensions.toPublicKey import com.getcode.crypt.Sha256Hash -import com.getcode.ed25519.Ed25519 -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519 +import com.getcode.ed25519kmp.Ed25519.KeyPair import com.getcode.opencode.model.core.ID import com.getcode.solana.keys.PublicKey import com.getcode.solana.keys.Seed32 diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/extensions/KeyPair.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/extensions/KeyPair.kt index 727cb06c3f..c48ed2738b 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/extensions/KeyPair.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/extensions/KeyPair.kt @@ -1,6 +1,6 @@ package com.flipcash.services.internal.extensions -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair import com.getcode.solana.keys.PublicKey internal fun KeyPair.asPublicKey(): PublicKey { diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/AccountApi.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/AccountApi.kt index fd6c0b52d6..987d1d8cab 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/AccountApi.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/AccountApi.kt @@ -9,7 +9,7 @@ import com.flipcash.services.internal.network.extensions.asPublicKey import com.flipcash.services.internal.network.extensions.asUserId import com.flipcash.services.internal.network.extensions.authenticate import com.flipcash.services.internal.network.extensions.sign -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair import com.getcode.opencode.internal.network.core.GrpcApi import com.getcode.opencode.model.core.ID import com.google.protobuf.Timestamp diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/ActivityFeedApi.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/ActivityFeedApi.kt index 27c4815e4a..92c55c6150 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/ActivityFeedApi.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/ActivityFeedApi.kt @@ -10,7 +10,7 @@ import com.flipcash.services.internal.network.extensions.authenticate import com.flipcash.services.internal.network.extensions.toNotificationIds import com.flipcash.services.models.ActivityFeedType import com.flipcash.services.models.QueryOptions -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair import com.getcode.opencode.internal.network.core.GrpcApi import com.getcode.opencode.model.core.ID import dev.bmcreations.protovalidate.orThrow diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/BlobStorageApi.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/BlobStorageApi.kt index 2f4a7f4654..66d4f657a7 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/BlobStorageApi.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/BlobStorageApi.kt @@ -12,7 +12,7 @@ import com.flipcash.services.internal.network.extensions.authenticate import com.flipcash.services.models.chat.BlobAccessContext import com.flipcash.services.models.chat.BlobId import com.flipcash.services.models.chat.ChatId -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.opencode.internal.network.core.GrpcApi import com.getcode.utils.toByteString import dev.bmcreations.protovalidate.orThrow diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/BlocklistApi.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/BlocklistApi.kt index 829de957a5..6f53872b87 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/BlocklistApi.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/BlocklistApi.kt @@ -8,7 +8,7 @@ import com.flipcash.services.internal.network.extensions.asQueryOptions import com.flipcash.services.internal.network.extensions.asUserId import com.flipcash.services.internal.network.extensions.authenticate import com.flipcash.services.models.QueryOptions -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair import com.getcode.opencode.internal.network.core.GrpcApi import com.getcode.opencode.model.core.ID import dev.bmcreations.protovalidate.orThrow diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/ChatApi.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/ChatApi.kt index 1dbae26170..64c6ddd113 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/ChatApi.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/ChatApi.kt @@ -26,7 +26,7 @@ import com.flipcash.services.models.chat.MuteState import com.flipcash.services.models.chat.StartChatParameters import com.flipcash.services.models.chat.ViewMode import com.getcode.utils.toByteString -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair import com.getcode.opencode.model.core.ID import com.getcode.opencode.internal.network.core.GrpcApi import dev.bmcreations.protovalidate.orThrow diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/ChatMessagingApi.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/ChatMessagingApi.kt index 3563dfd296..90837231bc 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/ChatMessagingApi.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/ChatMessagingApi.kt @@ -25,7 +25,7 @@ import com.flipcash.services.models.chat.TypingState import com.flipcash.services.models.chat.ViewMode import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flowOn -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair import com.getcode.opencode.internal.network.core.GrpcApi import dev.bmcreations.protovalidate.orThrow import io.grpc.ManagedChannel diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/CommunityApi.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/CommunityApi.kt index 837140bdce..3537dba74f 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/CommunityApi.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/CommunityApi.kt @@ -5,7 +5,7 @@ import com.codeinc.flipcash.gen.community.v1.CommunityGrpcKt import com.codeinc.flipcash.gen.community.v1.validate import com.flipcash.services.internal.annotations.FlipcashManagedChannel import com.flipcash.services.internal.network.extensions.authenticate -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair import com.getcode.opencode.internal.network.core.GrpcApi import com.getcode.solana.keys.Mint import com.getcode.utils.toByteString diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/ContactListApi.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/ContactListApi.kt index 46dfb6272d..84a95cf134 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/ContactListApi.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/ContactListApi.kt @@ -7,7 +7,7 @@ import com.flipcash.services.models.ContactMethod import com.flipcash.services.internal.annotations.FlipcashManagedChannel import com.flipcash.services.internal.network.extensions.asHash import com.flipcash.services.internal.network.extensions.authenticate -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair import com.getcode.opencode.internal.network.core.GrpcApi import com.getcode.solana.keys.Checksum import dev.bmcreations.protovalidate.orThrow diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/EmailVerificationApi.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/EmailVerificationApi.kt index e8ca56740d..dc9b764be6 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/EmailVerificationApi.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/EmailVerificationApi.kt @@ -7,7 +7,7 @@ import com.codeinc.flipcash.gen.common.v1.Common import com.flipcash.services.internal.annotations.FlipcashManagedChannel import com.flipcash.services.internal.network.extensions.authenticate import com.flipcash.services.models.ContactMethod -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.opencode.internal.network.core.GrpcApi import com.codeinc.flipcash.gen.email.v1.validate import dev.bmcreations.protovalidate.orThrow diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/ModerationApi.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/ModerationApi.kt index d5a28fb07b..9a75bace9a 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/ModerationApi.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/ModerationApi.kt @@ -5,7 +5,7 @@ import com.codeinc.flipcash.gen.moderation.v1.ModerationService import com.codeinc.flipcash.gen.moderation.v1.validate import com.flipcash.services.internal.annotations.FlipcashManagedChannel import com.flipcash.services.internal.network.extensions.authenticate -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.opencode.internal.network.core.GrpcApi import com.getcode.utils.toByteString import dev.bmcreations.protovalidate.orThrow diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/PhoneVerificationApi.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/PhoneVerificationApi.kt index 0cf8fc42a3..d97f5ed07a 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/PhoneVerificationApi.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/PhoneVerificationApi.kt @@ -7,7 +7,7 @@ import com.codeinc.flipcash.gen.phone.v1.PhoneVerificationService import com.flipcash.services.internal.annotations.FlipcashManagedChannel import com.flipcash.services.internal.network.extensions.authenticate import com.flipcash.services.models.ContactMethod -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.opencode.internal.network.core.GrpcApi import com.codeinc.flipcash.gen.phone.v1.validate import dev.bmcreations.protovalidate.orThrow diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/PollApi.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/PollApi.kt index fa14b13aa5..f75cbc2d87 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/PollApi.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/PollApi.kt @@ -8,7 +8,7 @@ import com.flipcash.services.internal.annotations.FlipcashManagedChannel import com.flipcash.services.internal.network.extensions.asChatId import com.flipcash.services.internal.network.extensions.authenticate import com.flipcash.services.models.chat.ChatId -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.opencode.internal.network.core.GrpcApi import dev.bmcreations.protovalidate.orThrow import io.grpc.ManagedChannel diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/ProfileApi.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/ProfileApi.kt index 0da8ac1a53..25be394dea 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/ProfileApi.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/ProfileApi.kt @@ -13,7 +13,7 @@ import com.flipcash.services.models.ProfileIdentifier import com.flipcash.services.models.SocialAccountLinkRequest import com.flipcash.services.models.SocialAccountUnlinkRequest import com.flipcash.services.models.chat.BlobId -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.opencode.internal.network.core.GrpcApi import com.getcode.opencode.model.financial.Fiat import com.getcode.utils.toByteString diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/PurchaseApi.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/PurchaseApi.kt index e357917859..a5285af4c8 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/PurchaseApi.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/PurchaseApi.kt @@ -8,7 +8,7 @@ import com.flipcash.services.internal.annotations.FlipcashManagedChannel import com.flipcash.services.internal.model.billing.IapMetadata import com.flipcash.services.internal.model.billing.Receipt import com.flipcash.services.internal.network.extensions.authenticate -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair import com.getcode.opencode.internal.network.core.GrpcApi import dev.bmcreations.protovalidate.orThrow import io.grpc.ManagedChannel diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/PushApi.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/PushApi.kt index 3ee2494b5b..ea3dcaa825 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/PushApi.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/PushApi.kt @@ -7,7 +7,7 @@ import com.codeinc.flipcash.gen.push.v1.PushService import com.codeinc.flipcash.gen.push.v1.validate import com.flipcash.services.internal.annotations.FlipcashManagedChannel import com.flipcash.services.internal.network.extensions.authenticate -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair import com.getcode.opencode.internal.network.core.GrpcApi import dev.bmcreations.protovalidate.orThrow import io.grpc.Deadline diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/ReportingApi.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/ReportingApi.kt index 1e000b00c2..7e840ce700 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/ReportingApi.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/ReportingApi.kt @@ -8,7 +8,7 @@ import com.flipcash.services.internal.network.extensions.asMessageId import com.flipcash.services.internal.network.extensions.asUserId import com.flipcash.services.internal.network.extensions.authenticate import com.flipcash.services.models.ReportTarget -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair import com.getcode.opencode.internal.network.core.GrpcApi import com.getcode.utils.toByteString import dev.bmcreations.protovalidate.orThrow diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/ResolverApi.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/ResolverApi.kt index 36ee7fa64a..cb5a3a173b 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/ResolverApi.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/ResolverApi.kt @@ -8,7 +8,7 @@ import com.flipcash.services.internal.annotations.FlipcashManagedChannel import com.flipcash.services.internal.network.extensions.asUserId import com.flipcash.services.internal.network.extensions.authenticate import com.flipcash.services.internal.network.extensions.asUsername -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair import com.getcode.opencode.internal.network.core.GrpcApi import dev.bmcreations.protovalidate.orThrow import io.grpc.ManagedChannel diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/SettingsApi.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/SettingsApi.kt index 13db7db1dc..df32d27e61 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/SettingsApi.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/SettingsApi.kt @@ -6,7 +6,7 @@ import com.codeinc.flipcash.gen.settings.v1.SettingsService import com.codeinc.flipcash.gen.settings.v1.validate import com.flipcash.services.internal.annotations.FlipcashManagedChannel import com.flipcash.services.internal.network.extensions.authenticate -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.opencode.internal.network.core.GrpcApi import dev.bmcreations.protovalidate.orThrow import io.grpc.ManagedChannel diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/ThirdPartyApi.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/ThirdPartyApi.kt index 157c7b8a8f..17218c4c4f 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/ThirdPartyApi.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/ThirdPartyApi.kt @@ -6,7 +6,7 @@ import com.codeinc.flipcash.gen.thirdparty.v1.validate import com.flipcash.services.internal.annotations.FlipcashManagedChannel import com.flipcash.services.internal.network.extensions.asApiKey import com.flipcash.services.internal.network.extensions.authenticate -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.network.jwt.JwtSecuredEndpoint import com.getcode.opencode.internal.network.core.GrpcApi import dev.bmcreations.protovalidate.orThrow diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/extensions/AuthenticateMessage.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/extensions/AuthenticateMessage.kt index 4ac8d6eece..4cb8ad9969 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/extensions/AuthenticateMessage.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/extensions/AuthenticateMessage.kt @@ -1,7 +1,7 @@ package com.flipcash.services.internal.network.extensions import com.codeinc.flipcash.gen.common.v1.Common -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.google.protobuf.GeneratedMessageLite import java.io.ByteArrayOutputStream diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/extensions/LocalToProtobuf.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/extensions/LocalToProtobuf.kt index f7a4fd6dc8..27991070c4 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/extensions/LocalToProtobuf.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/extensions/LocalToProtobuf.kt @@ -18,7 +18,7 @@ import com.flipcash.services.models.chat.MuteState import com.flipcash.services.models.chat.PointerType import com.flipcash.services.models.chat.TypingState import com.flipcash.services.models.chat.ViewMode -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair import com.getcode.network.jwt.ApiProvider import com.getcode.opencode.model.core.ID import com.getcode.opencode.model.financial.Fiat diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/extensions/SignMessage.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/extensions/SignMessage.kt index 5a7771f207..ff5f1184e9 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/extensions/SignMessage.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/extensions/SignMessage.kt @@ -1,7 +1,7 @@ package com.flipcash.services.internal.network.extensions import com.codeinc.flipcash.gen.common.v1.Common -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.solana.keys.PublicKey import com.google.protobuf.GeneratedMessageLite import java.io.ByteArrayOutputStream diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/AccountService.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/AccountService.kt index 31ff0cd3b6..509bb4ac68 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/AccountService.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/AccountService.kt @@ -6,7 +6,7 @@ import com.getcode.opencode.internal.network.extensions.foldWithSuppression import com.flipcash.services.models.GetUserFlagsError import com.flipcash.services.models.LoginError import com.flipcash.services.models.RegisterError -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair import com.getcode.opencode.model.core.ID import javax.inject.Inject import com.codeinc.flipcash.gen.account.v1.FlipcashAccountService as RpcAccountService diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/ActivityFeedService.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/ActivityFeedService.kt index 0760eae2be..dc22d083f7 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/ActivityFeedService.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/ActivityFeedService.kt @@ -8,7 +8,7 @@ import com.getcode.opencode.internal.network.extensions.foldWithSuppression import com.flipcash.services.models.ActivityFeedType import com.flipcash.services.models.GetActivityFeedMessagesError import com.flipcash.services.models.QueryOptions -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair import com.getcode.opencode.model.core.ID import javax.inject.Inject diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/BlobStorageService.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/BlobStorageService.kt index cdb154b747..c5bbb738fb 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/BlobStorageService.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/BlobStorageService.kt @@ -17,7 +17,7 @@ import com.flipcash.services.models.chat.BlobId import com.flipcash.services.models.chat.BlobState import com.flipcash.services.models.chat.BlobStatus import com.flipcash.services.models.chat.ChatId -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.opencode.internal.network.extensions.foldWithSuppression import com.getcode.opencode.utils.toValidationOrElse import javax.inject.Inject diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/BlocklistService.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/BlocklistService.kt index 8ecf02657f..2ad5ab4ea7 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/BlocklistService.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/BlocklistService.kt @@ -7,7 +7,7 @@ import com.flipcash.services.models.GetBlocklistError import com.flipcash.services.models.IsBlockedError import com.flipcash.services.models.QueryOptions import com.flipcash.services.models.UnblockUserError -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair import com.getcode.opencode.internal.network.extensions.foldWithSuppression import com.getcode.opencode.model.core.ID import com.getcode.opencode.utils.toValidationOrElse diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/ChatMessagingService.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/ChatMessagingService.kt index 4b331bd4f1..b275c397fc 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/ChatMessagingService.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/ChatMessagingService.kt @@ -32,7 +32,7 @@ import com.flipcash.services.models.chat.ReactionSummary import com.flipcash.services.models.chat.Reactor import com.flipcash.services.models.chat.TypingState import com.flipcash.services.models.chat.ViewMode -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair import com.getcode.opencode.internal.network.extensions.foldWithSuppression import com.getcode.opencode.utils.toValidationOrElse import kotlinx.coroutines.flow.Flow diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/ChatService.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/ChatService.kt index 77b514b9e1..c018912006 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/ChatService.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/ChatService.kt @@ -34,7 +34,7 @@ import com.flipcash.services.models.chat.MuteState import com.flipcash.services.models.chat.StartChatParameters import com.flipcash.services.models.chat.ChatType import com.flipcash.services.models.chat.ViewMode -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair import com.getcode.opencode.internal.network.extensions.foldWithSuppression import com.getcode.opencode.model.core.ID import com.getcode.opencode.utils.toValidationOrElse diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/CommunityService.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/CommunityService.kt index 734835b67b..e435bab7f0 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/CommunityService.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/CommunityService.kt @@ -2,7 +2,7 @@ package com.flipcash.services.internal.network.services import com.flipcash.services.internal.network.api.CommunityApi import com.flipcash.services.models.GetCommunityError -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair import com.getcode.opencode.internal.network.extensions.foldWithSuppression import com.getcode.opencode.utils.toValidationOrElse import com.getcode.solana.keys.Mint diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/ContactListService.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/ContactListService.kt index eb531ef5cf..f557a79186 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/ContactListService.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/ContactListService.kt @@ -7,7 +7,7 @@ import com.flipcash.services.models.CheckSyncError import com.flipcash.services.models.DeltaUploadError import com.flipcash.services.models.FullUploadError import com.flipcash.services.models.GetContactsError -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair import com.getcode.opencode.internal.network.extensions.foldWithSuppression import com.getcode.opencode.utils.toValidationOrElse import com.getcode.solana.keys.Checksum diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/EmailVerificationService.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/EmailVerificationService.kt index 662a69ee25..68612a47c8 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/EmailVerificationService.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/EmailVerificationService.kt @@ -4,7 +4,7 @@ import com.flipcash.services.internal.network.api.EmailVerificationApi import com.getcode.opencode.utils.toValidationOrElse import com.flipcash.services.models.ContactMethod import com.flipcash.services.models.EmailVerificationError -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.opencode.internal.network.extensions.foldWithSuppression import javax.inject.Inject import com.codeinc.flipcash.gen.email.v1.EmailVerificationService as RpcEmailService diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/EventStreamingService.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/EventStreamingService.kt index 6147f3a773..5c12725f8e 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/EventStreamingService.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/EventStreamingService.kt @@ -9,7 +9,7 @@ import com.flipcash.services.internal.network.extensions.toChatUpdate import com.flipcash.services.models.StreamEventsError import com.flipcash.services.models.chat.BlobUpdate import com.flipcash.services.models.chat.ChatUpdate -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair import com.getcode.opencode.internal.bidi.BidirectionalStreamReference import com.getcode.opencode.internal.bidi.openBidirectionalStream import com.getcode.utils.ClockSource diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/ModerationService.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/ModerationService.kt index ad53cba74e..542e804718 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/ModerationService.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/ModerationService.kt @@ -5,7 +5,7 @@ import com.flipcash.services.internal.network.api.ModerationApi import com.getcode.opencode.utils.toValidationOrElse import com.flipcash.services.models.ImageModerationError import com.flipcash.services.models.TextModerationError -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.opencode.internal.network.extensions.foldWithSuppression import javax.inject.Inject diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/PhoneVerificationService.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/PhoneVerificationService.kt index 1f91754338..25126929bb 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/PhoneVerificationService.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/PhoneVerificationService.kt @@ -5,7 +5,7 @@ import com.getcode.opencode.utils.toValidationOrElse import com.flipcash.services.models.ContactMethod import com.flipcash.services.models.LinkForPaymentError import com.flipcash.services.models.PhoneVerificationError -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.opencode.internal.network.extensions.foldWithSuppression import javax.inject.Inject import com.codeinc.flipcash.gen.phone.v1.PhoneVerificationService as RpcPhoneService diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/PollService.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/PollService.kt index 153369ada4..dd6c93282e 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/PollService.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/PollService.kt @@ -9,7 +9,7 @@ import com.flipcash.services.models.GetPollError import com.flipcash.services.models.GetPollsError import com.flipcash.services.models.VoteError import com.flipcash.services.models.chat.ChatId -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.opencode.internal.network.extensions.foldWithSuppression import com.getcode.opencode.utils.toValidationOrElse import javax.inject.Inject diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/ProfileService.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/ProfileService.kt index 8c4ab55269..7c607e07dd 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/ProfileService.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/ProfileService.kt @@ -21,7 +21,7 @@ import com.flipcash.services.models.UpdateTipCardError import com.flipcash.services.models.chat.BlobId import com.flipcash.services.models.chat.MediaItem import com.flipcash.services.internal.network.extensions.toMediaItem -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.opencode.internal.network.extensions.foldWithSuppression import com.getcode.opencode.model.financial.Fiat import javax.inject.Inject diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/PurchaseService.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/PurchaseService.kt index 1cded8a70e..ff831d66e2 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/PurchaseService.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/PurchaseService.kt @@ -7,7 +7,7 @@ import com.flipcash.services.internal.network.api.PurchaseApi import com.getcode.opencode.utils.toValidationOrElse import com.getcode.opencode.internal.network.extensions.foldWithSuppression import com.flipcash.services.models.PurchaseAckError -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair import javax.inject.Inject internal class PurchaseService @Inject constructor( diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/PushService.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/PushService.kt index acefecced7..df99f1137b 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/PushService.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/PushService.kt @@ -5,7 +5,7 @@ import com.getcode.opencode.utils.toValidationOrElse import com.getcode.opencode.internal.network.extensions.foldWithSuppression import com.flipcash.services.models.AddTokenError import com.flipcash.services.models.DeleteTokenError -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair import javax.inject.Inject import com.codeinc.flipcash.gen.push.v1.PushService as RpcPushService diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/ReportingService.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/ReportingService.kt index 2c175aa065..e39c90c848 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/ReportingService.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/ReportingService.kt @@ -3,7 +3,7 @@ package com.flipcash.services.internal.network.services import com.flipcash.services.internal.network.api.ReportingApi import com.flipcash.services.models.ReportError import com.flipcash.services.models.ReportTarget -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair import com.getcode.opencode.internal.network.extensions.foldWithSuppression import com.getcode.opencode.utils.toValidationOrElse import javax.inject.Inject diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/ResolverService.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/ResolverService.kt index 6b108116e8..25dec988be 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/ResolverService.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/ResolverService.kt @@ -4,7 +4,7 @@ import com.flipcash.services.internal.network.api.ResolverApi import com.flipcash.services.internal.network.extensions.toPublicKey import com.flipcash.services.models.ResolveContactError import com.flipcash.services.models.ResolveIdentifier -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair import com.getcode.opencode.internal.network.extensions.foldWithSuppression import com.getcode.opencode.utils.toValidationOrElse import com.getcode.solana.keys.PublicKey diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/SettingsService.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/SettingsService.kt index bc1aef9cc0..d1a63aa1bc 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/SettingsService.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/SettingsService.kt @@ -4,7 +4,7 @@ import com.codeinc.flipcash.gen.settings.v1.SettingsService import com.flipcash.services.internal.network.api.SettingsApi import com.getcode.opencode.utils.toValidationOrElse import com.flipcash.services.models.UpdateSettingsError -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.opencode.internal.network.extensions.foldWithSuppression import javax.inject.Inject diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/ThirdPartyService.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/ThirdPartyService.kt index 949abe7613..58613e8594 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/ThirdPartyService.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/ThirdPartyService.kt @@ -5,7 +5,7 @@ import com.flipcash.services.internal.network.api.ThirdPartyApi import com.getcode.opencode.utils.toValidationOrElse import com.flipcash.services.models.GetJwtError import com.flipcash.services.models.Jwt -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.network.jwt.JwtSecuredEndpoint import com.getcode.opencode.internal.network.extensions.foldWithSuppression import javax.inject.Inject diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalAccountRepository.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalAccountRepository.kt index 1fc023cd1b..aa0cddf95f 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalAccountRepository.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalAccountRepository.kt @@ -4,7 +4,7 @@ import com.flipcash.services.internal.domain.UserFlagsMapper import com.flipcash.services.models.UserFlags import com.flipcash.services.internal.network.services.AccountService import com.flipcash.services.repository.AccountRepository -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.opencode.model.core.ID import com.getcode.utils.ErrorUtils diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalActivityFeedRepository.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalActivityFeedRepository.kt index 462960041b..01c7c2182c 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalActivityFeedRepository.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalActivityFeedRepository.kt @@ -6,7 +6,7 @@ import com.flipcash.services.models.ActivityFeedNotification import com.flipcash.services.models.ActivityFeedType import com.flipcash.services.models.QueryOptions import com.flipcash.services.repository.ActivityFeedRepository -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.opencode.model.core.ID import com.getcode.utils.ErrorUtils diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalBlobStorageRepository.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalBlobStorageRepository.kt index 12333c5b2c..e53231a493 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalBlobStorageRepository.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalBlobStorageRepository.kt @@ -9,7 +9,7 @@ import com.flipcash.services.models.chat.BlobState import com.flipcash.services.models.chat.BlobStatus import com.flipcash.services.models.chat.ChatId import com.flipcash.services.repository.BlobStorageRepository -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.utils.ErrorUtils internal class InternalBlobStorageRepository( diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalBlocklistRepository.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalBlocklistRepository.kt index ef4a5cac06..053d0c8aa1 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalBlocklistRepository.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalBlocklistRepository.kt @@ -6,7 +6,7 @@ import com.flipcash.services.internal.network.services.BlocklistService import com.flipcash.services.models.BlocklistPage import com.flipcash.services.models.QueryOptions import com.flipcash.services.repository.BlocklistRepository -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.opencode.model.core.ID import com.getcode.utils.ErrorUtils diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalChatMessagingRepository.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalChatMessagingRepository.kt index 1e8ae54c97..5d78af8f7f 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalChatMessagingRepository.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalChatMessagingRepository.kt @@ -16,7 +16,7 @@ import com.flipcash.services.models.chat.ViewMode import com.flipcash.services.repository.ChatMessagingRepository import com.flipcash.services.repository.DeltaUpdate import com.flipcash.services.repository.ReactorsPage -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair import com.getcode.utils.ErrorUtils import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalChatRepository.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalChatRepository.kt index 4084edaec9..3637627e68 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalChatRepository.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalChatRepository.kt @@ -32,7 +32,7 @@ import com.flipcash.services.models.chat.StoredKeyEnvelope import com.flipcash.services.models.chat.ViewerState import com.flipcash.services.models.chat.ViewMode import com.flipcash.services.repository.ChatRepository -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair import com.getcode.opencode.model.core.ID import com.getcode.utils.ErrorUtils import kotlin.time.Instant diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalCommunityRepository.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalCommunityRepository.kt index f036295c6f..76a5a055b2 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalCommunityRepository.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalCommunityRepository.kt @@ -7,7 +7,7 @@ import com.flipcash.services.internal.network.services.CommunityService import com.flipcash.services.models.Community import com.flipcash.services.models.CommunityLeader import com.flipcash.services.repository.CommunityRepository -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair import com.getcode.solana.keys.Mint import com.getcode.utils.ErrorUtils diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalContactListRepository.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalContactListRepository.kt index 899f75f7ae..747eed4988 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalContactListRepository.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalContactListRepository.kt @@ -5,7 +5,7 @@ import com.flipcash.services.internal.network.services.ContactListService import com.flipcash.services.models.ContactMethod import com.flipcash.services.models.FlipcashContactEntry import com.flipcash.services.repository.ContactListRepository -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.solana.keys.Checksum import com.getcode.utils.ErrorUtils import kotlinx.coroutines.flow.Flow diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalContactVerificationRepository.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalContactVerificationRepository.kt index a39028866d..29abda4825 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalContactVerificationRepository.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalContactVerificationRepository.kt @@ -4,7 +4,7 @@ import com.flipcash.services.internal.network.services.EmailVerificationService import com.flipcash.services.internal.network.services.PhoneVerificationService import com.flipcash.services.models.ContactMethod import com.flipcash.services.repository.ContactVerificationRepository -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.utils.ErrorUtils internal class InternalContactVerificationRepository( diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalEventStreamingRepository.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalEventStreamingRepository.kt index 962cf1949a..35c0a84e83 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalEventStreamingRepository.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalEventStreamingRepository.kt @@ -5,7 +5,7 @@ import com.flipcash.services.internal.network.services.EventStreamingService import com.flipcash.services.models.chat.BlobUpdate import com.flipcash.services.models.chat.ChatUpdate import com.flipcash.services.repository.EventStreamingRepository -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair import kotlinx.coroutines.CoroutineScope internal class InternalEventStreamingRepository( diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalModerationRepository.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalModerationRepository.kt index 6f57a1fa66..fed70d6845 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalModerationRepository.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalModerationRepository.kt @@ -6,7 +6,7 @@ import com.flipcash.services.internal.model.moderation.ModerationRequest import com.flipcash.services.internal.network.services.ModerationService import com.flipcash.services.models.ModerationResult import com.flipcash.services.repository.ModerationRepository -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.utils.ErrorUtils internal class InternalModerationRepository( diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalPollRepository.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalPollRepository.kt index ff3c08da78..64cc033afb 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalPollRepository.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalPollRepository.kt @@ -7,7 +7,7 @@ import com.flipcash.services.models.GetPollError import com.flipcash.services.models.VoteError import com.flipcash.services.models.chat.ChatId import com.flipcash.services.repository.PollRepository -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair import com.getcode.utils.ErrorUtils internal class InternalPollRepository( diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalProfileRepository.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalProfileRepository.kt index 053fe18879..5e18d12b54 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalProfileRepository.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalProfileRepository.kt @@ -15,7 +15,7 @@ import com.flipcash.services.models.UserProfile import com.flipcash.services.models.chat.BlobId import com.flipcash.services.models.chat.MediaItem import com.flipcash.services.repository.ProfileRepository -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.opencode.model.financial.Fiat import com.getcode.utils.ErrorUtils diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalPurchaseRepository.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalPurchaseRepository.kt index 5ed5454830..afa33010c0 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalPurchaseRepository.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalPurchaseRepository.kt @@ -4,7 +4,7 @@ import com.flipcash.services.internal.model.billing.IapMetadata import com.flipcash.services.internal.model.billing.Receipt import com.flipcash.services.internal.network.services.PurchaseService import com.flipcash.services.repository.PurchaseRepository -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.utils.ErrorUtils internal class InternalPurchaseRepository( diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalPushRepository.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalPushRepository.kt index 8284b45dc0..22902e8510 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalPushRepository.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalPushRepository.kt @@ -2,7 +2,7 @@ package com.flipcash.services.internal.repositories import com.flipcash.services.internal.network.services.PushService import com.flipcash.services.repository.PushRepository -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.utils.ErrorUtils internal class InternalPushRepository( diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalReportingRepository.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalReportingRepository.kt index 8fa313459b..2814e6ca1b 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalReportingRepository.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalReportingRepository.kt @@ -3,7 +3,7 @@ package com.flipcash.services.internal.repositories import com.flipcash.services.internal.network.services.ReportingService import com.flipcash.services.models.ReportTarget import com.flipcash.services.repository.ReportingRepository -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.utils.ErrorUtils internal class InternalReportingRepository( diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalResolverRepository.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalResolverRepository.kt index a30a5e2889..2368a72356 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalResolverRepository.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalResolverRepository.kt @@ -3,7 +3,7 @@ package com.flipcash.services.internal.repositories import com.flipcash.services.internal.network.services.ResolverService import com.flipcash.services.models.ResolveIdentifier import com.flipcash.services.repository.ResolverRepository -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.solana.keys.PublicKey import com.getcode.utils.ErrorUtils diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalSettingsRepository.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalSettingsRepository.kt index e9a0982b6f..953326461e 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalSettingsRepository.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalSettingsRepository.kt @@ -2,7 +2,7 @@ package com.flipcash.services.internal.repositories import com.flipcash.services.internal.network.services.SettingsService import com.flipcash.services.repository.SettingsRepository -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.utils.ErrorUtils internal class InternalSettingsRepository( diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalThirdPartyRepository.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalThirdPartyRepository.kt index 27de642c1c..3053735059 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalThirdPartyRepository.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalThirdPartyRepository.kt @@ -3,7 +3,7 @@ package com.flipcash.services.internal.repositories import com.flipcash.services.internal.network.services.ThirdPartyService import com.flipcash.services.models.Jwt import com.flipcash.services.repository.ThirdPartyRepository -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.network.jwt.JwtSecuredEndpoint import com.getcode.utils.ErrorUtils diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/AccountRepository.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/repository/AccountRepository.kt index b74ef73ec8..8cf4f97cbd 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/AccountRepository.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/repository/AccountRepository.kt @@ -1,7 +1,7 @@ package com.flipcash.services.repository import com.flipcash.services.models.UserFlags -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair import com.getcode.opencode.model.core.ID interface AccountRepository { diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/ActivityFeedRepository.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/repository/ActivityFeedRepository.kt index df6b4a13ad..a6f3568e1c 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/ActivityFeedRepository.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/repository/ActivityFeedRepository.kt @@ -3,7 +3,7 @@ package com.flipcash.services.repository import com.flipcash.services.models.ActivityFeedNotification import com.flipcash.services.models.ActivityFeedType import com.flipcash.services.models.QueryOptions -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair import com.getcode.opencode.model.core.ID interface ActivityFeedRepository { diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/BlobStorageRepository.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/repository/BlobStorageRepository.kt index 9b743e830d..91e7058c88 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/BlobStorageRepository.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/repository/BlobStorageRepository.kt @@ -7,7 +7,7 @@ import com.flipcash.services.models.chat.BlobId import com.flipcash.services.models.chat.BlobState import com.flipcash.services.models.chat.BlobStatus import com.flipcash.services.models.chat.ChatId -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 interface BlobStorageRepository { suspend fun getUploadPolicy(owner: Ed25519.KeyPair): Result diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/BlocklistRepository.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/repository/BlocklistRepository.kt index 74d3cb391c..e356a47bbb 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/BlocklistRepository.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/repository/BlocklistRepository.kt @@ -2,7 +2,7 @@ package com.flipcash.services.repository import com.flipcash.services.models.BlocklistPage import com.flipcash.services.models.QueryOptions -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair import com.getcode.opencode.model.core.ID interface BlocklistRepository { diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/ChatMessagingRepository.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/repository/ChatMessagingRepository.kt index 56a5086347..a2890da48a 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/ChatMessagingRepository.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/repository/ChatMessagingRepository.kt @@ -12,7 +12,7 @@ import com.flipcash.services.models.chat.ReactionSummary import com.flipcash.services.models.chat.Reactor import com.flipcash.services.models.chat.TypingState import com.flipcash.services.models.chat.ViewMode -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair import kotlinx.coroutines.flow.Flow interface ChatMessagingRepository { diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/ChatRepository.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/repository/ChatRepository.kt index 7adaaa9b88..faa60b85b2 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/ChatRepository.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/repository/ChatRepository.kt @@ -20,7 +20,7 @@ import com.flipcash.services.models.chat.StartChatParameters import com.flipcash.services.models.chat.StoredKeyEnvelope import com.flipcash.services.models.chat.ViewerState import com.flipcash.services.models.chat.ViewMode -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair import com.getcode.opencode.model.core.ID interface ChatRepository { diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/CommunityRepository.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/repository/CommunityRepository.kt index 1a542b9d01..5d89f1ccdd 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/CommunityRepository.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/repository/CommunityRepository.kt @@ -1,7 +1,7 @@ package com.flipcash.services.repository import com.flipcash.services.models.Community -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair import com.getcode.solana.keys.Mint interface CommunityRepository { diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/ContactListRepository.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/repository/ContactListRepository.kt index d637bf49f1..3f0b4239e6 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/ContactListRepository.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/repository/ContactListRepository.kt @@ -2,7 +2,7 @@ package com.flipcash.services.repository import com.flipcash.services.models.ContactMethod import com.flipcash.services.models.FlipcashContactEntry -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair import com.getcode.solana.keys.Checksum import kotlinx.coroutines.flow.Flow diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/ContactVerificationRepository.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/repository/ContactVerificationRepository.kt index 54dbf6c330..abc94a7556 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/ContactVerificationRepository.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/repository/ContactVerificationRepository.kt @@ -1,7 +1,7 @@ package com.flipcash.services.repository import com.flipcash.services.models.ContactMethod -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 interface ContactVerificationRepository { suspend fun sendVerificationCode(method: ContactMethod, owner: Ed25519.KeyPair): Result diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/EventStreamingRepository.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/repository/EventStreamingRepository.kt index 3cb761ee6d..187805db92 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/EventStreamingRepository.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/repository/EventStreamingRepository.kt @@ -3,7 +3,7 @@ package com.flipcash.services.repository import com.flipcash.services.internal.network.services.EventStreamReference import com.flipcash.services.models.chat.BlobUpdate import com.flipcash.services.models.chat.ChatUpdate -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair import kotlinx.coroutines.CoroutineScope interface EventStreamingRepository { diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/ModerationRepository.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/repository/ModerationRepository.kt index c58e152b63..181846f831 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/ModerationRepository.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/repository/ModerationRepository.kt @@ -1,7 +1,7 @@ package com.flipcash.services.repository import com.flipcash.services.models.ModerationResult -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 interface ModerationRepository { suspend fun moderateText(text: String, owner: Ed25519.KeyPair): Result diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/PollRepository.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/repository/PollRepository.kt index 014d67b143..bd42a695e4 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/PollRepository.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/repository/PollRepository.kt @@ -2,7 +2,7 @@ package com.flipcash.services.repository import com.codeinc.flipcash.gen.poll.v1.Model import com.flipcash.services.models.chat.ChatId -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair /** * Polls in group chats. Poll values are the generated `poll.v1` types for now; a domain model diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/ProfileRepository.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/repository/ProfileRepository.kt index 13a175663b..4e20508129 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/ProfileRepository.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/repository/ProfileRepository.kt @@ -7,7 +7,7 @@ import com.flipcash.services.models.SocialAccountUnlinkRequest import com.flipcash.services.models.UserProfile import com.flipcash.services.models.chat.BlobId import com.flipcash.services.models.chat.MediaItem -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.opencode.model.financial.Fiat interface ProfileRepository { diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/PurchaseRepository.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/repository/PurchaseRepository.kt index 7ee1032aae..7a764f8a14 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/PurchaseRepository.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/repository/PurchaseRepository.kt @@ -2,7 +2,7 @@ package com.flipcash.services.repository import com.flipcash.services.internal.model.billing.IapMetadata import com.flipcash.services.internal.model.billing.Receipt -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair interface PurchaseRepository { suspend fun onPurchaseCompleted( diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/PushRepository.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/repository/PushRepository.kt index 229949d355..7333cf80a9 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/PushRepository.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/repository/PushRepository.kt @@ -1,6 +1,6 @@ package com.flipcash.services.repository -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair interface PushRepository { suspend fun addToken( diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/ReportingRepository.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/repository/ReportingRepository.kt index 071ceb7093..a502b3ddfc 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/ReportingRepository.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/repository/ReportingRepository.kt @@ -1,7 +1,7 @@ package com.flipcash.services.repository import com.flipcash.services.models.ReportTarget -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair interface ReportingRepository { /** Files a report against [target]. Reporting the same target more than once is a no-op. */ diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/ResolverRepository.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/repository/ResolverRepository.kt index 5e2b7ecf6a..fb06119465 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/ResolverRepository.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/repository/ResolverRepository.kt @@ -1,7 +1,7 @@ package com.flipcash.services.repository import com.flipcash.services.models.ResolveIdentifier -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair import com.getcode.solana.keys.PublicKey interface ResolverRepository { diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/SettingsRepository.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/repository/SettingsRepository.kt index 3871d4aa20..dcc3e3c81b 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/SettingsRepository.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/repository/SettingsRepository.kt @@ -1,6 +1,6 @@ package com.flipcash.services.repository -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 interface SettingsRepository { suspend fun update(locale: String?, region: String?, owner: Ed25519.KeyPair): Result diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/ThirdPartyRepository.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/repository/ThirdPartyRepository.kt index 861fb273c5..1a8a298d13 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/ThirdPartyRepository.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/repository/ThirdPartyRepository.kt @@ -1,7 +1,7 @@ package com.flipcash.services.repository import com.flipcash.services.models.Jwt -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.network.jwt.JwtSecuredEndpoint interface ThirdPartyRepository { diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/user/UserManager.kt b/services/flipcash/src/main/kotlin/com/flipcash/services/user/UserManager.kt index 2496834fb9..d733c0db35 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/user/UserManager.kt +++ b/services/flipcash/src/main/kotlin/com/flipcash/services/user/UserManager.kt @@ -1,5 +1,6 @@ package com.flipcash.services.user +import com.getcode.utils.BuildFlags import com.flipcash.services.models.UserFlags import com.flipcash.services.models.UserProfile import com.getcode.crypt.DerivePath @@ -14,7 +15,6 @@ import com.getcode.opencode.model.core.ID import com.getcode.opencode.model.core.NoId import com.getcode.opencode.model.financial.Token import com.getcode.opencode.model.financial.usdf -import com.getcode.services.opencode.BuildConfig import com.getcode.utils.TraceManager import com.getcode.utils.trace import com.hoc081098.channeleventbus.ChannelEventBus @@ -218,7 +218,7 @@ class UserManager @Inject constructor( } private fun associate() { - if (!BuildConfig.DEBUG) { + if (!BuildFlags.isDebug) { // Hex, not base58 — matches iOS so one user is one Mixpanel profile. // See AnalyticsIdentity.kt. val distinctId = accountId?.analyticsDistinctId() diff --git a/services/flipcash/src/test/kotlin/com/flipcash/services/controllers/BlobStorageControllerChatMediaTest.kt b/services/flipcash/src/test/kotlin/com/flipcash/services/controllers/BlobStorageControllerChatMediaTest.kt index f0c7fac5c0..fb61b682e1 100644 --- a/services/flipcash/src/test/kotlin/com/flipcash/services/controllers/BlobStorageControllerChatMediaTest.kt +++ b/services/flipcash/src/test/kotlin/com/flipcash/services/controllers/BlobStorageControllerChatMediaTest.kt @@ -18,7 +18,7 @@ import com.flipcash.services.models.chat.ChatId import com.flipcash.services.models.chat.RejectionReason import com.flipcash.services.repository.BlobStorageRepository import com.flipcash.services.user.UserManager -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.opencode.model.accounts.AccountCluster import io.mockk.coEvery import io.mockk.coVerify diff --git a/services/flipcash/src/test/kotlin/com/flipcash/services/controllers/BlobStorageControllerTest.kt b/services/flipcash/src/test/kotlin/com/flipcash/services/controllers/BlobStorageControllerTest.kt index 6199bde5b0..9d3d17dcfc 100644 --- a/services/flipcash/src/test/kotlin/com/flipcash/services/controllers/BlobStorageControllerTest.kt +++ b/services/flipcash/src/test/kotlin/com/flipcash/services/controllers/BlobStorageControllerTest.kt @@ -15,7 +15,7 @@ import com.flipcash.services.models.chat.BlobStatus import com.flipcash.services.models.chat.RejectionReason import com.flipcash.services.repository.BlobStorageRepository import com.flipcash.services.user.UserManager -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.opencode.model.accounts.AccountCluster import io.mockk.coEvery import io.mockk.coVerify diff --git a/services/flipcash/src/test/kotlin/com/flipcash/services/controllers/ChatControllerTest.kt b/services/flipcash/src/test/kotlin/com/flipcash/services/controllers/ChatControllerTest.kt index d4c2fa2f53..4326c47d0c 100644 --- a/services/flipcash/src/test/kotlin/com/flipcash/services/controllers/ChatControllerTest.kt +++ b/services/flipcash/src/test/kotlin/com/flipcash/services/controllers/ChatControllerTest.kt @@ -23,7 +23,7 @@ import com.flipcash.services.models.UserProfile import com.flipcash.services.models.chat.MentionSuggestion import com.flipcash.services.repository.ChatRepository import com.flipcash.services.user.UserManager -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.opencode.model.accounts.AccountCluster import com.getcode.opencode.model.core.ID import io.mockk.every diff --git a/services/flipcash/src/test/kotlin/com/flipcash/services/controllers/ChatMessagingControllerTest.kt b/services/flipcash/src/test/kotlin/com/flipcash/services/controllers/ChatMessagingControllerTest.kt index 3ddd48f844..1da44fb5b1 100644 --- a/services/flipcash/src/test/kotlin/com/flipcash/services/controllers/ChatMessagingControllerTest.kt +++ b/services/flipcash/src/test/kotlin/com/flipcash/services/controllers/ChatMessagingControllerTest.kt @@ -18,7 +18,7 @@ import com.flipcash.services.repository.ReactorsPage import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flowOf import com.flipcash.services.user.UserManager -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.opencode.model.accounts.AccountCluster import io.mockk.every import io.mockk.mockk diff --git a/services/flipcash/src/test/kotlin/com/flipcash/services/controllers/EventStreamingControllerTest.kt b/services/flipcash/src/test/kotlin/com/flipcash/services/controllers/EventStreamingControllerTest.kt index 0cd2a4ad36..21db53db5a 100644 --- a/services/flipcash/src/test/kotlin/com/flipcash/services/controllers/EventStreamingControllerTest.kt +++ b/services/flipcash/src/test/kotlin/com/flipcash/services/controllers/EventStreamingControllerTest.kt @@ -6,7 +6,7 @@ import com.flipcash.services.models.chat.ChatId import com.flipcash.services.models.chat.ChatUpdate import com.flipcash.services.repository.EventStreamingRepository import com.flipcash.services.user.UserManager -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.opencode.model.accounts.AccountCluster import io.mockk.every import io.mockk.mockk diff --git a/services/flipcash/src/test/kotlin/com/flipcash/services/controllers/ProfileControllerTest.kt b/services/flipcash/src/test/kotlin/com/flipcash/services/controllers/ProfileControllerTest.kt index 8118af6d55..f97941216a 100644 --- a/services/flipcash/src/test/kotlin/com/flipcash/services/controllers/ProfileControllerTest.kt +++ b/services/flipcash/src/test/kotlin/com/flipcash/services/controllers/ProfileControllerTest.kt @@ -12,7 +12,7 @@ import com.flipcash.services.models.chat.MediaItem import com.flipcash.services.models.ProfileIdentifier import com.flipcash.services.repository.ProfileRepository import com.flipcash.services.user.UserManager -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.opencode.model.accounts.AccountCluster import com.getcode.opencode.model.core.ID import com.getcode.opencode.model.financial.Fiat diff --git a/services/flipcash/src/test/kotlin/com/flipcash/services/internal/network/api/BlobStorageApiDeadlineTest.kt b/services/flipcash/src/test/kotlin/com/flipcash/services/internal/network/api/BlobStorageApiDeadlineTest.kt index 34861e284a..eac29fe23d 100644 --- a/services/flipcash/src/test/kotlin/com/flipcash/services/internal/network/api/BlobStorageApiDeadlineTest.kt +++ b/services/flipcash/src/test/kotlin/com/flipcash/services/internal/network/api/BlobStorageApiDeadlineTest.kt @@ -2,7 +2,7 @@ package com.flipcash.services.internal.network.api import androidx.lifecycle.ProcessLifecycleOwner import com.codeinc.flipcash.gen.common.v1.Common -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import io.grpc.ManagedChannel import io.grpc.Status import io.grpc.StatusException diff --git a/services/flipcash/src/test/kotlin/com/flipcash/services/internal/network/services/PhoneVerificationServiceTest.kt b/services/flipcash/src/test/kotlin/com/flipcash/services/internal/network/services/PhoneVerificationServiceTest.kt index 5fe017e87b..384b7cf66e 100644 --- a/services/flipcash/src/test/kotlin/com/flipcash/services/internal/network/services/PhoneVerificationServiceTest.kt +++ b/services/flipcash/src/test/kotlin/com/flipcash/services/internal/network/services/PhoneVerificationServiceTest.kt @@ -3,7 +3,7 @@ package com.flipcash.services.internal.network.services import com.flipcash.services.internal.network.api.PhoneVerificationApi import com.flipcash.services.models.ContactMethod import com.flipcash.services.models.PhoneVerificationError -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.opencode.model.core.errors.ValidationException import dev.bmcreations.protovalidate.FieldViolation import dev.bmcreations.protovalidate.ProtoValidationException diff --git a/services/opencode/build.gradle.kts b/services/opencode/build.gradle.kts index 67b88e1945..bccc54869c 100644 --- a/services/opencode/build.gradle.kts +++ b/services/opencode/build.gradle.kts @@ -1,96 +1,90 @@ plugins { - alias(libs.plugins.flipcash.android.library) - alias(libs.plugins.flipcash.android.ed25519.shadow) - id("com.google.devtools.ksp") - id("dagger.hilt.android.plugin") + alias(libs.plugins.flipcash.kmp.app.library) + alias(libs.plugins.kotlin.ksp) id("org.jetbrains.kotlin.plugin.parcelize") } -android { - namespace = "${Gradle.codeNamespace}.services.opencode" - - defaultConfig { - consumerProguardFiles("consumer-rules.pro") - - buildConfigField("Boolean", "NOTIFY_ERRORS", "false") - buildConfigField( - "String", - "GOOGLE_CLOUD_PROJECT_NUMBER", - "\"${tryReadProperty(rootProject.rootDir, "GOOGLE_CLOUD_PROJECT_NUMBER", "-1L")}\"" - ) +kotlin { + android { + namespace = "${Gradle.codeNamespace}.services.opencode" + androidResources { enable = true } } - buildFeatures { - buildConfig = true + sourceSets { + commonMain.dependencies { + implementation(libs.ocp.client.protocol) + api(project(":libs:currency-math")) + api(project(":libs:datetime")) + api(project(":libs:encryption:base58")) + api(project(":libs:encryption:ed25519")) + api(project(":libs:encryption:hmac")) + api(project(":libs:encryption:keys")) + api(project(":libs:encryption:mnemonic")) + api(project(":libs:encryption:sha256")) + api(project(":libs:encryption:sha512")) + api(project(":libs:encryption:utils")) + api(project(":libs:logging")) + api(project(":libs:locale:public")) + api(project(":libs:network:connectivity:public")) + implementation(project(":ui:resources")) + + implementation(libs.protobuf.validate.runtime) + implementation(libs.bundles.hilt.common) + implementation(libs.kotlinx.serialization.json) + implementation(libs.kotlinx.datetime) + implementation(libs.kotlinx.coroutines.core) + implementation(libs.grpc.okhttp) + implementation(libs.grpc.kotlin) + implementation(libs.grpc.protobuf.lite) + implementation(libs.event.bus) + } + androidMain.dependencies { + api(project(":libs:locale:bindings")) + implementation(project(":libs:locale:impl")) + api(project(":libs:network:connectivity:bindings")) + api(project(":vendor:kik:scanner")) + + implementation(libs.grpc.android) + implementation(libs.androidx.lifecycle.runtime) + implementation(libs.androidx.lifecycle.process) + implementation(libs.hilt.android) + + // Not imported by this module; kept so the app's runtime classpath is unchanged. + implementation(libs.androidx.datastore) + implementation(libs.okhttp) + implementation(libs.mixpanel) + implementation(project.dependencies.platform(libs.firebase.bom)) + implementation(libs.firebase.installations) + implementation(libs.firebase.perf) + implementation(libs.firebase.messaging) + implementation(libs.play.integrity) + implementation(libs.androidx.paging.runtime) + implementation(libs.fingerprint.pro) + implementation(libs.retrofit) + implementation(libs.retrofit.converter.gson) + implementation(libs.okhttp.logging.interceptor) + } + getByName("androidHostTest").dependencies { + implementation(kotlin("test")) + implementation(libs.bundles.unit.testing) + implementation(project(":libs:currency-math:test-fixtures")) + implementation(project(":libs:test-utils")) + } + jvmTest.dependencies { + implementation(kotlin("test")) + implementation(libs.kotlinx.coroutines.test) + } } - } dependencies { - implementation(libs.ocp.client.protocol) - api(project(":libs:currency-math")) - api(project(":libs:datetime")) - api(project(":libs:encryption:base58")) - api(project(":libs:encryption:ed25519")) - api(project(":libs:encryption:hmac")) - api(project(":libs:encryption:keys")) - api(project(":libs:encryption:mnemonic")) - api(project(":libs:encryption:sha256")) - api(project(":libs:encryption:sha512")) - api(project(":libs:encryption:utils")) - api(project(":libs:logging")) - api(project(":libs:locale:bindings")) - implementation(project(":libs:locale:impl")) - api(project(":libs:network:connectivity:bindings")) - implementation(project(":ui:resources")) - - api(project(":vendor:kik:scanner")) - - implementation(libs.protobuf.validate.runtime) - - implementation(libs.javax.inject) - - implementation(libs.kotlinx.serialization.json) - implementation(libs.javax.inject) - - implementation(libs.grpc.android) - implementation(libs.grpc.okhttp) - implementation(libs.grpc.kotlin) - implementation(libs.grpc.protobuf.lite) - implementation(libs.androidx.lifecycle.runtime) - implementation(libs.androidx.lifecycle.process) - implementation(libs.androidx.datastore) - implementation(libs.okhttp) - implementation(libs.mixpanel) - - implementation(platform(libs.firebase.bom)) - implementation(libs.firebase.installations) - implementation(libs.firebase.perf) - implementation(libs.firebase.messaging) - - implementation(libs.play.integrity) - - implementation(libs.androidx.paging.runtime) - - ksp(libs.androidx.room.compiler) - - implementation(libs.fingerprint.pro) - - androidTestImplementation(libs.androidx.junit) - androidTestImplementation(libs.junit) - androidTestImplementation(libs.androidx.test.runner) - - implementation(libs.retrofit) - implementation(libs.retrofit.converter.gson) - implementation(libs.okhttp.logging.interceptor) - - implementation(libs.hilt.android) - ksp(libs.hilt.android.compiler) - ksp(libs.hilt.compiler) - - implementation(libs.event.bus) + add("kspAndroid", libs.hilt.android.compiler) + add("kspAndroid", libs.hilt.compiler) +} - testImplementation(kotlin("test")) - testImplementation(libs.bundles.unit.testing) - testImplementation(project(":libs:currency-math:test-fixtures")) +// The headless balance test reads its recovery phrase from local.properties (gitignored) or the +// FLIPCASH_TEST_MNEMONIC environment variable, and skips when neither is set. +tasks.named("jvmTest") { + val mnemonic = tryReadProperty(rootProject.rootDir, "flipcash.test.mnemonic", "") + if (mnemonic.isNotBlank()) systemProperty("flipcash.test.mnemonic", mnemonic) } diff --git a/services/opencode/consumer-rules.pro b/services/opencode/consumer-rules.pro deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/services/opencode/src/androidTest/kotlin/com/getcode/opencode/model/core/OpenCodePayloadTests.kt b/services/opencode/src/androidDeviceTest/kotlin/com/getcode/opencode/model/core/OpenCodePayloadTests.kt similarity index 100% rename from services/opencode/src/androidTest/kotlin/com/getcode/opencode/model/core/OpenCodePayloadTests.kt rename to services/opencode/src/androidDeviceTest/kotlin/com/getcode/opencode/model/core/OpenCodePayloadTests.kt diff --git a/services/opencode/src/androidTest/kotlin/com/getcode/opencode/solana/swap/SwapTests.kt b/services/opencode/src/androidDeviceTest/kotlin/com/getcode/opencode/solana/swap/SwapTests.kt similarity index 100% rename from services/opencode/src/androidTest/kotlin/com/getcode/opencode/solana/swap/SwapTests.kt rename to services/opencode/src/androidDeviceTest/kotlin/com/getcode/opencode/solana/swap/SwapTests.kt diff --git a/services/opencode/src/androidTest/kotlin/com/getcode/opencode/tests/PublicKey.kt b/services/opencode/src/androidDeviceTest/kotlin/com/getcode/opencode/tests/PublicKey.kt similarity index 100% rename from services/opencode/src/androidTest/kotlin/com/getcode/opencode/tests/PublicKey.kt rename to services/opencode/src/androidDeviceTest/kotlin/com/getcode/opencode/tests/PublicKey.kt diff --git a/services/opencode/src/test/kotlin/com/getcode/opencode/controllers/AccountControllerTest.kt b/services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/controllers/AccountControllerTest.kt similarity index 99% rename from services/opencode/src/test/kotlin/com/getcode/opencode/controllers/AccountControllerTest.kt rename to services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/controllers/AccountControllerTest.kt index 4836c226f9..4a4d43843e 100644 --- a/services/opencode/src/test/kotlin/com/getcode/opencode/controllers/AccountControllerTest.kt +++ b/services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/controllers/AccountControllerTest.kt @@ -1,6 +1,6 @@ package com.getcode.opencode.controllers -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair import com.getcode.opencode.model.accounts.AccountCluster import com.getcode.opencode.model.accounts.AccountFilter import com.getcode.opencode.model.accounts.AccountInfo diff --git a/services/opencode/src/test/kotlin/com/getcode/opencode/controllers/TokenControllerFetchTokenBalancesTest.kt b/services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/controllers/TokenControllerFetchTokenBalancesTest.kt similarity index 100% rename from services/opencode/src/test/kotlin/com/getcode/opencode/controllers/TokenControllerFetchTokenBalancesTest.kt rename to services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/controllers/TokenControllerFetchTokenBalancesTest.kt diff --git a/services/opencode/src/test/kotlin/com/getcode/opencode/controllers/TransactionControllerPollIntentMetadataTest.kt b/services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/controllers/TransactionControllerPollIntentMetadataTest.kt similarity index 100% rename from services/opencode/src/test/kotlin/com/getcode/opencode/controllers/TransactionControllerPollIntentMetadataTest.kt rename to services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/controllers/TransactionControllerPollIntentMetadataTest.kt diff --git a/services/opencode/src/test/kotlin/com/getcode/opencode/internal/bidi/OpenBidirectionalStreamTest.kt b/services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/internal/bidi/OpenBidirectionalStreamTest.kt similarity index 100% rename from services/opencode/src/test/kotlin/com/getcode/opencode/internal/bidi/OpenBidirectionalStreamTest.kt rename to services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/internal/bidi/OpenBidirectionalStreamTest.kt diff --git a/services/opencode/src/test/kotlin/com/getcode/opencode/internal/exchange/RealVerifiedFiatCalculatorTest.kt b/services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/internal/exchange/RealVerifiedFiatCalculatorTest.kt similarity index 100% rename from services/opencode/src/test/kotlin/com/getcode/opencode/internal/exchange/RealVerifiedFiatCalculatorTest.kt rename to services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/internal/exchange/RealVerifiedFiatCalculatorTest.kt diff --git a/services/opencode/src/test/kotlin/com/getcode/opencode/internal/extensions/ByteArrayExtensionsTest.kt b/services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/internal/extensions/ByteArrayExtensionsTest.kt similarity index 100% rename from services/opencode/src/test/kotlin/com/getcode/opencode/internal/extensions/ByteArrayExtensionsTest.kt rename to services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/internal/extensions/ByteArrayExtensionsTest.kt diff --git a/services/opencode/src/test/kotlin/com/getcode/opencode/internal/extensions/CurrencyCodeExtensionsTest.kt b/services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/internal/extensions/CurrencyCodeExtensionsTest.kt similarity index 100% rename from services/opencode/src/test/kotlin/com/getcode/opencode/internal/extensions/CurrencyCodeExtensionsTest.kt rename to services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/internal/extensions/CurrencyCodeExtensionsTest.kt diff --git a/services/opencode/src/test/kotlin/com/getcode/opencode/internal/extensions/ResultExtensionsTest.kt b/services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/internal/extensions/ResultExtensionsTest.kt similarity index 100% rename from services/opencode/src/test/kotlin/com/getcode/opencode/internal/extensions/ResultExtensionsTest.kt rename to services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/internal/extensions/ResultExtensionsTest.kt diff --git a/services/opencode/src/test/kotlin/com/getcode/opencode/internal/extensions/VerifiedStateExtTest.kt b/services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/internal/extensions/VerifiedStateExtTest.kt similarity index 100% rename from services/opencode/src/test/kotlin/com/getcode/opencode/internal/extensions/VerifiedStateExtTest.kt rename to services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/internal/extensions/VerifiedStateExtTest.kt diff --git a/services/opencode/src/test/kotlin/com/getcode/opencode/internal/manager/VerifiedProtoManagerTest.kt b/services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/internal/manager/VerifiedProtoManagerTest.kt similarity index 100% rename from services/opencode/src/test/kotlin/com/getcode/opencode/internal/manager/VerifiedProtoManagerTest.kt rename to services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/internal/manager/VerifiedProtoManagerTest.kt diff --git a/services/opencode/src/test/kotlin/com/getcode/opencode/internal/network/api/intents/IntentMultiTransferTest.kt b/services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/internal/network/api/intents/IntentMultiTransferTest.kt similarity index 99% rename from services/opencode/src/test/kotlin/com/getcode/opencode/internal/network/api/intents/IntentMultiTransferTest.kt rename to services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/internal/network/api/intents/IntentMultiTransferTest.kt index b29ea9ccc0..f8224f5e97 100644 --- a/services/opencode/src/test/kotlin/com/getcode/opencode/internal/network/api/intents/IntentMultiTransferTest.kt +++ b/services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/internal/network/api/intents/IntentMultiTransferTest.kt @@ -3,7 +3,7 @@ package com.getcode.opencode.internal.network.api.intents import com.codeinc.opencode.gen.currency.v1.coreMintFiatExchangeRate import com.codeinc.opencode.gen.currency.v1.verifiedCoreMintFiatExchangeRate import com.getcode.crypt.DerivedKey -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.opencode.internal.manager.VerifiedState import com.getcode.opencode.internal.network.api.intents.actions.ActionPublicTransfer import com.getcode.opencode.model.accounts.AccountCluster diff --git a/services/opencode/src/test/kotlin/com/getcode/opencode/internal/network/pollers/SwapPollerTest.kt b/services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/internal/network/pollers/SwapPollerTest.kt similarity index 99% rename from services/opencode/src/test/kotlin/com/getcode/opencode/internal/network/pollers/SwapPollerTest.kt rename to services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/internal/network/pollers/SwapPollerTest.kt index 3a37cb8f77..ade9d37dda 100644 --- a/services/opencode/src/test/kotlin/com/getcode/opencode/internal/network/pollers/SwapPollerTest.kt +++ b/services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/internal/network/pollers/SwapPollerTest.kt @@ -1,6 +1,6 @@ package com.getcode.opencode.internal.network.pollers -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.opencode.internal.network.services.SwapService import com.getcode.opencode.internal.solana.model.SwapId import com.getcode.opencode.model.core.errors.GetSwapError diff --git a/services/opencode/src/test/kotlin/com/getcode/opencode/internal/network/services/CurrencyServiceTest.kt b/services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/internal/network/services/CurrencyServiceTest.kt similarity index 99% rename from services/opencode/src/test/kotlin/com/getcode/opencode/internal/network/services/CurrencyServiceTest.kt rename to services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/internal/network/services/CurrencyServiceTest.kt index 471001af39..38e141b3c6 100644 --- a/services/opencode/src/test/kotlin/com/getcode/opencode/internal/network/services/CurrencyServiceTest.kt +++ b/services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/internal/network/services/CurrencyServiceTest.kt @@ -2,7 +2,7 @@ package com.getcode.opencode.internal.network.services import com.codeinc.opencode.gen.common.v1.Model import com.codeinc.opencode.gen.currency.v1.OcpCurrencyService as CurrencyProto -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.opencode.internal.domain.mapping.HistoricalMintDataMapper import com.getcode.opencode.internal.domain.mapping.LiveMintDataMapper import com.getcode.opencode.internal.domain.mapping.MintMapper diff --git a/services/opencode/src/test/kotlin/com/getcode/opencode/internal/proto/ProtoWireFormatTest.kt b/services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/internal/proto/ProtoWireFormatTest.kt similarity index 100% rename from services/opencode/src/test/kotlin/com/getcode/opencode/internal/proto/ProtoWireFormatTest.kt rename to services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/internal/proto/ProtoWireFormatTest.kt diff --git a/services/opencode/src/test/kotlin/com/getcode/opencode/internal/solana/ShortVecTest.kt b/services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/internal/solana/ShortVecTest.kt similarity index 100% rename from services/opencode/src/test/kotlin/com/getcode/opencode/internal/solana/ShortVecTest.kt rename to services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/internal/solana/ShortVecTest.kt diff --git a/services/opencode/src/test/kotlin/com/getcode/opencode/internal/solana/extensions/PdaDerivationTest.kt b/services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/internal/solana/extensions/PdaDerivationTest.kt similarity index 99% rename from services/opencode/src/test/kotlin/com/getcode/opencode/internal/solana/extensions/PdaDerivationTest.kt rename to services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/internal/solana/extensions/PdaDerivationTest.kt index c199c269c9..df17956491 100644 --- a/services/opencode/src/test/kotlin/com/getcode/opencode/internal/solana/extensions/PdaDerivationTest.kt +++ b/services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/internal/solana/extensions/PdaDerivationTest.kt @@ -1,6 +1,6 @@ package com.getcode.opencode.internal.solana.extensions -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.solana.keys.Mint import com.getcode.solana.keys.PublicKey import com.getcode.vendor.Base58 diff --git a/services/opencode/src/test/kotlin/com/getcode/opencode/internal/solana/extensions/UInt16Test.kt b/services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/internal/solana/extensions/UInt16Test.kt similarity index 100% rename from services/opencode/src/test/kotlin/com/getcode/opencode/internal/solana/extensions/UInt16Test.kt rename to services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/internal/solana/extensions/UInt16Test.kt diff --git a/services/opencode/src/test/kotlin/com/getcode/opencode/internal/solana/model/CoinbaseStablecoinPoolAccountTest.kt b/services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/internal/solana/model/CoinbaseStablecoinPoolAccountTest.kt similarity index 100% rename from services/opencode/src/test/kotlin/com/getcode/opencode/internal/solana/model/CoinbaseStablecoinPoolAccountTest.kt rename to services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/internal/solana/model/CoinbaseStablecoinPoolAccountTest.kt diff --git a/services/opencode/src/test/kotlin/com/getcode/opencode/internal/solana/programs/CoinbaseStableSwapperProgramTest.kt b/services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/internal/solana/programs/CoinbaseStableSwapperProgramTest.kt similarity index 100% rename from services/opencode/src/test/kotlin/com/getcode/opencode/internal/solana/programs/CoinbaseStableSwapperProgramTest.kt rename to services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/internal/solana/programs/CoinbaseStableSwapperProgramTest.kt diff --git a/services/opencode/src/test/kotlin/com/getcode/opencode/internal/solana/programs/CurrencyCreatorProgramTest.kt b/services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/internal/solana/programs/CurrencyCreatorProgramTest.kt similarity index 100% rename from services/opencode/src/test/kotlin/com/getcode/opencode/internal/solana/programs/CurrencyCreatorProgramTest.kt rename to services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/internal/solana/programs/CurrencyCreatorProgramTest.kt diff --git a/services/opencode/src/test/kotlin/com/getcode/opencode/internal/solana/programs/ProgramAddressesTest.kt b/services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/internal/solana/programs/ProgramAddressesTest.kt similarity index 100% rename from services/opencode/src/test/kotlin/com/getcode/opencode/internal/solana/programs/ProgramAddressesTest.kt rename to services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/internal/solana/programs/ProgramAddressesTest.kt diff --git a/services/opencode/src/test/kotlin/com/getcode/opencode/internal/solana/programs/SysVarTest.kt b/services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/internal/solana/programs/SysVarTest.kt similarity index 100% rename from services/opencode/src/test/kotlin/com/getcode/opencode/internal/solana/programs/SysVarTest.kt rename to services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/internal/solana/programs/SysVarTest.kt diff --git a/services/opencode/src/test/kotlin/com/getcode/opencode/internal/solana/programs/VirtualMachineProgramTest.kt b/services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/internal/solana/programs/VirtualMachineProgramTest.kt similarity index 100% rename from services/opencode/src/test/kotlin/com/getcode/opencode/internal/solana/programs/VirtualMachineProgramTest.kt rename to services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/internal/solana/programs/VirtualMachineProgramTest.kt diff --git a/services/opencode/src/test/kotlin/com/getcode/opencode/internal/transactors/ClaimValidationTest.kt b/services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/internal/transactors/ClaimValidationTest.kt similarity index 100% rename from services/opencode/src/test/kotlin/com/getcode/opencode/internal/transactors/ClaimValidationTest.kt rename to services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/internal/transactors/ClaimValidationTest.kt diff --git a/services/opencode/src/test/kotlin/com/getcode/opencode/internal/transactors/GiveBillTransactorTest.kt b/services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/internal/transactors/GiveBillTransactorTest.kt similarity index 100% rename from services/opencode/src/test/kotlin/com/getcode/opencode/internal/transactors/GiveBillTransactorTest.kt rename to services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/internal/transactors/GiveBillTransactorTest.kt diff --git a/services/opencode/src/test/kotlin/com/getcode/opencode/internal/transactors/GrabBillTransactorTest.kt b/services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/internal/transactors/GrabBillTransactorTest.kt similarity index 100% rename from services/opencode/src/test/kotlin/com/getcode/opencode/internal/transactors/GrabBillTransactorTest.kt rename to services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/internal/transactors/GrabBillTransactorTest.kt diff --git a/services/opencode/src/test/kotlin/com/getcode/opencode/internal/transactors/ReceiveGiftCardTransactorTest.kt b/services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/internal/transactors/ReceiveGiftCardTransactorTest.kt similarity index 100% rename from services/opencode/src/test/kotlin/com/getcode/opencode/internal/transactors/ReceiveGiftCardTransactorTest.kt rename to services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/internal/transactors/ReceiveGiftCardTransactorTest.kt diff --git a/services/opencode/src/test/kotlin/com/getcode/opencode/internal/transactors/SendGiftCardTransactorTest.kt b/services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/internal/transactors/SendGiftCardTransactorTest.kt similarity index 100% rename from services/opencode/src/test/kotlin/com/getcode/opencode/internal/transactors/SendGiftCardTransactorTest.kt rename to services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/internal/transactors/SendGiftCardTransactorTest.kt diff --git a/services/opencode/src/test/kotlin/com/getcode/opencode/model/core/OpenCodePayloadTest.kt b/services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/model/core/OpenCodePayloadTest.kt similarity index 100% rename from services/opencode/src/test/kotlin/com/getcode/opencode/model/core/OpenCodePayloadTest.kt rename to services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/model/core/OpenCodePayloadTest.kt diff --git a/services/opencode/src/test/kotlin/com/getcode/opencode/model/core/errors/SodiumErrorTest.kt b/services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/model/core/errors/SodiumErrorTest.kt similarity index 100% rename from services/opencode/src/test/kotlin/com/getcode/opencode/model/core/errors/SodiumErrorTest.kt rename to services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/model/core/errors/SodiumErrorTest.kt diff --git a/services/opencode/src/test/kotlin/com/getcode/opencode/model/core/errors/SubmitIntentErrorTest.kt b/services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/model/core/errors/SubmitIntentErrorTest.kt similarity index 100% rename from services/opencode/src/test/kotlin/com/getcode/opencode/model/core/errors/SubmitIntentErrorTest.kt rename to services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/model/core/errors/SubmitIntentErrorTest.kt diff --git a/services/opencode/src/test/kotlin/com/getcode/opencode/model/core/errors/SwapErrorTest.kt b/services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/model/core/errors/SwapErrorTest.kt similarity index 100% rename from services/opencode/src/test/kotlin/com/getcode/opencode/model/core/errors/SwapErrorTest.kt rename to services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/model/core/errors/SwapErrorTest.kt diff --git a/services/opencode/src/test/kotlin/com/getcode/opencode/model/financial/DistributionTest.kt b/services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/model/financial/DistributionTest.kt similarity index 100% rename from services/opencode/src/test/kotlin/com/getcode/opencode/model/financial/DistributionTest.kt rename to services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/model/financial/DistributionTest.kt diff --git a/services/opencode/src/test/kotlin/com/getcode/opencode/model/financial/FeeTest.kt b/services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/model/financial/FeeTest.kt similarity index 100% rename from services/opencode/src/test/kotlin/com/getcode/opencode/model/financial/FeeTest.kt rename to services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/model/financial/FeeTest.kt diff --git a/services/opencode/src/test/kotlin/com/getcode/opencode/model/financial/FiatTest.kt b/services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/model/financial/FiatTest.kt similarity index 100% rename from services/opencode/src/test/kotlin/com/getcode/opencode/model/financial/FiatTest.kt rename to services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/model/financial/FiatTest.kt diff --git a/services/opencode/src/test/kotlin/com/getcode/opencode/model/financial/FiatTests.kt b/services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/model/financial/FiatTests.kt similarity index 100% rename from services/opencode/src/test/kotlin/com/getcode/opencode/model/financial/FiatTests.kt rename to services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/model/financial/FiatTests.kt diff --git a/services/opencode/src/test/kotlin/com/getcode/opencode/model/financial/HistoricalMintDataTest.kt b/services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/model/financial/HistoricalMintDataTest.kt similarity index 100% rename from services/opencode/src/test/kotlin/com/getcode/opencode/model/financial/HistoricalMintDataTest.kt rename to services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/model/financial/HistoricalMintDataTest.kt diff --git a/services/opencode/src/test/kotlin/com/getcode/opencode/model/financial/LaunchpadSellFeeTest.kt b/services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/model/financial/LaunchpadSellFeeTest.kt similarity index 100% rename from services/opencode/src/test/kotlin/com/getcode/opencode/model/financial/LaunchpadSellFeeTest.kt rename to services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/model/financial/LaunchpadSellFeeTest.kt diff --git a/services/opencode/src/test/kotlin/com/getcode/opencode/model/financial/LimitsTest.kt b/services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/model/financial/LimitsTest.kt similarity index 100% rename from services/opencode/src/test/kotlin/com/getcode/opencode/model/financial/LimitsTest.kt rename to services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/model/financial/LimitsTest.kt diff --git a/services/opencode/src/test/kotlin/com/getcode/opencode/model/financial/LocalFiatTest.kt b/services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/model/financial/LocalFiatTest.kt similarity index 100% rename from services/opencode/src/test/kotlin/com/getcode/opencode/model/financial/LocalFiatTest.kt rename to services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/model/financial/LocalFiatTest.kt diff --git a/services/opencode/src/test/kotlin/com/getcode/opencode/model/financial/MintMetadataTest.kt b/services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/model/financial/MintMetadataTest.kt similarity index 100% rename from services/opencode/src/test/kotlin/com/getcode/opencode/model/financial/MintMetadataTest.kt rename to services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/model/financial/MintMetadataTest.kt diff --git a/services/opencode/src/test/kotlin/com/getcode/opencode/model/financial/RateTest.kt b/services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/model/financial/RateTest.kt similarity index 100% rename from services/opencode/src/test/kotlin/com/getcode/opencode/model/financial/RateTest.kt rename to services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/model/financial/RateTest.kt diff --git a/services/opencode/src/test/kotlin/com/getcode/opencode/model/transactions/SwapMetadataTest.kt b/services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/model/transactions/SwapMetadataTest.kt similarity index 100% rename from services/opencode/src/test/kotlin/com/getcode/opencode/model/transactions/SwapMetadataTest.kt rename to services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/model/transactions/SwapMetadataTest.kt diff --git a/services/opencode/src/test/kotlin/com/getcode/opencode/solana/CompactMessageVectorTest.kt b/services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/solana/CompactMessageVectorTest.kt similarity index 100% rename from services/opencode/src/test/kotlin/com/getcode/opencode/solana/CompactMessageVectorTest.kt rename to services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/solana/CompactMessageVectorTest.kt diff --git a/services/opencode/src/test/kotlin/com/getcode/opencode/solana/InstructionIntegrationTest.kt b/services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/solana/InstructionIntegrationTest.kt similarity index 100% rename from services/opencode/src/test/kotlin/com/getcode/opencode/solana/InstructionIntegrationTest.kt rename to services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/solana/InstructionIntegrationTest.kt diff --git a/services/opencode/src/test/kotlin/com/getcode/opencode/solana/MultiPaymentIntentVectorTest.kt b/services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/solana/MultiPaymentIntentVectorTest.kt similarity index 99% rename from services/opencode/src/test/kotlin/com/getcode/opencode/solana/MultiPaymentIntentVectorTest.kt rename to services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/solana/MultiPaymentIntentVectorTest.kt index 65d18b2fa0..9d043be112 100644 --- a/services/opencode/src/test/kotlin/com/getcode/opencode/solana/MultiPaymentIntentVectorTest.kt +++ b/services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/solana/MultiPaymentIntentVectorTest.kt @@ -3,7 +3,7 @@ package com.getcode.opencode.solana import com.codeinc.opencode.gen.currency.v1.coreMintFiatExchangeRate import com.codeinc.opencode.gen.currency.v1.verifiedCoreMintFiatExchangeRate import com.getcode.crypt.DerivedKey -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.opencode.internal.manager.VerifiedState import com.getcode.opencode.internal.network.api.intents.IntentMultiTransfer import com.getcode.opencode.model.accounts.AccountCluster diff --git a/services/opencode/src/test/kotlin/com/getcode/opencode/solana/SolanaMessageVectorTest.kt b/services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/solana/SolanaMessageVectorTest.kt similarity index 100% rename from services/opencode/src/test/kotlin/com/getcode/opencode/solana/SolanaMessageVectorTest.kt rename to services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/solana/SolanaMessageVectorTest.kt diff --git a/services/opencode/src/test/kotlin/com/getcode/opencode/solana/SolanaTransactionLookupTableTest.kt b/services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/solana/SolanaTransactionLookupTableTest.kt similarity index 100% rename from services/opencode/src/test/kotlin/com/getcode/opencode/solana/SolanaTransactionLookupTableTest.kt rename to services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/solana/SolanaTransactionLookupTableTest.kt diff --git a/services/opencode/src/test/kotlin/com/getcode/opencode/solana/VersionedMessageV0Test.kt b/services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/solana/VersionedMessageV0Test.kt similarity index 100% rename from services/opencode/src/test/kotlin/com/getcode/opencode/solana/VersionedMessageV0Test.kt rename to services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/solana/VersionedMessageV0Test.kt diff --git a/services/opencode/src/test/kotlin/com/getcode/opencode/solana/swap/ClientBuiltDepositSwapV2Test.kt b/services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/solana/swap/ClientBuiltDepositSwapV2Test.kt similarity index 100% rename from services/opencode/src/test/kotlin/com/getcode/opencode/solana/swap/ClientBuiltDepositSwapV2Test.kt rename to services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/solana/swap/ClientBuiltDepositSwapV2Test.kt diff --git a/services/opencode/src/test/kotlin/com/getcode/opencode/solana/swap/CoinbaseStablecoinDepositTransactionTest.kt b/services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/solana/swap/CoinbaseStablecoinDepositTransactionTest.kt similarity index 100% rename from services/opencode/src/test/kotlin/com/getcode/opencode/solana/swap/CoinbaseStablecoinDepositTransactionTest.kt rename to services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/solana/swap/CoinbaseStablecoinDepositTransactionTest.kt diff --git a/services/opencode/src/test/kotlin/com/getcode/opencode/solana/swap/CoinbaseStablecoinSwapperInstructionsTest.kt b/services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/solana/swap/CoinbaseStablecoinSwapperInstructionsTest.kt similarity index 100% rename from services/opencode/src/test/kotlin/com/getcode/opencode/solana/swap/CoinbaseStablecoinSwapperInstructionsTest.kt rename to services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/solana/swap/CoinbaseStablecoinSwapperInstructionsTest.kt diff --git a/services/opencode/src/test/kotlin/com/getcode/opencode/solana/swap/ExistingCurrencyBuyFeeTest.kt b/services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/solana/swap/ExistingCurrencyBuyFeeTest.kt similarity index 99% rename from services/opencode/src/test/kotlin/com/getcode/opencode/solana/swap/ExistingCurrencyBuyFeeTest.kt rename to services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/solana/swap/ExistingCurrencyBuyFeeTest.kt index 5f01ae02b9..c1ec51f146 100644 --- a/services/opencode/src/test/kotlin/com/getcode/opencode/solana/swap/ExistingCurrencyBuyFeeTest.kt +++ b/services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/solana/swap/ExistingCurrencyBuyFeeTest.kt @@ -1,6 +1,6 @@ package com.getcode.opencode.solana.swap -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair import com.getcode.opencode.internal.manager.VerifiedState import com.getcode.opencode.internal.network.api.intents.IntentStatefulSwap import com.getcode.opencode.internal.solana.model.SwapId diff --git a/services/opencode/src/test/kotlin/com/getcode/opencode/solana/swap/StablecoinSwapVersionRequestTest.kt b/services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/solana/swap/StablecoinSwapVersionRequestTest.kt similarity index 98% rename from services/opencode/src/test/kotlin/com/getcode/opencode/solana/swap/StablecoinSwapVersionRequestTest.kt rename to services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/solana/swap/StablecoinSwapVersionRequestTest.kt index ad8168edc2..4928b382dd 100644 --- a/services/opencode/src/test/kotlin/com/getcode/opencode/solana/swap/StablecoinSwapVersionRequestTest.kt +++ b/services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/solana/swap/StablecoinSwapVersionRequestTest.kt @@ -1,6 +1,6 @@ package com.getcode.opencode.solana.swap -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair import com.getcode.opencode.internal.network.api.intents.IntentStatelessSwap import com.getcode.opencode.internal.network.extensions.stablecoinParams import com.getcode.opencode.internal.solana.model.SwapId diff --git a/services/opencode/src/test/kotlin/com/getcode/opencode/solana/swap/StatelessSwapInstructionsTest.kt b/services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/solana/swap/StatelessSwapInstructionsTest.kt similarity index 100% rename from services/opencode/src/test/kotlin/com/getcode/opencode/solana/swap/StatelessSwapInstructionsTest.kt rename to services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/solana/swap/StatelessSwapInstructionsTest.kt diff --git a/services/opencode/src/test/kotlin/com/getcode/opencode/tests/PublicKey.kt b/services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/tests/PublicKey.kt similarity index 100% rename from services/opencode/src/test/kotlin/com/getcode/opencode/tests/PublicKey.kt rename to services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/tests/PublicKey.kt diff --git a/services/opencode/src/test/kotlin/com/getcode/opencode/utils/DoubleExtensionsTest.kt b/services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/utils/DoubleExtensionsTest.kt similarity index 100% rename from services/opencode/src/test/kotlin/com/getcode/opencode/utils/DoubleExtensionsTest.kt rename to services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/utils/DoubleExtensionsTest.kt diff --git a/services/opencode/src/test/kotlin/com/getcode/opencode/utils/LongTest.kt b/services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/utils/LongTest.kt similarity index 100% rename from services/opencode/src/test/kotlin/com/getcode/opencode/utils/LongTest.kt rename to services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/utils/LongTest.kt diff --git a/services/opencode/src/test/kotlin/com/getcode/opencode/utils/MapsTest.kt b/services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/utils/MapsTest.kt similarity index 100% rename from services/opencode/src/test/kotlin/com/getcode/opencode/utils/MapsTest.kt rename to services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/utils/MapsTest.kt diff --git a/services/opencode/src/test/kotlin/com/getcode/opencode/utils/StringExtensionsTest.kt b/services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/utils/StringExtensionsTest.kt similarity index 100% rename from services/opencode/src/test/kotlin/com/getcode/opencode/utils/StringExtensionsTest.kt rename to services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/utils/StringExtensionsTest.kt diff --git a/services/opencode/src/test/kotlin/com/getcode/opencode/utils/ThrowableExtensionsTest.kt b/services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/utils/ThrowableExtensionsTest.kt similarity index 100% rename from services/opencode/src/test/kotlin/com/getcode/opencode/utils/ThrowableExtensionsTest.kt rename to services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/utils/ThrowableExtensionsTest.kt diff --git a/services/opencode/src/test/resources/compact_message.json b/services/opencode/src/androidHostTest/resources/compact_message.json similarity index 100% rename from services/opencode/src/test/resources/compact_message.json rename to services/opencode/src/androidHostTest/resources/compact_message.json diff --git a/services/opencode/src/test/resources/multi_payment_intent.json b/services/opencode/src/androidHostTest/resources/multi_payment_intent.json similarity index 100% rename from services/opencode/src/test/resources/multi_payment_intent.json rename to services/opencode/src/androidHostTest/resources/multi_payment_intent.json diff --git a/services/opencode/src/test/resources/solana_message.json b/services/opencode/src/androidHostTest/resources/solana_message.json similarity index 100% rename from services/opencode/src/test/resources/solana_message.json rename to services/opencode/src/androidHostTest/resources/solana_message.json diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/ControllerFactory.kt b/services/opencode/src/androidMain/kotlin/com/getcode/opencode/ControllerFactory.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/ControllerFactory.kt rename to services/opencode/src/androidMain/kotlin/com/getcode/opencode/ControllerFactory.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/ExchangeFactory.kt b/services/opencode/src/androidMain/kotlin/com/getcode/opencode/ExchangeFactory.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/ExchangeFactory.kt rename to services/opencode/src/androidMain/kotlin/com/getcode/opencode/ExchangeFactory.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/NetworkFactory.kt b/services/opencode/src/androidMain/kotlin/com/getcode/opencode/NetworkFactory.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/NetworkFactory.kt rename to services/opencode/src/androidMain/kotlin/com/getcode/opencode/NetworkFactory.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/RepositoryFactory.kt b/services/opencode/src/androidMain/kotlin/com/getcode/opencode/RepositoryFactory.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/RepositoryFactory.kt rename to services/opencode/src/androidMain/kotlin/com/getcode/opencode/RepositoryFactory.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/inject/OpenCodeModule.kt b/services/opencode/src/androidMain/kotlin/com/getcode/opencode/inject/OpenCodeModule.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/inject/OpenCodeModule.kt rename to services/opencode/src/androidMain/kotlin/com/getcode/opencode/inject/OpenCodeModule.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/inject/SessionListenersModule.kt b/services/opencode/src/androidMain/kotlin/com/getcode/opencode/inject/SessionListenersModule.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/inject/SessionListenersModule.kt rename to services/opencode/src/androidMain/kotlin/com/getcode/opencode/inject/SessionListenersModule.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/inject/TransactorModule.kt b/services/opencode/src/androidMain/kotlin/com/getcode/opencode/inject/TransactorModule.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/inject/TransactorModule.kt rename to services/opencode/src/androidMain/kotlin/com/getcode/opencode/inject/TransactorModule.kt diff --git a/services/opencode/src/androidMain/kotlin/com/getcode/opencode/internal/platform/ProcessLifecycle.android.kt b/services/opencode/src/androidMain/kotlin/com/getcode/opencode/internal/platform/ProcessLifecycle.android.kt new file mode 100644 index 0000000000..5b35bce979 --- /dev/null +++ b/services/opencode/src/androidMain/kotlin/com/getcode/opencode/internal/platform/ProcessLifecycle.android.kt @@ -0,0 +1,25 @@ +package com.getcode.opencode.internal.platform + +import android.os.Handler +import android.os.Looper +import androidx.lifecycle.DefaultLifecycleObserver +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.ProcessLifecycleOwner + +internal actual fun observeProcessLifecycle( + immediateOnMain: Boolean, + onStart: () -> Unit, + onStop: () -> Unit, +) { + val observer = object : DefaultLifecycleObserver { + override fun onStart(owner: LifecycleOwner) = onStart() + override fun onStop(owner: LifecycleOwner) = onStop() + } + // LifecycleRegistry.addObserver rejects any thread but the main one. + val register = Runnable { ProcessLifecycleOwner.get().lifecycle.addObserver(observer) } + if (immediateOnMain && Looper.myLooper() == Looper.getMainLooper()) { + register.run() + } else { + Handler(Looper.getMainLooper()).post(register) + } +} diff --git a/services/opencode/src/androidMain/kotlin/com/getcode/opencode/model/core/ScanCodeEncoder.android.kt b/services/opencode/src/androidMain/kotlin/com/getcode/opencode/model/core/ScanCodeEncoder.android.kt new file mode 100644 index 0000000000..b788a36e57 --- /dev/null +++ b/services/opencode/src/androidMain/kotlin/com/getcode/opencode/model/core/ScanCodeEncoder.android.kt @@ -0,0 +1,5 @@ +package com.getcode.opencode.model.core + +import com.kik.scan.Scanner + +internal actual fun encodeScanCode(payload: ByteArray): ByteArray? = Scanner.encode(payload) diff --git a/services/opencode/src/main/res/drawable/ic_currency_dollar_active.xml b/services/opencode/src/androidMain/res/drawable/ic_currency_dollar_active.xml similarity index 100% rename from services/opencode/src/main/res/drawable/ic_currency_dollar_active.xml rename to services/opencode/src/androidMain/res/drawable/ic_currency_dollar_active.xml diff --git a/services/opencode/src/main/res/drawable/ic_currency_dollar_inactive.xml b/services/opencode/src/androidMain/res/drawable/ic_currency_dollar_inactive.xml similarity index 100% rename from services/opencode/src/main/res/drawable/ic_currency_dollar_inactive.xml rename to services/opencode/src/androidMain/res/drawable/ic_currency_dollar_inactive.xml diff --git a/services/opencode/src/main/res/drawable/ic_currency_xaf.xml b/services/opencode/src/androidMain/res/drawable/ic_currency_xaf.xml similarity index 100% rename from services/opencode/src/main/res/drawable/ic_currency_xaf.xml rename to services/opencode/src/androidMain/res/drawable/ic_currency_xaf.xml diff --git a/services/opencode/src/main/res/drawable/ic_currency_xof.xml b/services/opencode/src/androidMain/res/drawable/ic_currency_xof.xml similarity index 100% rename from services/opencode/src/main/res/drawable/ic_currency_xof.xml rename to services/opencode/src/androidMain/res/drawable/ic_currency_xof.xml diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/ManagerFactory.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/ManagerFactory.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/ManagerFactory.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/ManagerFactory.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/ProtocolConfig.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/ProtocolConfig.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/ProtocolConfig.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/ProtocolConfig.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/controllers/AccountController.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/controllers/AccountController.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/controllers/AccountController.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/controllers/AccountController.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/controllers/BalanceController.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/controllers/BalanceController.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/controllers/BalanceController.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/controllers/BalanceController.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/controllers/CurrencyController.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/controllers/CurrencyController.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/controllers/CurrencyController.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/controllers/CurrencyController.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/controllers/MessagingController.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/controllers/MessagingController.kt similarity index 99% rename from services/opencode/src/main/kotlin/com/getcode/opencode/controllers/MessagingController.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/controllers/MessagingController.kt index d543271c26..bf7eca2735 100644 --- a/services/opencode/src/main/kotlin/com/getcode/opencode/controllers/MessagingController.kt +++ b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/controllers/MessagingController.kt @@ -1,7 +1,7 @@ package com.getcode.opencode.controllers import com.codeinc.opencode.gen.messaging.v1.OcpMessagingService -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair import com.getcode.opencode.internal.domain.mapping.BillCustomizationMapper import com.getcode.opencode.internal.domain.mapping.HolderMetricsMapper import com.getcode.opencode.internal.domain.mapping.MarketCapMetricsMapper diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/controllers/TokenController.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/controllers/TokenController.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/controllers/TokenController.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/controllers/TokenController.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/controllers/TransactionController.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/controllers/TransactionController.kt similarity index 99% rename from services/opencode/src/main/kotlin/com/getcode/opencode/controllers/TransactionController.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/controllers/TransactionController.kt index ce500e641e..092e741e4c 100644 --- a/services/opencode/src/main/kotlin/com/getcode/opencode/controllers/TransactionController.kt +++ b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/controllers/TransactionController.kt @@ -1,6 +1,6 @@ package com.getcode.opencode.controllers -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair import com.getcode.opencode.exchange.VerifiedFiat import com.getcode.opencode.exchange.valuedAt import com.getcode.opencode.internal.manager.VerifiedState diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/controllers/TransactionOperations.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/controllers/TransactionOperations.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/controllers/TransactionOperations.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/controllers/TransactionOperations.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/events/Events.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/events/Events.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/events/Events.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/events/Events.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/exchange/Exchange.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/exchange/Exchange.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/exchange/Exchange.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/exchange/Exchange.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/exchange/VerifiedFiatCalculator.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/exchange/VerifiedFiatCalculator.kt similarity index 91% rename from services/opencode/src/main/kotlin/com/getcode/opencode/exchange/VerifiedFiatCalculator.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/exchange/VerifiedFiatCalculator.kt index 39d46804fc..3e9a656a4c 100644 --- a/services/opencode/src/main/kotlin/com/getcode/opencode/exchange/VerifiedFiatCalculator.kt +++ b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/exchange/VerifiedFiatCalculator.kt @@ -1,6 +1,6 @@ package com.getcode.opencode.exchange -import android.os.Parcelable +import com.getcode.libs.parcelable.Parcelable import com.getcode.opencode.internal.manager.VerifiedState import com.getcode.opencode.model.financial.CurrencyCode import com.getcode.opencode.model.financial.Fiat @@ -8,8 +8,8 @@ import com.getcode.opencode.model.financial.LocalFiat import com.getcode.opencode.model.financial.Rate import com.getcode.opencode.model.financial.Token import com.getcode.solana.keys.Mint -import kotlinx.parcelize.IgnoredOnParcel -import kotlinx.parcelize.Parcelize +import com.getcode.libs.parcelable.IgnoredOnParcel +import com.getcode.libs.parcelable.Parcelize import kotlinx.serialization.Serializable import kotlinx.serialization.Transient diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/generators/GiftCardGenerator.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/generators/GiftCardGenerator.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/generators/GiftCardGenerator.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/generators/GiftCardGenerator.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/generators/MnemonicGenerator.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/generators/MnemonicGenerator.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/generators/MnemonicGenerator.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/generators/MnemonicGenerator.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/annotations/OpenCodeManagedChannel.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/annotations/OpenCodeManagedChannel.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/annotations/OpenCodeManagedChannel.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/annotations/OpenCodeManagedChannel.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/annotations/Protocol.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/annotations/Protocol.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/annotations/Protocol.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/annotations/Protocol.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/bidi/BidirectionalStreamReference.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/bidi/BidirectionalStreamReference.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/bidi/BidirectionalStreamReference.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/bidi/BidirectionalStreamReference.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/bidi/OpenStream.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/bidi/OpenStream.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/bidi/OpenStream.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/bidi/OpenStream.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/bidi/OpenStreamForResult.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/bidi/OpenStreamForResult.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/bidi/OpenStreamForResult.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/bidi/OpenStreamForResult.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/domain/mapping/BillCustomizationMapper.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/domain/mapping/BillCustomizationMapper.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/domain/mapping/BillCustomizationMapper.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/domain/mapping/BillCustomizationMapper.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/domain/mapping/HistoricalMintDataMapper.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/domain/mapping/HistoricalMintDataMapper.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/domain/mapping/HistoricalMintDataMapper.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/domain/mapping/HistoricalMintDataMapper.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/domain/mapping/HolderMetricsMapper.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/domain/mapping/HolderMetricsMapper.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/domain/mapping/HolderMetricsMapper.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/domain/mapping/HolderMetricsMapper.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/domain/mapping/LaunchpadMetadataMapper.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/domain/mapping/LaunchpadMetadataMapper.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/domain/mapping/LaunchpadMetadataMapper.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/domain/mapping/LaunchpadMetadataMapper.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/domain/mapping/LiveMintDataMapper.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/domain/mapping/LiveMintDataMapper.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/domain/mapping/LiveMintDataMapper.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/domain/mapping/LiveMintDataMapper.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/domain/mapping/MarketCapMetricsMapper.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/domain/mapping/MarketCapMetricsMapper.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/domain/mapping/MarketCapMetricsMapper.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/domain/mapping/MarketCapMetricsMapper.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/domain/mapping/MessageMapper.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/domain/mapping/MessageMapper.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/domain/mapping/MessageMapper.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/domain/mapping/MessageMapper.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/domain/mapping/MintMapper.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/domain/mapping/MintMapper.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/domain/mapping/MintMapper.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/domain/mapping/MintMapper.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/domain/mapping/OwnerBalanceMapper.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/domain/mapping/OwnerBalanceMapper.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/domain/mapping/OwnerBalanceMapper.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/domain/mapping/OwnerBalanceMapper.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/domain/mapping/SocialLinkMapper.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/domain/mapping/SocialLinkMapper.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/domain/mapping/SocialLinkMapper.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/domain/mapping/SocialLinkMapper.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/domain/mapping/SwapMetadataMapper.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/domain/mapping/SwapMetadataMapper.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/domain/mapping/SwapMetadataMapper.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/domain/mapping/SwapMetadataMapper.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/domain/mapping/TransactionMetadataMapper.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/domain/mapping/TransactionMetadataMapper.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/domain/mapping/TransactionMetadataMapper.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/domain/mapping/TransactionMetadataMapper.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/domain/mapping/VmMetadataMapper.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/domain/mapping/VmMetadataMapper.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/domain/mapping/VmMetadataMapper.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/domain/mapping/VmMetadataMapper.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/domain/repositories/InternalAccountRepository.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/domain/repositories/InternalAccountRepository.kt similarity index 98% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/domain/repositories/InternalAccountRepository.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/domain/repositories/InternalAccountRepository.kt index 645fcdd99f..1a55e433f7 100644 --- a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/domain/repositories/InternalAccountRepository.kt +++ b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/domain/repositories/InternalAccountRepository.kt @@ -1,6 +1,6 @@ package com.getcode.opencode.internal.domain.repositories -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.opencode.internal.network.api.TransactionApi import com.getcode.opencode.internal.network.api.intents.IntentCreateAccount import com.getcode.opencode.internal.network.executors.IntentExecutor diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/domain/repositories/InternalBalanceRepository.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/domain/repositories/InternalBalanceRepository.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/domain/repositories/InternalBalanceRepository.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/domain/repositories/InternalBalanceRepository.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/domain/repositories/InternalCurrencyRepository.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/domain/repositories/InternalCurrencyRepository.kt similarity index 98% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/domain/repositories/InternalCurrencyRepository.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/domain/repositories/InternalCurrencyRepository.kt index e046c1679f..80e01bd3a1 100644 --- a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/domain/repositories/InternalCurrencyRepository.kt +++ b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/domain/repositories/InternalCurrencyRepository.kt @@ -1,6 +1,6 @@ package com.getcode.opencode.internal.domain.repositories -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.opencode.model.ui.DiscoverCategory import com.getcode.opencode.model.financial.LiveMintDataResponse import com.getcode.opencode.model.ui.WindowedRange diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/domain/repositories/InternalEventRepository.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/domain/repositories/InternalEventRepository.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/domain/repositories/InternalEventRepository.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/domain/repositories/InternalEventRepository.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/domain/repositories/InternalMessagingRepository.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/domain/repositories/InternalMessagingRepository.kt similarity index 98% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/domain/repositories/InternalMessagingRepository.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/domain/repositories/InternalMessagingRepository.kt index 040ff1f5e6..11d8e44244 100644 --- a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/domain/repositories/InternalMessagingRepository.kt +++ b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/domain/repositories/InternalMessagingRepository.kt @@ -1,6 +1,6 @@ package com.getcode.opencode.internal.domain.repositories -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.opencode.internal.network.extensions.asMessageId import com.getcode.opencode.internal.network.extensions.asSolanaAccountId import com.getcode.opencode.internal.network.services.MessagingService diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/domain/repositories/InternalSwapRepository.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/domain/repositories/InternalSwapRepository.kt similarity index 97% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/domain/repositories/InternalSwapRepository.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/domain/repositories/InternalSwapRepository.kt index 900cce6fd6..54088e9f31 100644 --- a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/domain/repositories/InternalSwapRepository.kt +++ b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/domain/repositories/InternalSwapRepository.kt @@ -1,6 +1,6 @@ package com.getcode.opencode.internal.domain.repositories -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.opencode.internal.network.pollers.SwapPoller import com.getcode.opencode.internal.network.services.SwapService import com.getcode.opencode.internal.solana.model.SwapId diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/domain/repositories/InternalTransactionRepository.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/domain/repositories/InternalTransactionRepository.kt similarity index 99% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/domain/repositories/InternalTransactionRepository.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/domain/repositories/InternalTransactionRepository.kt index 5a689cc613..fe67be6c6b 100644 --- a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/domain/repositories/InternalTransactionRepository.kt +++ b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/domain/repositories/InternalTransactionRepository.kt @@ -1,6 +1,6 @@ package com.getcode.opencode.internal.domain.repositories -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.opencode.internal.manager.VerifiedState import com.getcode.opencode.internal.network.services.TransactionService import com.getcode.opencode.internal.solana.model.SwapId diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/exchange/OpenCodeExchange.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/exchange/OpenCodeExchange.kt similarity index 89% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/exchange/OpenCodeExchange.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/exchange/OpenCodeExchange.kt index a481d72cab..2a41088692 100644 --- a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/exchange/OpenCodeExchange.kt +++ b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/exchange/OpenCodeExchange.kt @@ -1,14 +1,10 @@ package com.getcode.opencode.internal.exchange -import androidx.lifecycle.DefaultLifecycleObserver -import androidx.lifecycle.LifecycleOwner -import android.os.Handler -import android.os.Looper -import androidx.lifecycle.ProcessLifecycleOwner import com.getcode.opencode.controllers.CurrencyController import com.getcode.opencode.exchange.Exchange import com.getcode.opencode.internal.extensions.fromCode import com.getcode.opencode.internal.manager.VerifiedProtoManager +import com.getcode.opencode.internal.platform.observeProcessLifecycle import com.getcode.opencode.model.financial.Currency import com.getcode.opencode.model.financial.CurrencyCode import com.getcode.opencode.model.financial.Rate @@ -34,7 +30,7 @@ internal class OpenCodeExchange @Inject constructor( private val verifiedStateManager: VerifiedProtoManager, private val resources: ResourceHelper, private val locale: LocaleHelper, -) : Exchange, DefaultLifecycleObserver { +) : Exchange { private var ratesCollectionJob: Job? = null private var exchangeRatesStream: Job? = null @@ -42,26 +38,19 @@ internal class OpenCodeExchange @Inject constructor( private val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO) init { - // Posted, not called directly: addObserver is main-thread-only, and this singleton is built - // off the main thread so its construction stays off the startup path. - Handler(Looper.getMainLooper()).post { - ProcessLifecycleOwner.get().lifecycle.addObserver(this) - } + // Deferred, not registered in place: this singleton is built off the main thread so its + // construction stays off the startup path, and its fields below are not yet initialized. + observeProcessLifecycle( + immediateOnMain = false, + onStart = ::streamRates, + onStop = ::stopStreamingRates, + ) scope.launch { val currencyCode = locale.getDefaultCurrencyName() preferredCurrency = CurrencyCode.tryValueOf(currencyCode) } } - override fun onStart(owner: LifecycleOwner) { - streamRates() - } - - override fun onStop(owner: LifecycleOwner) { - super.onStop(owner) - stopStreamingRates() - } - private val _preferredRate = MutableStateFlow(Rate.oneToOne) override val preferredRate: Rate diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/exchange/RealVerifiedFiatCalculator.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/exchange/RealVerifiedFiatCalculator.kt similarity index 99% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/exchange/RealVerifiedFiatCalculator.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/exchange/RealVerifiedFiatCalculator.kt index 6767901e9b..61b0a98d0b 100644 --- a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/exchange/RealVerifiedFiatCalculator.kt +++ b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/exchange/RealVerifiedFiatCalculator.kt @@ -16,7 +16,6 @@ import com.getcode.opencode.model.financial.Rate import com.getcode.opencode.model.core.errors.ComputeVerifiedFiatError import com.getcode.opencode.model.financial.Token import com.getcode.opencode.model.financial.min -import com.getcode.services.opencode.BuildConfig import com.getcode.solana.keys.Mint import com.getcode.utils.TraceType import com.getcode.utils.trace diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/extensions/ByteArray.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/extensions/ByteArray.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/extensions/ByteArray.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/extensions/ByteArray.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/extensions/Currency.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/extensions/Currency.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/extensions/Currency.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/extensions/Currency.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/extensions/CurrencyCode.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/extensions/CurrencyCode.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/extensions/CurrencyCode.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/extensions/CurrencyCode.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/extensions/Instant.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/extensions/Instant.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/extensions/Instant.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/extensions/Instant.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/extensions/KeyPair.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/extensions/KeyPair.kt similarity index 80% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/extensions/KeyPair.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/extensions/KeyPair.kt index cd92a63dc7..70f54933b7 100644 --- a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/extensions/KeyPair.kt +++ b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/extensions/KeyPair.kt @@ -1,6 +1,6 @@ package com.getcode.opencode.internal.extensions -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair import com.getcode.solana.keys.PublicKey internal fun KeyPair.toPublicKey(): PublicKey { diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/extensions/PublicKey.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/extensions/PublicKey.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/extensions/PublicKey.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/extensions/PublicKey.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/extensions/Result.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/extensions/Result.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/extensions/Result.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/extensions/Result.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/extensions/VerifiedState.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/extensions/VerifiedState.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/extensions/VerifiedState.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/extensions/VerifiedState.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/generator/Generator.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/generator/Generator.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/generator/Generator.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/generator/Generator.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/manager/VerifiedProtoManager.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/manager/VerifiedProtoManager.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/manager/VerifiedProtoManager.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/manager/VerifiedProtoManager.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/api/AccountApi.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/api/AccountApi.kt similarity index 98% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/api/AccountApi.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/api/AccountApi.kt index 39f245770a..c1534cb1d9 100644 --- a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/api/AccountApi.kt +++ b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/api/AccountApi.kt @@ -3,7 +3,7 @@ package com.getcode.opencode.internal.network.api import com.codeinc.opencode.gen.account.v1.AccountGrpcKt import com.codeinc.opencode.gen.account.v1.OcpAccountService import com.codeinc.opencode.gen.account.v1.validate -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair import com.getcode.opencode.internal.annotations.OpenCodeManagedChannel import com.getcode.opencode.internal.network.core.GrpcApi import com.getcode.opencode.internal.network.extensions.asSolanaAccountId diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/api/BalanceApi.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/api/BalanceApi.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/api/BalanceApi.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/api/BalanceApi.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/api/CurrencyApi.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/api/CurrencyApi.kt similarity index 99% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/api/CurrencyApi.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/api/CurrencyApi.kt index 95453a5f0a..59391faf70 100644 --- a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/api/CurrencyApi.kt +++ b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/api/CurrencyApi.kt @@ -3,7 +3,7 @@ package com.getcode.opencode.internal.network.api import com.codeinc.opencode.gen.currency.v1.CurrencyGrpcKt import com.codeinc.opencode.gen.currency.v1.OcpCurrencyService import com.codeinc.opencode.gen.currency.v1.validate -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.opencode.internal.annotations.OpenCodeManagedChannel import com.getcode.opencode.internal.annotations.OpenCodeManagedStreamingChannel import com.getcode.opencode.model.ui.DiscoverCategory diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/api/MessagingApi.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/api/MessagingApi.kt similarity index 98% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/api/MessagingApi.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/api/MessagingApi.kt index d925ca6ce9..bbed853fa3 100644 --- a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/api/MessagingApi.kt +++ b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/api/MessagingApi.kt @@ -4,8 +4,8 @@ import com.codeinc.opencode.gen.common.v1.Model import com.codeinc.opencode.gen.messaging.v1.MessagingGrpcKt import com.codeinc.opencode.gen.messaging.v1.OcpMessagingService import com.codeinc.opencode.gen.messaging.v1.validate -import com.getcode.ed25519.Ed25519 -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519 +import com.getcode.ed25519kmp.Ed25519.KeyPair import com.getcode.opencode.internal.annotations.OpenCodeManagedChannel import com.getcode.opencode.internal.network.core.GrpcApi import com.getcode.opencode.internal.network.extensions.asRendezvousKey diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/api/TransactionApi.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/api/TransactionApi.kt similarity index 99% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/api/TransactionApi.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/api/TransactionApi.kt index b277484aef..a0d520f467 100644 --- a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/api/TransactionApi.kt +++ b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/api/TransactionApi.kt @@ -15,7 +15,7 @@ import com.codeinc.opencode.gen.transaction.v1.OcpTransactionService.VoidGiftCar import com.codeinc.opencode.gen.transaction.v1.OcpTransactionService.VoidGiftCardResponse import com.codeinc.opencode.gen.transaction.v1.TransactionGrpcKt import com.codeinc.opencode.gen.transaction.v1.validate -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair import com.getcode.opencode.internal.annotations.OpenCodeManagedChannel import com.getcode.opencode.internal.network.core.GrpcApi import com.getcode.opencode.internal.network.extensions.asIntentId diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/api/intents/IntentCreateAccount.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/api/intents/IntentCreateAccount.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/api/intents/IntentCreateAccount.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/api/intents/IntentCreateAccount.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/api/intents/IntentDistribution.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/api/intents/IntentDistribution.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/api/intents/IntentDistribution.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/api/intents/IntentDistribution.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/api/intents/IntentFundSwap.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/api/intents/IntentFundSwap.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/api/intents/IntentFundSwap.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/api/intents/IntentFundSwap.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/api/intents/IntentMultiTransfer.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/api/intents/IntentMultiTransfer.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/api/intents/IntentMultiTransfer.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/api/intents/IntentMultiTransfer.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/api/intents/IntentRemoteReceive.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/api/intents/IntentRemoteReceive.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/api/intents/IntentRemoteReceive.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/api/intents/IntentRemoteReceive.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/api/intents/IntentRemoteSend.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/api/intents/IntentRemoteSend.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/api/intents/IntentRemoteSend.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/api/intents/IntentRemoteSend.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/api/intents/IntentStatefulSwap.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/api/intents/IntentStatefulSwap.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/api/intents/IntentStatefulSwap.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/api/intents/IntentStatefulSwap.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/api/intents/IntentStatelessSwap.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/api/intents/IntentStatelessSwap.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/api/intents/IntentStatelessSwap.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/api/intents/IntentStatelessSwap.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/api/intents/IntentTransfer.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/api/intents/IntentTransfer.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/api/intents/IntentTransfer.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/api/intents/IntentTransfer.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/api/intents/IntentWithdraw.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/api/intents/IntentWithdraw.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/api/intents/IntentWithdraw.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/api/intents/IntentWithdraw.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/api/intents/actions/ActionFeePayment.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/api/intents/actions/ActionFeePayment.kt similarity index 98% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/api/intents/actions/ActionFeePayment.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/api/intents/actions/ActionFeePayment.kt index 2e079ba676..aa2a3d7365 100644 --- a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/api/intents/actions/ActionFeePayment.kt +++ b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/api/intents/actions/ActionFeePayment.kt @@ -1,7 +1,7 @@ package com.getcode.opencode.internal.network.api.intents.actions import com.codeinc.opencode.gen.transaction.v1.OcpTransactionService -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.opencode.internal.network.extensions.asSolanaAccountId import com.getcode.opencode.model.accounts.AccountCluster import com.getcode.opencode.model.financial.Fee diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/api/intents/actions/ActionOpenAccount.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/api/intents/actions/ActionOpenAccount.kt similarity index 98% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/api/intents/actions/ActionOpenAccount.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/api/intents/actions/ActionOpenAccount.kt index 780e364902..3c00018eea 100644 --- a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/api/intents/actions/ActionOpenAccount.kt +++ b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/api/intents/actions/ActionOpenAccount.kt @@ -1,7 +1,7 @@ package com.getcode.opencode.internal.network.api.intents.actions import com.codeinc.opencode.gen.transaction.v1.OcpTransactionService -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.opencode.solana.intents.ServerParameter import com.getcode.opencode.model.accounts.AccountCluster import com.getcode.opencode.internal.network.extensions.asSolanaAccountId diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/api/intents/actions/ActionPublicTransfer.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/api/intents/actions/ActionPublicTransfer.kt similarity index 98% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/api/intents/actions/ActionPublicTransfer.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/api/intents/actions/ActionPublicTransfer.kt index 2cc1150ea6..dc92f00e77 100644 --- a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/api/intents/actions/ActionPublicTransfer.kt +++ b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/api/intents/actions/ActionPublicTransfer.kt @@ -1,7 +1,7 @@ package com.getcode.opencode.internal.network.api.intents.actions import com.codeinc.opencode.gen.transaction.v1.OcpTransactionService -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair import com.getcode.opencode.internal.network.extensions.asSolanaAccountId import com.getcode.opencode.model.financial.Fiat import com.getcode.opencode.solana.SolanaTransaction diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/api/intents/actions/ActionPublicWithdraw.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/api/intents/actions/ActionPublicWithdraw.kt similarity index 98% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/api/intents/actions/ActionPublicWithdraw.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/api/intents/actions/ActionPublicWithdraw.kt index 7ed8af366f..9416f027b8 100644 --- a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/api/intents/actions/ActionPublicWithdraw.kt +++ b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/api/intents/actions/ActionPublicWithdraw.kt @@ -1,7 +1,7 @@ package com.getcode.opencode.internal.network.api.intents.actions import com.codeinc.opencode.gen.transaction.v1.OcpTransactionService -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.opencode.internal.network.extensions.asSolanaAccountId import com.getcode.opencode.model.accounts.AccountCluster import com.getcode.opencode.model.financial.Fiat diff --git a/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/core/GrpcApi.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/core/GrpcApi.kt new file mode 100644 index 0000000000..88f65bded9 --- /dev/null +++ b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/core/GrpcApi.kt @@ -0,0 +1,24 @@ +package com.getcode.opencode.internal.network.core + +import com.getcode.opencode.internal.platform.observeProcessLifecycle +import io.grpc.ManagedChannel + +abstract class GrpcApi(protected val managedChannels: List) { + + constructor(managedChannel: ManagedChannel): this(listOf(managedChannel)) + constructor(vararg managedChannels: ManagedChannel): this(managedChannels.toList()) + + init { + // Registering on the constructing thread would pin construction of every api -- and so of the whole object graph hanging off + // them -- to the main thread. Posting keeps that off the startup path. addObserver replays the + // current state, so a registration that lands after the process is already started still warms + // the channel. + observeProcessLifecycle(immediateOnMain = true, onStart = ::warmUp) + } + + private fun warmUp() { + // getState(true) requests a connection attempt if idle, + // pre-connecting TCP + TLS + HTTP/2 in the background + managedChannels.onEach { it.getState(true) } + } +} diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/executors/IntentExecutor.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/executors/IntentExecutor.kt similarity index 98% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/executors/IntentExecutor.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/executors/IntentExecutor.kt index 6d9f07fbb6..3ff1cd101e 100644 --- a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/executors/IntentExecutor.kt +++ b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/executors/IntentExecutor.kt @@ -1,9 +1,10 @@ package com.getcode.opencode.internal.network.executors +import com.getcode.utils.BuildFlags import com.codeinc.opencode.gen.transaction.v1.OcpTransactionService import com.codeinc.opencode.gen.transaction.v1.OcpTransactionService.SubmitIntentRequest import com.codeinc.opencode.gen.transaction.v1.OcpTransactionService.SubmitIntentResponse -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair import com.getcode.opencode.internal.bidi.BidirectionalStreamReference import com.getcode.opencode.internal.bidi.openBidirectionalStreamForResult import com.getcode.opencode.internal.network.api.TransactionApi @@ -12,7 +13,6 @@ import com.getcode.opencode.solana.SolanaTransaction import com.getcode.opencode.solana.diff import com.getcode.opencode.solana.intents.IntentType import com.getcode.opencode.solana.intents.ServerParameter -import com.getcode.services.opencode.BuildConfig import com.getcode.solana.keys.base58 import com.getcode.solana.keys.redact import com.getcode.utils.TraceType @@ -161,7 +161,7 @@ class IntentExecutor( val submitSignatures = intent.requestToSubmitSignatures() requestChannel(submitSignatures) } catch (e: Exception) { - if (BuildConfig.DEBUG) { + if (BuildFlags.isDebug) { e.printStackTrace() } trace( diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/executors/StatefulSwapExecutor.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/executors/StatefulSwapExecutor.kt similarity index 99% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/executors/StatefulSwapExecutor.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/executors/StatefulSwapExecutor.kt index 3781ce5302..794709daee 100644 --- a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/executors/StatefulSwapExecutor.kt +++ b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/executors/StatefulSwapExecutor.kt @@ -1,5 +1,6 @@ package com.getcode.opencode.internal.network.executors +import com.getcode.utils.BuildFlags import com.codeinc.opencode.gen.transaction.v1.OcpTransactionService import com.getcode.opencode.internal.bidi.BidirectionalStreamReference import com.getcode.opencode.internal.bidi.openBidirectionalStreamForResult @@ -15,7 +16,6 @@ import com.getcode.opencode.model.transactions.SwapProgram import com.getcode.opencode.model.transactions.VerifiedSwapMetadata import com.getcode.opencode.solana.SolanaTransaction import com.getcode.opencode.solana.diff -import com.getcode.services.opencode.BuildConfig import com.getcode.solana.keys.Signature import com.getcode.solana.keys.base58 import com.getcode.utils.TraceType @@ -209,7 +209,7 @@ private fun handleServerParameters( onResult(Result.failure(SwapError.Other(cause = IllegalArgumentException("Invalid server parameters")))) } } catch (e: Exception) { - if (BuildConfig.DEBUG) { + if (BuildFlags.isDebug) { e.printStackTrace() } onResult(Result.failure(SwapError.Other(cause = e))) diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/executors/StatelessSwapExecutor.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/executors/StatelessSwapExecutor.kt similarity index 98% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/executors/StatelessSwapExecutor.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/executors/StatelessSwapExecutor.kt index a05c274d10..71b9bae9b5 100644 --- a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/executors/StatelessSwapExecutor.kt +++ b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/executors/StatelessSwapExecutor.kt @@ -1,5 +1,6 @@ package com.getcode.opencode.internal.network.executors +import com.getcode.utils.BuildFlags import com.codeinc.opencode.gen.transaction.v1.OcpTransactionService import com.getcode.opencode.internal.bidi.BidirectionalStreamReference import com.getcode.opencode.internal.bidi.openBidirectionalStreamForResult @@ -13,7 +14,6 @@ import com.getcode.opencode.model.core.errors.SwapError import com.getcode.opencode.model.transactions.StatelessSwapRequest import com.getcode.opencode.model.transactions.StatelessSwapResult import com.getcode.opencode.model.transactions.StatelessSwapSuccess -import com.getcode.services.opencode.BuildConfig import com.getcode.utils.TraceType import com.getcode.utils.trace import kotlinx.coroutines.CoroutineScope @@ -141,7 +141,7 @@ private fun handleServerParameters( intent.parameters = params requestChannel(intent.requestToSubmitSignatures()) } catch (e: Exception) { - if (BuildConfig.DEBUG) e.printStackTrace() + if (BuildFlags.isDebug) e.printStackTrace() onResult(Result.failure(SwapError.Other(cause = e))) } } diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/extensions/FoldWithSuppression.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/extensions/FoldWithSuppression.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/extensions/FoldWithSuppression.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/extensions/FoldWithSuppression.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/extensions/LocalToProtobuf.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/extensions/LocalToProtobuf.kt similarity index 99% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/extensions/LocalToProtobuf.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/extensions/LocalToProtobuf.kt index 377ea7a5ff..c8ef1d48d6 100644 --- a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/extensions/LocalToProtobuf.kt +++ b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/extensions/LocalToProtobuf.kt @@ -7,7 +7,7 @@ import com.codeinc.opencode.gen.messaging.v1.requestToGiveBill import com.codeinc.opencode.gen.messaging.v1.requestToGrabBill import com.codeinc.opencode.gen.transaction.v1.OcpTransactionService import com.codeinc.opencode.gen.transaction.v1.OcpTransactionService.OpenAccountsMetadata.AccountSet -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair import com.getcode.opencode.internal.solana.model.SwapId import com.getcode.opencode.internal.solana.programs.CoinbaseStableSwapperProgram import com.getcode.opencode.model.accounts.AccountType diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/extensions/ProtobufToLocal.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/extensions/ProtobufToLocal.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/extensions/ProtobufToLocal.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/extensions/ProtobufToLocal.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/extensions/SignMessage.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/extensions/SignMessage.kt similarity index 94% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/extensions/SignMessage.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/extensions/SignMessage.kt index 07b782112b..68948875a4 100644 --- a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/extensions/SignMessage.kt +++ b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/extensions/SignMessage.kt @@ -1,7 +1,7 @@ package com.getcode.opencode.internal.network.extensions import com.codeinc.opencode.gen.common.v1.Model -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.google.protobuf.GeneratedMessageLite import java.io.ByteArrayOutputStream diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/funding/SwapFunding.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/funding/SwapFunding.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/funding/SwapFunding.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/funding/SwapFunding.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/pollers/SwapPoller.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/pollers/SwapPoller.kt similarity index 99% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/pollers/SwapPoller.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/pollers/SwapPoller.kt index 31e70afcd8..9d9eac6b7e 100644 --- a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/pollers/SwapPoller.kt +++ b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/pollers/SwapPoller.kt @@ -1,6 +1,6 @@ package com.getcode.opencode.internal.network.pollers -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.opencode.internal.network.services.SwapService import com.getcode.opencode.internal.solana.model.SwapId import com.getcode.opencode.model.core.errors.GetSwapError diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/serializer/UUIDSerializer.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/serializer/UUIDSerializer.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/serializer/UUIDSerializer.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/serializer/UUIDSerializer.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/services/AccountService.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/services/AccountService.kt similarity index 98% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/services/AccountService.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/services/AccountService.kt index 4e6348afbe..87eaf5412d 100644 --- a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/services/AccountService.kt +++ b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/services/AccountService.kt @@ -1,7 +1,7 @@ package com.getcode.opencode.internal.network.services import com.codeinc.opencode.gen.account.v1.OcpAccountService -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair import com.getcode.opencode.internal.network.api.AccountApi import com.getcode.opencode.internal.network.extensions.foldWithSuppression import com.getcode.opencode.model.accounts.AccountFilter diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/services/BalanceService.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/services/BalanceService.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/services/BalanceService.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/services/BalanceService.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/services/CurrencyService.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/services/CurrencyService.kt similarity index 99% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/services/CurrencyService.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/services/CurrencyService.kt index 81287849ab..12e14c2b76 100644 --- a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/services/CurrencyService.kt +++ b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/services/CurrencyService.kt @@ -1,6 +1,6 @@ package com.getcode.opencode.internal.network.services -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.opencode.internal.domain.mapping.HistoricalMintDataMapper import com.getcode.opencode.internal.domain.mapping.LiveMintDataMapper import com.getcode.opencode.internal.domain.mapping.MintMapper diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/services/MessagingService.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/services/MessagingService.kt similarity index 99% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/services/MessagingService.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/services/MessagingService.kt index 7234016308..7e1fd4828c 100644 --- a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/services/MessagingService.kt +++ b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/services/MessagingService.kt @@ -1,6 +1,6 @@ package com.getcode.opencode.internal.network.services -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair import com.getcode.opencode.internal.bidi.BidirectionalStreamReference import com.getcode.opencode.internal.bidi.openBidirectionalStreamForResult import com.getcode.opencode.internal.network.api.MessagingApi diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/services/SwapService.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/services/SwapService.kt similarity index 98% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/services/SwapService.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/services/SwapService.kt index da68c86837..3f0fa99e44 100644 --- a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/services/SwapService.kt +++ b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/services/SwapService.kt @@ -1,6 +1,6 @@ package com.getcode.opencode.internal.network.services -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair import com.getcode.opencode.internal.domain.mapping.SwapMetadataMapper import com.codeinc.opencode.gen.transaction.v1.OcpTransactionService import com.getcode.opencode.internal.network.api.TransactionApi diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/services/TransactionService.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/services/TransactionService.kt similarity index 99% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/services/TransactionService.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/services/TransactionService.kt index 332e90afc3..4804c6c971 100644 --- a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/services/TransactionService.kt +++ b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/services/TransactionService.kt @@ -2,8 +2,8 @@ package com.getcode.opencode.internal.network.services import com.codeinc.opencode.gen.transaction.v1.OcpTransactionService import com.codeinc.opencode.gen.transaction.v1.feeAmountOrNull -import com.getcode.ed25519.Ed25519 -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519 +import com.getcode.ed25519kmp.Ed25519.KeyPair import com.getcode.opencode.internal.domain.mapping.TransactionMetadataMapper import com.getcode.opencode.internal.manager.VerifiedState import com.getcode.opencode.internal.network.api.TransactionApi diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/streamers/LiveMintDataStreamer.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/streamers/LiveMintDataStreamer.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/streamers/LiveMintDataStreamer.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/network/streamers/LiveMintDataStreamer.kt diff --git a/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/platform/ProcessLifecycle.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/platform/ProcessLifecycle.kt new file mode 100644 index 0000000000..43ba429751 --- /dev/null +++ b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/platform/ProcessLifecycle.kt @@ -0,0 +1,15 @@ +package com.getcode.opencode.internal.platform + +/** + * Calls [onStart] and [onStop] as the app process enters and leaves the foreground. + * + * Registration replays the current state, so a process that is already started calls [onStart] + * once registered. With [immediateOnMain], a caller already on the main thread registers in place; + * otherwise registration is always deferred, so neither callback runs during the caller's own + * construction. + */ +internal expect fun observeProcessLifecycle( + immediateOnMain: Boolean, + onStart: () -> Unit, + onStop: () -> Unit = {}, +) diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/Definitions.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/Definitions.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/Definitions.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/Definitions.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/ShortVec.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/ShortVec.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/ShortVec.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/ShortVec.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/extensions/AssociatedTokenAccount.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/extensions/AssociatedTokenAccount.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/extensions/AssociatedTokenAccount.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/extensions/AssociatedTokenAccount.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/extensions/ExtractServerParameters.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/extensions/ExtractServerParameters.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/extensions/ExtractServerParameters.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/extensions/ExtractServerParameters.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/extensions/PublicKey.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/extensions/PublicKey.kt similarity index 99% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/extensions/PublicKey.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/extensions/PublicKey.kt index 766c543ae1..d0beab61a7 100644 --- a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/extensions/PublicKey.kt +++ b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/extensions/PublicKey.kt @@ -1,7 +1,7 @@ package com.getcode.opencode.internal.solana.extensions import com.getcode.crypt.Sha256Hash -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.opencode.internal.solana.vmAuthority import com.getcode.opencode.internal.solana.programs.AssociatedTokenProgram import com.getcode.opencode.internal.solana.programs.CoinbaseStableSwapperProgram diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/extensions/TimelockDerivedAccounts.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/extensions/TimelockDerivedAccounts.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/extensions/TimelockDerivedAccounts.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/extensions/TimelockDerivedAccounts.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/extensions/Token.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/extensions/Token.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/extensions/Token.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/extensions/Token.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/extensions/UInt16.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/extensions/UInt16.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/extensions/UInt16.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/extensions/UInt16.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/model/CoinbaseStablecoinPoolAccount.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/model/CoinbaseStablecoinPoolAccount.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/model/CoinbaseStablecoinPoolAccount.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/model/CoinbaseStablecoinPoolAccount.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/model/CoinbaseSwapAccounts.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/model/CoinbaseSwapAccounts.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/model/CoinbaseSwapAccounts.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/model/CoinbaseSwapAccounts.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/model/MessageAddressLookupTable.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/model/MessageAddressLookupTable.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/model/MessageAddressLookupTable.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/model/MessageAddressLookupTable.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/model/SwapId.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/model/SwapId.kt similarity index 90% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/model/SwapId.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/model/SwapId.kt index 0177547be0..084b97a961 100644 --- a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/model/SwapId.kt +++ b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/model/SwapId.kt @@ -1,10 +1,10 @@ package com.getcode.opencode.internal.solana.model -import android.os.Parcelable +import com.getcode.libs.parcelable.Parcelable import com.getcode.opencode.utils.generate import com.getcode.solana.keys.PublicKey import com.getcode.utils.serializer.ByteListAsBase64Serializer -import kotlinx.parcelize.Parcelize +import com.getcode.libs.parcelable.Parcelize import kotlinx.serialization.Serializable @Serializable diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/model/Vault.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/model/Vault.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/model/Vault.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/model/Vault.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/programs/AssociatedTokenProgram.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/programs/AssociatedTokenProgram.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/programs/AssociatedTokenProgram.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/programs/AssociatedTokenProgram.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/programs/AssociatedTokenProgram_CreateIdempotent.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/programs/AssociatedTokenProgram_CreateIdempotent.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/programs/AssociatedTokenProgram_CreateIdempotent.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/programs/AssociatedTokenProgram_CreateIdempotent.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/programs/CoinbaseStableSwapperProgram.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/programs/CoinbaseStableSwapperProgram.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/programs/CoinbaseStableSwapperProgram.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/programs/CoinbaseStableSwapperProgram.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/programs/CoinbaseStableSwapperProgram_SwapV2.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/programs/CoinbaseStableSwapperProgram_SwapV2.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/programs/CoinbaseStableSwapperProgram_SwapV2.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/programs/CoinbaseStableSwapperProgram_SwapV2.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/programs/ComputeBudgetProgram.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/programs/ComputeBudgetProgram.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/programs/ComputeBudgetProgram.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/programs/ComputeBudgetProgram.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/programs/ComputeBudgetProgram_SetComputeUnitLimit.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/programs/ComputeBudgetProgram_SetComputeUnitLimit.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/programs/ComputeBudgetProgram_SetComputeUnitLimit.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/programs/ComputeBudgetProgram_SetComputeUnitLimit.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/programs/ComputeBudgetProgram_SetComputeUnitPrice.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/programs/ComputeBudgetProgram_SetComputeUnitPrice.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/programs/ComputeBudgetProgram_SetComputeUnitPrice.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/programs/ComputeBudgetProgram_SetComputeUnitPrice.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/programs/CurrencyCreatorProgram.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/programs/CurrencyCreatorProgram.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/programs/CurrencyCreatorProgram.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/programs/CurrencyCreatorProgram.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/programs/CurrencyCreatorProgram_BuyAndDepositIntoVm.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/programs/CurrencyCreatorProgram_BuyAndDepositIntoVm.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/programs/CurrencyCreatorProgram_BuyAndDepositIntoVm.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/programs/CurrencyCreatorProgram_BuyAndDepositIntoVm.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/programs/CurrencyCreatorProgram_BuyTokens.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/programs/CurrencyCreatorProgram_BuyTokens.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/programs/CurrencyCreatorProgram_BuyTokens.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/programs/CurrencyCreatorProgram_BuyTokens.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/programs/CurrencyCreatorProgram_InitializeCurrency.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/programs/CurrencyCreatorProgram_InitializeCurrency.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/programs/CurrencyCreatorProgram_InitializeCurrency.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/programs/CurrencyCreatorProgram_InitializeCurrency.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/programs/CurrencyCreatorProgram_InitializePool.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/programs/CurrencyCreatorProgram_InitializePool.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/programs/CurrencyCreatorProgram_InitializePool.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/programs/CurrencyCreatorProgram_InitializePool.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/programs/CurrencyCreatorProgram_SellAndDepositIntoVm.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/programs/CurrencyCreatorProgram_SellAndDepositIntoVm.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/programs/CurrencyCreatorProgram_SellAndDepositIntoVm.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/programs/CurrencyCreatorProgram_SellAndDepositIntoVm.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/programs/CurrencyCreatorProgram_SellTokens.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/programs/CurrencyCreatorProgram_SellTokens.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/programs/CurrencyCreatorProgram_SellTokens.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/programs/CurrencyCreatorProgram_SellTokens.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/programs/InstructionType.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/programs/InstructionType.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/programs/InstructionType.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/programs/InstructionType.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/programs/MemoProgram.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/programs/MemoProgram.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/programs/MemoProgram.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/programs/MemoProgram.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/programs/MemoProgram_Memo.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/programs/MemoProgram_Memo.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/programs/MemoProgram_Memo.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/programs/MemoProgram_Memo.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/programs/SwapValidatorProgram.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/programs/SwapValidatorProgram.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/programs/SwapValidatorProgram.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/programs/SwapValidatorProgram.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/programs/SysVar.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/programs/SysVar.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/programs/SysVar.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/programs/SysVar.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/programs/SystemProgram.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/programs/SystemProgram.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/programs/SystemProgram.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/programs/SystemProgram.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/programs/SystemProgram_AdvanceNonce.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/programs/SystemProgram_AdvanceNonce.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/programs/SystemProgram_AdvanceNonce.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/programs/SystemProgram_AdvanceNonce.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/programs/TimelockProgram.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/programs/TimelockProgram.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/programs/TimelockProgram.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/programs/TimelockProgram.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/programs/TokenProgram.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/programs/TokenProgram.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/programs/TokenProgram.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/programs/TokenProgram.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/programs/TokenProgram_CloseAccount.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/programs/TokenProgram_CloseAccount.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/programs/TokenProgram_CloseAccount.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/programs/TokenProgram_CloseAccount.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/programs/TokenProgram_Transfer.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/programs/TokenProgram_Transfer.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/programs/TokenProgram_Transfer.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/programs/TokenProgram_Transfer.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/programs/UsdfProgram.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/programs/UsdfProgram.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/programs/UsdfProgram.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/programs/UsdfProgram.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/programs/UsdfProgram_Swap.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/programs/UsdfProgram_Swap.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/programs/UsdfProgram_Swap.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/programs/UsdfProgram_Swap.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/programs/UsdfProgram_Transfer.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/programs/UsdfProgram_Transfer.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/programs/UsdfProgram_Transfer.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/programs/UsdfProgram_Transfer.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/programs/VirtualMachineProgram.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/programs/VirtualMachineProgram.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/programs/VirtualMachineProgram.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/programs/VirtualMachineProgram.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/programs/VirtualMachineProgram_CloseSwapAccountIfEmpty.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/programs/VirtualMachineProgram_CloseSwapAccountIfEmpty.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/programs/VirtualMachineProgram_CloseSwapAccountIfEmpty.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/programs/VirtualMachineProgram_CloseSwapAccountIfEmpty.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/programs/VirtualMachineProgram_InitVm.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/programs/VirtualMachineProgram_InitVm.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/programs/VirtualMachineProgram_InitVm.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/programs/VirtualMachineProgram_InitVm.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/programs/VirtualMachineProgram_TransferForSwap.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/programs/VirtualMachineProgram_TransferForSwap.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/programs/VirtualMachineProgram_TransferForSwap.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/programs/VirtualMachineProgram_TransferForSwap.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/programs/VirtualMachineProgram_TransferForSwapWithFee.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/programs/VirtualMachineProgram_TransferForSwapWithFee.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/programs/VirtualMachineProgram_TransferForSwapWithFee.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/programs/VirtualMachineProgram_TransferForSwapWithFee.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/utils/DataSlice.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/utils/DataSlice.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/utils/DataSlice.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/utils/DataSlice.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/utils/Differ.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/utils/Differ.kt similarity index 75% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/utils/Differ.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/utils/Differ.kt index d0225bfeca..bee155f223 100644 --- a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/solana/utils/Differ.kt +++ b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/solana/utils/Differ.kt @@ -1,6 +1,6 @@ package com.getcode.opencode.internal.solana.utils -import timber.log.Timber +import com.getcode.utils.Log import kotlin.math.max internal fun printDiff(title: String, one: String, two: String) { @@ -10,8 +10,8 @@ internal fun printDiff(title: String, one: String, two: String) { internal fun printDiff(title: String, one: List, two: List) { val lineSeparator = "\n -\n" - Timber.d("✗ $title") - Timber.d("|----------------------------------------------------------------------") + Log.d("✗ $title") + Log.d("|----------------------------------------------------------------------") val lines = (0 until max(one.count(), two.count())).joinToString(lineSeparator) { i -> var oneValue = "-" @@ -32,10 +32,10 @@ internal fun printDiff(title: String, one: List, two: List) { content } - Timber.d(lines) - Timber.d("|----------------------------------------------------------------------") + Log.d(lines) + Log.d("|----------------------------------------------------------------------") } internal fun printMatch(title: String) { - Timber.d("✓ $title") + Log.d("✓ $title") } \ No newline at end of file diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/transactors/AccountClusterFactory.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/transactors/AccountClusterFactory.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/transactors/AccountClusterFactory.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/transactors/AccountClusterFactory.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/transactors/BillPresentationData.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/transactors/BillPresentationData.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/transactors/BillPresentationData.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/transactors/BillPresentationData.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/transactors/GiveBillTransactor.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/transactors/GiveBillTransactor.kt similarity index 99% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/transactors/GiveBillTransactor.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/transactors/GiveBillTransactor.kt index 2a0d282ab2..b2ee048f37 100644 --- a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/transactors/GiveBillTransactor.kt +++ b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/transactors/GiveBillTransactor.kt @@ -1,6 +1,6 @@ package com.getcode.opencode.internal.transactors -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair import com.getcode.opencode.controllers.MessagingController import com.getcode.opencode.controllers.TransactionController import com.getcode.opencode.exchange.VerifiedFiatCalculator diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/transactors/GrabBillTransactor.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/transactors/GrabBillTransactor.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/transactors/GrabBillTransactor.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/transactors/GrabBillTransactor.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/transactors/PayloadFactory.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/transactors/PayloadFactory.kt similarity index 96% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/transactors/PayloadFactory.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/transactors/PayloadFactory.kt index 88461f9456..0a3d208db7 100644 --- a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/transactors/PayloadFactory.kt +++ b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/transactors/PayloadFactory.kt @@ -1,6 +1,6 @@ package com.getcode.opencode.internal.transactors -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair import com.getcode.opencode.model.core.OpenCodePayload import com.getcode.opencode.model.core.PayloadKind import com.getcode.opencode.model.financial.Fiat diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/transactors/ReceiveGiftCardTransactor.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/transactors/ReceiveGiftCardTransactor.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/transactors/ReceiveGiftCardTransactor.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/transactors/ReceiveGiftCardTransactor.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/transactors/SendGiftCardTransactor.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/transactors/SendGiftCardTransactor.kt similarity index 99% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/transactors/SendGiftCardTransactor.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/transactors/SendGiftCardTransactor.kt index 4719a2c027..c309343607 100644 --- a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/transactors/SendGiftCardTransactor.kt +++ b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/transactors/SendGiftCardTransactor.kt @@ -1,6 +1,6 @@ package com.getcode.opencode.internal.transactors -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair import com.getcode.opencode.controllers.TransactionController import com.getcode.opencode.internal.extensions.toPublicKey import com.getcode.opencode.internal.manager.VerifiedState diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/transactors/Transactor.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/transactors/Transactor.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/internal/transactors/Transactor.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/transactors/Transactor.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/managers/BillTransactionManager.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/managers/BillTransactionManager.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/managers/BillTransactionManager.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/managers/BillTransactionManager.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/managers/GiftCardManager.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/managers/GiftCardManager.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/managers/GiftCardManager.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/managers/GiftCardManager.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/managers/MnemonicManager.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/managers/MnemonicManager.kt similarity index 96% rename from services/opencode/src/main/kotlin/com/getcode/opencode/managers/MnemonicManager.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/managers/MnemonicManager.kt index a89333f879..02ea7ff2f6 100644 --- a/services/opencode/src/main/kotlin/com/getcode/opencode/managers/MnemonicManager.kt +++ b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/managers/MnemonicManager.kt @@ -3,7 +3,7 @@ package com.getcode.opencode.managers import com.getcode.crypt.MnemonicCache import com.getcode.crypt.MnemonicCode import com.getcode.crypt.MnemonicPhrase -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair import com.getcode.opencode.generators.MnemonicGenerator import com.getcode.opencode.utils.Base58String import com.getcode.opencode.utils.Base64String diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/mapper/Mapper.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/mapper/Mapper.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/mapper/Mapper.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/mapper/Mapper.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/model/accounts/AccountCluster.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/accounts/AccountCluster.kt similarity index 98% rename from services/opencode/src/main/kotlin/com/getcode/opencode/model/accounts/AccountCluster.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/accounts/AccountCluster.kt index 465d7799e0..7e872f5944 100644 --- a/services/opencode/src/main/kotlin/com/getcode/opencode/model/accounts/AccountCluster.kt +++ b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/accounts/AccountCluster.kt @@ -1,7 +1,7 @@ package com.getcode.opencode.model.accounts import com.getcode.crypt.DerivedKey -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.opencode.internal.solana.extensions.newInstance import com.getcode.opencode.internal.extensions.toPublicKey import com.getcode.opencode.internal.solana.extensions.deriveAssociatedAccount diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/model/accounts/AccountFilter.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/accounts/AccountFilter.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/model/accounts/AccountFilter.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/accounts/AccountFilter.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/model/accounts/AccountInfo.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/accounts/AccountInfo.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/model/accounts/AccountInfo.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/accounts/AccountInfo.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/model/accounts/AccountResponse.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/accounts/AccountResponse.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/model/accounts/AccountResponse.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/accounts/AccountResponse.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/model/accounts/AccountType.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/accounts/AccountType.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/model/accounts/AccountType.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/accounts/AccountType.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/model/accounts/GiftCardAccount.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/accounts/GiftCardAccount.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/model/accounts/GiftCardAccount.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/accounts/GiftCardAccount.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/model/accounts/PoolAccount.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/accounts/PoolAccount.kt similarity index 95% rename from services/opencode/src/main/kotlin/com/getcode/opencode/model/accounts/PoolAccount.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/accounts/PoolAccount.kt index 335e7d5eb5..792bb4bb82 100644 --- a/services/opencode/src/main/kotlin/com/getcode/opencode/model/accounts/PoolAccount.kt +++ b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/accounts/PoolAccount.kt @@ -3,7 +3,7 @@ package com.getcode.opencode.model.accounts import com.getcode.crypt.DerivePath import com.getcode.crypt.DerivedKey import com.getcode.crypt.MnemonicPhrase -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.solana.keys.Mint class PoolAccount( diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/model/core/EncryptedData.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/core/EncryptedData.kt similarity index 89% rename from services/opencode/src/main/kotlin/com/getcode/opencode/model/core/EncryptedData.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/core/EncryptedData.kt index 4a3817244c..842de6dacd 100644 --- a/services/opencode/src/main/kotlin/com/getcode/opencode/model/core/EncryptedData.kt +++ b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/core/EncryptedData.kt @@ -1,6 +1,6 @@ package com.getcode.opencode.model.core -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair import com.getcode.solana.keys.PublicKey import com.getcode.utils.serializer.PublicKeyAsStringSerializer import kotlinx.serialization.Serializable diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/model/core/ID.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/core/ID.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/model/core/ID.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/core/ID.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/model/core/OpenCodePayload.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/core/OpenCodePayload.kt similarity index 96% rename from services/opencode/src/main/kotlin/com/getcode/opencode/model/core/OpenCodePayload.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/core/OpenCodePayload.kt index cb4604f248..dc0b684f0c 100644 --- a/services/opencode/src/main/kotlin/com/getcode/opencode/model/core/OpenCodePayload.kt +++ b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/core/OpenCodePayload.kt @@ -1,12 +1,11 @@ package com.getcode.opencode.model.core -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair import com.getcode.opencode.internal.solana.utils.DataSlice.byteToUnsignedInt import com.getcode.opencode.internal.solana.utils.DataSlice.suffix import com.getcode.opencode.model.financial.CurrencyCode import com.getcode.opencode.model.financial.Fiat import com.getcode.opencode.utils.deriveRendezvousKey -import com.kik.scan.Scanner import com.getcode.utils.byteArrayToLong import com.getcode.utils.longToByteArray @@ -28,7 +27,7 @@ data class OpenCodePayload( get() = (value as? UserId)?.value val codeData: ByteArray - get() = Scanner.encode(encode().toByteArray()) ?: ByteArray(LENGTH) + get() = encodeScanCode(encode().toByteArray()) ?: ByteArray(LENGTH) /** Serializes this payload into the fixed [LENGTH]-byte scan frame. */ fun encode(): List = kind.encode(value, nonce) diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/model/core/PayloadKind.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/core/PayloadKind.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/model/core/PayloadKind.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/core/PayloadKind.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/model/core/PayloadValue.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/core/PayloadValue.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/model/core/PayloadValue.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/core/PayloadValue.kt diff --git a/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/core/ScanCodeEncoder.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/core/ScanCodeEncoder.kt new file mode 100644 index 0000000000..ebe437ac05 --- /dev/null +++ b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/core/ScanCodeEncoder.kt @@ -0,0 +1,4 @@ +package com.getcode.opencode.model.core + +/** Reed-Solomon encodes a payload frame into the bytes a Kik code draws, or null if it can't. */ +internal expect fun encodeScanCode(payload: ByteArray): ByteArray? diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/model/core/UUID.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/core/UUID.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/model/core/UUID.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/core/UUID.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/model/core/errors/Errors.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/core/errors/Errors.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/model/core/errors/Errors.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/core/errors/Errors.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/model/core/errors/SodiumError.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/core/errors/SodiumError.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/model/core/errors/SodiumError.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/core/errors/SodiumError.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/model/core/errors/ValidationException.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/core/errors/ValidationException.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/model/core/errors/ValidationException.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/core/errors/ValidationException.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/model/financial/Currency.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/financial/Currency.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/model/financial/Currency.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/financial/Currency.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/model/financial/CurrencyCode.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/financial/CurrencyCode.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/model/financial/CurrencyCode.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/financial/CurrencyCode.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/model/financial/Distribution.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/financial/Distribution.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/model/financial/Distribution.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/financial/Distribution.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/model/financial/Fee.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/financial/Fee.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/model/financial/Fee.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/financial/Fee.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/model/financial/Fiat.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/financial/Fiat.kt similarity index 99% rename from services/opencode/src/main/kotlin/com/getcode/opencode/model/financial/Fiat.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/financial/Fiat.kt index 1c5f917293..f4afe0d6e8 100644 --- a/services/opencode/src/main/kotlin/com/getcode/opencode/model/financial/Fiat.kt +++ b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/financial/Fiat.kt @@ -1,6 +1,6 @@ package com.getcode.opencode.model.financial -import android.os.Parcelable +import com.getcode.libs.parcelable.Parcelable import com.flipcash.libs.currency.math.Estimator import com.flipcash.libs.currency.math.MarketState import com.flipcash.libs.currency.math.Valuation @@ -9,7 +9,7 @@ import com.getcode.opencode.model.core.PayloadValue import com.getcode.opencode.utils.roundTo import com.getcode.opencode.utils.toLocaleAwareDoubleOrNull import com.getcode.solana.keys.Mint -import kotlinx.parcelize.Parcelize +import com.getcode.libs.parcelable.Parcelize import kotlinx.serialization.Serializable import java.math.BigDecimal import java.math.RoundingMode diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/model/financial/HistoricalMintData.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/financial/HistoricalMintData.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/model/financial/HistoricalMintData.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/financial/HistoricalMintData.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/model/financial/LaunchpadReserveStateSnapshot.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/financial/LaunchpadReserveStateSnapshot.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/model/financial/LaunchpadReserveStateSnapshot.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/financial/LaunchpadReserveStateSnapshot.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/model/financial/LaunchpadSellFee.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/financial/LaunchpadSellFee.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/model/financial/LaunchpadSellFee.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/financial/LaunchpadSellFee.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/model/financial/Limits.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/financial/Limits.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/model/financial/Limits.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/financial/Limits.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/model/financial/LocalFiat.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/financial/LocalFiat.kt similarity index 98% rename from services/opencode/src/main/kotlin/com/getcode/opencode/model/financial/LocalFiat.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/financial/LocalFiat.kt index abb86f2be4..f44d659897 100644 --- a/services/opencode/src/main/kotlin/com/getcode/opencode/model/financial/LocalFiat.kt +++ b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/financial/LocalFiat.kt @@ -1,10 +1,10 @@ package com.getcode.opencode.model.financial -import android.os.Parcelable +import com.getcode.libs.parcelable.Parcelable import com.getcode.opencode.internal.extensions.fractionDigits import com.getcode.opencode.model.transactions.ExchangeData import com.getcode.solana.keys.Mint -import kotlinx.parcelize.Parcelize +import com.getcode.libs.parcelable.Parcelize import kotlinx.serialization.Serializable import javax.annotation.concurrent.Immutable diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/model/financial/MintMetadata.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/financial/MintMetadata.kt similarity index 98% rename from services/opencode/src/main/kotlin/com/getcode/opencode/model/financial/MintMetadata.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/financial/MintMetadata.kt index f94f71caa0..2a5db22793 100644 --- a/services/opencode/src/main/kotlin/com/getcode/opencode/model/financial/MintMetadata.kt +++ b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/financial/MintMetadata.kt @@ -1,6 +1,6 @@ package com.getcode.opencode.model.financial -import android.os.Parcelable +import com.getcode.libs.parcelable.Parcelable import com.flipcash.libs.currency.math.Estimator import com.getcode.opencode.model.ui.WindowedRange import com.getcode.opencode.internal.solana.extensions.deriveVirtualMachineAccount @@ -10,8 +10,8 @@ import com.getcode.opencode.model.ui.TokenBillCustomizations import com.getcode.opencode.solana.keys.TimelockDerivedAccounts import com.getcode.solana.keys.Mint import com.getcode.solana.keys.PublicKey -import kotlinx.parcelize.IgnoredOnParcel -import kotlinx.parcelize.Parcelize +import com.getcode.libs.parcelable.IgnoredOnParcel +import com.getcode.libs.parcelable.Parcelize import java.math.BigDecimal import java.math.RoundingMode import java.text.DecimalFormat diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/model/financial/MintStreamingData.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/financial/MintStreamingData.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/model/financial/MintStreamingData.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/financial/MintStreamingData.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/model/financial/OwnerBalance.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/financial/OwnerBalance.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/model/financial/OwnerBalance.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/financial/OwnerBalance.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/model/financial/Rate.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/financial/Rate.kt similarity index 83% rename from services/opencode/src/main/kotlin/com/getcode/opencode/model/financial/Rate.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/financial/Rate.kt index 393eaa8ca1..18672bd7e6 100644 --- a/services/opencode/src/main/kotlin/com/getcode/opencode/model/financial/Rate.kt +++ b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/financial/Rate.kt @@ -1,7 +1,7 @@ package com.getcode.opencode.model.financial -import android.os.Parcelable -import kotlinx.parcelize.Parcelize +import com.getcode.libs.parcelable.Parcelable +import com.getcode.libs.parcelable.Parcelize import kotlinx.serialization.Serializable @Parcelize diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/model/financial/RegionCode.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/financial/RegionCode.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/model/financial/RegionCode.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/financial/RegionCode.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/model/financial/TokenCreateRequest.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/financial/TokenCreateRequest.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/model/financial/TokenCreateRequest.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/financial/TokenCreateRequest.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/model/financial/TokenResult.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/financial/TokenResult.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/model/financial/TokenResult.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/financial/TokenResult.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/model/financial/TokenUpdateRequest.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/financial/TokenUpdateRequest.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/model/financial/TokenUpdateRequest.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/financial/TokenUpdateRequest.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/model/messaging/KeepAliveRequest.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/messaging/KeepAliveRequest.kt similarity index 83% rename from services/opencode/src/main/kotlin/com/getcode/opencode/model/messaging/KeepAliveRequest.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/messaging/KeepAliveRequest.kt index b89658df92..ebb886d0ec 100644 --- a/services/opencode/src/main/kotlin/com/getcode/opencode/model/messaging/KeepAliveRequest.kt +++ b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/messaging/KeepAliveRequest.kt @@ -1,6 +1,6 @@ package com.getcode.opencode.model.messaging -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair sealed interface KeepAliveRequest { data class OpenStreamRequest(val rendezvous: KeyPair): KeepAliveRequest diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/model/messaging/Message.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/messaging/Message.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/model/messaging/Message.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/messaging/Message.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/model/moderation/ModerationAttestation.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/moderation/ModerationAttestation.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/model/moderation/ModerationAttestation.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/moderation/ModerationAttestation.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/model/transactions/AddressLookupTable.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/transactions/AddressLookupTable.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/model/transactions/AddressLookupTable.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/transactions/AddressLookupTable.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/model/transactions/ExchangeData.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/transactions/ExchangeData.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/model/transactions/ExchangeData.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/transactions/ExchangeData.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/model/transactions/FundSwapPool.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/transactions/FundSwapPool.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/model/transactions/FundSwapPool.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/transactions/FundSwapPool.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/model/transactions/LiquidityPool.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/transactions/LiquidityPool.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/model/transactions/LiquidityPool.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/transactions/LiquidityPool.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/model/transactions/StartSwapServerParameters.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/transactions/StartSwapServerParameters.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/model/transactions/StartSwapServerParameters.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/transactions/StartSwapServerParameters.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/model/transactions/StatefulSwapRequest.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/transactions/StatefulSwapRequest.kt similarity index 98% rename from services/opencode/src/main/kotlin/com/getcode/opencode/model/transactions/StatefulSwapRequest.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/transactions/StatefulSwapRequest.kt index f959512ab8..8d41ba2ee6 100644 --- a/services/opencode/src/main/kotlin/com/getcode/opencode/model/transactions/StatefulSwapRequest.kt +++ b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/transactions/StatefulSwapRequest.kt @@ -1,6 +1,6 @@ package com.getcode.opencode.model.transactions -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair import com.getcode.opencode.internal.manager.VerifiedState import com.getcode.opencode.internal.solana.model.SwapId import com.getcode.opencode.model.accounts.AccountCluster diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/model/transactions/StatefulSwapResponseServerParameters.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/transactions/StatefulSwapResponseServerParameters.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/model/transactions/StatefulSwapResponseServerParameters.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/transactions/StatefulSwapResponseServerParameters.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/model/transactions/StatefulSwapResult.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/transactions/StatefulSwapResult.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/model/transactions/StatefulSwapResult.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/transactions/StatefulSwapResult.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/model/transactions/StatelessSwapRequest.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/transactions/StatelessSwapRequest.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/model/transactions/StatelessSwapRequest.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/transactions/StatelessSwapRequest.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/model/transactions/StatelessSwapResult.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/transactions/StatelessSwapResult.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/model/transactions/StatelessSwapResult.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/transactions/StatelessSwapResult.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/model/transactions/StatelessSwapServerParameters.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/transactions/StatelessSwapServerParameters.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/model/transactions/StatelessSwapServerParameters.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/transactions/StatelessSwapServerParameters.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/model/transactions/SwapFundingSource.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/transactions/SwapFundingSource.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/model/transactions/SwapFundingSource.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/transactions/SwapFundingSource.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/model/transactions/SwapMetadata.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/transactions/SwapMetadata.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/model/transactions/SwapMetadata.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/transactions/SwapMetadata.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/model/transactions/SwapRoute.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/transactions/SwapRoute.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/model/transactions/SwapRoute.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/transactions/SwapRoute.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/model/transactions/TransactionMetadata.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/transactions/TransactionMetadata.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/model/transactions/TransactionMetadata.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/transactions/TransactionMetadata.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/model/transactions/TransferRequest.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/transactions/TransferRequest.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/model/transactions/TransferRequest.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/transactions/TransferRequest.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/model/transactions/WithdrawalAvailability.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/transactions/WithdrawalAvailability.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/model/transactions/WithdrawalAvailability.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/transactions/WithdrawalAvailability.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/model/ui/BillCustomization.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/ui/BillCustomization.kt similarity index 95% rename from services/opencode/src/main/kotlin/com/getcode/opencode/model/ui/BillCustomization.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/ui/BillCustomization.kt index 2c8f156724..1f9b2f14c8 100644 --- a/services/opencode/src/main/kotlin/com/getcode/opencode/model/ui/BillCustomization.kt +++ b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/ui/BillCustomization.kt @@ -1,7 +1,7 @@ package com.getcode.opencode.model.ui -import android.os.Parcelable -import kotlinx.parcelize.Parcelize +import com.getcode.libs.parcelable.Parcelable +import com.getcode.libs.parcelable.Parcelize import kotlinx.serialization.Serializable @Parcelize diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/model/ui/DiscoverCategory.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/ui/DiscoverCategory.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/model/ui/DiscoverCategory.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/ui/DiscoverCategory.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/model/ui/WindowedRange.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/ui/WindowedRange.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/model/ui/WindowedRange.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/model/ui/WindowedRange.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/providers/SessionListener.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/providers/SessionListener.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/providers/SessionListener.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/providers/SessionListener.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/providers/TokenMetadataProvider.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/providers/TokenMetadataProvider.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/providers/TokenMetadataProvider.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/providers/TokenMetadataProvider.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/repositories/AccountRepository.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/repositories/AccountRepository.kt similarity index 95% rename from services/opencode/src/main/kotlin/com/getcode/opencode/repositories/AccountRepository.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/repositories/AccountRepository.kt index 1be940dc76..ac8bced161 100644 --- a/services/opencode/src/main/kotlin/com/getcode/opencode/repositories/AccountRepository.kt +++ b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/repositories/AccountRepository.kt @@ -1,6 +1,6 @@ package com.getcode.opencode.repositories -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair import com.getcode.opencode.model.accounts.AccountCluster import com.getcode.opencode.model.accounts.AccountFilter import com.getcode.opencode.model.accounts.AccountInfo diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/repositories/BalanceRepository.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/repositories/BalanceRepository.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/repositories/BalanceRepository.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/repositories/BalanceRepository.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/repositories/CurrencyRepository.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/repositories/CurrencyRepository.kt similarity index 97% rename from services/opencode/src/main/kotlin/com/getcode/opencode/repositories/CurrencyRepository.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/repositories/CurrencyRepository.kt index d3a90efe19..d4d9e1c367 100644 --- a/services/opencode/src/main/kotlin/com/getcode/opencode/repositories/CurrencyRepository.kt +++ b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/repositories/CurrencyRepository.kt @@ -1,6 +1,6 @@ package com.getcode.opencode.repositories -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.opencode.model.ui.DiscoverCategory import com.getcode.opencode.model.financial.LiveMintDataResponse import com.getcode.opencode.model.ui.WindowedRange diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/repositories/EventRepository.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/repositories/EventRepository.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/repositories/EventRepository.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/repositories/EventRepository.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/repositories/MessagingRepository.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/repositories/MessagingRepository.kt similarity index 96% rename from services/opencode/src/main/kotlin/com/getcode/opencode/repositories/MessagingRepository.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/repositories/MessagingRepository.kt index a625665baf..8ca430010e 100644 --- a/services/opencode/src/main/kotlin/com/getcode/opencode/repositories/MessagingRepository.kt +++ b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/repositories/MessagingRepository.kt @@ -1,7 +1,7 @@ package com.getcode.opencode.repositories import com.codeinc.opencode.gen.messaging.v1.OcpMessagingService -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair import com.getcode.opencode.internal.network.services.OcpMessageStreamReference import com.getcode.opencode.model.transactions.GrabRequest import com.getcode.opencode.model.transactions.TransferRequest diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/repositories/SwapRepository.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/repositories/SwapRepository.kt similarity index 94% rename from services/opencode/src/main/kotlin/com/getcode/opencode/repositories/SwapRepository.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/repositories/SwapRepository.kt index a65cd1811d..835ee90939 100644 --- a/services/opencode/src/main/kotlin/com/getcode/opencode/repositories/SwapRepository.kt +++ b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/repositories/SwapRepository.kt @@ -1,6 +1,6 @@ package com.getcode.opencode.repositories -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair import com.getcode.opencode.internal.solana.model.SwapId import com.getcode.opencode.model.transactions.Swap import com.getcode.opencode.model.transactions.SwapMetadata diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/repositories/TransactionRepository.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/repositories/TransactionRepository.kt similarity index 98% rename from services/opencode/src/main/kotlin/com/getcode/opencode/repositories/TransactionRepository.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/repositories/TransactionRepository.kt index 05f893705e..b0f05a15fb 100644 --- a/services/opencode/src/main/kotlin/com/getcode/opencode/repositories/TransactionRepository.kt +++ b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/repositories/TransactionRepository.kt @@ -1,6 +1,6 @@ package com.getcode.opencode.repositories -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair import com.getcode.opencode.internal.manager.VerifiedState import com.getcode.opencode.internal.solana.model.SwapId import com.getcode.opencode.model.accounts.AccountCluster diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/solana/Instruction.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/solana/Instruction.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/solana/Instruction.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/solana/Instruction.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/solana/LegacyMessage.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/solana/LegacyMessage.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/solana/LegacyMessage.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/solana/LegacyMessage.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/solana/Message.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/solana/Message.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/solana/Message.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/solana/Message.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/solana/MessageHeader.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/solana/MessageHeader.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/solana/MessageHeader.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/solana/MessageHeader.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/solana/SolanaTransaction.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/solana/SolanaTransaction.kt similarity index 99% rename from services/opencode/src/main/kotlin/com/getcode/opencode/solana/SolanaTransaction.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/solana/SolanaTransaction.kt index 299cd2fe8f..805d6fb3ab 100644 --- a/services/opencode/src/main/kotlin/com/getcode/opencode/solana/SolanaTransaction.kt +++ b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/solana/SolanaTransaction.kt @@ -1,6 +1,6 @@ package com.getcode.opencode.solana -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.opencode.internal.solana.ShortVec import com.getcode.opencode.internal.solana.model.MessageAddressLookupTable import com.getcode.opencode.internal.solana.utils.DataSlice.chunk diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/solana/TransactionBuilder.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/solana/TransactionBuilder.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/solana/TransactionBuilder.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/solana/TransactionBuilder.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/solana/VersionedMessage.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/solana/VersionedMessage.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/solana/VersionedMessage.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/solana/VersionedMessage.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/solana/intents/ActionGroup.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/solana/intents/ActionGroup.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/solana/intents/ActionGroup.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/solana/intents/ActionGroup.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/solana/intents/IntentType.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/solana/intents/IntentType.kt similarity index 98% rename from services/opencode/src/main/kotlin/com/getcode/opencode/solana/intents/IntentType.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/solana/intents/IntentType.kt index 71bd5857cc..b4db344cc2 100644 --- a/services/opencode/src/main/kotlin/com/getcode/opencode/solana/intents/IntentType.kt +++ b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/solana/intents/IntentType.kt @@ -1,7 +1,7 @@ package com.getcode.opencode.solana.intents import com.codeinc.opencode.gen.transaction.v1.OcpTransactionService -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.opencode.solana.intents.actions.ActionType import com.getcode.opencode.internal.network.extensions.asIntentId import com.getcode.opencode.internal.network.extensions.asSolanaAccountId diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/solana/intents/ServerParameter.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/solana/intents/ServerParameter.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/solana/intents/ServerParameter.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/solana/intents/ServerParameter.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/solana/intents/actions/ActionType.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/solana/intents/actions/ActionType.kt similarity index 98% rename from services/opencode/src/main/kotlin/com/getcode/opencode/solana/intents/actions/ActionType.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/solana/intents/actions/ActionType.kt index 4f6117522e..63278cddf9 100644 --- a/services/opencode/src/main/kotlin/com/getcode/opencode/solana/intents/actions/ActionType.kt +++ b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/solana/intents/actions/ActionType.kt @@ -2,7 +2,7 @@ package com.getcode.opencode.solana.intents.actions import com.codeinc.opencode.gen.transaction.v1.OcpTransactionService import com.getcode.crypt.Sha256Hash -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.opencode.solana.intents.CompactMessage import com.getcode.opencode.solana.intents.CompactMessageArgs import com.getcode.opencode.solana.intents.ServerParameter diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/solana/keys/ProgramDerivedAccount.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/solana/keys/ProgramDerivedAccount.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/solana/keys/ProgramDerivedAccount.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/solana/keys/ProgramDerivedAccount.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/solana/keys/TimelockVmSwapAccounts.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/solana/keys/TimelockVmSwapAccounts.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/solana/keys/TimelockVmSwapAccounts.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/solana/keys/TimelockVmSwapAccounts.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/solana/swap/CoinbaseStablecoinSwapperInstructions.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/solana/swap/CoinbaseStablecoinSwapperInstructions.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/solana/swap/CoinbaseStablecoinSwapperInstructions.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/solana/swap/CoinbaseStablecoinSwapperInstructions.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/solana/swap/CrossCurrencyExistingSwapInstructions.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/solana/swap/CrossCurrencyExistingSwapInstructions.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/solana/swap/CrossCurrencyExistingSwapInstructions.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/solana/swap/CrossCurrencyExistingSwapInstructions.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/solana/swap/ExistingCurrencyBuyInstructions.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/solana/swap/ExistingCurrencyBuyInstructions.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/solana/swap/ExistingCurrencyBuyInstructions.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/solana/swap/ExistingCurrencyBuyInstructions.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/solana/swap/NewCurrencyBuyInstructions.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/solana/swap/NewCurrencyBuyInstructions.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/solana/swap/NewCurrencyBuyInstructions.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/solana/swap/NewCurrencyBuyInstructions.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/solana/swap/SellInstructions.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/solana/swap/SellInstructions.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/solana/swap/SellInstructions.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/solana/swap/SellInstructions.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/solana/swap/UsdcDepositInstructions.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/solana/swap/UsdcDepositInstructions.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/solana/swap/UsdcDepositInstructions.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/solana/swap/UsdcDepositInstructions.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/solana/swap/UsdcDepositSweepInstructions.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/solana/swap/UsdcDepositSweepInstructions.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/solana/swap/UsdcDepositSweepInstructions.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/solana/swap/UsdcDepositSweepInstructions.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/solana/swap/UsdcToUsdfSwapInstructions.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/solana/swap/UsdcToUsdfSwapInstructions.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/solana/swap/UsdcToUsdfSwapInstructions.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/solana/swap/UsdcToUsdfSwapInstructions.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/solana/swap/UsdfDepositInstructions.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/solana/swap/UsdfDepositInstructions.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/solana/swap/UsdfDepositInstructions.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/solana/swap/UsdfDepositInstructions.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/utils/Double.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/utils/Double.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/utils/Double.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/utils/Double.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/utils/Flow.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/utils/Flow.kt similarity index 97% rename from services/opencode/src/main/kotlin/com/getcode/opencode/utils/Flow.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/utils/Flow.kt index a13688dd90..71105d7e4e 100644 --- a/services/opencode/src/main/kotlin/com/getcode/opencode/utils/Flow.kt +++ b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/utils/Flow.kt @@ -9,7 +9,7 @@ import kotlinx.coroutines.flow.cancellable import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.map -import timber.log.Timber +import com.getcode.utils.Log import kotlin.time.Duration fun tickerFlow(period: Duration): Flow = flow { @@ -37,11 +37,11 @@ fun flowInterval( fun Flow.catchSafely( action: suspend (T) -> Unit, -): Flow = catchSafely(action, onFailure = { Timber.e(it, it.message) }) +): Flow = catchSafely(action, onFailure = { Log.e(it, it.message) }) fun Flow.catchSafely( action: suspend (T) -> Unit, - onFailure: (Throwable) -> Unit = { Timber.e(it, it.message) }, + onFailure: (Throwable) -> Unit = { Log.e(it, it.message) }, ): Flow = map { try { action(it) diff --git a/services/opencode/src/commonMain/kotlin/com/getcode/opencode/utils/KeyPair.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/utils/KeyPair.kt new file mode 100644 index 0000000000..02ccfc96cb --- /dev/null +++ b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/utils/KeyPair.kt @@ -0,0 +1,10 @@ +package com.getcode.opencode.utils + +import com.getcode.crypt.Sha256Hash +import com.getcode.ed25519kmp.Ed25519 +import com.getcode.ed25519kmp.Ed25519.KeyPair + +fun deriveRendezvousKey(from: ByteArray): KeyPair { + // Same key and seed string as the former Base64.DEFAULT-encoded seed. + return Ed25519.createKeyPair(Sha256Hash.hash(from)) +} diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/utils/Long.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/utils/Long.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/utils/Long.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/utils/Long.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/utils/Maps.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/utils/Maps.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/utils/Maps.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/utils/Maps.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/utils/Nonce.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/utils/Nonce.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/utils/Nonce.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/utils/Nonce.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/utils/PublicKey.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/utils/PublicKey.kt similarity index 85% rename from services/opencode/src/main/kotlin/com/getcode/opencode/utils/PublicKey.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/utils/PublicKey.kt index 66fa66dedb..163314eef3 100644 --- a/services/opencode/src/main/kotlin/com/getcode/opencode/utils/PublicKey.kt +++ b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/utils/PublicKey.kt @@ -1,6 +1,6 @@ package com.getcode.opencode.utils -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.opencode.internal.extensions.toPublicKey import com.getcode.solana.keys.PublicKey diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/utils/Result.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/utils/Result.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/utils/Result.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/utils/Result.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/utils/String.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/utils/String.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/utils/String.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/utils/String.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/utils/Throwable.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/utils/Throwable.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/utils/Throwable.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/utils/Throwable.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/utils/logging/LoggingClientCall.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/utils/logging/LoggingClientCall.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/utils/logging/LoggingClientCall.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/utils/logging/LoggingClientCall.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/utils/logging/LoggingClientCallListener.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/utils/logging/LoggingClientCallListener.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/utils/logging/LoggingClientCallListener.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/utils/logging/LoggingClientCallListener.kt diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/utils/logging/LoggingClientInterceptor.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/utils/logging/LoggingClientInterceptor.kt similarity index 100% rename from services/opencode/src/main/kotlin/com/getcode/opencode/utils/logging/LoggingClientInterceptor.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/utils/logging/LoggingClientInterceptor.kt diff --git a/services/opencode/src/jvmMain/kotlin/com/getcode/opencode/internal/platform/ProcessLifecycle.jvm.kt b/services/opencode/src/jvmMain/kotlin/com/getcode/opencode/internal/platform/ProcessLifecycle.jvm.kt new file mode 100644 index 0000000000..d00eadf201 --- /dev/null +++ b/services/opencode/src/jvmMain/kotlin/com/getcode/opencode/internal/platform/ProcessLifecycle.jvm.kt @@ -0,0 +1,14 @@ +package com.getcode.opencode.internal.platform + +import java.util.concurrent.Executors + +private val dispatcher = Executors.newSingleThreadExecutor { Thread(it, "process-lifecycle").apply { isDaemon = true } } + +/** A desktop process is in the foreground for as long as it runs, so only [onStart] is ever called. */ +internal actual fun observeProcessLifecycle( + immediateOnMain: Boolean, + onStart: () -> Unit, + onStop: () -> Unit, +) { + dispatcher.execute(onStart) +} diff --git a/services/opencode/src/jvmMain/kotlin/com/getcode/opencode/model/core/ScanCodeEncoder.jvm.kt b/services/opencode/src/jvmMain/kotlin/com/getcode/opencode/model/core/ScanCodeEncoder.jvm.kt new file mode 100644 index 0000000000..a5dfcd0b6d --- /dev/null +++ b/services/opencode/src/jvmMain/kotlin/com/getcode/opencode/model/core/ScanCodeEncoder.jvm.kt @@ -0,0 +1,4 @@ +package com.getcode.opencode.model.core + +// The encoder is the JNI library in vendor/kik/scanner, which has no desktop build yet. +internal actual fun encodeScanCode(payload: ByteArray): ByteArray? = null diff --git a/services/opencode/src/jvmTest/kotlin/com/getcode/opencode/HeadlessBalanceTest.kt b/services/opencode/src/jvmTest/kotlin/com/getcode/opencode/HeadlessBalanceTest.kt new file mode 100644 index 0000000000..9b726529b7 --- /dev/null +++ b/services/opencode/src/jvmTest/kotlin/com/getcode/opencode/HeadlessBalanceTest.kt @@ -0,0 +1,51 @@ +package com.getcode.opencode + +import com.getcode.crypt.DerivePath +import com.getcode.crypt.DerivedKey +import com.getcode.crypt.MnemonicPhrase +import com.getcode.opencode.internal.network.api.AccountApi +import com.getcode.opencode.internal.network.services.AccountService +import io.grpc.okhttp.OkHttpChannelBuilder +import kotlinx.coroutines.runBlocking +import org.junit.Assume.assumeTrue +import java.util.concurrent.TimeUnit +import kotlin.test.Test +import kotlin.test.assertTrue + +/** + * Fetches an account's token balances from the live OCP backend on the JVM, with no UI and no DI. + * + * The account's recovery phrase comes from the `FLIPCASH_TEST_MNEMONIC` environment variable or the + * `flipcash.test.mnemonic` entry in `local.properties`. The test is skipped when neither is set, and + * never prints the phrase or any key. + */ +class HeadlessBalanceTest { + + @Test + fun fetchesBalancesFromBackend() = runBlocking { + val words = System.getenv("FLIPCASH_TEST_MNEMONIC") + ?: System.getProperty("flipcash.test.mnemonic") + assumeTrue("no test mnemonic configured", !words.isNullOrBlank()) + + val mnemonic = requireNotNull(MnemonicPhrase.newInstance(words!!.trim().split(Regex("\\s+")))) { + "test mnemonic is not a valid phrase" + } + val owner = DerivedKey.derive(DerivePath.primary, mnemonic).keyPair + + val channel = OkHttpChannelBuilder.forAddress("ocp-v2.api.flipcash-infra.net", 443) + .userAgent("OpenCodeProtocol/Desktop/spike") + .build() + try { + val service = AccountService(AccountApi(channel)) + val response = service.getAccounts(owner, owner).getOrThrow() + + assertTrue(response.accounts.isNotEmpty(), "backend returned no token accounts") + val balances = response.accounts.values + .groupBy { it.mint } + .mapValues { (_, infos) -> infos.sumOf { it.balance } } + println("token accounts: ${response.accounts.size}, balance by mint (quarks): $balances") + } finally { + channel.shutdownNow().awaitTermination(5, TimeUnit.SECONDS) + } + } +} diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/core/GrpcApi.kt b/services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/core/GrpcApi.kt deleted file mode 100644 index 22906ddb98..0000000000 --- a/services/opencode/src/main/kotlin/com/getcode/opencode/internal/network/core/GrpcApi.kt +++ /dev/null @@ -1,39 +0,0 @@ -package com.getcode.opencode.internal.network.core - -import android.os.Handler -import android.os.Looper -import androidx.lifecycle.DefaultLifecycleObserver -import androidx.lifecycle.LifecycleOwner -import androidx.lifecycle.ProcessLifecycleOwner -import io.grpc.ManagedChannel - -abstract class GrpcApi(protected val managedChannels: List): DefaultLifecycleObserver { - - constructor(managedChannel: ManagedChannel): this(listOf(managedChannel)) - constructor(vararg managedChannels: ManagedChannel): this(managedChannels.toList()) - - init { - // LifecycleRegistry.addObserver rejects any thread but the main one, so registering here - // directly would pin construction of every api -- and so of the whole object graph hanging off - // them -- to the main thread. Posting keeps that off the startup path. addObserver replays the - // current state, so a registration that lands after the process is already started still warms - // the channel. - val register = Runnable { ProcessLifecycleOwner.get().lifecycle.addObserver(this) } - if (Looper.myLooper() == Looper.getMainLooper()) { - register.run() - } else { - Handler(Looper.getMainLooper()).post(register) - } - } - - override fun onStart(owner: LifecycleOwner) { - super.onStart(owner) - warmUp() - } - - private fun warmUp() { - // getState(true) requests a connection attempt if idle, - // pre-connecting TCP + TLS + HTTP/2 in the background - managedChannels.onEach { it.getState(true) } - } -} diff --git a/services/opencode/src/main/kotlin/com/getcode/opencode/utils/KeyPair.kt b/services/opencode/src/main/kotlin/com/getcode/opencode/utils/KeyPair.kt deleted file mode 100644 index e8d987a1fb..0000000000 --- a/services/opencode/src/main/kotlin/com/getcode/opencode/utils/KeyPair.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.getcode.opencode.utils - -import android.util.Base64 -import com.getcode.crypt.Sha256Hash -import com.getcode.ed25519.Ed25519 -import com.getcode.ed25519.Ed25519.KeyPair - -fun deriveRendezvousKey(from: ByteArray): KeyPair { - return Ed25519.createKeyPair(Base64.encodeToString(Sha256Hash.hash(from), Base64.DEFAULT)) -} \ No newline at end of file From 451e56a1e23803696a15d33fea83ed64e8b0d656 Mon Sep 17 00:00:00 2001 From: Brandon McAnsh Date: Fri, 23 Oct 2026 16:52:11 -0400 Subject: [PATCH 10/50] refactor(services): move flipcash services to android+jvm KMP services:flipcash now applies flipcash.kmp.app.library with Hilt run through kspAndroid. Android-only pieces sit behind seams: - UserManager takes an AnalyticsIdentifier instead of MixpanelAPI; FlipcashModule binds it to Mixpanel.identify. - ForegroundGate is a common interface; the process-lifecycle implementation stays in androidMain. - ChatId's hand-written parcel code moves to ManualParcelable. - KeyPair derivation goes through the byte-seed path shared with services:opencode, so derived keys are unchanged. Test fakes move to :services:flipcash:test-fixtures. shared:analytics reads BuildFlags.isDebug instead of this module's BuildConfig. --- .../shared/analytics/build.gradle.kts | 1 + .../internal/MixpanelAnalyticsDelegate.kt | 6 +- apps/flipcash/shared/chat/build.gradle.kts | 2 +- .../persistence/sources/build.gradle.kts | 2 +- gradle/libs.versions.toml | 1 + services/flipcash/build.gradle.kts | 123 ++++++++---------- .../services/chat/ChatContentCryptoTest.kt | 0 .../flipcash/services/chat/E2eePolicyTest.kt | 0 .../services/chat/GroupContentCryptoTest.kt | 0 .../services/chat/GroupKeyEnvelopesTest.kt | 0 .../BlobStorageControllerChatMediaTest.kt | 0 .../controllers/BlobStorageControllerTest.kt | 0 .../controllers/ChatControllerTest.kt | 0 .../ChatMessagingControllerTest.kt | 0 .../ContactVerificationControllerTest.kt | 0 .../EventStreamingControllerTest.kt | 0 .../controllers/ProfileControllerTest.kt | 0 .../domain/ActivityFeedMessageMapperTest.kt | 0 .../internal/domain/ChatMetadataMapperTest.kt | 0 .../domain/SocialAccountMapperTest.kt | 0 .../internal/domain/UserFlagsMapperTest.kt | 0 .../internal/domain/UserProfileMapperTest.kt | 0 .../internal/extensions/JpegMetadataTest.kt | 0 .../api/BlobAccessContextValidationTest.kt | 0 .../network/api/BlobStorageApiDeadlineTest.kt | 0 .../network/api/GetBlobsRequestSigningTest.kt | 0 .../extensions/CashContentMappingTest.kt | 0 .../extensions/ChatMetadataExtensionTest.kt | 0 .../extensions/ChatRulesProtoMappingTest.kt | 0 .../extensions/MediaContentMappingTest.kt | 0 .../MessageContentEncryptedMappingTest.kt | 0 .../extensions/PushPayloadMuteMappingTest.kt | 0 .../extensions/RosterUpdateExtensionTest.kt | 0 .../extensions/SystemContentMappingTest.kt | 0 .../extensions/WidgetAndNeverMappingTest.kt | 0 .../services/PhoneVerificationServiceTest.kt | 0 .../internal/proto/ProtoWireFormatTest.kt | 0 .../services/models/DmPaymentMetadataTest.kt | 0 .../flipcash/services/models/ErrorsTest.kt | 0 .../flipcash/services/models/HandleTest.kt | 0 .../services/models/blob/UploadPolicyTest.kt | 0 .../services/models/chat/BlobExpiryTest.kt | 0 .../models/chat/BlobIdEqualityTest.kt | 0 .../models/chat/BlobIdSerializationTest.kt | 0 .../services/models/chat/ChatIdTest.kt | 0 .../models/chat/DmAddressabilityTest.kt | 0 .../services/models/chat/DomainModelsTest.kt | 0 .../services/models/chat/MediaItemTest.kt | 0 .../services/models/chat/MuteLapseTest.kt | 0 .../services/user/AnalyticsIdentityTest.kt | 0 .../flipcash/services/user/UserManagerTest.kt | 5 +- .../services/ProcessForegroundGate.kt} | 10 -- .../controllers/ModerationController.kt | 0 .../services/controllers/PushController.kt | 0 .../services/inject/FlipcashModule.kt | 6 + .../internal/extensions/Installations.kt | 0 .../com/flipcash/services/BlobUploader.kt | 0 .../com/flipcash/services/ForegroundGate.kt | 11 ++ .../services/chat/ChatContentCrypto.kt | 0 .../flipcash/services/chat/ChatKeySource.kt | 0 .../com/flipcash/services/chat/E2eePolicy.kt | 0 .../services/chat/GroupContentCrypto.kt | 0 .../services/chat/GroupKeyEnvelopes.kt | 0 .../services/chat/MessageEncryption.kt | 0 .../com/flipcash/services/chat/SealedMedia.kt | 0 .../services/controllers/AccountController.kt | 0 .../controllers/ActivityFeedController.kt | 0 .../controllers/BlobStorageController.kt | 0 .../controllers/BlocklistController.kt | 0 .../services/controllers/ChatController.kt | 0 .../controllers/ChatMessagingController.kt | 0 .../controllers/CommunityController.kt | 0 .../controllers/ContactListController.kt | 0 .../ContactVerificationController.kt | 0 .../controllers/EventStreamingController.kt | 0 .../services/controllers/PollController.kt | 0 .../services/controllers/ProfileController.kt | 0 .../controllers/PurchaseController.kt | 0 .../controllers/ReportingController.kt | 0 .../controllers/ResolverController.kt | 0 .../controllers/SettingsController.kt | 0 .../controllers/ThirdPartyController.kt | 0 .../flipcash/services/extensions/KeyPair.kt | 7 +- .../services/inject/ChatCryptoModule.kt | 0 .../annotations/FlipcashManagedChannel.kt | 0 .../internal/annotations/FlipcashProtocol.kt | 0 .../domain/ActivityFeedMessageMapper.kt | 0 .../internal/domain/BlockedUserMapper.kt | 0 .../internal/domain/ChatMetadataMapper.kt | 0 .../services/internal/domain/ContactMapper.kt | 0 .../domain/ImageModerationResponseMapper.kt | 0 .../domain/ModerationAttestationMapper.kt | 0 .../internal/domain/SocialAccountMapper.kt | 0 .../domain/TextModerationResponseMapper.kt | 0 .../internal/domain/UserFlagsMapper.kt | 0 .../internal/domain/UserProfileMapper.kt | 0 .../services/internal/domain/mapper/Mapper.kt | 0 .../services/internal/extensions/ByteArray.kt | 0 .../services/internal/extensions/Instant.kt | 0 .../internal/extensions/JpegMetadata.kt | 0 .../services/internal/extensions/KeyPair.kt | 0 .../services/internal/extensions/PublicKey.kt | 0 .../internal/model/billing/IapMetadata.kt | 0 .../internal/model/billing/Receipt.kt | 0 .../model/moderation/ModerationRequest.kt | 0 .../model/thirdparty/OnRampProvider.kt | 0 .../model/thirdparty/UsdcLiquidtyPool.kt | 0 .../internal/network/HttpBlobUploader.kt | 0 .../internal/network/api/AccountApi.kt | 0 .../internal/network/api/ActivityFeedApi.kt | 0 .../internal/network/api/BlobStorageApi.kt | 0 .../internal/network/api/BlocklistApi.kt | 0 .../services/internal/network/api/ChatApi.kt | 0 .../internal/network/api/ChatMessagingApi.kt | 0 .../internal/network/api/CommunityApi.kt | 0 .../internal/network/api/ContactListApi.kt | 0 .../network/api/EmailVerificationApi.kt | 0 .../internal/network/api/EventStreamingApi.kt | 0 .../internal/network/api/ModerationApi.kt | 0 .../network/api/PhoneVerificationApi.kt | 0 .../services/internal/network/api/PollApi.kt | 0 .../internal/network/api/ProfileApi.kt | 0 .../internal/network/api/PurchaseApi.kt | 0 .../services/internal/network/api/PushApi.kt | 0 .../internal/network/api/ReportingApi.kt | 0 .../internal/network/api/ResolverApi.kt | 0 .../internal/network/api/SettingsApi.kt | 0 .../internal/network/api/ThirdPartyApi.kt | 0 .../network/extensions/AuthenticateMessage.kt | 0 .../network/extensions/LocalToProtobuf.kt | 0 .../network/extensions/ProtobufToLocal.kt | 0 .../network/extensions/SignMessage.kt | 0 .../network/services/AccountService.kt | 0 .../network/services/ActivityFeedService.kt | 0 .../network/services/BlobStorageService.kt | 0 .../network/services/BlocklistService.kt | 0 .../network/services/ChatMessagingService.kt | 0 .../internal/network/services/ChatService.kt | 0 .../network/services/CommunityService.kt | 0 .../network/services/ContactListService.kt | 0 .../services/EmailVerificationService.kt | 0 .../network/services/EventStreamingService.kt | 0 .../network/services/ModerationService.kt | 0 .../services/PhoneVerificationService.kt | 0 .../internal/network/services/PollService.kt | 0 .../network/services/ProfileService.kt | 0 .../network/services/PurchaseService.kt | 0 .../internal/network/services/PushService.kt | 0 .../network/services/ReportingService.kt | 0 .../network/services/ResolverService.kt | 0 .../network/services/SettingsService.kt | 0 .../network/services/ThirdPartyService.kt | 0 .../repositories/InternalAccountRepository.kt | 0 .../InternalActivityFeedRepository.kt | 0 .../InternalBlobStorageRepository.kt | 0 .../InternalBlocklistRepository.kt | 0 .../InternalChatMessagingRepository.kt | 0 .../repositories/InternalChatRepository.kt | 0 .../InternalCommunityRepository.kt | 0 .../InternalContactListRepository.kt | 0 .../InternalContactVerificationRepository.kt | 0 .../InternalEventStreamingRepository.kt | 0 .../InternalModerationRepository.kt | 0 .../repositories/InternalPollRepository.kt | 0 .../repositories/InternalProfileRepository.kt | 0 .../InternalPurchaseRepository.kt | 0 .../repositories/InternalPushRepository.kt | 0 .../InternalReportingRepository.kt | 0 .../InternalResolverRepository.kt | 0 .../InternalSettingsRepository.kt | 0 .../InternalThirdPartyRepository.kt | 0 .../flipcash/services/modals/ModalManager.kt | 0 .../models/ActivityFeedNotification.kt | 0 .../services/models/ActivityFeedType.kt | 0 .../flipcash/services/models/BlockedUser.kt | 0 .../com/flipcash/services/models/Community.kt | 0 .../flipcash/services/models/ContactMethod.kt | 0 .../services/models/DmPaymentMetadata.kt | 0 .../com/flipcash/services/models/Errors.kt | 0 .../services/models/FlipcashContactEntry.kt | 0 .../com/flipcash/services/models/Handle.kt | 0 .../com/flipcash/services/models/Jwt.kt | 0 .../services/models/ModerationResult.kt | 0 .../services/models/NotificationPayload.kt | 0 .../services/models/ProfileIdentifier.kt | 0 .../flipcash/services/models/QueryOptions.kt | 0 .../services/models/ReactionBoostMetadata.kt | 0 .../flipcash/services/models/ReportTarget.kt | 0 .../services/models/ResolveIdentifier.kt | 0 .../services/models/SocialAccountLinking.kt | 0 .../flipcash/services/models/TipPresets.kt | 0 .../com/flipcash/services/models/UserFlags.kt | 0 .../flipcash/services/models/UserProfile.kt | 4 +- .../models/VerifiableContactMethod.kt | 4 +- .../services/models/blob/UploadPolicy.kt | 0 .../services/models/blob/UploadTarget.kt | 0 .../services/models/chat/BlobAccessContext.kt | 0 .../flipcash/services/models/chat/BlobId.kt | 4 +- .../services/models/chat/BlobMetadata.kt | 4 +- .../services/models/chat/BlobUpdate.kt | 0 .../services/models/chat/ChatEvent.kt | 0 .../services/models/chat/ChatFeedPage.kt | 0 .../flipcash/services/models/chat/ChatId.kt | 13 +- .../services/models/chat/ChatMember.kt | 0 .../services/models/chat/ChatMessage.kt | 0 .../services/models/chat/ChatMetadata.kt | 0 .../services/models/chat/ChatMutation.kt | 0 .../services/models/chat/ChatRules.kt | 0 .../flipcash/services/models/chat/ChatType.kt | 0 .../services/models/chat/ChatUpdate.kt | 0 .../services/models/chat/ClientMessageId.kt | 0 .../services/models/chat/DeliveryStatus.kt | 0 .../services/models/chat/DmAddressability.kt | 0 .../models/chat/EditChatParameters.kt | 0 .../flipcash/services/models/chat/Emoji.kt | 0 .../services/models/chat/EmojiReaction.kt | 0 .../services/models/chat/HoldingsSummary.kt | 0 .../services/models/chat/IdempotencyKey.kt | 0 .../services/models/chat/ImageMetadata.kt | 4 +- .../services/models/chat/KeyEnvelope.kt | 0 .../services/models/chat/LinkPreview.kt | 0 .../flipcash/services/models/chat/Lobby.kt | 0 .../services/models/chat/MediaItem.kt | 4 +- .../models/chat/MediaItemRendition.kt | 4 +- .../services/models/chat/MentionSuggestion.kt | 0 .../services/models/chat/MessageContent.kt | 0 .../services/models/chat/MessagePointer.kt | 0 .../services/models/chat/MetadataUpdate.kt | 0 .../services/models/chat/MuteExtensions.kt | 0 .../services/models/chat/MuteState.kt | 0 .../services/models/chat/ReactionSummary.kt | 0 .../services/models/chat/ReactionUpdate.kt | 0 .../flipcash/services/models/chat/Reactor.kt | 0 .../services/models/chat/RosterChange.kt | 0 .../services/models/chat/RosterPage.kt | 0 .../services/models/chat/RosterSummary.kt | 0 .../services/models/chat/SampledChatter.kt | 0 .../models/chat/StartChatParameters.kt | 0 .../models/chat/TypingNotification.kt | 0 .../flipcash/services/models/chat/ViewMode.kt | 0 .../services/models/chat/ViewerState.kt | 0 .../services/models/chat/WidgetContent.kt | 0 .../services/persistence/DataSource.kt | 0 .../services/repository/AccountRepository.kt | 0 .../repository/ActivityFeedRepository.kt | 0 .../repository/BlobStorageRepository.kt | 0 .../repository/BlocklistRepository.kt | 0 .../repository/ChatMessagingRepository.kt | 0 .../services/repository/ChatRepository.kt | 0 .../repository/CommunityRepository.kt | 0 .../repository/ContactListRepository.kt | 0 .../ContactVerificationRepository.kt | 0 .../repository/EventStreamingRepository.kt | 0 .../repository/ModerationRepository.kt | 0 .../services/repository/PollRepository.kt | 0 .../services/repository/ProfileRepository.kt | 0 .../services/repository/PurchaseRepository.kt | 0 .../services/repository/PushRepository.kt | 0 .../repository/ReportingRepository.kt | 0 .../services/repository/ResolverRepository.kt | 0 .../services/repository/SettingsRepository.kt | 0 .../repository/ThirdPartyRepository.kt | 0 .../services/user/AnalyticsIdentity.kt | 5 + .../com/flipcash/services/user/UserManager.kt | 5 +- .../flipcash/services/validators/Validator.kt | 0 .../flipcash/test-fixtures/build.gradle.kts | 16 +++ .../flipcash/services/chat/FakeChatCipher.kt | 0 settings.gradle.kts | 1 + 268 files changed, 125 insertions(+), 117 deletions(-) rename services/flipcash/src/{test => androidHostTest}/kotlin/com/flipcash/services/chat/ChatContentCryptoTest.kt (100%) rename services/flipcash/src/{test => androidHostTest}/kotlin/com/flipcash/services/chat/E2eePolicyTest.kt (100%) rename services/flipcash/src/{test => androidHostTest}/kotlin/com/flipcash/services/chat/GroupContentCryptoTest.kt (100%) rename services/flipcash/src/{test => androidHostTest}/kotlin/com/flipcash/services/chat/GroupKeyEnvelopesTest.kt (100%) rename services/flipcash/src/{test => androidHostTest}/kotlin/com/flipcash/services/controllers/BlobStorageControllerChatMediaTest.kt (100%) rename services/flipcash/src/{test => androidHostTest}/kotlin/com/flipcash/services/controllers/BlobStorageControllerTest.kt (100%) rename services/flipcash/src/{test => androidHostTest}/kotlin/com/flipcash/services/controllers/ChatControllerTest.kt (100%) rename services/flipcash/src/{test => androidHostTest}/kotlin/com/flipcash/services/controllers/ChatMessagingControllerTest.kt (100%) rename services/flipcash/src/{test => androidHostTest}/kotlin/com/flipcash/services/controllers/ContactVerificationControllerTest.kt (100%) rename services/flipcash/src/{test => androidHostTest}/kotlin/com/flipcash/services/controllers/EventStreamingControllerTest.kt (100%) rename services/flipcash/src/{test => androidHostTest}/kotlin/com/flipcash/services/controllers/ProfileControllerTest.kt (100%) rename services/flipcash/src/{test => androidHostTest}/kotlin/com/flipcash/services/internal/domain/ActivityFeedMessageMapperTest.kt (100%) rename services/flipcash/src/{test => androidHostTest}/kotlin/com/flipcash/services/internal/domain/ChatMetadataMapperTest.kt (100%) rename services/flipcash/src/{test => androidHostTest}/kotlin/com/flipcash/services/internal/domain/SocialAccountMapperTest.kt (100%) rename services/flipcash/src/{test => androidHostTest}/kotlin/com/flipcash/services/internal/domain/UserFlagsMapperTest.kt (100%) rename services/flipcash/src/{test => androidHostTest}/kotlin/com/flipcash/services/internal/domain/UserProfileMapperTest.kt (100%) rename services/flipcash/src/{test => androidHostTest}/kotlin/com/flipcash/services/internal/extensions/JpegMetadataTest.kt (100%) rename services/flipcash/src/{test => androidHostTest}/kotlin/com/flipcash/services/internal/network/api/BlobAccessContextValidationTest.kt (100%) rename services/flipcash/src/{test => androidHostTest}/kotlin/com/flipcash/services/internal/network/api/BlobStorageApiDeadlineTest.kt (100%) rename services/flipcash/src/{test => androidHostTest}/kotlin/com/flipcash/services/internal/network/api/GetBlobsRequestSigningTest.kt (100%) rename services/flipcash/src/{test => androidHostTest}/kotlin/com/flipcash/services/internal/network/extensions/CashContentMappingTest.kt (100%) rename services/flipcash/src/{test => androidHostTest}/kotlin/com/flipcash/services/internal/network/extensions/ChatMetadataExtensionTest.kt (100%) rename services/flipcash/src/{test => androidHostTest}/kotlin/com/flipcash/services/internal/network/extensions/ChatRulesProtoMappingTest.kt (100%) rename services/flipcash/src/{test => androidHostTest}/kotlin/com/flipcash/services/internal/network/extensions/MediaContentMappingTest.kt (100%) rename services/flipcash/src/{test => androidHostTest}/kotlin/com/flipcash/services/internal/network/extensions/MessageContentEncryptedMappingTest.kt (100%) rename services/flipcash/src/{test => androidHostTest}/kotlin/com/flipcash/services/internal/network/extensions/PushPayloadMuteMappingTest.kt (100%) rename services/flipcash/src/{test => androidHostTest}/kotlin/com/flipcash/services/internal/network/extensions/RosterUpdateExtensionTest.kt (100%) rename services/flipcash/src/{test => androidHostTest}/kotlin/com/flipcash/services/internal/network/extensions/SystemContentMappingTest.kt (100%) rename services/flipcash/src/{test => androidHostTest}/kotlin/com/flipcash/services/internal/network/extensions/WidgetAndNeverMappingTest.kt (100%) rename services/flipcash/src/{test => androidHostTest}/kotlin/com/flipcash/services/internal/network/services/PhoneVerificationServiceTest.kt (100%) rename services/flipcash/src/{test => androidHostTest}/kotlin/com/flipcash/services/internal/proto/ProtoWireFormatTest.kt (100%) rename services/flipcash/src/{test => androidHostTest}/kotlin/com/flipcash/services/models/DmPaymentMetadataTest.kt (100%) rename services/flipcash/src/{test => androidHostTest}/kotlin/com/flipcash/services/models/ErrorsTest.kt (100%) rename services/flipcash/src/{test => androidHostTest}/kotlin/com/flipcash/services/models/HandleTest.kt (100%) rename services/flipcash/src/{test => androidHostTest}/kotlin/com/flipcash/services/models/blob/UploadPolicyTest.kt (100%) rename services/flipcash/src/{test => androidHostTest}/kotlin/com/flipcash/services/models/chat/BlobExpiryTest.kt (100%) rename services/flipcash/src/{test => androidHostTest}/kotlin/com/flipcash/services/models/chat/BlobIdEqualityTest.kt (100%) rename services/flipcash/src/{test => androidHostTest}/kotlin/com/flipcash/services/models/chat/BlobIdSerializationTest.kt (100%) rename services/flipcash/src/{test => androidHostTest}/kotlin/com/flipcash/services/models/chat/ChatIdTest.kt (100%) rename services/flipcash/src/{test => androidHostTest}/kotlin/com/flipcash/services/models/chat/DmAddressabilityTest.kt (100%) rename services/flipcash/src/{test => androidHostTest}/kotlin/com/flipcash/services/models/chat/DomainModelsTest.kt (100%) rename services/flipcash/src/{test => androidHostTest}/kotlin/com/flipcash/services/models/chat/MediaItemTest.kt (100%) rename services/flipcash/src/{test => androidHostTest}/kotlin/com/flipcash/services/models/chat/MuteLapseTest.kt (100%) rename services/flipcash/src/{test => androidHostTest}/kotlin/com/flipcash/services/user/AnalyticsIdentityTest.kt (100%) rename services/flipcash/src/{test => androidHostTest}/kotlin/com/flipcash/services/user/UserManagerTest.kt (96%) rename services/flipcash/src/{main/kotlin/com/flipcash/services/ForegroundGate.kt => androidMain/kotlin/com/flipcash/services/ProcessForegroundGate.kt} (64%) rename services/flipcash/src/{main => androidMain}/kotlin/com/flipcash/services/controllers/ModerationController.kt (100%) rename services/flipcash/src/{main => androidMain}/kotlin/com/flipcash/services/controllers/PushController.kt (100%) rename services/flipcash/src/{main => androidMain}/kotlin/com/flipcash/services/inject/FlipcashModule.kt (97%) rename services/flipcash/src/{main => androidMain}/kotlin/com/flipcash/services/internal/extensions/Installations.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/BlobUploader.kt (100%) create mode 100644 services/flipcash/src/commonMain/kotlin/com/flipcash/services/ForegroundGate.kt rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/chat/ChatContentCrypto.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/chat/ChatKeySource.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/chat/E2eePolicy.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/chat/GroupContentCrypto.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/chat/GroupKeyEnvelopes.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/chat/MessageEncryption.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/chat/SealedMedia.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/controllers/AccountController.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/controllers/ActivityFeedController.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/controllers/BlobStorageController.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/controllers/BlocklistController.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/controllers/ChatController.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/controllers/ChatMessagingController.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/controllers/CommunityController.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/controllers/ContactListController.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/controllers/ContactVerificationController.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/controllers/EventStreamingController.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/controllers/PollController.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/controllers/ProfileController.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/controllers/PurchaseController.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/controllers/ReportingController.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/controllers/ResolverController.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/controllers/SettingsController.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/controllers/ThirdPartyController.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/extensions/KeyPair.kt (69%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/inject/ChatCryptoModule.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/annotations/FlipcashManagedChannel.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/annotations/FlipcashProtocol.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/domain/ActivityFeedMessageMapper.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/domain/BlockedUserMapper.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/domain/ChatMetadataMapper.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/domain/ContactMapper.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/domain/ImageModerationResponseMapper.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/domain/ModerationAttestationMapper.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/domain/SocialAccountMapper.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/domain/TextModerationResponseMapper.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/domain/UserFlagsMapper.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/domain/UserProfileMapper.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/domain/mapper/Mapper.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/extensions/ByteArray.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/extensions/Instant.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/extensions/JpegMetadata.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/extensions/KeyPair.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/extensions/PublicKey.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/model/billing/IapMetadata.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/model/billing/Receipt.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/model/moderation/ModerationRequest.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/model/thirdparty/OnRampProvider.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/model/thirdparty/UsdcLiquidtyPool.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/network/HttpBlobUploader.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/network/api/AccountApi.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/network/api/ActivityFeedApi.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/network/api/BlobStorageApi.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/network/api/BlocklistApi.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/network/api/ChatApi.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/network/api/ChatMessagingApi.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/network/api/CommunityApi.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/network/api/ContactListApi.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/network/api/EmailVerificationApi.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/network/api/EventStreamingApi.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/network/api/ModerationApi.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/network/api/PhoneVerificationApi.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/network/api/PollApi.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/network/api/ProfileApi.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/network/api/PurchaseApi.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/network/api/PushApi.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/network/api/ReportingApi.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/network/api/ResolverApi.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/network/api/SettingsApi.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/network/api/ThirdPartyApi.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/network/extensions/AuthenticateMessage.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/network/extensions/LocalToProtobuf.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/network/extensions/ProtobufToLocal.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/network/extensions/SignMessage.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/network/services/AccountService.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/network/services/ActivityFeedService.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/network/services/BlobStorageService.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/network/services/BlocklistService.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/network/services/ChatMessagingService.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/network/services/ChatService.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/network/services/CommunityService.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/network/services/ContactListService.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/network/services/EmailVerificationService.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/network/services/EventStreamingService.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/network/services/ModerationService.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/network/services/PhoneVerificationService.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/network/services/PollService.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/network/services/ProfileService.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/network/services/PurchaseService.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/network/services/PushService.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/network/services/ReportingService.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/network/services/ResolverService.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/network/services/SettingsService.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/network/services/ThirdPartyService.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/repositories/InternalAccountRepository.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/repositories/InternalActivityFeedRepository.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/repositories/InternalBlobStorageRepository.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/repositories/InternalBlocklistRepository.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/repositories/InternalChatMessagingRepository.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/repositories/InternalChatRepository.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/repositories/InternalCommunityRepository.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/repositories/InternalContactListRepository.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/repositories/InternalContactVerificationRepository.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/repositories/InternalEventStreamingRepository.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/repositories/InternalModerationRepository.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/repositories/InternalPollRepository.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/repositories/InternalProfileRepository.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/repositories/InternalPurchaseRepository.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/repositories/InternalPushRepository.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/repositories/InternalReportingRepository.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/repositories/InternalResolverRepository.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/repositories/InternalSettingsRepository.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/internal/repositories/InternalThirdPartyRepository.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/modals/ModalManager.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/models/ActivityFeedNotification.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/models/ActivityFeedType.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/models/BlockedUser.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/models/Community.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/models/ContactMethod.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/models/DmPaymentMetadata.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/models/Errors.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/models/FlipcashContactEntry.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/models/Handle.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/models/Jwt.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/models/ModerationResult.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/models/NotificationPayload.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/models/ProfileIdentifier.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/models/QueryOptions.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/models/ReactionBoostMetadata.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/models/ReportTarget.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/models/ResolveIdentifier.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/models/SocialAccountLinking.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/models/TipPresets.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/models/UserFlags.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/models/UserProfile.kt (97%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/models/VerifiableContactMethod.kt (83%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/models/blob/UploadPolicy.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/models/blob/UploadTarget.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/models/chat/BlobAccessContext.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/models/chat/BlobId.kt (96%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/models/chat/BlobMetadata.kt (95%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/models/chat/BlobUpdate.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/models/chat/ChatEvent.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/models/chat/ChatFeedPage.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/models/chat/ChatId.kt (82%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/models/chat/ChatMember.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/models/chat/ChatMessage.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/models/chat/ChatMetadata.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/models/chat/ChatMutation.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/models/chat/ChatRules.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/models/chat/ChatType.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/models/chat/ChatUpdate.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/models/chat/ClientMessageId.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/models/chat/DeliveryStatus.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/models/chat/DmAddressability.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/models/chat/EditChatParameters.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/models/chat/Emoji.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/models/chat/EmojiReaction.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/models/chat/HoldingsSummary.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/models/chat/IdempotencyKey.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/models/chat/ImageMetadata.kt (70%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/models/chat/KeyEnvelope.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/models/chat/LinkPreview.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/models/chat/Lobby.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/models/chat/MediaItem.kt (98%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/models/chat/MediaItemRendition.kt (92%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/models/chat/MentionSuggestion.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/models/chat/MessageContent.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/models/chat/MessagePointer.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/models/chat/MetadataUpdate.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/models/chat/MuteExtensions.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/models/chat/MuteState.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/models/chat/ReactionSummary.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/models/chat/ReactionUpdate.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/models/chat/Reactor.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/models/chat/RosterChange.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/models/chat/RosterPage.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/models/chat/RosterSummary.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/models/chat/SampledChatter.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/models/chat/StartChatParameters.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/models/chat/TypingNotification.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/models/chat/ViewMode.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/models/chat/ViewerState.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/models/chat/WidgetContent.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/persistence/DataSource.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/repository/AccountRepository.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/repository/ActivityFeedRepository.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/repository/BlobStorageRepository.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/repository/BlocklistRepository.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/repository/ChatMessagingRepository.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/repository/ChatRepository.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/repository/CommunityRepository.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/repository/ContactListRepository.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/repository/ContactVerificationRepository.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/repository/EventStreamingRepository.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/repository/ModerationRepository.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/repository/PollRepository.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/repository/ProfileRepository.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/repository/PurchaseRepository.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/repository/PushRepository.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/repository/ReportingRepository.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/repository/ResolverRepository.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/repository/SettingsRepository.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/repository/ThirdPartyRepository.kt (100%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/user/AnalyticsIdentity.kt (74%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/user/UserManager.kt (98%) rename services/flipcash/src/{main => commonMain}/kotlin/com/flipcash/services/validators/Validator.kt (100%) create mode 100644 services/flipcash/test-fixtures/build.gradle.kts rename services/flipcash/{src/testFixtures => test-fixtures/src/commonMain}/kotlin/com/flipcash/services/chat/FakeChatCipher.kt (100%) diff --git a/apps/flipcash/shared/analytics/build.gradle.kts b/apps/flipcash/shared/analytics/build.gradle.kts index 371f23ce36..c17b1a59e6 100644 --- a/apps/flipcash/shared/analytics/build.gradle.kts +++ b/apps/flipcash/shared/analytics/build.gradle.kts @@ -22,6 +22,7 @@ dependencies { implementation(libs.bugsnag) api(project(":libs:analytics-events")) + implementation(project(":libs:logging")) implementation(project(":services:flipcash")) implementation(project(":services:opencode")) diff --git a/apps/flipcash/shared/analytics/src/main/kotlin/com/flipcash/app/analytics/internal/MixpanelAnalyticsDelegate.kt b/apps/flipcash/shared/analytics/src/main/kotlin/com/flipcash/app/analytics/internal/MixpanelAnalyticsDelegate.kt index 39408e19a3..ecd4b149db 100644 --- a/apps/flipcash/shared/analytics/src/main/kotlin/com/flipcash/app/analytics/internal/MixpanelAnalyticsDelegate.kt +++ b/apps/flipcash/shared/analytics/src/main/kotlin/com/flipcash/app/analytics/internal/MixpanelAnalyticsDelegate.kt @@ -5,7 +5,7 @@ import com.flipcash.analytics.PeopleCounter import com.flipcash.app.analytics.FlipcashAnalytics import com.flipcash.analytics.PropertyValue import com.flipcash.app.analytics.TokenSymbolResolver -import com.getcode.services.flipcash.BuildConfig +import com.getcode.utils.BuildFlags import com.getcode.utils.TraceType import com.getcode.utils.trace import com.mixpanel.android.mpmetrics.MixpanelAPI @@ -20,7 +20,7 @@ internal class MixpanelAnalyticsDelegate @Inject constructor( override fun track(event: AnalyticsEvent) { val properties = event.toMixpanelProperties(tokenSymbolResolver) - if (BuildConfig.DEBUG) { + if (BuildFlags.isDebug) { val propsString = properties.entries.joinToString { "${it.key} => ${it.value}" } trace( buildString { @@ -42,7 +42,7 @@ internal class MixpanelAnalyticsDelegate @Inject constructor( // region Internal private fun increment(property: String, amount: Double) { - if (BuildConfig.DEBUG) { + if (BuildFlags.isDebug) { trace("debug increment $property by $amount", type = TraceType.Silent) return } diff --git a/apps/flipcash/shared/chat/build.gradle.kts b/apps/flipcash/shared/chat/build.gradle.kts index fd45bb87cc..a21772a251 100644 --- a/apps/flipcash/shared/chat/build.gradle.kts +++ b/apps/flipcash/shared/chat/build.gradle.kts @@ -35,7 +35,7 @@ dependencies { implementation(project(":apps:flipcash:shared:analytics")) testImplementation(testFixtures(project(":apps:flipcash:shared:analytics"))) implementation(project(":services:flipcash")) - testImplementation(testFixtures(project(":services:flipcash"))) + testImplementation(project(":services:flipcash:test-fixtures")) implementation(project(":libs:network:connectivity:public")) implementation(project(":libs:emojis")) implementation(libs.androidx.lifecycle.process) diff --git a/apps/flipcash/shared/persistence/sources/build.gradle.kts b/apps/flipcash/shared/persistence/sources/build.gradle.kts index 5fa1f607cf..ea4b055ca7 100644 --- a/apps/flipcash/shared/persistence/sources/build.gradle.kts +++ b/apps/flipcash/shared/persistence/sources/build.gradle.kts @@ -17,7 +17,7 @@ dependencies { testImplementation(kotlin("test")) testImplementation(libs.bundles.unit.testing) testImplementation(libs.robolectric) - testImplementation(testFixtures(project(":services:flipcash"))) + testImplementation(project(":services:flipcash:test-fixtures")) implementation(libs.bundles.kotlinx.serialization) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1b6dc7816c..54a4decc30 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -147,6 +147,7 @@ navigation3-runtime = { module = "androidx.navigation3:navigation3-runtime", ver navigation3-ui = { module = "androidx.navigation3:navigation3-ui", version.ref = "navigation3" } lifecycle-viewmodel-navigation3 = { module = "androidx.lifecycle:lifecycle-viewmodel-navigation3", version.ref = "navigation3-lifecycle" } androidx-browser = { module = "androidx.browser:browser", version.ref = "androidx-browser" } +androidx-paging-common = { module = "androidx.paging:paging-common", version.ref = "androidx-paging" } androidx-paging-runtime = { module = "androidx.paging:paging-runtime-ktx", version.ref = "androidx-paging" } androidx-paging-testing = { module = "androidx.paging:paging-testing", version.ref = "androidx-paging" } androidx-room-runtime = { module = "androidx.room:room-runtime", version.ref = "androidx-room" } diff --git a/services/flipcash/build.gradle.kts b/services/flipcash/build.gradle.kts index 6770471c04..97e107fbf0 100644 --- a/services/flipcash/build.gradle.kts +++ b/services/flipcash/build.gradle.kts @@ -1,80 +1,65 @@ plugins { - alias(libs.plugins.flipcash.android.library) - id("com.google.devtools.ksp") + alias(libs.plugins.flipcash.kmp.app.library) + alias(libs.plugins.kotlin.ksp) id("org.jetbrains.kotlin.plugin.parcelize") } -android { - namespace = "${Gradle.codeNamespace}.services.flipcash" - - defaultConfig { - consumerProguardFiles("consumer-rules.pro") - - buildConfigField("Boolean", "NOTIFY_ERRORS", "false") - buildConfigField( - "String", - "GOOGLE_CLOUD_PROJECT_NUMBER", - "\"${tryReadProperty(rootProject.rootDir, "GOOGLE_CLOUD_PROJECT_NUMBER", "-1L")}\"" - ) - } - - buildFeatures { - buildConfig = true +kotlin { + android { + namespace = "${Gradle.codeNamespace}.services.flipcash" + optimization { + consumerKeepRules.apply { + publish = true + file("consumer-rules.pro") + } + } } - testFixtures { - enable = true + sourceSets { + commonMain.dependencies { + implementation(libs.flipcash2.client.protocol) + api(project(":libs:network:jwt")) + api(project(":services:opencode")) + implementation(project(":ui:resources")) + // `api`: ChatContentCrypto and ChatKeySource name ChatCipher and its KeyPair. + api(project(":libs:encryption:chat-cipher")) + + implementation(libs.bundles.hilt.common) + implementation(libs.kotlinx.serialization.json) + implementation(libs.grpc.okhttp) + implementation(libs.grpc.kotlin) + implementation(libs.grpc.protobuf.lite) + implementation(libs.protobuf.validate.runtime) + implementation(libs.androidx.paging.common) + implementation(libs.okhttp) + implementation(libs.event.bus) + } + androidMain.dependencies { + implementation(libs.grpc.android) + implementation(libs.androidx.lifecycle.runtime) + implementation(libs.androidx.lifecycle.process) + implementation(libs.mixpanel) + implementation(project.dependencies.platform(libs.firebase.bom)) + implementation(libs.firebase.installations) + implementation(libs.play.integrity) + implementation(libs.fingerprint.pro) + implementation(libs.hilt.android) + + // Not imported by this module; kept so the app's runtime classpath is unchanged. + implementation(libs.androidx.room.runtime) + implementation(libs.androidx.room.ktx) + implementation(libs.androidx.room.paging) + implementation(libs.androidx.paging.runtime) + } + getByName("androidHostTest").dependencies { + implementation(kotlin("test")) + implementation(libs.bundles.unit.testing) + implementation(project(":services:flipcash:test-fixtures")) + } } } dependencies { - implementation(libs.flipcash2.client.protocol) - api(project(":libs:network:jwt")) - api(project(":services:opencode")) - implementation(project(":ui:resources")) - // `api`: ChatContentCrypto and ChatKeySource name ChatCipher and its KeyPair. - api(project(":libs:encryption:chat-cipher")) - testFixturesImplementation(project(":libs:encryption:chat-cipher")) - - implementation(libs.javax.inject) - - implementation(libs.kotlinx.serialization.json) - implementation(libs.javax.inject) - - implementation(libs.grpc.android) - implementation(libs.grpc.okhttp) - implementation(libs.grpc.kotlin) - implementation(libs.grpc.protobuf.lite) - implementation(libs.protobuf.validate.runtime) - implementation(libs.androidx.lifecycle.runtime) - implementation(libs.androidx.lifecycle.process) - implementation(libs.androidx.room.runtime) - implementation(libs.androidx.room.ktx) - implementation(libs.androidx.room.paging) - implementation(libs.okhttp) - implementation(libs.mixpanel) - - implementation(platform(libs.firebase.bom)) - implementation(libs.firebase.installations) - - implementation(libs.play.integrity) - - implementation(libs.androidx.paging.runtime) - - ksp(libs.androidx.room.compiler) - - implementation(libs.fingerprint.pro) - - androidTestImplementation(libs.androidx.junit) - androidTestImplementation(libs.junit) - androidTestImplementation(libs.androidx.test.runner) - - implementation(libs.hilt.android) - ksp(libs.hilt.android.compiler) - ksp(libs.hilt.compiler) - - implementation(libs.event.bus) - - testImplementation(kotlin("test")) - testImplementation(libs.bundles.unit.testing) + add("kspAndroid", libs.hilt.android.compiler) + add("kspAndroid", libs.hilt.compiler) } diff --git a/services/flipcash/src/test/kotlin/com/flipcash/services/chat/ChatContentCryptoTest.kt b/services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/chat/ChatContentCryptoTest.kt similarity index 100% rename from services/flipcash/src/test/kotlin/com/flipcash/services/chat/ChatContentCryptoTest.kt rename to services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/chat/ChatContentCryptoTest.kt diff --git a/services/flipcash/src/test/kotlin/com/flipcash/services/chat/E2eePolicyTest.kt b/services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/chat/E2eePolicyTest.kt similarity index 100% rename from services/flipcash/src/test/kotlin/com/flipcash/services/chat/E2eePolicyTest.kt rename to services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/chat/E2eePolicyTest.kt diff --git a/services/flipcash/src/test/kotlin/com/flipcash/services/chat/GroupContentCryptoTest.kt b/services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/chat/GroupContentCryptoTest.kt similarity index 100% rename from services/flipcash/src/test/kotlin/com/flipcash/services/chat/GroupContentCryptoTest.kt rename to services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/chat/GroupContentCryptoTest.kt diff --git a/services/flipcash/src/test/kotlin/com/flipcash/services/chat/GroupKeyEnvelopesTest.kt b/services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/chat/GroupKeyEnvelopesTest.kt similarity index 100% rename from services/flipcash/src/test/kotlin/com/flipcash/services/chat/GroupKeyEnvelopesTest.kt rename to services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/chat/GroupKeyEnvelopesTest.kt diff --git a/services/flipcash/src/test/kotlin/com/flipcash/services/controllers/BlobStorageControllerChatMediaTest.kt b/services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/controllers/BlobStorageControllerChatMediaTest.kt similarity index 100% rename from services/flipcash/src/test/kotlin/com/flipcash/services/controllers/BlobStorageControllerChatMediaTest.kt rename to services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/controllers/BlobStorageControllerChatMediaTest.kt diff --git a/services/flipcash/src/test/kotlin/com/flipcash/services/controllers/BlobStorageControllerTest.kt b/services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/controllers/BlobStorageControllerTest.kt similarity index 100% rename from services/flipcash/src/test/kotlin/com/flipcash/services/controllers/BlobStorageControllerTest.kt rename to services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/controllers/BlobStorageControllerTest.kt diff --git a/services/flipcash/src/test/kotlin/com/flipcash/services/controllers/ChatControllerTest.kt b/services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/controllers/ChatControllerTest.kt similarity index 100% rename from services/flipcash/src/test/kotlin/com/flipcash/services/controllers/ChatControllerTest.kt rename to services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/controllers/ChatControllerTest.kt diff --git a/services/flipcash/src/test/kotlin/com/flipcash/services/controllers/ChatMessagingControllerTest.kt b/services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/controllers/ChatMessagingControllerTest.kt similarity index 100% rename from services/flipcash/src/test/kotlin/com/flipcash/services/controllers/ChatMessagingControllerTest.kt rename to services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/controllers/ChatMessagingControllerTest.kt diff --git a/services/flipcash/src/test/kotlin/com/flipcash/services/controllers/ContactVerificationControllerTest.kt b/services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/controllers/ContactVerificationControllerTest.kt similarity index 100% rename from services/flipcash/src/test/kotlin/com/flipcash/services/controllers/ContactVerificationControllerTest.kt rename to services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/controllers/ContactVerificationControllerTest.kt diff --git a/services/flipcash/src/test/kotlin/com/flipcash/services/controllers/EventStreamingControllerTest.kt b/services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/controllers/EventStreamingControllerTest.kt similarity index 100% rename from services/flipcash/src/test/kotlin/com/flipcash/services/controllers/EventStreamingControllerTest.kt rename to services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/controllers/EventStreamingControllerTest.kt diff --git a/services/flipcash/src/test/kotlin/com/flipcash/services/controllers/ProfileControllerTest.kt b/services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/controllers/ProfileControllerTest.kt similarity index 100% rename from services/flipcash/src/test/kotlin/com/flipcash/services/controllers/ProfileControllerTest.kt rename to services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/controllers/ProfileControllerTest.kt diff --git a/services/flipcash/src/test/kotlin/com/flipcash/services/internal/domain/ActivityFeedMessageMapperTest.kt b/services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/internal/domain/ActivityFeedMessageMapperTest.kt similarity index 100% rename from services/flipcash/src/test/kotlin/com/flipcash/services/internal/domain/ActivityFeedMessageMapperTest.kt rename to services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/internal/domain/ActivityFeedMessageMapperTest.kt diff --git a/services/flipcash/src/test/kotlin/com/flipcash/services/internal/domain/ChatMetadataMapperTest.kt b/services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/internal/domain/ChatMetadataMapperTest.kt similarity index 100% rename from services/flipcash/src/test/kotlin/com/flipcash/services/internal/domain/ChatMetadataMapperTest.kt rename to services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/internal/domain/ChatMetadataMapperTest.kt diff --git a/services/flipcash/src/test/kotlin/com/flipcash/services/internal/domain/SocialAccountMapperTest.kt b/services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/internal/domain/SocialAccountMapperTest.kt similarity index 100% rename from services/flipcash/src/test/kotlin/com/flipcash/services/internal/domain/SocialAccountMapperTest.kt rename to services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/internal/domain/SocialAccountMapperTest.kt diff --git a/services/flipcash/src/test/kotlin/com/flipcash/services/internal/domain/UserFlagsMapperTest.kt b/services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/internal/domain/UserFlagsMapperTest.kt similarity index 100% rename from services/flipcash/src/test/kotlin/com/flipcash/services/internal/domain/UserFlagsMapperTest.kt rename to services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/internal/domain/UserFlagsMapperTest.kt diff --git a/services/flipcash/src/test/kotlin/com/flipcash/services/internal/domain/UserProfileMapperTest.kt b/services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/internal/domain/UserProfileMapperTest.kt similarity index 100% rename from services/flipcash/src/test/kotlin/com/flipcash/services/internal/domain/UserProfileMapperTest.kt rename to services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/internal/domain/UserProfileMapperTest.kt diff --git a/services/flipcash/src/test/kotlin/com/flipcash/services/internal/extensions/JpegMetadataTest.kt b/services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/internal/extensions/JpegMetadataTest.kt similarity index 100% rename from services/flipcash/src/test/kotlin/com/flipcash/services/internal/extensions/JpegMetadataTest.kt rename to services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/internal/extensions/JpegMetadataTest.kt diff --git a/services/flipcash/src/test/kotlin/com/flipcash/services/internal/network/api/BlobAccessContextValidationTest.kt b/services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/internal/network/api/BlobAccessContextValidationTest.kt similarity index 100% rename from services/flipcash/src/test/kotlin/com/flipcash/services/internal/network/api/BlobAccessContextValidationTest.kt rename to services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/internal/network/api/BlobAccessContextValidationTest.kt diff --git a/services/flipcash/src/test/kotlin/com/flipcash/services/internal/network/api/BlobStorageApiDeadlineTest.kt b/services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/internal/network/api/BlobStorageApiDeadlineTest.kt similarity index 100% rename from services/flipcash/src/test/kotlin/com/flipcash/services/internal/network/api/BlobStorageApiDeadlineTest.kt rename to services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/internal/network/api/BlobStorageApiDeadlineTest.kt diff --git a/services/flipcash/src/test/kotlin/com/flipcash/services/internal/network/api/GetBlobsRequestSigningTest.kt b/services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/internal/network/api/GetBlobsRequestSigningTest.kt similarity index 100% rename from services/flipcash/src/test/kotlin/com/flipcash/services/internal/network/api/GetBlobsRequestSigningTest.kt rename to services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/internal/network/api/GetBlobsRequestSigningTest.kt diff --git a/services/flipcash/src/test/kotlin/com/flipcash/services/internal/network/extensions/CashContentMappingTest.kt b/services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/internal/network/extensions/CashContentMappingTest.kt similarity index 100% rename from services/flipcash/src/test/kotlin/com/flipcash/services/internal/network/extensions/CashContentMappingTest.kt rename to services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/internal/network/extensions/CashContentMappingTest.kt diff --git a/services/flipcash/src/test/kotlin/com/flipcash/services/internal/network/extensions/ChatMetadataExtensionTest.kt b/services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/internal/network/extensions/ChatMetadataExtensionTest.kt similarity index 100% rename from services/flipcash/src/test/kotlin/com/flipcash/services/internal/network/extensions/ChatMetadataExtensionTest.kt rename to services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/internal/network/extensions/ChatMetadataExtensionTest.kt diff --git a/services/flipcash/src/test/kotlin/com/flipcash/services/internal/network/extensions/ChatRulesProtoMappingTest.kt b/services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/internal/network/extensions/ChatRulesProtoMappingTest.kt similarity index 100% rename from services/flipcash/src/test/kotlin/com/flipcash/services/internal/network/extensions/ChatRulesProtoMappingTest.kt rename to services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/internal/network/extensions/ChatRulesProtoMappingTest.kt diff --git a/services/flipcash/src/test/kotlin/com/flipcash/services/internal/network/extensions/MediaContentMappingTest.kt b/services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/internal/network/extensions/MediaContentMappingTest.kt similarity index 100% rename from services/flipcash/src/test/kotlin/com/flipcash/services/internal/network/extensions/MediaContentMappingTest.kt rename to services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/internal/network/extensions/MediaContentMappingTest.kt diff --git a/services/flipcash/src/test/kotlin/com/flipcash/services/internal/network/extensions/MessageContentEncryptedMappingTest.kt b/services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/internal/network/extensions/MessageContentEncryptedMappingTest.kt similarity index 100% rename from services/flipcash/src/test/kotlin/com/flipcash/services/internal/network/extensions/MessageContentEncryptedMappingTest.kt rename to services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/internal/network/extensions/MessageContentEncryptedMappingTest.kt diff --git a/services/flipcash/src/test/kotlin/com/flipcash/services/internal/network/extensions/PushPayloadMuteMappingTest.kt b/services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/internal/network/extensions/PushPayloadMuteMappingTest.kt similarity index 100% rename from services/flipcash/src/test/kotlin/com/flipcash/services/internal/network/extensions/PushPayloadMuteMappingTest.kt rename to services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/internal/network/extensions/PushPayloadMuteMappingTest.kt diff --git a/services/flipcash/src/test/kotlin/com/flipcash/services/internal/network/extensions/RosterUpdateExtensionTest.kt b/services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/internal/network/extensions/RosterUpdateExtensionTest.kt similarity index 100% rename from services/flipcash/src/test/kotlin/com/flipcash/services/internal/network/extensions/RosterUpdateExtensionTest.kt rename to services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/internal/network/extensions/RosterUpdateExtensionTest.kt diff --git a/services/flipcash/src/test/kotlin/com/flipcash/services/internal/network/extensions/SystemContentMappingTest.kt b/services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/internal/network/extensions/SystemContentMappingTest.kt similarity index 100% rename from services/flipcash/src/test/kotlin/com/flipcash/services/internal/network/extensions/SystemContentMappingTest.kt rename to services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/internal/network/extensions/SystemContentMappingTest.kt diff --git a/services/flipcash/src/test/kotlin/com/flipcash/services/internal/network/extensions/WidgetAndNeverMappingTest.kt b/services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/internal/network/extensions/WidgetAndNeverMappingTest.kt similarity index 100% rename from services/flipcash/src/test/kotlin/com/flipcash/services/internal/network/extensions/WidgetAndNeverMappingTest.kt rename to services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/internal/network/extensions/WidgetAndNeverMappingTest.kt diff --git a/services/flipcash/src/test/kotlin/com/flipcash/services/internal/network/services/PhoneVerificationServiceTest.kt b/services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/internal/network/services/PhoneVerificationServiceTest.kt similarity index 100% rename from services/flipcash/src/test/kotlin/com/flipcash/services/internal/network/services/PhoneVerificationServiceTest.kt rename to services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/internal/network/services/PhoneVerificationServiceTest.kt diff --git a/services/flipcash/src/test/kotlin/com/flipcash/services/internal/proto/ProtoWireFormatTest.kt b/services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/internal/proto/ProtoWireFormatTest.kt similarity index 100% rename from services/flipcash/src/test/kotlin/com/flipcash/services/internal/proto/ProtoWireFormatTest.kt rename to services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/internal/proto/ProtoWireFormatTest.kt diff --git a/services/flipcash/src/test/kotlin/com/flipcash/services/models/DmPaymentMetadataTest.kt b/services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/models/DmPaymentMetadataTest.kt similarity index 100% rename from services/flipcash/src/test/kotlin/com/flipcash/services/models/DmPaymentMetadataTest.kt rename to services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/models/DmPaymentMetadataTest.kt diff --git a/services/flipcash/src/test/kotlin/com/flipcash/services/models/ErrorsTest.kt b/services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/models/ErrorsTest.kt similarity index 100% rename from services/flipcash/src/test/kotlin/com/flipcash/services/models/ErrorsTest.kt rename to services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/models/ErrorsTest.kt diff --git a/services/flipcash/src/test/kotlin/com/flipcash/services/models/HandleTest.kt b/services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/models/HandleTest.kt similarity index 100% rename from services/flipcash/src/test/kotlin/com/flipcash/services/models/HandleTest.kt rename to services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/models/HandleTest.kt diff --git a/services/flipcash/src/test/kotlin/com/flipcash/services/models/blob/UploadPolicyTest.kt b/services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/models/blob/UploadPolicyTest.kt similarity index 100% rename from services/flipcash/src/test/kotlin/com/flipcash/services/models/blob/UploadPolicyTest.kt rename to services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/models/blob/UploadPolicyTest.kt diff --git a/services/flipcash/src/test/kotlin/com/flipcash/services/models/chat/BlobExpiryTest.kt b/services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/models/chat/BlobExpiryTest.kt similarity index 100% rename from services/flipcash/src/test/kotlin/com/flipcash/services/models/chat/BlobExpiryTest.kt rename to services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/models/chat/BlobExpiryTest.kt diff --git a/services/flipcash/src/test/kotlin/com/flipcash/services/models/chat/BlobIdEqualityTest.kt b/services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/models/chat/BlobIdEqualityTest.kt similarity index 100% rename from services/flipcash/src/test/kotlin/com/flipcash/services/models/chat/BlobIdEqualityTest.kt rename to services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/models/chat/BlobIdEqualityTest.kt diff --git a/services/flipcash/src/test/kotlin/com/flipcash/services/models/chat/BlobIdSerializationTest.kt b/services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/models/chat/BlobIdSerializationTest.kt similarity index 100% rename from services/flipcash/src/test/kotlin/com/flipcash/services/models/chat/BlobIdSerializationTest.kt rename to services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/models/chat/BlobIdSerializationTest.kt diff --git a/services/flipcash/src/test/kotlin/com/flipcash/services/models/chat/ChatIdTest.kt b/services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/models/chat/ChatIdTest.kt similarity index 100% rename from services/flipcash/src/test/kotlin/com/flipcash/services/models/chat/ChatIdTest.kt rename to services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/models/chat/ChatIdTest.kt diff --git a/services/flipcash/src/test/kotlin/com/flipcash/services/models/chat/DmAddressabilityTest.kt b/services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/models/chat/DmAddressabilityTest.kt similarity index 100% rename from services/flipcash/src/test/kotlin/com/flipcash/services/models/chat/DmAddressabilityTest.kt rename to services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/models/chat/DmAddressabilityTest.kt diff --git a/services/flipcash/src/test/kotlin/com/flipcash/services/models/chat/DomainModelsTest.kt b/services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/models/chat/DomainModelsTest.kt similarity index 100% rename from services/flipcash/src/test/kotlin/com/flipcash/services/models/chat/DomainModelsTest.kt rename to services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/models/chat/DomainModelsTest.kt diff --git a/services/flipcash/src/test/kotlin/com/flipcash/services/models/chat/MediaItemTest.kt b/services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/models/chat/MediaItemTest.kt similarity index 100% rename from services/flipcash/src/test/kotlin/com/flipcash/services/models/chat/MediaItemTest.kt rename to services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/models/chat/MediaItemTest.kt diff --git a/services/flipcash/src/test/kotlin/com/flipcash/services/models/chat/MuteLapseTest.kt b/services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/models/chat/MuteLapseTest.kt similarity index 100% rename from services/flipcash/src/test/kotlin/com/flipcash/services/models/chat/MuteLapseTest.kt rename to services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/models/chat/MuteLapseTest.kt diff --git a/services/flipcash/src/test/kotlin/com/flipcash/services/user/AnalyticsIdentityTest.kt b/services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/user/AnalyticsIdentityTest.kt similarity index 100% rename from services/flipcash/src/test/kotlin/com/flipcash/services/user/AnalyticsIdentityTest.kt rename to services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/user/AnalyticsIdentityTest.kt diff --git a/services/flipcash/src/test/kotlin/com/flipcash/services/user/UserManagerTest.kt b/services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/user/UserManagerTest.kt similarity index 96% rename from services/flipcash/src/test/kotlin/com/flipcash/services/user/UserManagerTest.kt rename to services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/user/UserManagerTest.kt index 8fa1dd64f5..fde805c379 100644 --- a/services/flipcash/src/test/kotlin/com/flipcash/services/user/UserManagerTest.kt +++ b/services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/user/UserManagerTest.kt @@ -10,7 +10,6 @@ import com.getcode.opencode.model.financial.usdf import com.getcode.opencode.utils.generate import com.getcode.solana.keys.PublicKey import com.hoc081098.channeleventbus.ChannelEventBus -import com.mixpanel.android.mpmetrics.MixpanelAPI import io.mockk.clearMocks import io.mockk.every import io.mockk.mockk @@ -28,7 +27,7 @@ import kotlin.test.assertNull class UserManagerTest { private val mnemonicManager: MnemonicManager = mockk(relaxed = true) - private val mixpanelAPI: MixpanelAPI = mockk(relaxed = true) + private val analyticsIdentifier: AnalyticsIdentifier = mockk(relaxed = true) private val eventBus: ChannelEventBus = mockk(relaxed = true) private val accountController: AccountController = mockk(relaxed = true) @@ -58,7 +57,7 @@ class UserManagerTest { private fun createUserManager() = UserManager( mnemonicManager = mnemonicManager, - mixpanelAPI = mixpanelAPI, + analyticsIdentifier = analyticsIdentifier, eventBus = eventBus, accountController = accountController, ) diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/ForegroundGate.kt b/services/flipcash/src/androidMain/kotlin/com/flipcash/services/ProcessForegroundGate.kt similarity index 64% rename from services/flipcash/src/main/kotlin/com/flipcash/services/ForegroundGate.kt rename to services/flipcash/src/androidMain/kotlin/com/flipcash/services/ProcessForegroundGate.kt index c6256c461c..23afd99b8a 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/ForegroundGate.kt +++ b/services/flipcash/src/androidMain/kotlin/com/flipcash/services/ProcessForegroundGate.kt @@ -8,16 +8,6 @@ import kotlinx.coroutines.withContext import javax.inject.Inject import javax.inject.Singleton -/** - * Whether the app is in the foreground. Work whose deadline should count foreground time only - * (chat media finalization) waits on [awaitForeground] before each step, so a backgrounded app - * neither burns its budget nor polls from a process the OS may be about to freeze. - */ -fun interface ForegroundGate { - /** Returns immediately when the app is foregrounded, otherwise suspends until it is. */ - suspend fun awaitForeground() -} - /** [ForegroundGate] backed by [ProcessLifecycleOwner]: foreground means at least STARTED. */ @Singleton internal class ProcessForegroundGate @Inject constructor() : ForegroundGate { diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/controllers/ModerationController.kt b/services/flipcash/src/androidMain/kotlin/com/flipcash/services/controllers/ModerationController.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/controllers/ModerationController.kt rename to services/flipcash/src/androidMain/kotlin/com/flipcash/services/controllers/ModerationController.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/controllers/PushController.kt b/services/flipcash/src/androidMain/kotlin/com/flipcash/services/controllers/PushController.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/controllers/PushController.kt rename to services/flipcash/src/androidMain/kotlin/com/flipcash/services/controllers/PushController.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/inject/FlipcashModule.kt b/services/flipcash/src/androidMain/kotlin/com/flipcash/services/inject/FlipcashModule.kt similarity index 97% rename from services/flipcash/src/main/kotlin/com/flipcash/services/inject/FlipcashModule.kt rename to services/flipcash/src/androidMain/kotlin/com/flipcash/services/inject/FlipcashModule.kt index 1daeefddf9..e45cd2ff18 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/inject/FlipcashModule.kt +++ b/services/flipcash/src/androidMain/kotlin/com/flipcash/services/inject/FlipcashModule.kt @@ -1,6 +1,8 @@ package com.flipcash.services.inject import android.content.Context +import com.flipcash.services.user.AnalyticsIdentifier +import com.mixpanel.android.mpmetrics.MixpanelAPI import com.flipcash.services.internal.annotations.FlipcashManagedChannel import com.flipcash.services.internal.annotations.FlipcashManagedStreamingChannel import com.flipcash.services.internal.annotations.FlipcashProtocol @@ -94,6 +96,10 @@ import javax.inject.Singleton @Module @InstallIn(SingletonComponent::class) internal object FlipcashModule { + @Provides + fun provideAnalyticsIdentifier(mixpanelAPI: MixpanelAPI): AnalyticsIdentifier = + AnalyticsIdentifier { mixpanelAPI.identify(it) } + @Singleton @FlipcashProtocol @Provides diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/extensions/Installations.kt b/services/flipcash/src/androidMain/kotlin/com/flipcash/services/internal/extensions/Installations.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/extensions/Installations.kt rename to services/flipcash/src/androidMain/kotlin/com/flipcash/services/internal/extensions/Installations.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/BlobUploader.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/BlobUploader.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/BlobUploader.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/BlobUploader.kt diff --git a/services/flipcash/src/commonMain/kotlin/com/flipcash/services/ForegroundGate.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/ForegroundGate.kt new file mode 100644 index 0000000000..e0fb571324 --- /dev/null +++ b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/ForegroundGate.kt @@ -0,0 +1,11 @@ +package com.flipcash.services + +/** + * Whether the app is in the foreground. Work whose deadline should count foreground time only + * (chat media finalization) waits on [awaitForeground] before each step, so a backgrounded app + * neither burns its budget nor polls from a process the OS may be about to freeze. + */ +fun interface ForegroundGate { + /** Returns immediately when the app is foregrounded, otherwise suspends until it is. */ + suspend fun awaitForeground() +} diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/chat/ChatContentCrypto.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/chat/ChatContentCrypto.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/chat/ChatContentCrypto.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/chat/ChatContentCrypto.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/chat/ChatKeySource.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/chat/ChatKeySource.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/chat/ChatKeySource.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/chat/ChatKeySource.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/chat/E2eePolicy.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/chat/E2eePolicy.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/chat/E2eePolicy.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/chat/E2eePolicy.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/chat/GroupContentCrypto.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/chat/GroupContentCrypto.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/chat/GroupContentCrypto.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/chat/GroupContentCrypto.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/chat/GroupKeyEnvelopes.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/chat/GroupKeyEnvelopes.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/chat/GroupKeyEnvelopes.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/chat/GroupKeyEnvelopes.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/chat/MessageEncryption.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/chat/MessageEncryption.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/chat/MessageEncryption.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/chat/MessageEncryption.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/chat/SealedMedia.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/chat/SealedMedia.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/chat/SealedMedia.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/chat/SealedMedia.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/controllers/AccountController.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/controllers/AccountController.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/controllers/AccountController.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/controllers/AccountController.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/controllers/ActivityFeedController.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/controllers/ActivityFeedController.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/controllers/ActivityFeedController.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/controllers/ActivityFeedController.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/controllers/BlobStorageController.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/controllers/BlobStorageController.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/controllers/BlobStorageController.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/controllers/BlobStorageController.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/controllers/BlocklistController.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/controllers/BlocklistController.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/controllers/BlocklistController.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/controllers/BlocklistController.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/controllers/ChatController.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/controllers/ChatController.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/controllers/ChatController.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/controllers/ChatController.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/controllers/ChatMessagingController.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/controllers/ChatMessagingController.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/controllers/ChatMessagingController.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/controllers/ChatMessagingController.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/controllers/CommunityController.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/controllers/CommunityController.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/controllers/CommunityController.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/controllers/CommunityController.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/controllers/ContactListController.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/controllers/ContactListController.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/controllers/ContactListController.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/controllers/ContactListController.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/controllers/ContactVerificationController.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/controllers/ContactVerificationController.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/controllers/ContactVerificationController.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/controllers/ContactVerificationController.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/controllers/EventStreamingController.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/controllers/EventStreamingController.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/controllers/EventStreamingController.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/controllers/EventStreamingController.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/controllers/PollController.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/controllers/PollController.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/controllers/PollController.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/controllers/PollController.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/controllers/ProfileController.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/controllers/ProfileController.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/controllers/ProfileController.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/controllers/ProfileController.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/controllers/PurchaseController.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/controllers/PurchaseController.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/controllers/PurchaseController.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/controllers/PurchaseController.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/controllers/ReportingController.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/controllers/ReportingController.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/controllers/ReportingController.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/controllers/ReportingController.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/controllers/ResolverController.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/controllers/ResolverController.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/controllers/ResolverController.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/controllers/ResolverController.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/controllers/SettingsController.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/controllers/SettingsController.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/controllers/SettingsController.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/controllers/SettingsController.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/controllers/ThirdPartyController.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/controllers/ThirdPartyController.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/controllers/ThirdPartyController.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/controllers/ThirdPartyController.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/extensions/KeyPair.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/extensions/KeyPair.kt similarity index 69% rename from services/flipcash/src/main/kotlin/com/flipcash/services/extensions/KeyPair.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/extensions/KeyPair.kt index 446d1e9c70..8b139b66b8 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/extensions/KeyPair.kt +++ b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/extensions/KeyPair.kt @@ -1,13 +1,10 @@ package com.flipcash.services.extensions -import android.util.Base64 import com.flipcash.services.internal.extensions.toPublicKey import com.getcode.crypt.Sha256Hash import com.getcode.ed25519kmp.Ed25519 -import com.getcode.ed25519kmp.Ed25519.KeyPair import com.getcode.opencode.model.core.ID import com.getcode.solana.keys.PublicKey -import com.getcode.solana.keys.Seed32 import java.io.ByteArrayOutputStream fun derivePoolBetId(poolId: ID, userId: ID): PublicKey { @@ -15,6 +12,6 @@ fun derivePoolBetId(poolId: ID, userId: ID): PublicKey { buffer.write(poolId.toByteArray()) buffer.write(userId.toByteArray()) val hash = Sha256Hash.hash(buffer.toByteArray()) - val seed = Base64.encodeToString(hash, Base64.DEFAULT) - return Ed25519.createKeyPair(seed).publicKeyBytes.toPublicKey() + // Same key as the former Base64.DEFAULT-encoded seed string. + return Ed25519.createKeyPair(hash).publicKeyBytes.toPublicKey() } \ No newline at end of file diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/inject/ChatCryptoModule.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/inject/ChatCryptoModule.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/inject/ChatCryptoModule.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/inject/ChatCryptoModule.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/annotations/FlipcashManagedChannel.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/annotations/FlipcashManagedChannel.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/annotations/FlipcashManagedChannel.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/annotations/FlipcashManagedChannel.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/annotations/FlipcashProtocol.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/annotations/FlipcashProtocol.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/annotations/FlipcashProtocol.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/annotations/FlipcashProtocol.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/domain/ActivityFeedMessageMapper.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/domain/ActivityFeedMessageMapper.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/domain/ActivityFeedMessageMapper.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/domain/ActivityFeedMessageMapper.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/domain/BlockedUserMapper.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/domain/BlockedUserMapper.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/domain/BlockedUserMapper.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/domain/BlockedUserMapper.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/domain/ChatMetadataMapper.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/domain/ChatMetadataMapper.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/domain/ChatMetadataMapper.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/domain/ChatMetadataMapper.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/domain/ContactMapper.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/domain/ContactMapper.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/domain/ContactMapper.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/domain/ContactMapper.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/domain/ImageModerationResponseMapper.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/domain/ImageModerationResponseMapper.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/domain/ImageModerationResponseMapper.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/domain/ImageModerationResponseMapper.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/domain/ModerationAttestationMapper.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/domain/ModerationAttestationMapper.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/domain/ModerationAttestationMapper.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/domain/ModerationAttestationMapper.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/domain/SocialAccountMapper.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/domain/SocialAccountMapper.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/domain/SocialAccountMapper.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/domain/SocialAccountMapper.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/domain/TextModerationResponseMapper.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/domain/TextModerationResponseMapper.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/domain/TextModerationResponseMapper.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/domain/TextModerationResponseMapper.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/domain/UserFlagsMapper.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/domain/UserFlagsMapper.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/domain/UserFlagsMapper.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/domain/UserFlagsMapper.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/domain/UserProfileMapper.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/domain/UserProfileMapper.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/domain/UserProfileMapper.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/domain/UserProfileMapper.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/domain/mapper/Mapper.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/domain/mapper/Mapper.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/domain/mapper/Mapper.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/domain/mapper/Mapper.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/extensions/ByteArray.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/extensions/ByteArray.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/extensions/ByteArray.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/extensions/ByteArray.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/extensions/Instant.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/extensions/Instant.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/extensions/Instant.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/extensions/Instant.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/extensions/JpegMetadata.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/extensions/JpegMetadata.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/extensions/JpegMetadata.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/extensions/JpegMetadata.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/extensions/KeyPair.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/extensions/KeyPair.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/extensions/KeyPair.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/extensions/KeyPair.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/extensions/PublicKey.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/extensions/PublicKey.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/extensions/PublicKey.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/extensions/PublicKey.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/model/billing/IapMetadata.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/model/billing/IapMetadata.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/model/billing/IapMetadata.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/model/billing/IapMetadata.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/model/billing/Receipt.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/model/billing/Receipt.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/model/billing/Receipt.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/model/billing/Receipt.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/model/moderation/ModerationRequest.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/model/moderation/ModerationRequest.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/model/moderation/ModerationRequest.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/model/moderation/ModerationRequest.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/model/thirdparty/OnRampProvider.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/model/thirdparty/OnRampProvider.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/model/thirdparty/OnRampProvider.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/model/thirdparty/OnRampProvider.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/model/thirdparty/UsdcLiquidtyPool.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/model/thirdparty/UsdcLiquidtyPool.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/model/thirdparty/UsdcLiquidtyPool.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/model/thirdparty/UsdcLiquidtyPool.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/HttpBlobUploader.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/HttpBlobUploader.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/HttpBlobUploader.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/HttpBlobUploader.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/AccountApi.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/api/AccountApi.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/AccountApi.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/api/AccountApi.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/ActivityFeedApi.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/api/ActivityFeedApi.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/ActivityFeedApi.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/api/ActivityFeedApi.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/BlobStorageApi.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/api/BlobStorageApi.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/BlobStorageApi.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/api/BlobStorageApi.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/BlocklistApi.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/api/BlocklistApi.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/BlocklistApi.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/api/BlocklistApi.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/ChatApi.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/api/ChatApi.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/ChatApi.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/api/ChatApi.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/ChatMessagingApi.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/api/ChatMessagingApi.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/ChatMessagingApi.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/api/ChatMessagingApi.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/CommunityApi.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/api/CommunityApi.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/CommunityApi.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/api/CommunityApi.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/ContactListApi.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/api/ContactListApi.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/ContactListApi.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/api/ContactListApi.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/EmailVerificationApi.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/api/EmailVerificationApi.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/EmailVerificationApi.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/api/EmailVerificationApi.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/EventStreamingApi.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/api/EventStreamingApi.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/EventStreamingApi.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/api/EventStreamingApi.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/ModerationApi.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/api/ModerationApi.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/ModerationApi.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/api/ModerationApi.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/PhoneVerificationApi.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/api/PhoneVerificationApi.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/PhoneVerificationApi.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/api/PhoneVerificationApi.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/PollApi.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/api/PollApi.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/PollApi.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/api/PollApi.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/ProfileApi.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/api/ProfileApi.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/ProfileApi.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/api/ProfileApi.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/PurchaseApi.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/api/PurchaseApi.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/PurchaseApi.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/api/PurchaseApi.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/PushApi.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/api/PushApi.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/PushApi.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/api/PushApi.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/ReportingApi.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/api/ReportingApi.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/ReportingApi.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/api/ReportingApi.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/ResolverApi.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/api/ResolverApi.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/ResolverApi.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/api/ResolverApi.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/SettingsApi.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/api/SettingsApi.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/SettingsApi.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/api/SettingsApi.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/ThirdPartyApi.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/api/ThirdPartyApi.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/ThirdPartyApi.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/api/ThirdPartyApi.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/extensions/AuthenticateMessage.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/extensions/AuthenticateMessage.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/extensions/AuthenticateMessage.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/extensions/AuthenticateMessage.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/extensions/LocalToProtobuf.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/extensions/LocalToProtobuf.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/extensions/LocalToProtobuf.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/extensions/LocalToProtobuf.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/extensions/ProtobufToLocal.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/extensions/ProtobufToLocal.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/extensions/ProtobufToLocal.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/extensions/ProtobufToLocal.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/extensions/SignMessage.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/extensions/SignMessage.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/extensions/SignMessage.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/extensions/SignMessage.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/AccountService.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/services/AccountService.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/AccountService.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/services/AccountService.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/ActivityFeedService.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/services/ActivityFeedService.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/ActivityFeedService.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/services/ActivityFeedService.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/BlobStorageService.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/services/BlobStorageService.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/BlobStorageService.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/services/BlobStorageService.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/BlocklistService.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/services/BlocklistService.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/BlocklistService.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/services/BlocklistService.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/ChatMessagingService.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/services/ChatMessagingService.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/ChatMessagingService.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/services/ChatMessagingService.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/ChatService.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/services/ChatService.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/ChatService.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/services/ChatService.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/CommunityService.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/services/CommunityService.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/CommunityService.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/services/CommunityService.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/ContactListService.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/services/ContactListService.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/ContactListService.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/services/ContactListService.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/EmailVerificationService.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/services/EmailVerificationService.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/EmailVerificationService.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/services/EmailVerificationService.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/EventStreamingService.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/services/EventStreamingService.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/EventStreamingService.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/services/EventStreamingService.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/ModerationService.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/services/ModerationService.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/ModerationService.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/services/ModerationService.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/PhoneVerificationService.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/services/PhoneVerificationService.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/PhoneVerificationService.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/services/PhoneVerificationService.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/PollService.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/services/PollService.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/PollService.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/services/PollService.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/ProfileService.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/services/ProfileService.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/ProfileService.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/services/ProfileService.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/PurchaseService.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/services/PurchaseService.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/PurchaseService.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/services/PurchaseService.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/PushService.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/services/PushService.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/PushService.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/services/PushService.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/ReportingService.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/services/ReportingService.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/ReportingService.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/services/ReportingService.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/ResolverService.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/services/ResolverService.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/ResolverService.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/services/ResolverService.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/SettingsService.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/services/SettingsService.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/SettingsService.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/services/SettingsService.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/ThirdPartyService.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/services/ThirdPartyService.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/ThirdPartyService.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/services/ThirdPartyService.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalAccountRepository.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/repositories/InternalAccountRepository.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalAccountRepository.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/repositories/InternalAccountRepository.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalActivityFeedRepository.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/repositories/InternalActivityFeedRepository.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalActivityFeedRepository.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/repositories/InternalActivityFeedRepository.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalBlobStorageRepository.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/repositories/InternalBlobStorageRepository.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalBlobStorageRepository.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/repositories/InternalBlobStorageRepository.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalBlocklistRepository.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/repositories/InternalBlocklistRepository.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalBlocklistRepository.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/repositories/InternalBlocklistRepository.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalChatMessagingRepository.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/repositories/InternalChatMessagingRepository.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalChatMessagingRepository.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/repositories/InternalChatMessagingRepository.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalChatRepository.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/repositories/InternalChatRepository.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalChatRepository.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/repositories/InternalChatRepository.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalCommunityRepository.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/repositories/InternalCommunityRepository.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalCommunityRepository.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/repositories/InternalCommunityRepository.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalContactListRepository.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/repositories/InternalContactListRepository.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalContactListRepository.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/repositories/InternalContactListRepository.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalContactVerificationRepository.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/repositories/InternalContactVerificationRepository.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalContactVerificationRepository.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/repositories/InternalContactVerificationRepository.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalEventStreamingRepository.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/repositories/InternalEventStreamingRepository.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalEventStreamingRepository.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/repositories/InternalEventStreamingRepository.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalModerationRepository.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/repositories/InternalModerationRepository.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalModerationRepository.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/repositories/InternalModerationRepository.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalPollRepository.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/repositories/InternalPollRepository.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalPollRepository.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/repositories/InternalPollRepository.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalProfileRepository.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/repositories/InternalProfileRepository.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalProfileRepository.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/repositories/InternalProfileRepository.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalPurchaseRepository.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/repositories/InternalPurchaseRepository.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalPurchaseRepository.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/repositories/InternalPurchaseRepository.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalPushRepository.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/repositories/InternalPushRepository.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalPushRepository.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/repositories/InternalPushRepository.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalReportingRepository.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/repositories/InternalReportingRepository.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalReportingRepository.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/repositories/InternalReportingRepository.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalResolverRepository.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/repositories/InternalResolverRepository.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalResolverRepository.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/repositories/InternalResolverRepository.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalSettingsRepository.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/repositories/InternalSettingsRepository.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalSettingsRepository.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/repositories/InternalSettingsRepository.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalThirdPartyRepository.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/repositories/InternalThirdPartyRepository.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalThirdPartyRepository.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/repositories/InternalThirdPartyRepository.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/modals/ModalManager.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/modals/ModalManager.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/modals/ModalManager.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/modals/ModalManager.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/ActivityFeedNotification.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/ActivityFeedNotification.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/ActivityFeedNotification.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/ActivityFeedNotification.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/ActivityFeedType.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/ActivityFeedType.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/ActivityFeedType.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/ActivityFeedType.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/BlockedUser.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/BlockedUser.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/BlockedUser.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/BlockedUser.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/Community.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/Community.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/Community.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/Community.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/ContactMethod.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/ContactMethod.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/ContactMethod.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/ContactMethod.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/DmPaymentMetadata.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/DmPaymentMetadata.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/DmPaymentMetadata.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/DmPaymentMetadata.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/Errors.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/Errors.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/Errors.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/Errors.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/FlipcashContactEntry.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/FlipcashContactEntry.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/FlipcashContactEntry.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/FlipcashContactEntry.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/Handle.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/Handle.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/Handle.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/Handle.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/Jwt.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/Jwt.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/Jwt.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/Jwt.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/ModerationResult.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/ModerationResult.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/ModerationResult.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/ModerationResult.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/NotificationPayload.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/NotificationPayload.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/NotificationPayload.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/NotificationPayload.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/ProfileIdentifier.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/ProfileIdentifier.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/ProfileIdentifier.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/ProfileIdentifier.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/QueryOptions.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/QueryOptions.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/QueryOptions.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/QueryOptions.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/ReactionBoostMetadata.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/ReactionBoostMetadata.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/ReactionBoostMetadata.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/ReactionBoostMetadata.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/ReportTarget.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/ReportTarget.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/ReportTarget.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/ReportTarget.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/ResolveIdentifier.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/ResolveIdentifier.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/ResolveIdentifier.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/ResolveIdentifier.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/SocialAccountLinking.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/SocialAccountLinking.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/SocialAccountLinking.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/SocialAccountLinking.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/TipPresets.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/TipPresets.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/TipPresets.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/TipPresets.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/UserFlags.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/UserFlags.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/UserFlags.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/UserFlags.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/UserProfile.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/UserProfile.kt similarity index 97% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/UserProfile.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/UserProfile.kt index a136ddb90e..055704e556 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/models/UserProfile.kt +++ b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/UserProfile.kt @@ -1,10 +1,10 @@ package com.flipcash.services.models -import android.os.Parcelable +import com.getcode.libs.parcelable.Parcelable import com.flipcash.services.models.chat.MediaItem import com.getcode.opencode.model.core.ID import com.getcode.opencode.model.financial.Fiat -import kotlinx.parcelize.Parcelize +import com.getcode.libs.parcelable.Parcelize import kotlinx.serialization.Serializable import kotlin.time.Instant diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/VerifiableContactMethod.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/VerifiableContactMethod.kt similarity index 83% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/VerifiableContactMethod.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/VerifiableContactMethod.kt index fcbf85dad4..4c481fa6d3 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/models/VerifiableContactMethod.kt +++ b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/VerifiableContactMethod.kt @@ -1,7 +1,7 @@ package com.flipcash.services.models -import android.os.Parcelable -import kotlinx.parcelize.Parcelize +import com.getcode.libs.parcelable.Parcelable +import com.getcode.libs.parcelable.Parcelize import kotlinx.serialization.Serializable /** diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/blob/UploadPolicy.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/blob/UploadPolicy.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/blob/UploadPolicy.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/blob/UploadPolicy.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/blob/UploadTarget.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/blob/UploadTarget.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/blob/UploadTarget.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/blob/UploadTarget.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/BlobAccessContext.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/BlobAccessContext.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/BlobAccessContext.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/BlobAccessContext.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/BlobId.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/BlobId.kt similarity index 96% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/BlobId.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/BlobId.kt index 4e33312965..ff0ee4912c 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/BlobId.kt +++ b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/BlobId.kt @@ -1,7 +1,7 @@ package com.flipcash.services.models.chat -import android.os.Parcelable -import kotlinx.parcelize.Parcelize +import com.getcode.libs.parcelable.Parcelable +import com.getcode.libs.parcelable.Parcelize import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.KSerializer import kotlinx.serialization.Serializable diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/BlobMetadata.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/BlobMetadata.kt similarity index 95% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/BlobMetadata.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/BlobMetadata.kt index e8c716ed51..bc78eea3a9 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/BlobMetadata.kt +++ b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/BlobMetadata.kt @@ -1,10 +1,10 @@ package com.flipcash.services.models.chat -import android.os.Parcelable +import com.getcode.libs.parcelable.Parcelable import kotlin.time.Duration import kotlin.time.Duration.Companion.seconds import kotlin.time.Instant -import kotlinx.parcelize.Parcelize +import com.getcode.libs.parcelable.Parcelize import kotlinx.serialization.Serializable @Parcelize diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/BlobUpdate.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/BlobUpdate.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/BlobUpdate.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/BlobUpdate.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/ChatEvent.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/ChatEvent.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/ChatEvent.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/ChatEvent.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/ChatFeedPage.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/ChatFeedPage.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/ChatFeedPage.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/ChatFeedPage.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/ChatId.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/ChatId.kt similarity index 82% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/ChatId.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/ChatId.kt index c8e5fb00d8..6627b85909 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/ChatId.kt +++ b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/ChatId.kt @@ -1,7 +1,8 @@ package com.flipcash.services.models.chat -import android.os.Parcel -import android.os.Parcelable +import com.getcode.libs.parcelable.ManualParcelable +import com.getcode.libs.parcelable.Parcel +import com.getcode.libs.parcelable.parcelableCreator import com.getcode.utils.base58 import kotlinx.serialization.KSerializer import kotlinx.serialization.Serializable @@ -26,7 +27,7 @@ object ChatIdAsHexSerializer : KSerializer { } @Serializable(with = ChatIdAsHexSerializer::class) -data class ChatId(val bytes: ByteArray) : Parcelable { +data class ChatId(val bytes: ByteArray) : ManualParcelable { constructor(bytes: List): this(bytes.toByteArray()) @OptIn(ExperimentalStdlibApi::class) @@ -53,10 +54,6 @@ data class ChatId(val bytes: ByteArray) : Parcelable { companion object { @JvmField - val CREATOR: Parcelable.Creator = - object : Parcelable.Creator { - override fun createFromParcel(parcel: Parcel) = ChatId(parcel) - override fun newArray(size: Int) = arrayOfNulls(size) - } + val CREATOR: Any = parcelableCreator({ arrayOfNulls(it) }) { parcel -> ChatId(parcel) } } } diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/ChatMember.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/ChatMember.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/ChatMember.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/ChatMember.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/ChatMessage.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/ChatMessage.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/ChatMessage.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/ChatMessage.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/ChatMetadata.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/ChatMetadata.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/ChatMetadata.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/ChatMetadata.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/ChatMutation.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/ChatMutation.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/ChatMutation.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/ChatMutation.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/ChatRules.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/ChatRules.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/ChatRules.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/ChatRules.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/ChatType.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/ChatType.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/ChatType.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/ChatType.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/ChatUpdate.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/ChatUpdate.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/ChatUpdate.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/ChatUpdate.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/ClientMessageId.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/ClientMessageId.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/ClientMessageId.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/ClientMessageId.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/DeliveryStatus.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/DeliveryStatus.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/DeliveryStatus.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/DeliveryStatus.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/DmAddressability.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/DmAddressability.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/DmAddressability.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/DmAddressability.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/EditChatParameters.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/EditChatParameters.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/EditChatParameters.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/EditChatParameters.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/Emoji.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/Emoji.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/Emoji.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/Emoji.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/EmojiReaction.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/EmojiReaction.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/EmojiReaction.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/EmojiReaction.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/HoldingsSummary.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/HoldingsSummary.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/HoldingsSummary.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/HoldingsSummary.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/IdempotencyKey.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/IdempotencyKey.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/IdempotencyKey.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/IdempotencyKey.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/ImageMetadata.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/ImageMetadata.kt similarity index 70% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/ImageMetadata.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/ImageMetadata.kt index 56b0ba1771..5b6a99e17a 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/ImageMetadata.kt +++ b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/ImageMetadata.kt @@ -1,7 +1,7 @@ package com.flipcash.services.models.chat -import android.os.Parcelable -import kotlinx.parcelize.Parcelize +import com.getcode.libs.parcelable.Parcelable +import com.getcode.libs.parcelable.Parcelize import kotlinx.serialization.Serializable @Parcelize diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/KeyEnvelope.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/KeyEnvelope.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/KeyEnvelope.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/KeyEnvelope.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/LinkPreview.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/LinkPreview.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/LinkPreview.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/LinkPreview.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/Lobby.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/Lobby.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/Lobby.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/Lobby.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/MediaItem.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/MediaItem.kt similarity index 98% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/MediaItem.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/MediaItem.kt index 105ce557a3..83801dc5eb 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/MediaItem.kt +++ b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/MediaItem.kt @@ -1,8 +1,8 @@ package com.flipcash.services.models.chat -import android.os.Parcelable +import com.getcode.libs.parcelable.Parcelable import kotlin.time.Instant -import kotlinx.parcelize.Parcelize +import com.getcode.libs.parcelable.Parcelize import kotlinx.serialization.Serializable @Parcelize diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/MediaItemRendition.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/MediaItemRendition.kt similarity index 92% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/MediaItemRendition.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/MediaItemRendition.kt index 00ee018398..d9cedba26d 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/MediaItemRendition.kt +++ b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/MediaItemRendition.kt @@ -1,9 +1,9 @@ package com.flipcash.services.models.chat -import android.os.Parcelable +import com.getcode.libs.parcelable.Parcelable import com.getcode.utils.base58 import kotlin.time.Instant -import kotlinx.parcelize.Parcelize +import com.getcode.libs.parcelable.Parcelize import kotlinx.serialization.Serializable @Parcelize diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/MentionSuggestion.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/MentionSuggestion.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/MentionSuggestion.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/MentionSuggestion.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/MessageContent.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/MessageContent.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/MessageContent.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/MessageContent.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/MessagePointer.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/MessagePointer.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/MessagePointer.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/MessagePointer.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/MetadataUpdate.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/MetadataUpdate.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/MetadataUpdate.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/MetadataUpdate.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/MuteExtensions.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/MuteExtensions.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/MuteExtensions.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/MuteExtensions.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/MuteState.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/MuteState.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/MuteState.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/MuteState.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/ReactionSummary.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/ReactionSummary.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/ReactionSummary.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/ReactionSummary.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/ReactionUpdate.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/ReactionUpdate.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/ReactionUpdate.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/ReactionUpdate.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/Reactor.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/Reactor.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/Reactor.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/Reactor.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/RosterChange.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/RosterChange.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/RosterChange.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/RosterChange.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/RosterPage.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/RosterPage.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/RosterPage.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/RosterPage.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/RosterSummary.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/RosterSummary.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/RosterSummary.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/RosterSummary.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/SampledChatter.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/SampledChatter.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/SampledChatter.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/SampledChatter.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/StartChatParameters.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/StartChatParameters.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/StartChatParameters.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/StartChatParameters.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/TypingNotification.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/TypingNotification.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/TypingNotification.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/TypingNotification.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/ViewMode.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/ViewMode.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/ViewMode.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/ViewMode.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/ViewerState.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/ViewerState.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/ViewerState.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/ViewerState.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/WidgetContent.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/WidgetContent.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/WidgetContent.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/WidgetContent.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/persistence/DataSource.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/persistence/DataSource.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/persistence/DataSource.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/persistence/DataSource.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/AccountRepository.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/repository/AccountRepository.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/repository/AccountRepository.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/repository/AccountRepository.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/ActivityFeedRepository.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/repository/ActivityFeedRepository.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/repository/ActivityFeedRepository.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/repository/ActivityFeedRepository.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/BlobStorageRepository.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/repository/BlobStorageRepository.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/repository/BlobStorageRepository.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/repository/BlobStorageRepository.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/BlocklistRepository.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/repository/BlocklistRepository.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/repository/BlocklistRepository.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/repository/BlocklistRepository.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/ChatMessagingRepository.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/repository/ChatMessagingRepository.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/repository/ChatMessagingRepository.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/repository/ChatMessagingRepository.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/ChatRepository.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/repository/ChatRepository.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/repository/ChatRepository.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/repository/ChatRepository.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/CommunityRepository.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/repository/CommunityRepository.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/repository/CommunityRepository.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/repository/CommunityRepository.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/ContactListRepository.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/repository/ContactListRepository.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/repository/ContactListRepository.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/repository/ContactListRepository.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/ContactVerificationRepository.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/repository/ContactVerificationRepository.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/repository/ContactVerificationRepository.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/repository/ContactVerificationRepository.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/EventStreamingRepository.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/repository/EventStreamingRepository.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/repository/EventStreamingRepository.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/repository/EventStreamingRepository.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/ModerationRepository.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/repository/ModerationRepository.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/repository/ModerationRepository.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/repository/ModerationRepository.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/PollRepository.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/repository/PollRepository.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/repository/PollRepository.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/repository/PollRepository.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/ProfileRepository.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/repository/ProfileRepository.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/repository/ProfileRepository.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/repository/ProfileRepository.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/PurchaseRepository.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/repository/PurchaseRepository.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/repository/PurchaseRepository.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/repository/PurchaseRepository.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/PushRepository.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/repository/PushRepository.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/repository/PushRepository.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/repository/PushRepository.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/ReportingRepository.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/repository/ReportingRepository.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/repository/ReportingRepository.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/repository/ReportingRepository.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/ResolverRepository.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/repository/ResolverRepository.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/repository/ResolverRepository.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/repository/ResolverRepository.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/SettingsRepository.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/repository/SettingsRepository.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/repository/SettingsRepository.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/repository/SettingsRepository.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/ThirdPartyRepository.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/repository/ThirdPartyRepository.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/repository/ThirdPartyRepository.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/repository/ThirdPartyRepository.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/user/AnalyticsIdentity.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/user/AnalyticsIdentity.kt similarity index 74% rename from services/flipcash/src/main/kotlin/com/flipcash/services/user/AnalyticsIdentity.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/user/AnalyticsIdentity.kt index 5c94772ab2..c9ad4f9b0d 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/user/AnalyticsIdentity.kt +++ b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/user/AnalyticsIdentity.kt @@ -12,3 +12,8 @@ import com.getcode.opencode.model.core.ID */ @OptIn(ExperimentalStdlibApi::class) fun ID.analyticsDistinctId(): String = toByteArray().toHexString() + +/** Tells the analytics backend which account is signed in (Mixpanel's `identify` on Android). */ +fun interface AnalyticsIdentifier { + fun identify(distinctId: String?) +} diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/user/UserManager.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/user/UserManager.kt similarity index 98% rename from services/flipcash/src/main/kotlin/com/flipcash/services/user/UserManager.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/user/UserManager.kt index d733c0db35..260abee535 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/user/UserManager.kt +++ b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/user/UserManager.kt @@ -18,7 +18,6 @@ import com.getcode.opencode.model.financial.usdf import com.getcode.utils.TraceManager import com.getcode.utils.trace import com.hoc081098.channeleventbus.ChannelEventBus -import com.mixpanel.android.mpmetrics.MixpanelAPI import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow @@ -82,7 +81,7 @@ sealed interface AuthState { @Singleton class UserManager @Inject constructor( private val mnemonicManager: MnemonicManager, - private val mixpanelAPI: MixpanelAPI, + private val analyticsIdentifier: AnalyticsIdentifier, private val eventBus: ChannelEventBus, accountController: AccountController, ) { @@ -223,7 +222,7 @@ class UserManager @Inject constructor( // See AnalyticsIdentity.kt. val distinctId = accountId?.analyticsDistinctId() TraceManager.userId = distinctId - mixpanelAPI.identify(distinctId) + analyticsIdentifier.identify(distinctId) } } diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/validators/Validator.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/validators/Validator.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/validators/Validator.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/validators/Validator.kt diff --git a/services/flipcash/test-fixtures/build.gradle.kts b/services/flipcash/test-fixtures/build.gradle.kts new file mode 100644 index 0000000000..4ff5c24cc8 --- /dev/null +++ b/services/flipcash/test-fixtures/build.gradle.kts @@ -0,0 +1,16 @@ +plugins { + alias(libs.plugins.flipcash.kmp.app.library) +} + +kotlin { + android { + namespace = "${Gradle.codeNamespace}.services.flipcash.testfixtures" + } + + sourceSets { + commonMain.dependencies { + api(project(":services:flipcash")) + implementation(project(":libs:encryption:chat-cipher")) + } + } +} diff --git a/services/flipcash/src/testFixtures/kotlin/com/flipcash/services/chat/FakeChatCipher.kt b/services/flipcash/test-fixtures/src/commonMain/kotlin/com/flipcash/services/chat/FakeChatCipher.kt similarity index 100% rename from services/flipcash/src/testFixtures/kotlin/com/flipcash/services/chat/FakeChatCipher.kt rename to services/flipcash/test-fixtures/src/commonMain/kotlin/com/flipcash/services/chat/FakeChatCipher.kt diff --git a/settings.gradle.kts b/settings.gradle.kts index 9db5357f60..99cf20e5ba 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -254,6 +254,7 @@ include( ":services:opencode", ":services:opencode-compose", ":services:flipcash", + ":services:flipcash:test-fixtures", ":services:flipcash-compose", // common UI From 36386fa1046acab3026b19c2fd6d37108cad45a7 Mon Sep 17 00:00:00 2001 From: Brandon McAnsh Date: Fri, 23 Oct 2026 17:08:48 -0400 Subject: [PATCH 11/50] build(persistence): move the Room database to android+jvm KMP FlipcashDatabase, its DAOs, entities and migrations now live in commonMain. Migrations run on SQLiteConnection, MessageDao's raw query takes a RoomRawQuery, and init() takes a builder factory: Android passes Room.databaseBuilder(context), desktop opens a file through BundledSQLiteDriver. isOpen() stays Android-only, since Room exposes RoomDatabase.isOpen there alone. --- .../shared/chat/FullRefreshMembersTest.kt | 1 + .../shared/chat/RealChatArchiveStoreTest.kt | 1 + .../shared/persistence/db/build.gradle.kts | 61 +++++++---- .../persistence/ChatFeedUpsertClampTest.kt | 0 .../persistence/ChatMetadataCatchUpTest.kt | 0 .../persistence/EncryptedRowMigrationTest.kt | 0 .../persistence/FlipcashDatabaseInitTest.kt | 0 .../TransactionHistoryMigrationTest.kt | 0 .../persistence/UserProfileMigrationTest.kt | 3 +- .../converters/ChatTypeConvertersTest.kt | 0 .../converters/TokenTypeConvertersTest.kt | 0 .../app/persistence/dao/BlockedUserDaoTest.kt | 0 .../app/persistence/dao/ChatArchiveDaoTest.kt | 0 .../app/persistence/dao/ChatDraftDaoTest.kt | 0 .../app/persistence/dao/ChatMemberDaoTest.kt | 0 .../app/persistence/dao/ChatMessageDaoTest.kt | 0 .../dao/ChatMessageUpsertGuardTest.kt | 0 .../persistence/dao/ChatMetadataDaoTest.kt | 0 .../app/persistence/dao/ContactDaoTest.kt | 0 .../app/persistence/dao/LinkPreviewDaoTest.kt | 0 .../app/persistence/dao/MessageDaoTest.kt | 0 .../persistence/dao/PendingMediaDaoTest.kt | 0 .../app/persistence/dao/TokenDaoTest.kt | 0 .../persistence/dao/UnreadBelowBadgeTest.kt | 0 .../app/persistence/FlipcashDatabaseInit.kt | 11 ++ .../app/persistence/FlipcashDatabase.kt | 100 ++++++++++-------- .../app/persistence/UserProfileBackfill.kt | 0 .../converters/ChatTypeConverters.kt | 0 .../converters/TokenTypeConverters.kt | 0 .../app/persistence/dao/BlockedUserDao.kt | 0 .../app/persistence/dao/ChatArchiveDao.kt | 0 .../app/persistence/dao/ChatDraftDao.kt | 0 .../app/persistence/dao/ChatMemberDao.kt | 0 .../app/persistence/dao/ChatMessageDao.kt | 0 .../app/persistence/dao/ChatMetadataDao.kt | 0 .../app/persistence/dao/ContactDao.kt | 0 .../dao/CurrencyCreatorDraftDao.kt | 0 .../app/persistence/dao/LinkPreviewDao.kt | 0 .../app/persistence/dao/MessageDao.kt | 4 +- .../app/persistence/dao/PendingMediaDao.kt | 0 .../flipcash/app/persistence/dao/TokenDao.kt | 0 .../app/persistence/dao/UserProfileDao.kt | 0 .../embedded/LaunchpadMetadataEmbedded.kt | 0 .../embedded/VmMetadataEmbedded.kt | 0 .../persistence/entities/BlockedUserEntity.kt | 0 .../persistence/entities/ChatArchiveEntity.kt | 0 .../persistence/entities/ChatDraftEntity.kt | 0 .../persistence/entities/ChatMemberEntity.kt | 0 .../persistence/entities/ChatMessageEntity.kt | 0 .../entities/ChatMetadataEntity.kt | 0 .../entities/ContactMappingEntity.kt | 0 .../entities/ContactSyncStateEntity.kt | 0 .../entities/CurrencyCreatorDraftEntity.kt | 0 .../persistence/entities/LinkPreviewEntity.kt | 0 .../app/persistence/entities/MessageEntity.kt | 0 .../entities/PendingMediaEntity.kt | 0 .../persistence/entities/SocialLinkEntity.kt | 0 .../app/persistence/entities/TokenEntity.kt | 0 .../entities/TokenValuationEntity.kt | 0 .../persistence/entities/UserProfileEntity.kt | 0 .../entities/UserProfileEntityMapping.kt | 0 .../app/persistence/FlipcashDatabaseInit.kt | 15 +++ .../persistence/sources/MessageDataSource.kt | 4 +- .../sources/UnreadStreamReadinessTest.kt | 1 + .../sources/UserProfileDataSourceTest.kt | 1 + gradle/libs.versions.toml | 2 + 66 files changed, 131 insertions(+), 73 deletions(-) rename apps/flipcash/shared/persistence/db/src/{test => androidHostTest}/kotlin/com/flipcash/app/persistence/ChatFeedUpsertClampTest.kt (100%) rename apps/flipcash/shared/persistence/db/src/{test => androidHostTest}/kotlin/com/flipcash/app/persistence/ChatMetadataCatchUpTest.kt (100%) rename apps/flipcash/shared/persistence/db/src/{test => androidHostTest}/kotlin/com/flipcash/app/persistence/EncryptedRowMigrationTest.kt (100%) rename apps/flipcash/shared/persistence/db/src/{test => androidHostTest}/kotlin/com/flipcash/app/persistence/FlipcashDatabaseInitTest.kt (100%) rename apps/flipcash/shared/persistence/db/src/{test => androidHostTest}/kotlin/com/flipcash/app/persistence/TransactionHistoryMigrationTest.kt (100%) rename apps/flipcash/shared/persistence/db/src/{test => androidHostTest}/kotlin/com/flipcash/app/persistence/UserProfileMigrationTest.kt (98%) rename apps/flipcash/shared/persistence/db/src/{test => androidHostTest}/kotlin/com/flipcash/app/persistence/converters/ChatTypeConvertersTest.kt (100%) rename apps/flipcash/shared/persistence/db/src/{test => androidHostTest}/kotlin/com/flipcash/app/persistence/converters/TokenTypeConvertersTest.kt (100%) rename apps/flipcash/shared/persistence/db/src/{test => androidHostTest}/kotlin/com/flipcash/app/persistence/dao/BlockedUserDaoTest.kt (100%) rename apps/flipcash/shared/persistence/db/src/{test => androidHostTest}/kotlin/com/flipcash/app/persistence/dao/ChatArchiveDaoTest.kt (100%) rename apps/flipcash/shared/persistence/db/src/{test => androidHostTest}/kotlin/com/flipcash/app/persistence/dao/ChatDraftDaoTest.kt (100%) rename apps/flipcash/shared/persistence/db/src/{test => androidHostTest}/kotlin/com/flipcash/app/persistence/dao/ChatMemberDaoTest.kt (100%) rename apps/flipcash/shared/persistence/db/src/{test => androidHostTest}/kotlin/com/flipcash/app/persistence/dao/ChatMessageDaoTest.kt (100%) rename apps/flipcash/shared/persistence/db/src/{test => androidHostTest}/kotlin/com/flipcash/app/persistence/dao/ChatMessageUpsertGuardTest.kt (100%) rename apps/flipcash/shared/persistence/db/src/{test => androidHostTest}/kotlin/com/flipcash/app/persistence/dao/ChatMetadataDaoTest.kt (100%) rename apps/flipcash/shared/persistence/db/src/{test => androidHostTest}/kotlin/com/flipcash/app/persistence/dao/ContactDaoTest.kt (100%) rename apps/flipcash/shared/persistence/db/src/{test => androidHostTest}/kotlin/com/flipcash/app/persistence/dao/LinkPreviewDaoTest.kt (100%) rename apps/flipcash/shared/persistence/db/src/{test => androidHostTest}/kotlin/com/flipcash/app/persistence/dao/MessageDaoTest.kt (100%) rename apps/flipcash/shared/persistence/db/src/{test => androidHostTest}/kotlin/com/flipcash/app/persistence/dao/PendingMediaDaoTest.kt (100%) rename apps/flipcash/shared/persistence/db/src/{test => androidHostTest}/kotlin/com/flipcash/app/persistence/dao/TokenDaoTest.kt (100%) rename apps/flipcash/shared/persistence/db/src/{test => androidHostTest}/kotlin/com/flipcash/app/persistence/dao/UnreadBelowBadgeTest.kt (100%) create mode 100644 apps/flipcash/shared/persistence/db/src/androidMain/kotlin/com/flipcash/app/persistence/FlipcashDatabaseInit.kt rename apps/flipcash/shared/persistence/db/src/{main => commonMain}/kotlin/com/flipcash/app/persistence/FlipcashDatabase.kt (86%) rename apps/flipcash/shared/persistence/db/src/{main => commonMain}/kotlin/com/flipcash/app/persistence/UserProfileBackfill.kt (100%) rename apps/flipcash/shared/persistence/db/src/{main => commonMain}/kotlin/com/flipcash/app/persistence/converters/ChatTypeConverters.kt (100%) rename apps/flipcash/shared/persistence/db/src/{main => commonMain}/kotlin/com/flipcash/app/persistence/converters/TokenTypeConverters.kt (100%) rename apps/flipcash/shared/persistence/db/src/{main => commonMain}/kotlin/com/flipcash/app/persistence/dao/BlockedUserDao.kt (100%) rename apps/flipcash/shared/persistence/db/src/{main => commonMain}/kotlin/com/flipcash/app/persistence/dao/ChatArchiveDao.kt (100%) rename apps/flipcash/shared/persistence/db/src/{main => commonMain}/kotlin/com/flipcash/app/persistence/dao/ChatDraftDao.kt (100%) rename apps/flipcash/shared/persistence/db/src/{main => commonMain}/kotlin/com/flipcash/app/persistence/dao/ChatMemberDao.kt (100%) rename apps/flipcash/shared/persistence/db/src/{main => commonMain}/kotlin/com/flipcash/app/persistence/dao/ChatMessageDao.kt (100%) rename apps/flipcash/shared/persistence/db/src/{main => commonMain}/kotlin/com/flipcash/app/persistence/dao/ChatMetadataDao.kt (100%) rename apps/flipcash/shared/persistence/db/src/{main => commonMain}/kotlin/com/flipcash/app/persistence/dao/ContactDao.kt (100%) rename apps/flipcash/shared/persistence/db/src/{main => commonMain}/kotlin/com/flipcash/app/persistence/dao/CurrencyCreatorDraftDao.kt (100%) rename apps/flipcash/shared/persistence/db/src/{main => commonMain}/kotlin/com/flipcash/app/persistence/dao/LinkPreviewDao.kt (100%) rename apps/flipcash/shared/persistence/db/src/{main => commonMain}/kotlin/com/flipcash/app/persistence/dao/MessageDao.kt (97%) rename apps/flipcash/shared/persistence/db/src/{main => commonMain}/kotlin/com/flipcash/app/persistence/dao/PendingMediaDao.kt (100%) rename apps/flipcash/shared/persistence/db/src/{main => commonMain}/kotlin/com/flipcash/app/persistence/dao/TokenDao.kt (100%) rename apps/flipcash/shared/persistence/db/src/{main => commonMain}/kotlin/com/flipcash/app/persistence/dao/UserProfileDao.kt (100%) rename apps/flipcash/shared/persistence/db/src/{main => commonMain}/kotlin/com/flipcash/app/persistence/embedded/LaunchpadMetadataEmbedded.kt (100%) rename apps/flipcash/shared/persistence/db/src/{main => commonMain}/kotlin/com/flipcash/app/persistence/embedded/VmMetadataEmbedded.kt (100%) rename apps/flipcash/shared/persistence/db/src/{main => commonMain}/kotlin/com/flipcash/app/persistence/entities/BlockedUserEntity.kt (100%) rename apps/flipcash/shared/persistence/db/src/{main => commonMain}/kotlin/com/flipcash/app/persistence/entities/ChatArchiveEntity.kt (100%) rename apps/flipcash/shared/persistence/db/src/{main => commonMain}/kotlin/com/flipcash/app/persistence/entities/ChatDraftEntity.kt (100%) rename apps/flipcash/shared/persistence/db/src/{main => commonMain}/kotlin/com/flipcash/app/persistence/entities/ChatMemberEntity.kt (100%) rename apps/flipcash/shared/persistence/db/src/{main => commonMain}/kotlin/com/flipcash/app/persistence/entities/ChatMessageEntity.kt (100%) rename apps/flipcash/shared/persistence/db/src/{main => commonMain}/kotlin/com/flipcash/app/persistence/entities/ChatMetadataEntity.kt (100%) rename apps/flipcash/shared/persistence/db/src/{main => commonMain}/kotlin/com/flipcash/app/persistence/entities/ContactMappingEntity.kt (100%) rename apps/flipcash/shared/persistence/db/src/{main => commonMain}/kotlin/com/flipcash/app/persistence/entities/ContactSyncStateEntity.kt (100%) rename apps/flipcash/shared/persistence/db/src/{main => commonMain}/kotlin/com/flipcash/app/persistence/entities/CurrencyCreatorDraftEntity.kt (100%) rename apps/flipcash/shared/persistence/db/src/{main => commonMain}/kotlin/com/flipcash/app/persistence/entities/LinkPreviewEntity.kt (100%) rename apps/flipcash/shared/persistence/db/src/{main => commonMain}/kotlin/com/flipcash/app/persistence/entities/MessageEntity.kt (100%) rename apps/flipcash/shared/persistence/db/src/{main => commonMain}/kotlin/com/flipcash/app/persistence/entities/PendingMediaEntity.kt (100%) rename apps/flipcash/shared/persistence/db/src/{main => commonMain}/kotlin/com/flipcash/app/persistence/entities/SocialLinkEntity.kt (100%) rename apps/flipcash/shared/persistence/db/src/{main => commonMain}/kotlin/com/flipcash/app/persistence/entities/TokenEntity.kt (100%) rename apps/flipcash/shared/persistence/db/src/{main => commonMain}/kotlin/com/flipcash/app/persistence/entities/TokenValuationEntity.kt (100%) rename apps/flipcash/shared/persistence/db/src/{main => commonMain}/kotlin/com/flipcash/app/persistence/entities/UserProfileEntity.kt (100%) rename apps/flipcash/shared/persistence/db/src/{main => commonMain}/kotlin/com/flipcash/app/persistence/entities/UserProfileEntityMapping.kt (100%) create mode 100644 apps/flipcash/shared/persistence/db/src/jvmMain/kotlin/com/flipcash/app/persistence/FlipcashDatabaseInit.kt diff --git a/apps/flipcash/shared/chat/src/test/kotlin/com/flipcash/shared/chat/FullRefreshMembersTest.kt b/apps/flipcash/shared/chat/src/test/kotlin/com/flipcash/shared/chat/FullRefreshMembersTest.kt index 44a674844b..9057715047 100644 --- a/apps/flipcash/shared/chat/src/test/kotlin/com/flipcash/shared/chat/FullRefreshMembersTest.kt +++ b/apps/flipcash/shared/chat/src/test/kotlin/com/flipcash/shared/chat/FullRefreshMembersTest.kt @@ -3,6 +3,7 @@ package com.flipcash.shared.chat import android.content.Context import androidx.test.core.app.ApplicationProvider import com.flipcash.app.persistence.FlipcashDatabase +import com.flipcash.app.persistence.init import com.flipcash.app.persistence.sources.ChatMemberDataSource import com.flipcash.app.persistence.sources.mapper.chat.ChatEntityMapper import com.flipcash.services.controllers.EventStreamingController diff --git a/apps/flipcash/shared/chat/src/test/kotlin/com/flipcash/shared/chat/RealChatArchiveStoreTest.kt b/apps/flipcash/shared/chat/src/test/kotlin/com/flipcash/shared/chat/RealChatArchiveStoreTest.kt index 819673697c..996c9270be 100644 --- a/apps/flipcash/shared/chat/src/test/kotlin/com/flipcash/shared/chat/RealChatArchiveStoreTest.kt +++ b/apps/flipcash/shared/chat/src/test/kotlin/com/flipcash/shared/chat/RealChatArchiveStoreTest.kt @@ -3,6 +3,7 @@ package com.flipcash.shared.chat import android.content.Context import androidx.test.core.app.ApplicationProvider import com.flipcash.app.persistence.FlipcashDatabase +import com.flipcash.app.persistence.init import com.flipcash.app.persistence.sources.ChatArchiveDataSource import com.flipcash.services.models.chat.ChatId import com.flipcash.shared.chat.internal.RealChatArchiveStore diff --git a/apps/flipcash/shared/persistence/db/build.gradle.kts b/apps/flipcash/shared/persistence/db/build.gradle.kts index 75f2a790f1..e3e0a706cf 100644 --- a/apps/flipcash/shared/persistence/db/build.gradle.kts +++ b/apps/flipcash/shared/persistence/db/build.gradle.kts @@ -1,32 +1,49 @@ plugins { - alias(libs.plugins.flipcash.android.feature) + alias(libs.plugins.flipcash.kmp.app.library) + alias(libs.plugins.kotlin.ksp) alias(libs.plugins.androidx.room) } -android { - namespace = "${Gradle.flipcashNamespace}.shared.persistence.db" +kotlin { + android { + namespace = "${Gradle.flipcashNamespace}.shared.persistence.db" + } - room { - schemaDirectory("$projectDir/schemas") + sourceSets { + commonMain.dependencies { + implementation(libs.bundles.kotlinx.serialization) + implementation(libs.androidx.room.runtime) + implementation(libs.androidx.room.paging) + implementation(libs.androidx.paging.common) + + implementation(project(":libs:models")) + implementation(project(":libs:encryption:base58")) + implementation(project(":libs:encryption:utils")) + implementation(project(":libs:logging")) + + implementation(project(":services:flipcash")) + } + androidMain.dependencies { + implementation(libs.androidx.room.ktx) + implementation(libs.androidx.paging.runtime) + } + jvmMain.dependencies { + implementation(libs.androidx.sqlite.bundled) + } + getByName("androidHostTest").dependencies { + implementation(kotlin("test")) + implementation(libs.bundles.unit.testing) + implementation(libs.robolectric) + implementation(libs.androidx.room.testing) + } } } -dependencies { - testImplementation(kotlin("test")) - testImplementation(libs.bundles.unit.testing) - testImplementation(libs.robolectric) - testImplementation(libs.androidx.room.testing) - - implementation(libs.bundles.kotlinx.serialization) - - implementation(libs.bundles.room) - implementation(libs.androidx.paging.runtime) - - ksp(libs.androidx.room.compiler) - - implementation(project(":libs:models")) - implementation(project(":libs:encryption:base58")) - implementation(project(":libs:encryption:utils")) +room { + schemaDirectory("$projectDir/schemas") +} - implementation(project(":services:flipcash")) +dependencies { + add("kspAndroid", libs.androidx.room.compiler) + add("kspJvm", libs.androidx.room.compiler) } diff --git a/apps/flipcash/shared/persistence/db/src/test/kotlin/com/flipcash/app/persistence/ChatFeedUpsertClampTest.kt b/apps/flipcash/shared/persistence/db/src/androidHostTest/kotlin/com/flipcash/app/persistence/ChatFeedUpsertClampTest.kt similarity index 100% rename from apps/flipcash/shared/persistence/db/src/test/kotlin/com/flipcash/app/persistence/ChatFeedUpsertClampTest.kt rename to apps/flipcash/shared/persistence/db/src/androidHostTest/kotlin/com/flipcash/app/persistence/ChatFeedUpsertClampTest.kt diff --git a/apps/flipcash/shared/persistence/db/src/test/kotlin/com/flipcash/app/persistence/ChatMetadataCatchUpTest.kt b/apps/flipcash/shared/persistence/db/src/androidHostTest/kotlin/com/flipcash/app/persistence/ChatMetadataCatchUpTest.kt similarity index 100% rename from apps/flipcash/shared/persistence/db/src/test/kotlin/com/flipcash/app/persistence/ChatMetadataCatchUpTest.kt rename to apps/flipcash/shared/persistence/db/src/androidHostTest/kotlin/com/flipcash/app/persistence/ChatMetadataCatchUpTest.kt diff --git a/apps/flipcash/shared/persistence/db/src/test/kotlin/com/flipcash/app/persistence/EncryptedRowMigrationTest.kt b/apps/flipcash/shared/persistence/db/src/androidHostTest/kotlin/com/flipcash/app/persistence/EncryptedRowMigrationTest.kt similarity index 100% rename from apps/flipcash/shared/persistence/db/src/test/kotlin/com/flipcash/app/persistence/EncryptedRowMigrationTest.kt rename to apps/flipcash/shared/persistence/db/src/androidHostTest/kotlin/com/flipcash/app/persistence/EncryptedRowMigrationTest.kt diff --git a/apps/flipcash/shared/persistence/db/src/test/kotlin/com/flipcash/app/persistence/FlipcashDatabaseInitTest.kt b/apps/flipcash/shared/persistence/db/src/androidHostTest/kotlin/com/flipcash/app/persistence/FlipcashDatabaseInitTest.kt similarity index 100% rename from apps/flipcash/shared/persistence/db/src/test/kotlin/com/flipcash/app/persistence/FlipcashDatabaseInitTest.kt rename to apps/flipcash/shared/persistence/db/src/androidHostTest/kotlin/com/flipcash/app/persistence/FlipcashDatabaseInitTest.kt diff --git a/apps/flipcash/shared/persistence/db/src/test/kotlin/com/flipcash/app/persistence/TransactionHistoryMigrationTest.kt b/apps/flipcash/shared/persistence/db/src/androidHostTest/kotlin/com/flipcash/app/persistence/TransactionHistoryMigrationTest.kt similarity index 100% rename from apps/flipcash/shared/persistence/db/src/test/kotlin/com/flipcash/app/persistence/TransactionHistoryMigrationTest.kt rename to apps/flipcash/shared/persistence/db/src/androidHostTest/kotlin/com/flipcash/app/persistence/TransactionHistoryMigrationTest.kt diff --git a/apps/flipcash/shared/persistence/db/src/test/kotlin/com/flipcash/app/persistence/UserProfileMigrationTest.kt b/apps/flipcash/shared/persistence/db/src/androidHostTest/kotlin/com/flipcash/app/persistence/UserProfileMigrationTest.kt similarity index 98% rename from apps/flipcash/shared/persistence/db/src/test/kotlin/com/flipcash/app/persistence/UserProfileMigrationTest.kt rename to apps/flipcash/shared/persistence/db/src/androidHostTest/kotlin/com/flipcash/app/persistence/UserProfileMigrationTest.kt index 60042d32c1..cca91c9547 100644 --- a/apps/flipcash/shared/persistence/db/src/test/kotlin/com/flipcash/app/persistence/UserProfileMigrationTest.kt +++ b/apps/flipcash/shared/persistence/db/src/androidHostTest/kotlin/com/flipcash/app/persistence/UserProfileMigrationTest.kt @@ -5,6 +5,7 @@ import androidx.room.Room import androidx.sqlite.db.SupportSQLiteDatabase import androidx.sqlite.db.SupportSQLiteOpenHelper import androidx.sqlite.db.framework.FrameworkSQLiteOpenHelperFactory +import androidx.sqlite.driver.SupportSQLiteConnection import androidx.test.core.app.ApplicationProvider import com.flipcash.app.persistence.converters.ChatTypeConverters import com.flipcash.app.persistence.converters.SocialAccountSerialized @@ -111,7 +112,7 @@ class UserProfileMigrationTest { arrayOf("u2", 111L, partialProfileJson), ) - FlipcashDatabase.MIGRATION_25_26.migrate(db) + FlipcashDatabase.MIGRATION_25_26.migrate(SupportSQLiteConnection(db)) // One profile row per user (u1 deduped across its two memberships). assertEquals(2, db.count("user_profiles")) diff --git a/apps/flipcash/shared/persistence/db/src/test/kotlin/com/flipcash/app/persistence/converters/ChatTypeConvertersTest.kt b/apps/flipcash/shared/persistence/db/src/androidHostTest/kotlin/com/flipcash/app/persistence/converters/ChatTypeConvertersTest.kt similarity index 100% rename from apps/flipcash/shared/persistence/db/src/test/kotlin/com/flipcash/app/persistence/converters/ChatTypeConvertersTest.kt rename to apps/flipcash/shared/persistence/db/src/androidHostTest/kotlin/com/flipcash/app/persistence/converters/ChatTypeConvertersTest.kt diff --git a/apps/flipcash/shared/persistence/db/src/test/kotlin/com/flipcash/app/persistence/converters/TokenTypeConvertersTest.kt b/apps/flipcash/shared/persistence/db/src/androidHostTest/kotlin/com/flipcash/app/persistence/converters/TokenTypeConvertersTest.kt similarity index 100% rename from apps/flipcash/shared/persistence/db/src/test/kotlin/com/flipcash/app/persistence/converters/TokenTypeConvertersTest.kt rename to apps/flipcash/shared/persistence/db/src/androidHostTest/kotlin/com/flipcash/app/persistence/converters/TokenTypeConvertersTest.kt diff --git a/apps/flipcash/shared/persistence/db/src/test/kotlin/com/flipcash/app/persistence/dao/BlockedUserDaoTest.kt b/apps/flipcash/shared/persistence/db/src/androidHostTest/kotlin/com/flipcash/app/persistence/dao/BlockedUserDaoTest.kt similarity index 100% rename from apps/flipcash/shared/persistence/db/src/test/kotlin/com/flipcash/app/persistence/dao/BlockedUserDaoTest.kt rename to apps/flipcash/shared/persistence/db/src/androidHostTest/kotlin/com/flipcash/app/persistence/dao/BlockedUserDaoTest.kt diff --git a/apps/flipcash/shared/persistence/db/src/test/kotlin/com/flipcash/app/persistence/dao/ChatArchiveDaoTest.kt b/apps/flipcash/shared/persistence/db/src/androidHostTest/kotlin/com/flipcash/app/persistence/dao/ChatArchiveDaoTest.kt similarity index 100% rename from apps/flipcash/shared/persistence/db/src/test/kotlin/com/flipcash/app/persistence/dao/ChatArchiveDaoTest.kt rename to apps/flipcash/shared/persistence/db/src/androidHostTest/kotlin/com/flipcash/app/persistence/dao/ChatArchiveDaoTest.kt diff --git a/apps/flipcash/shared/persistence/db/src/test/kotlin/com/flipcash/app/persistence/dao/ChatDraftDaoTest.kt b/apps/flipcash/shared/persistence/db/src/androidHostTest/kotlin/com/flipcash/app/persistence/dao/ChatDraftDaoTest.kt similarity index 100% rename from apps/flipcash/shared/persistence/db/src/test/kotlin/com/flipcash/app/persistence/dao/ChatDraftDaoTest.kt rename to apps/flipcash/shared/persistence/db/src/androidHostTest/kotlin/com/flipcash/app/persistence/dao/ChatDraftDaoTest.kt diff --git a/apps/flipcash/shared/persistence/db/src/test/kotlin/com/flipcash/app/persistence/dao/ChatMemberDaoTest.kt b/apps/flipcash/shared/persistence/db/src/androidHostTest/kotlin/com/flipcash/app/persistence/dao/ChatMemberDaoTest.kt similarity index 100% rename from apps/flipcash/shared/persistence/db/src/test/kotlin/com/flipcash/app/persistence/dao/ChatMemberDaoTest.kt rename to apps/flipcash/shared/persistence/db/src/androidHostTest/kotlin/com/flipcash/app/persistence/dao/ChatMemberDaoTest.kt diff --git a/apps/flipcash/shared/persistence/db/src/test/kotlin/com/flipcash/app/persistence/dao/ChatMessageDaoTest.kt b/apps/flipcash/shared/persistence/db/src/androidHostTest/kotlin/com/flipcash/app/persistence/dao/ChatMessageDaoTest.kt similarity index 100% rename from apps/flipcash/shared/persistence/db/src/test/kotlin/com/flipcash/app/persistence/dao/ChatMessageDaoTest.kt rename to apps/flipcash/shared/persistence/db/src/androidHostTest/kotlin/com/flipcash/app/persistence/dao/ChatMessageDaoTest.kt diff --git a/apps/flipcash/shared/persistence/db/src/test/kotlin/com/flipcash/app/persistence/dao/ChatMessageUpsertGuardTest.kt b/apps/flipcash/shared/persistence/db/src/androidHostTest/kotlin/com/flipcash/app/persistence/dao/ChatMessageUpsertGuardTest.kt similarity index 100% rename from apps/flipcash/shared/persistence/db/src/test/kotlin/com/flipcash/app/persistence/dao/ChatMessageUpsertGuardTest.kt rename to apps/flipcash/shared/persistence/db/src/androidHostTest/kotlin/com/flipcash/app/persistence/dao/ChatMessageUpsertGuardTest.kt diff --git a/apps/flipcash/shared/persistence/db/src/test/kotlin/com/flipcash/app/persistence/dao/ChatMetadataDaoTest.kt b/apps/flipcash/shared/persistence/db/src/androidHostTest/kotlin/com/flipcash/app/persistence/dao/ChatMetadataDaoTest.kt similarity index 100% rename from apps/flipcash/shared/persistence/db/src/test/kotlin/com/flipcash/app/persistence/dao/ChatMetadataDaoTest.kt rename to apps/flipcash/shared/persistence/db/src/androidHostTest/kotlin/com/flipcash/app/persistence/dao/ChatMetadataDaoTest.kt diff --git a/apps/flipcash/shared/persistence/db/src/test/kotlin/com/flipcash/app/persistence/dao/ContactDaoTest.kt b/apps/flipcash/shared/persistence/db/src/androidHostTest/kotlin/com/flipcash/app/persistence/dao/ContactDaoTest.kt similarity index 100% rename from apps/flipcash/shared/persistence/db/src/test/kotlin/com/flipcash/app/persistence/dao/ContactDaoTest.kt rename to apps/flipcash/shared/persistence/db/src/androidHostTest/kotlin/com/flipcash/app/persistence/dao/ContactDaoTest.kt diff --git a/apps/flipcash/shared/persistence/db/src/test/kotlin/com/flipcash/app/persistence/dao/LinkPreviewDaoTest.kt b/apps/flipcash/shared/persistence/db/src/androidHostTest/kotlin/com/flipcash/app/persistence/dao/LinkPreviewDaoTest.kt similarity index 100% rename from apps/flipcash/shared/persistence/db/src/test/kotlin/com/flipcash/app/persistence/dao/LinkPreviewDaoTest.kt rename to apps/flipcash/shared/persistence/db/src/androidHostTest/kotlin/com/flipcash/app/persistence/dao/LinkPreviewDaoTest.kt diff --git a/apps/flipcash/shared/persistence/db/src/test/kotlin/com/flipcash/app/persistence/dao/MessageDaoTest.kt b/apps/flipcash/shared/persistence/db/src/androidHostTest/kotlin/com/flipcash/app/persistence/dao/MessageDaoTest.kt similarity index 100% rename from apps/flipcash/shared/persistence/db/src/test/kotlin/com/flipcash/app/persistence/dao/MessageDaoTest.kt rename to apps/flipcash/shared/persistence/db/src/androidHostTest/kotlin/com/flipcash/app/persistence/dao/MessageDaoTest.kt diff --git a/apps/flipcash/shared/persistence/db/src/test/kotlin/com/flipcash/app/persistence/dao/PendingMediaDaoTest.kt b/apps/flipcash/shared/persistence/db/src/androidHostTest/kotlin/com/flipcash/app/persistence/dao/PendingMediaDaoTest.kt similarity index 100% rename from apps/flipcash/shared/persistence/db/src/test/kotlin/com/flipcash/app/persistence/dao/PendingMediaDaoTest.kt rename to apps/flipcash/shared/persistence/db/src/androidHostTest/kotlin/com/flipcash/app/persistence/dao/PendingMediaDaoTest.kt diff --git a/apps/flipcash/shared/persistence/db/src/test/kotlin/com/flipcash/app/persistence/dao/TokenDaoTest.kt b/apps/flipcash/shared/persistence/db/src/androidHostTest/kotlin/com/flipcash/app/persistence/dao/TokenDaoTest.kt similarity index 100% rename from apps/flipcash/shared/persistence/db/src/test/kotlin/com/flipcash/app/persistence/dao/TokenDaoTest.kt rename to apps/flipcash/shared/persistence/db/src/androidHostTest/kotlin/com/flipcash/app/persistence/dao/TokenDaoTest.kt diff --git a/apps/flipcash/shared/persistence/db/src/test/kotlin/com/flipcash/app/persistence/dao/UnreadBelowBadgeTest.kt b/apps/flipcash/shared/persistence/db/src/androidHostTest/kotlin/com/flipcash/app/persistence/dao/UnreadBelowBadgeTest.kt similarity index 100% rename from apps/flipcash/shared/persistence/db/src/test/kotlin/com/flipcash/app/persistence/dao/UnreadBelowBadgeTest.kt rename to apps/flipcash/shared/persistence/db/src/androidHostTest/kotlin/com/flipcash/app/persistence/dao/UnreadBelowBadgeTest.kt diff --git a/apps/flipcash/shared/persistence/db/src/androidMain/kotlin/com/flipcash/app/persistence/FlipcashDatabaseInit.kt b/apps/flipcash/shared/persistence/db/src/androidMain/kotlin/com/flipcash/app/persistence/FlipcashDatabaseInit.kt new file mode 100644 index 0000000000..339434e031 --- /dev/null +++ b/apps/flipcash/shared/persistence/db/src/androidMain/kotlin/com/flipcash/app/persistence/FlipcashDatabaseInit.kt @@ -0,0 +1,11 @@ +package com.flipcash.app.persistence + +import android.content.Context +import androidx.room.Room + +/** Opens the per-account database in the app's database directory. */ +fun FlipcashDatabase.Companion.init(context: Context, entropyB64: String) = + init(entropyB64) { name -> Room.databaseBuilder(context, FlipcashDatabase::class.java, name) } + +/** Whether the current database's connection is open. Room exposes this on Android only. */ +fun FlipcashDatabase.Companion.isOpen() = getInstance()?.isOpen == true diff --git a/apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/FlipcashDatabase.kt b/apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/FlipcashDatabase.kt similarity index 86% rename from apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/FlipcashDatabase.kt rename to apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/FlipcashDatabase.kt index 309f74ac3d..670f7326c1 100644 --- a/apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/FlipcashDatabase.kt +++ b/apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/FlipcashDatabase.kt @@ -1,17 +1,16 @@ package com.flipcash.app.persistence -import android.content.Context import androidx.room.AutoMigration +import androidx.room.ConstructedBy import androidx.room.Database import androidx.room.DeleteColumn import androidx.room.DeleteTable -import androidx.room.Room import androidx.room.RoomDatabase +import androidx.room.RoomDatabaseConstructor import androidx.room.TypeConverters import androidx.room.migration.AutoMigrationSpec import androidx.room.migration.Migration import androidx.sqlite.SQLiteConnection -import androidx.sqlite.db.SupportSQLiteDatabase import androidx.sqlite.execSQL import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow @@ -51,6 +50,7 @@ import com.getcode.utils.TraceType import com.getcode.utils.trace import com.getcode.vendor.Base58 import com.getcode.utils.subByteArray +import kotlin.jvm.Synchronized @Database( entities = [ @@ -130,6 +130,7 @@ import com.getcode.utils.subByteArray version = 45, ) @TypeConverters(TokenTypeConverters::class, ChatTypeConverters::class) +@ConstructedBy(FlipcashDatabaseConstructor::class) abstract class FlipcashDatabase : RoomDatabase() { abstract fun messageDao(): MessageDao @@ -147,22 +148,22 @@ abstract class FlipcashDatabase : RoomDatabase() { abstract fun pendingMediaDao(): PendingMediaDao class Migration1To2 : Migration(1, 2), AutoMigrationSpec { - override fun migrate(db: SupportSQLiteDatabase) { - db.execSQL("DELETE FROM messages") + override fun migrate(connection: SQLiteConnection) { + connection.execSQL("DELETE FROM messages") } } class Migration3To4 : Migration(3, 4), AutoMigrationSpec { - override fun migrate(db: SupportSQLiteDatabase) { - db.execSQL("DELETE FROM pool_metadata") - db.execSQL("DELETE FROM pool_bet_metadata") + override fun migrate(connection: SQLiteConnection) { + connection.execSQL("DELETE FROM pool_metadata") + connection.execSQL("DELETE FROM pool_bet_metadata") } } class Migration4To5 : Migration(4, 5), AutoMigrationSpec { - override fun migrate(db: SupportSQLiteDatabase) { - db.execSQL("DELETE FROM pool_metadata") - db.execSQL("DELETE FROM pool_bet_metadata") + override fun migrate(connection: SQLiteConnection) { + connection.execSQL("DELETE FROM pool_metadata") + connection.execSQL("DELETE FROM pool_bet_metadata") } } @@ -181,27 +182,27 @@ abstract class FlipcashDatabase : RoomDatabase() { ), ) class Migration5To6 : Migration(5, 6), AutoMigrationSpec { - override fun migrate(db: SupportSQLiteDatabase) { - db.execSQL("DELETE FROM pool_metadata") - db.execSQL("DELETE FROM pool_bet_metadata") + override fun migrate(connection: SQLiteConnection) { + connection.execSQL("DELETE FROM pool_metadata") + connection.execSQL("DELETE FROM pool_bet_metadata") } } class Migration6To7 : Migration(6, 7), AutoMigrationSpec { - override fun migrate(db: SupportSQLiteDatabase) { - db.execSQL("DELETE FROM messages") + override fun migrate(connection: SQLiteConnection) { + connection.execSQL("DELETE FROM messages") } } class Migration7To8 : Migration(7, 8), AutoMigrationSpec { - override fun migrate(db: SupportSQLiteDatabase) { - db.execSQL("DELETE FROM messages") + override fun migrate(connection: SQLiteConnection) { + connection.execSQL("DELETE FROM messages") } } class Migration9To10 : Migration(9, 10), AutoMigrationSpec { - override fun migrate(db: SupportSQLiteDatabase) { - db.execSQL("DELETE FROM messages") + override fun migrate(connection: SQLiteConnection) { + connection.execSQL("DELETE FROM messages") } } @@ -213,9 +214,9 @@ abstract class FlipcashDatabase : RoomDatabase() { class Migration10To11 : Migration(10, 11), AutoMigrationSpec class Migration12To13 : Migration(12, 13), AutoMigrationSpec { - override fun migrate(db: SupportSQLiteDatabase) { - db.execSQL("DELETE FROM tokens") - db.execSQL("DELETE FROM token_valuation") + override fun migrate(connection: SQLiteConnection) { + connection.execSQL("DELETE FROM tokens") + connection.execSQL("DELETE FROM token_valuation") } } @@ -225,8 +226,8 @@ abstract class FlipcashDatabase : RoomDatabase() { // in onPostMigrate so they keep resolving after the rename instead of falling // through to UNKNOWN. class Migration22To23 : AutoMigrationSpec { - override fun onPostMigrate(db: SupportSQLiteDatabase) { - db.execSQL("UPDATE chat_metadata SET chat_type = 'CONTACT_DM' WHERE chat_type = 'DM'") + override fun onPostMigrate(connection: SQLiteConnection) { + connection.execSQL("UPDATE chat_metadata SET chat_type = 'CONTACT_DM' WHERE chat_type = 'DM'") } } @@ -242,9 +243,8 @@ abstract class FlipcashDatabase : RoomDatabase() { * descending re-seed, and re-fetches the recent feed from scratch; paging refills older * history on demand. * - * Takes the [SQLiteConnection] overload rather than the [SupportSQLiteDatabase] one used by - * [Migration22To23]: the latter only fires when Room is built without a driver, so a future - * `setDriver` would turn the delete into a silent no-op. + * Every migration here takes the [SQLiteConnection] overload: the `SupportSQLiteDatabase` one + * only fires when Room is built without a driver, and the desktop build sets one. */ class Migration28To29 : AutoMigrationSpec { override fun onPostMigrate(connection: SQLiteConnection) { @@ -331,10 +331,10 @@ abstract class FlipcashDatabase : RoomDatabase() { * compatibility with the minSdk-29 SQLite build. */ val MIGRATION_25_26 = object : Migration(25, 26) { - override fun migrate(db: SupportSQLiteDatabase) { + override fun migrate(connection: SQLiteConnection) { // 1. New normalized table. Column set must match UserProfileEntity so // Room's post-migration schema validation passes. - db.execSQL( + connection.execSQL( "CREATE TABLE IF NOT EXISTS `user_profiles` (" + "`user_id_hex` TEXT NOT NULL, " + "`display_name` TEXT NOT NULL, " + @@ -352,45 +352,45 @@ abstract class FlipcashDatabase : RoomDatabase() { // the full profile, so insert it first; blocked_users (name+avatar only) // fills in users not in any chat. display_name is a placeholder until // the backfill parses the blob. - db.execSQL( + connection.execSQL( "INSERT OR IGNORE INTO user_profiles (user_id_hex, display_name, pending_migration_json) " + "SELECT user_id_hex, '', user_profile_json FROM chat_members " + "WHERE user_profile_json IS NOT NULL" ) - db.execSQL( + connection.execSQL( "INSERT OR IGNORE INTO user_profiles (user_id_hex, display_name, pending_migration_json) " + "SELECT user_id_hex, '', user_profile_json FROM blocked_users " + "WHERE user_profile_json IS NOT NULL" ) // 3. Drop the duplicated blob column from chat_members via table-recreate. - db.execSQL( + connection.execSQL( "CREATE TABLE `chat_members_new` (" + "`chat_id_hex` TEXT NOT NULL, " + "`user_id_hex` TEXT NOT NULL, " + "`pointers_json` TEXT, " + "PRIMARY KEY(`chat_id_hex`, `user_id_hex`))" ) - db.execSQL( + connection.execSQL( "INSERT INTO `chat_members_new` (chat_id_hex, user_id_hex, pointers_json) " + "SELECT chat_id_hex, user_id_hex, pointers_json FROM chat_members" ) - db.execSQL("DROP TABLE chat_members") - db.execSQL("ALTER TABLE chat_members_new RENAME TO chat_members") + connection.execSQL("DROP TABLE chat_members") + connection.execSQL("ALTER TABLE chat_members_new RENAME TO chat_members") // 4. Same for blocked_users. - db.execSQL( + connection.execSQL( "CREATE TABLE `blocked_users_new` (" + "`user_id_hex` TEXT NOT NULL, " + "`blocked_at_epoch_ms` INTEGER NOT NULL, " + "PRIMARY KEY(`user_id_hex`))" ) - db.execSQL( + connection.execSQL( "INSERT INTO `blocked_users_new` (user_id_hex, blocked_at_epoch_ms) " + "SELECT user_id_hex, blocked_at_epoch_ms FROM blocked_users" ) - db.execSQL("DROP TABLE blocked_users") - db.execSQL("ALTER TABLE blocked_users_new RENAME TO blocked_users") + connection.execSQL("DROP TABLE blocked_users") + connection.execSQL("ALTER TABLE blocked_users_new RENAME TO blocked_users") } } @@ -411,10 +411,12 @@ abstract class FlipcashDatabase : RoomDatabase() { private const val dbNamePrefix = "fcash_database" - fun isOpen() = instance?.isOpen == true - + /** + * Opens the per-account database. [builder] creates the platform's Room builder for the file + * name; the Android and desktop `init` overloads supply it. + */ @Synchronized - fun init(context: Context, entropyB64: String) { + fun init(entropyB64: String, builder: (name: String) -> RoomDatabase.Builder) { val dbUniqueName = Base58.encode(entropyB64.toByteArray().subByteArray(0, 6)) val targetName = "$dbNamePrefix-$dbUniqueName.db" @@ -433,9 +435,9 @@ abstract class FlipcashDatabase : RoomDatabase() { dbName = targetName instance = - Room.databaseBuilder(context, FlipcashDatabase::class.java, dbName) + builder(dbName) .addMigrations(MIGRATION_25_26) - .fallbackToDestructiveMigration() + .fallbackToDestructiveMigration(dropAllTables = false) .build() trace("database init end", type = TraceType.Process) @@ -449,4 +451,10 @@ abstract class FlipcashDatabase : RoomDatabase() { } } } -} \ No newline at end of file +} + +// Room generates the actual for each target. +@Suppress("KotlinNoActualForExpect") +expect object FlipcashDatabaseConstructor : RoomDatabaseConstructor { + override fun initialize(): FlipcashDatabase +} diff --git a/apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/UserProfileBackfill.kt b/apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/UserProfileBackfill.kt similarity index 100% rename from apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/UserProfileBackfill.kt rename to apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/UserProfileBackfill.kt diff --git a/apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/converters/ChatTypeConverters.kt b/apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/converters/ChatTypeConverters.kt similarity index 100% rename from apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/converters/ChatTypeConverters.kt rename to apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/converters/ChatTypeConverters.kt diff --git a/apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/converters/TokenTypeConverters.kt b/apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/converters/TokenTypeConverters.kt similarity index 100% rename from apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/converters/TokenTypeConverters.kt rename to apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/converters/TokenTypeConverters.kt diff --git a/apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/dao/BlockedUserDao.kt b/apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/dao/BlockedUserDao.kt similarity index 100% rename from apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/dao/BlockedUserDao.kt rename to apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/dao/BlockedUserDao.kt diff --git a/apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/dao/ChatArchiveDao.kt b/apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/dao/ChatArchiveDao.kt similarity index 100% rename from apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/dao/ChatArchiveDao.kt rename to apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/dao/ChatArchiveDao.kt diff --git a/apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/dao/ChatDraftDao.kt b/apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/dao/ChatDraftDao.kt similarity index 100% rename from apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/dao/ChatDraftDao.kt rename to apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/dao/ChatDraftDao.kt diff --git a/apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/dao/ChatMemberDao.kt b/apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/dao/ChatMemberDao.kt similarity index 100% rename from apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/dao/ChatMemberDao.kt rename to apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/dao/ChatMemberDao.kt diff --git a/apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/dao/ChatMessageDao.kt b/apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/dao/ChatMessageDao.kt similarity index 100% rename from apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/dao/ChatMessageDao.kt rename to apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/dao/ChatMessageDao.kt diff --git a/apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/dao/ChatMetadataDao.kt b/apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/dao/ChatMetadataDao.kt similarity index 100% rename from apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/dao/ChatMetadataDao.kt rename to apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/dao/ChatMetadataDao.kt diff --git a/apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/dao/ContactDao.kt b/apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/dao/ContactDao.kt similarity index 100% rename from apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/dao/ContactDao.kt rename to apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/dao/ContactDao.kt diff --git a/apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/dao/CurrencyCreatorDraftDao.kt b/apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/dao/CurrencyCreatorDraftDao.kt similarity index 100% rename from apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/dao/CurrencyCreatorDraftDao.kt rename to apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/dao/CurrencyCreatorDraftDao.kt diff --git a/apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/dao/LinkPreviewDao.kt b/apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/dao/LinkPreviewDao.kt similarity index 100% rename from apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/dao/LinkPreviewDao.kt rename to apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/dao/LinkPreviewDao.kt diff --git a/apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/dao/MessageDao.kt b/apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/dao/MessageDao.kt similarity index 97% rename from apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/dao/MessageDao.kt rename to apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/dao/MessageDao.kt index 6b9bc75c02..77a4986179 100644 --- a/apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/dao/MessageDao.kt +++ b/apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/dao/MessageDao.kt @@ -7,7 +7,7 @@ import androidx.room.OnConflictStrategy import androidx.room.Query import androidx.room.RawQuery import androidx.room.Transaction -import androidx.sqlite.db.SupportSQLiteQuery +import androidx.room.RoomRawQuery import com.flipcash.app.persistence.entities.MessageEntity import com.getcode.utils.base58 import kotlinx.coroutines.flow.Flow @@ -34,7 +34,7 @@ interface MessageDao { fun observeMessageById(id: List): Flow = observeMessageById(id.base58) @RawQuery - suspend fun queryDirectly(query: SupportSQLiteQuery): List + suspend fun queryDirectly(query: RoomRawQuery): List @Query("SELECT * FROM messages ORDER BY timestamp DESC LIMIT 1") suspend fun getNewestMessage(): MessageEntity? diff --git a/apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/dao/PendingMediaDao.kt b/apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/dao/PendingMediaDao.kt similarity index 100% rename from apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/dao/PendingMediaDao.kt rename to apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/dao/PendingMediaDao.kt diff --git a/apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/dao/TokenDao.kt b/apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/dao/TokenDao.kt similarity index 100% rename from apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/dao/TokenDao.kt rename to apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/dao/TokenDao.kt diff --git a/apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/dao/UserProfileDao.kt b/apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/dao/UserProfileDao.kt similarity index 100% rename from apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/dao/UserProfileDao.kt rename to apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/dao/UserProfileDao.kt diff --git a/apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/embedded/LaunchpadMetadataEmbedded.kt b/apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/embedded/LaunchpadMetadataEmbedded.kt similarity index 100% rename from apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/embedded/LaunchpadMetadataEmbedded.kt rename to apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/embedded/LaunchpadMetadataEmbedded.kt diff --git a/apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/embedded/VmMetadataEmbedded.kt b/apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/embedded/VmMetadataEmbedded.kt similarity index 100% rename from apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/embedded/VmMetadataEmbedded.kt rename to apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/embedded/VmMetadataEmbedded.kt diff --git a/apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/entities/BlockedUserEntity.kt b/apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/entities/BlockedUserEntity.kt similarity index 100% rename from apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/entities/BlockedUserEntity.kt rename to apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/entities/BlockedUserEntity.kt diff --git a/apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/entities/ChatArchiveEntity.kt b/apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/entities/ChatArchiveEntity.kt similarity index 100% rename from apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/entities/ChatArchiveEntity.kt rename to apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/entities/ChatArchiveEntity.kt diff --git a/apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/entities/ChatDraftEntity.kt b/apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/entities/ChatDraftEntity.kt similarity index 100% rename from apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/entities/ChatDraftEntity.kt rename to apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/entities/ChatDraftEntity.kt diff --git a/apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/entities/ChatMemberEntity.kt b/apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/entities/ChatMemberEntity.kt similarity index 100% rename from apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/entities/ChatMemberEntity.kt rename to apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/entities/ChatMemberEntity.kt diff --git a/apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/entities/ChatMessageEntity.kt b/apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/entities/ChatMessageEntity.kt similarity index 100% rename from apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/entities/ChatMessageEntity.kt rename to apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/entities/ChatMessageEntity.kt diff --git a/apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/entities/ChatMetadataEntity.kt b/apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/entities/ChatMetadataEntity.kt similarity index 100% rename from apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/entities/ChatMetadataEntity.kt rename to apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/entities/ChatMetadataEntity.kt diff --git a/apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/entities/ContactMappingEntity.kt b/apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/entities/ContactMappingEntity.kt similarity index 100% rename from apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/entities/ContactMappingEntity.kt rename to apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/entities/ContactMappingEntity.kt diff --git a/apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/entities/ContactSyncStateEntity.kt b/apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/entities/ContactSyncStateEntity.kt similarity index 100% rename from apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/entities/ContactSyncStateEntity.kt rename to apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/entities/ContactSyncStateEntity.kt diff --git a/apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/entities/CurrencyCreatorDraftEntity.kt b/apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/entities/CurrencyCreatorDraftEntity.kt similarity index 100% rename from apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/entities/CurrencyCreatorDraftEntity.kt rename to apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/entities/CurrencyCreatorDraftEntity.kt diff --git a/apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/entities/LinkPreviewEntity.kt b/apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/entities/LinkPreviewEntity.kt similarity index 100% rename from apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/entities/LinkPreviewEntity.kt rename to apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/entities/LinkPreviewEntity.kt diff --git a/apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/entities/MessageEntity.kt b/apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/entities/MessageEntity.kt similarity index 100% rename from apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/entities/MessageEntity.kt rename to apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/entities/MessageEntity.kt diff --git a/apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/entities/PendingMediaEntity.kt b/apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/entities/PendingMediaEntity.kt similarity index 100% rename from apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/entities/PendingMediaEntity.kt rename to apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/entities/PendingMediaEntity.kt diff --git a/apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/entities/SocialLinkEntity.kt b/apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/entities/SocialLinkEntity.kt similarity index 100% rename from apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/entities/SocialLinkEntity.kt rename to apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/entities/SocialLinkEntity.kt diff --git a/apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/entities/TokenEntity.kt b/apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/entities/TokenEntity.kt similarity index 100% rename from apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/entities/TokenEntity.kt rename to apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/entities/TokenEntity.kt diff --git a/apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/entities/TokenValuationEntity.kt b/apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/entities/TokenValuationEntity.kt similarity index 100% rename from apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/entities/TokenValuationEntity.kt rename to apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/entities/TokenValuationEntity.kt diff --git a/apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/entities/UserProfileEntity.kt b/apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/entities/UserProfileEntity.kt similarity index 100% rename from apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/entities/UserProfileEntity.kt rename to apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/entities/UserProfileEntity.kt diff --git a/apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/entities/UserProfileEntityMapping.kt b/apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/entities/UserProfileEntityMapping.kt similarity index 100% rename from apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/entities/UserProfileEntityMapping.kt rename to apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/entities/UserProfileEntityMapping.kt diff --git a/apps/flipcash/shared/persistence/db/src/jvmMain/kotlin/com/flipcash/app/persistence/FlipcashDatabaseInit.kt b/apps/flipcash/shared/persistence/db/src/jvmMain/kotlin/com/flipcash/app/persistence/FlipcashDatabaseInit.kt new file mode 100644 index 0000000000..bc1291b0ed --- /dev/null +++ b/apps/flipcash/shared/persistence/db/src/jvmMain/kotlin/com/flipcash/app/persistence/FlipcashDatabaseInit.kt @@ -0,0 +1,15 @@ +package com.flipcash.app.persistence + +import androidx.room.Room +import androidx.sqlite.driver.bundled.BundledSQLiteDriver +import java.io.File +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO + +/** Opens the per-account database under [directory], using the bundled SQLite driver. */ +fun FlipcashDatabase.Companion.init(directory: File, entropyB64: String) = + init(entropyB64) { name -> + Room.databaseBuilder(name = File(directory, name).absolutePath) + .setDriver(BundledSQLiteDriver()) + .setQueryCoroutineContext(Dispatchers.IO) + } diff --git a/apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/MessageDataSource.kt b/apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/MessageDataSource.kt index ad35b8678f..9ec8e017cd 100644 --- a/apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/MessageDataSource.kt +++ b/apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/MessageDataSource.kt @@ -2,7 +2,7 @@ package com.flipcash.app.persistence.sources import androidx.paging.PagingSource import androidx.paging.PagingState -import androidx.sqlite.db.SimpleSQLiteQuery +import androidx.room.RoomRawQuery import com.flipcash.app.persistence.entities.MessageEntity import com.flipcash.app.core.feed.ActivityFeedMessage import com.flipcash.app.persistence.FlipcashDatabase @@ -54,7 +54,7 @@ class MessageDataSource @Inject constructor( } override suspend fun query(whereClause: String): List { - val query = SimpleSQLiteQuery("SELECT * FROM messages WHERE $whereClause") + val query = RoomRawQuery("SELECT * FROM messages WHERE $whereClause") val result = db?.messageDao()?.queryDirectly(query) ?: return emptyList() return result.map { messageEntityMapper.map(it) } } diff --git a/apps/flipcash/shared/persistence/sources/src/test/kotlin/com/flipcash/app/persistence/sources/UnreadStreamReadinessTest.kt b/apps/flipcash/shared/persistence/sources/src/test/kotlin/com/flipcash/app/persistence/sources/UnreadStreamReadinessTest.kt index 931396eff4..1af5af307b 100644 --- a/apps/flipcash/shared/persistence/sources/src/test/kotlin/com/flipcash/app/persistence/sources/UnreadStreamReadinessTest.kt +++ b/apps/flipcash/shared/persistence/sources/src/test/kotlin/com/flipcash/app/persistence/sources/UnreadStreamReadinessTest.kt @@ -4,6 +4,7 @@ import android.content.Context import androidx.test.core.app.ApplicationProvider import app.cash.turbine.test import com.flipcash.app.persistence.FlipcashDatabase +import com.flipcash.app.persistence.init import com.flipcash.app.persistence.converters.MessageContentSerialized import com.flipcash.app.persistence.converters.MessagePointerSerialized import com.flipcash.app.persistence.entities.ChatMemberEntity diff --git a/apps/flipcash/shared/persistence/sources/src/test/kotlin/com/flipcash/app/persistence/sources/UserProfileDataSourceTest.kt b/apps/flipcash/shared/persistence/sources/src/test/kotlin/com/flipcash/app/persistence/sources/UserProfileDataSourceTest.kt index ee494c58c0..5880636e2e 100644 --- a/apps/flipcash/shared/persistence/sources/src/test/kotlin/com/flipcash/app/persistence/sources/UserProfileDataSourceTest.kt +++ b/apps/flipcash/shared/persistence/sources/src/test/kotlin/com/flipcash/app/persistence/sources/UserProfileDataSourceTest.kt @@ -2,6 +2,7 @@ package com.flipcash.app.persistence.sources import app.cash.turbine.test import com.flipcash.app.persistence.FlipcashDatabase +import com.flipcash.app.persistence.init import com.flipcash.services.models.UserProfile import com.getcode.utils.hexEncodedString import kotlinx.coroutines.test.runTest diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 54a4decc30..b5f8ec6c08 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -30,6 +30,7 @@ navigation3-lifecycle = "2.11.0" androidx-browser = "1.10.0" androidx-paging = "3.5.3" androidx-room = "2.8.5" +androidx-sqlite = "2.6.2" androidx-work = "2.12.0" androidx-webkit = "1.17.0" @@ -155,6 +156,7 @@ androidx-room-compiler = { module = "androidx.room:room-compiler", version.ref = androidx-room-ktx = { module = "androidx.room:room-ktx", version.ref = "androidx-room" } androidx-room-paging = { module = "androidx.room:room-paging", version.ref = "androidx-room" } androidx-room-testing = { module = "androidx.room:room-testing", version.ref = "androidx-room" } +androidx-sqlite-bundled = { module = "androidx.sqlite:sqlite-bundled", version.ref = "androidx-sqlite" } androidx-work = { module = "androidx.work:work-runtime", version.ref = "androidx-work" } androidx-work-testing = { module = "androidx.work:work-testing", version.ref = "androidx-work" } androidx-datastore = { module = "androidx.datastore:datastore-preferences", version.ref = "androidx-datastore" } From 074c62ef84721cab3f66dfd37a50fab141af5697 Mon Sep 17 00:00:00 2001 From: Brandon McAnsh Date: Fri, 23 Oct 2026 17:16:54 -0400 Subject: [PATCH 12/50] build(core): move apps:flipcash:core to android+jvm KMP The module keeps everything it had in androidMain, with the dependencies flipcash.android.feature used to add. Only the blocklist and activity feed models, which persistence:sources maps to and from, move to commonMain. --- apps/flipcash/core/build.gradle.kts | 105 +++++++++++------- .../flipcash/app/core/MainCoroutineRule.kt | 0 .../flipcash/app/core/bill/BillStateTest.kt | 0 .../flipcash/app/core/bill/ScannableTest.kt | 0 .../app/core/cache/CachePolicyHandlerTest.kt | 0 .../app/core/chat/ProfileOriginTest.kt | 0 .../flipcash/app/core/data/LoadableTest.kt | 0 .../app/core/extensions/ListExtensionsTest.kt | 0 .../app/core/feed/ActivityFeedMessageTest.kt | 0 .../core/internal/bill/BillControllerTest.kt | 0 .../extensions/ResultExtensionsTest.kt | 0 .../app/core/links/ExternalLinksTest.kt | 0 .../app/core/links/TrustedLinksTest.kt | 0 .../app/core/media/MediaUrlResolverTest.kt | 0 .../app/core/money/FormatUtilsTest.kt | 0 .../core/navigation/DeeplinkFragmentsTest.kt | 0 .../core/navigation/DeeplinkScanPolicyTest.kt | 0 .../app/core/navigation/HomeRouteTest.kt | 0 .../app/core/navigation/NavBarRoutesTest.kt | 0 .../app/core/share/KikCodePainterTest.kt | 0 .../app/core/share/TipCodeExportNameTest.kt | 0 .../core/share/groupcard/GroupCardQrTest.kt | 0 .../app/core/time/FakeTimeProviderTest.kt | 0 .../app/core/tokens/CompletedInPlaceTest.kt | 0 .../app/core/tokens/TokenInfoEntryTest.kt | 0 .../app/core/updater/NetworkUpdaterTest.kt | 0 .../app/core/util/AbbreviatedLinkTest.kt | 0 .../com/flipcash/app/core/util/FiatTest.kt | 0 .../com/flipcash/app/core/util/NumberTest.kt | 0 .../kotlin/com/flipcash/app/core/AppRoute.kt | 0 .../kotlin/com/flipcash/app/core/Locals.kt | 0 .../app/core/android/ActivityProvider.kt | 0 .../app/core/android/IntentLauncher.kt | 0 .../flipcash/app/core/android/IntentUtils.kt | 0 .../flipcash/app/core/android/VersionInfo.kt | 0 .../app/core/android/extensions/Context.kt | 0 .../app/core/android/extensions/Uri.kt | 0 .../app/core/annotations/AccountType.kt | 0 .../com/flipcash/app/core/bill/BillState.kt | 0 .../flipcash/app/core/bill/PaymentRequest.kt | 0 .../com/flipcash/app/core/bill/Scannable.kt | 0 .../com/flipcash/app/core/cache/CacheEntry.kt | 0 .../flipcash/app/core/cache/CachePolicy.kt | 0 .../app/core/cache/CachePolicyHandler.kt | 0 .../flipcash/app/core/chat/ChatIdentifier.kt | 0 .../flipcash/app/core/chat/ChatParticipant.kt | 0 .../com/flipcash/app/core/chat/ChatStep.kt | 0 .../flipcash/app/core/chat/DmDestination.kt | 0 .../flipcash/app/core/chat/NewGroupStep.kt | 0 .../flipcash/app/core/chat/ProfileAddress.kt | 0 .../flipcash/app/core/chat/ReportSubject.kt | 0 .../app/core/chrome/ChromeTabsUtils.kt | 0 .../app/core/contacts/DeviceContact.kt | 0 .../com/flipcash/app/core/data/Loadable.kt | 0 .../app/core/deposit/DepositResult.kt | 0 .../flipcash/app/core/deposit/DepositStep.kt | 0 .../flipcash/app/core/encryption/Sodium.kt | 0 .../flipcash/app/core/extensions/Boolean.kt | 0 .../flipcash/app/core/extensions/Clipboard.kt | 0 .../app/core/extensions/CodeNavigator.kt | 0 .../com/flipcash/app/core/extensions/Flow.kt | 0 .../com/flipcash/app/core/extensions/List.kt | 0 .../com/flipcash/app/core/extensions/Pair.kt | 0 .../flipcash/app/core/extensions/Result.kt | 0 .../app/core/internal/bill/BillController.kt | 0 .../app/core/internal/errors/ErrorUtil.kt | 0 .../app/core/internal/extensions/Bitmap.kt | 0 .../app/core/internal/extensions/Result.kt | 0 .../core/internal/updater/ProfileUpdater.kt | 0 .../flipcash/app/core/links/ExternalLinks.kt | 0 .../app/core/links/TrustedWebsites.kt | 0 .../app/core/media/ImageCachePresence.kt | 0 .../app/core/media/MediaUrlResolver.kt | 0 .../app/core/media/RememberMediaUrl.kt | 0 .../app/core/moderation/ModerationMessages.kt | 0 .../flipcash/app/core/money/FormatUtils.kt | 0 .../app/core/navigation/DeeplinkAction.kt | 0 .../app/core/navigation/DeeplinkType.kt | 0 .../flipcash/app/core/navigation/HomeRoute.kt | 0 .../app/core/navigation/LocalTabBarPadding.kt | 0 .../app/core/navigation/NavBarButton.kt | 0 .../app/core/navigation/NavBarRoutes.kt | 0 .../app/core/navigation/SteppedFlowRoute.kt | 0 .../app/core/navigation/TabBarVisibility.kt | 0 .../app/core/onboarding/OnboardingStep.kt | 0 .../WalletDeeplinkConnectionResult.kt | 0 .../onramp/ui/ConfirmInWalletButtonLabel.kt | 0 .../app/core/onramp/ui/PhantomLabel.kt | 0 .../flipcash/app/core/reporting/ReportStep.kt | 0 .../app/core/share/SharePreviewImage.kt | 0 .../flipcash/app/core/share/TipCodeExport.kt | 0 .../app/core/share/TipCodeExporter.kt | 0 .../flipcash/app/core/share/TipCodePreview.kt | 0 .../app/core/share/TipCodePreviewRenderer.kt | 0 .../app/core/share/TipCodePreviewStorage.kt | 0 .../core/share/groupcard/GroupCardExporter.kt | 0 .../app/core/share/groupcard/QrMatrix.kt | 0 .../core/share/groupcard/StyledQrGeometry.kt | 0 .../core/share/groupcard/StyledQrRenderer.kt | 0 .../flipcash/app/core/storage/MediaSaver.kt | 0 .../app/core/time/FakeTimeProvider.kt | 0 .../flipcash/app/core/time/TimeProvider.kt | 0 .../flipcash/app/core/tipping/OwnTipCard.kt | 0 .../flipcash/app/core/tipping/TipCardOwner.kt | 0 .../flipcash/app/core/tipping/TipSelection.kt | 0 .../app/core/toast/SystemToastController.kt | 0 .../app/core/toast/ToastController.kt | 0 .../app/core/tokens/CurrencyCreatorDraft.kt | 0 .../app/core/tokens/CurrencyCreatorResult.kt | 0 .../app/core/tokens/CurrencyCreatorStep.kt | 0 .../flipcash/app/core/tokens/SwapResult.kt | 0 .../com/flipcash/app/core/tokens/SwapStep.kt | 0 .../app/core/tokens/TokenDisplayName.kt | 0 .../app/core/tokens/TokenInfoEntry.kt | 0 .../flipcash/app/core/tokens/TokenPurpose.kt | 0 .../app/core/tokens/TokenSwapPurpose.kt | 0 .../app/core/updater/NetworkUpdater.kt | 0 .../core/userprofile/UpdateProfileResult.kt | 0 .../app/core/userprofile/UpdateProfileStep.kt | 0 .../flipcash/app/core/util/AbbreviatedLink.kt | 0 .../kotlin/com/flipcash/app/core/util/Fiat.kt | 0 .../com/flipcash/app/core/util/Linkify.kt | 0 .../app/core/util/MessagingPackages.kt | 0 .../com/flipcash/app/core/util/Number.kt | 0 .../core/verification/VerificationResult.kt | 0 .../app/core/verification/VerificationStep.kt | 0 .../verification/email/EmailCodeChannel.kt | 0 .../verification/email/EmailDeeplinkOrigin.kt | 0 .../email/LocalEmailCodeChannel.kt | 0 .../app/core/withdrawal/WithdrawalResult.kt | 0 .../app/core/withdrawal/WithdrawalStep.kt | 0 .../res/drawable-xxhdpi/ic_coin_dollars.webp | Bin .../res/drawable/bill_texture_1.webp | Bin .../res/drawable/bill_texture_2.webp | Bin .../res/drawable/bill_texture_3.webp | Bin .../res/drawable/bill_texture_4.webp | Bin .../res/drawable/bill_texture_5.webp | Bin .../res/drawable/bill_texture_6.webp | Bin .../res/drawable/bill_texture_7.webp | Bin .../res/drawable/bill_texture_8.webp | Bin .../res/drawable/close_right_arrow.xml | 0 .../res/drawable/ic_access_key_in_photos.webp | Bin .../res/drawable/ic_advanced_features.xml | 0 .../res/drawable/ic_app_update_required.xml | 0 .../res/drawable/ic_arrow_down.xml | 0 .../res/drawable/ic_arrow_right.xml | 0 .../res/drawable/ic_arrow_up_large.xml | 0 .../res/drawable/ic_at.xml | 0 .../res/drawable/ic_backpack_wallet.webp | Bin .../res/drawable/ic_banknote.xml | 0 .../res/drawable/ic_bill_previews.webp | Bin .../res/drawable/ic_biometrics.xml | 0 .../res/drawable/ic_bottom_navigation.xml | 0 .../res/drawable/ic_bubble_outline.xml | 0 .../res/drawable/ic_buy_with_google_pay.xml | 0 .../res/drawable/ic_callout_warning.xml | 0 .../res/drawable/ic_camera.xml | 0 .../res/drawable/ic_camera_request.webp | Bin .../res/drawable/ic_cash_bill.webp | Bin .../res/drawable/ic_checked.xml | 0 .../res/drawable/ic_checked_green.xml | 0 .../res/drawable/ic_checklist.xml | 0 .../res/drawable/ic_chevron_down_small.xml | 0 .../res/drawable/ic_circle_check_large.xml | 0 .../drawable/ic_circle_exclamation_large.xml | 0 .../res/drawable/ic_coins.xml | 0 .../res/drawable/ic_coins_add.xml | 0 .../res/drawable/ic_color_tune_hsl.xml | 0 .../ic_contact_method_verification.xml | 0 .../res/drawable/ic_convert.xml | 0 .../res/drawable/ic_currency_coin.xml | 0 .../drawable/ic_currencycreator_cashbill.xml | 0 .../ic_currencycreator_description.xml | 0 .../res/drawable/ic_currencycreator_gift.xml | 0 .../res/drawable/ic_currencycreator_icon.xml | 0 .../res/drawable/ic_currencycreator_name.xml | 0 .../drawable/ic_currencycreator_purchase.xml | 0 .../res/drawable/ic_debit_card.xml | 0 .../res/drawable/ic_device_frame.xml | 0 .../res/drawable/ic_existing_contact.xml | 0 .../res/drawable/ic_flipcash_badge.xml | 0 .../res/drawable/ic_flipcash_balance.xml | 0 .../res/drawable/ic_flipcash_logo.xml | 0 .../ic_flipcash_logo_offwhite_small.xml | 0 .../res/drawable/ic_flipcash_logo_w_name.xml | 0 .../ic_flipcash_logo_w_name_large.xml | 0 .../res/drawable/ic_flipcash_pools.xml | 0 .../res/drawable/ic_globe.xml | 0 .../res/drawable/ic_google_pay.xml | 0 .../res/drawable/ic_google_pay_brand_mark.xml | 0 .../res/drawable/ic_group_3.xml | 0 .../res/drawable/ic_hardware_security_key.xml | 0 .../res/drawable/ic_home_options.xml | 0 .../res/drawable/ic_host.xml | 0 .../res/drawable/ic_info_bars.xml | 0 .../res/drawable/ic_linked_payment_method.xml | 0 .../res/drawable/ic_lock.xml | 0 .../res/drawable/ic_logo_round_white.xml | 0 .../res/drawable/ic_market_cap_curve.xml | 0 .../res/drawable/ic_menu_account.xml | 0 .../res/drawable/ic_menu_deposit.xml | 0 .../res/drawable/ic_menu_key.xml | 0 .../res/drawable/ic_menu_logout.xml | 0 .../res/drawable/ic_menu_switchaccounts.xml | 0 .../res/drawable/ic_menu_withdraw.xml | 0 .../res/drawable/ic_minus.xml | 0 .../res/drawable/ic_nav_chat.xml | 0 .../res/drawable/ic_nav_chat_selected.xml | 0 .../res/drawable/ic_nav_tipcard.xml | 0 .../res/drawable/ic_nav_tipcard_selected.xml | 0 .../res/drawable/ic_nav_wallet.xml | 0 .../res/drawable/ic_nav_wallet_selected.xml | 0 .../res/drawable/ic_new_email.xml | 0 .../drawable/ic_notification_preview_icon.png | Bin .../res/drawable/ic_notification_request.webp | Bin .../res/drawable/ic_pay_with_google_pay.xml | 0 .../res/drawable/ic_people_circle.xml | 0 .../res/drawable/ic_people_gear.xml | 0 .../res/drawable/ic_phantom_buy_connect.xml | 0 .../res/drawable/ic_phantom_connected.xml | 0 .../res/drawable/ic_phantom_wallet.xml | 0 .../res/drawable/ic_plus.xml | 0 .../res/drawable/ic_qr_code.xml | 0 .../res/drawable/ic_screen_frame.xml | 0 .../res/drawable/ic_send_large.xml | 0 .../res/drawable/ic_send_outlined.xml | 0 .../res/drawable/ic_social_discord.xml | 0 .../res/drawable/ic_social_tg.xml | 0 .../res/drawable/ic_social_web.xml | 0 .../res/drawable/ic_social_x.xml | 0 .../res/drawable/ic_solana_logo.xml | 0 .../res/drawable/ic_solflare_wallet.xml | 0 .../res/drawable/ic_tipcode.xml | 0 .../res/drawable/ic_tipping_hand.xml | 0 .../res/drawable/ic_transfer_deposit.xml | 0 .../res/drawable/ic_transfer_withdraw.xml | 0 .../res/drawable/ic_trophy.xml | 0 .../res/drawable/ic_unchecked.xml | 0 .../res/drawable/ic_undo.xml | 0 .../res/drawable/ic_unknown_contact.xml | 0 .../res/drawable/ic_usdc.xml | 0 .../res/drawable/ic_usdc_on_solana.xml | 0 .../res/drawable/ic_wallet.xml | 0 .../res/drawable/ic_warning_alert_large.xml | 0 .../res/drawable/ic_withdraw_usdf_as_usdc.xml | 0 .../res/values/strings-universal.xml | 0 .../res/values/strings.xml | 0 .../app/core/blocklist/BlockedUserProfile.kt | 0 .../app/core/feed/ActivityFeedMessage.kt | 0 249 files changed, 64 insertions(+), 41 deletions(-) rename apps/flipcash/core/src/{test => androidHostTest}/kotlin/com/flipcash/app/core/MainCoroutineRule.kt (100%) rename apps/flipcash/core/src/{test => androidHostTest}/kotlin/com/flipcash/app/core/bill/BillStateTest.kt (100%) rename apps/flipcash/core/src/{test => androidHostTest}/kotlin/com/flipcash/app/core/bill/ScannableTest.kt (100%) rename apps/flipcash/core/src/{test => androidHostTest}/kotlin/com/flipcash/app/core/cache/CachePolicyHandlerTest.kt (100%) rename apps/flipcash/core/src/{test => androidHostTest}/kotlin/com/flipcash/app/core/chat/ProfileOriginTest.kt (100%) rename apps/flipcash/core/src/{test => androidHostTest}/kotlin/com/flipcash/app/core/data/LoadableTest.kt (100%) rename apps/flipcash/core/src/{test => androidHostTest}/kotlin/com/flipcash/app/core/extensions/ListExtensionsTest.kt (100%) rename apps/flipcash/core/src/{test => androidHostTest}/kotlin/com/flipcash/app/core/feed/ActivityFeedMessageTest.kt (100%) rename apps/flipcash/core/src/{test => androidHostTest}/kotlin/com/flipcash/app/core/internal/bill/BillControllerTest.kt (100%) rename apps/flipcash/core/src/{test => androidHostTest}/kotlin/com/flipcash/app/core/internal/extensions/ResultExtensionsTest.kt (100%) rename apps/flipcash/core/src/{test => androidHostTest}/kotlin/com/flipcash/app/core/links/ExternalLinksTest.kt (100%) rename apps/flipcash/core/src/{test => androidHostTest}/kotlin/com/flipcash/app/core/links/TrustedLinksTest.kt (100%) rename apps/flipcash/core/src/{test => androidHostTest}/kotlin/com/flipcash/app/core/media/MediaUrlResolverTest.kt (100%) rename apps/flipcash/core/src/{test => androidHostTest}/kotlin/com/flipcash/app/core/money/FormatUtilsTest.kt (100%) rename apps/flipcash/core/src/{test => androidHostTest}/kotlin/com/flipcash/app/core/navigation/DeeplinkFragmentsTest.kt (100%) rename apps/flipcash/core/src/{test => androidHostTest}/kotlin/com/flipcash/app/core/navigation/DeeplinkScanPolicyTest.kt (100%) rename apps/flipcash/core/src/{test => androidHostTest}/kotlin/com/flipcash/app/core/navigation/HomeRouteTest.kt (100%) rename apps/flipcash/core/src/{test => androidHostTest}/kotlin/com/flipcash/app/core/navigation/NavBarRoutesTest.kt (100%) rename apps/flipcash/core/src/{test => androidHostTest}/kotlin/com/flipcash/app/core/share/KikCodePainterTest.kt (100%) rename apps/flipcash/core/src/{test => androidHostTest}/kotlin/com/flipcash/app/core/share/TipCodeExportNameTest.kt (100%) rename apps/flipcash/core/src/{test => androidHostTest}/kotlin/com/flipcash/app/core/share/groupcard/GroupCardQrTest.kt (100%) rename apps/flipcash/core/src/{test => androidHostTest}/kotlin/com/flipcash/app/core/time/FakeTimeProviderTest.kt (100%) rename apps/flipcash/core/src/{test => androidHostTest}/kotlin/com/flipcash/app/core/tokens/CompletedInPlaceTest.kt (100%) rename apps/flipcash/core/src/{test => androidHostTest}/kotlin/com/flipcash/app/core/tokens/TokenInfoEntryTest.kt (100%) rename apps/flipcash/core/src/{test => androidHostTest}/kotlin/com/flipcash/app/core/updater/NetworkUpdaterTest.kt (100%) rename apps/flipcash/core/src/{test => androidHostTest}/kotlin/com/flipcash/app/core/util/AbbreviatedLinkTest.kt (100%) rename apps/flipcash/core/src/{test => androidHostTest}/kotlin/com/flipcash/app/core/util/FiatTest.kt (100%) rename apps/flipcash/core/src/{test => androidHostTest}/kotlin/com/flipcash/app/core/util/NumberTest.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/AppRoute.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/Locals.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/android/ActivityProvider.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/android/IntentLauncher.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/android/IntentUtils.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/android/VersionInfo.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/android/extensions/Context.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/android/extensions/Uri.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/annotations/AccountType.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/bill/BillState.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/bill/PaymentRequest.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/bill/Scannable.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/cache/CacheEntry.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/cache/CachePolicy.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/cache/CachePolicyHandler.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/chat/ChatIdentifier.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/chat/ChatParticipant.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/chat/ChatStep.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/chat/DmDestination.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/chat/NewGroupStep.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/chat/ProfileAddress.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/chat/ReportSubject.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/chrome/ChromeTabsUtils.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/contacts/DeviceContact.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/data/Loadable.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/deposit/DepositResult.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/deposit/DepositStep.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/encryption/Sodium.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/extensions/Boolean.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/extensions/Clipboard.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/extensions/CodeNavigator.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/extensions/Flow.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/extensions/List.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/extensions/Pair.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/extensions/Result.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/internal/bill/BillController.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/internal/errors/ErrorUtil.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/internal/extensions/Bitmap.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/internal/extensions/Result.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/internal/updater/ProfileUpdater.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/links/ExternalLinks.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/links/TrustedWebsites.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/media/ImageCachePresence.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/media/MediaUrlResolver.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/media/RememberMediaUrl.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/moderation/ModerationMessages.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/money/FormatUtils.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/navigation/DeeplinkAction.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/navigation/DeeplinkType.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/navigation/HomeRoute.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/navigation/LocalTabBarPadding.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/navigation/NavBarButton.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/navigation/NavBarRoutes.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/navigation/SteppedFlowRoute.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/navigation/TabBarVisibility.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/onboarding/OnboardingStep.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/onramp/deeplinks/WalletDeeplinkConnectionResult.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/onramp/ui/ConfirmInWalletButtonLabel.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/onramp/ui/PhantomLabel.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/reporting/ReportStep.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/share/SharePreviewImage.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/share/TipCodeExport.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/share/TipCodeExporter.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/share/TipCodePreview.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/share/TipCodePreviewRenderer.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/share/TipCodePreviewStorage.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/share/groupcard/GroupCardExporter.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/share/groupcard/QrMatrix.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/share/groupcard/StyledQrGeometry.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/share/groupcard/StyledQrRenderer.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/storage/MediaSaver.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/time/FakeTimeProvider.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/time/TimeProvider.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/tipping/OwnTipCard.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/tipping/TipCardOwner.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/tipping/TipSelection.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/toast/SystemToastController.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/toast/ToastController.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/tokens/CurrencyCreatorDraft.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/tokens/CurrencyCreatorResult.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/tokens/CurrencyCreatorStep.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/tokens/SwapResult.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/tokens/SwapStep.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/tokens/TokenDisplayName.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/tokens/TokenInfoEntry.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/tokens/TokenPurpose.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/tokens/TokenSwapPurpose.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/updater/NetworkUpdater.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/userprofile/UpdateProfileResult.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/userprofile/UpdateProfileStep.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/util/AbbreviatedLink.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/util/Fiat.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/util/Linkify.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/util/MessagingPackages.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/util/Number.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/verification/VerificationResult.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/verification/VerificationStep.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/verification/email/EmailCodeChannel.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/verification/email/EmailDeeplinkOrigin.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/verification/email/LocalEmailCodeChannel.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/withdrawal/WithdrawalResult.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/kotlin/com/flipcash/app/core/withdrawal/WithdrawalStep.kt (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable-xxhdpi/ic_coin_dollars.webp (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/bill_texture_1.webp (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/bill_texture_2.webp (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/bill_texture_3.webp (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/bill_texture_4.webp (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/bill_texture_5.webp (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/bill_texture_6.webp (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/bill_texture_7.webp (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/bill_texture_8.webp (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/close_right_arrow.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_access_key_in_photos.webp (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_advanced_features.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_app_update_required.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_arrow_down.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_arrow_right.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_arrow_up_large.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_at.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_backpack_wallet.webp (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_banknote.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_bill_previews.webp (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_biometrics.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_bottom_navigation.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_bubble_outline.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_buy_with_google_pay.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_callout_warning.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_camera.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_camera_request.webp (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_cash_bill.webp (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_checked.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_checked_green.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_checklist.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_chevron_down_small.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_circle_check_large.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_circle_exclamation_large.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_coins.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_coins_add.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_color_tune_hsl.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_contact_method_verification.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_convert.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_currency_coin.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_currencycreator_cashbill.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_currencycreator_description.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_currencycreator_gift.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_currencycreator_icon.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_currencycreator_name.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_currencycreator_purchase.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_debit_card.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_device_frame.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_existing_contact.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_flipcash_badge.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_flipcash_balance.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_flipcash_logo.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_flipcash_logo_offwhite_small.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_flipcash_logo_w_name.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_flipcash_logo_w_name_large.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_flipcash_pools.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_globe.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_google_pay.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_google_pay_brand_mark.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_group_3.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_hardware_security_key.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_home_options.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_host.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_info_bars.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_linked_payment_method.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_lock.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_logo_round_white.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_market_cap_curve.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_menu_account.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_menu_deposit.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_menu_key.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_menu_logout.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_menu_switchaccounts.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_menu_withdraw.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_minus.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_nav_chat.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_nav_chat_selected.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_nav_tipcard.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_nav_tipcard_selected.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_nav_wallet.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_nav_wallet_selected.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_new_email.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_notification_preview_icon.png (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_notification_request.webp (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_pay_with_google_pay.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_people_circle.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_people_gear.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_phantom_buy_connect.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_phantom_connected.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_phantom_wallet.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_plus.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_qr_code.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_screen_frame.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_send_large.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_send_outlined.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_social_discord.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_social_tg.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_social_web.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_social_x.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_solana_logo.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_solflare_wallet.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_tipcode.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_tipping_hand.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_transfer_deposit.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_transfer_withdraw.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_trophy.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_unchecked.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_undo.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_unknown_contact.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_usdc.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_usdc_on_solana.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_wallet.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_warning_alert_large.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/drawable/ic_withdraw_usdf_as_usdc.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/values/strings-universal.xml (100%) rename apps/flipcash/core/src/{main => androidMain}/res/values/strings.xml (100%) rename apps/flipcash/core/src/{main => commonMain}/kotlin/com/flipcash/app/core/blocklist/BlockedUserProfile.kt (100%) rename apps/flipcash/core/src/{main => commonMain}/kotlin/com/flipcash/app/core/feed/ActivityFeedMessage.kt (100%) diff --git a/apps/flipcash/core/build.gradle.kts b/apps/flipcash/core/build.gradle.kts index f9e14795ad..0967c1843a 100644 --- a/apps/flipcash/core/build.gradle.kts +++ b/apps/flipcash/core/build.gradle.kts @@ -1,49 +1,72 @@ plugins { - alias(libs.plugins.flipcash.android.feature) + alias(libs.plugins.flipcash.kmp.app.library) + alias(libs.plugins.compose.compiler) + alias(libs.plugins.kotlin.ksp) } -android { - namespace = "${Gradle.flipcashNamespace}.core" -} - -dependencies { - implementation(libs.bundles.haze) - implementation(libs.zxing) - testImplementation(kotlin("test")) - testImplementation(libs.bundles.unit.testing) - testImplementation(libs.robolectric) - - implementation(libs.androidx.browser) - - implementation(libs.kotlinx.serialization.core) - implementation(libs.kotlinx.serialization.json) - - implementation(platform(libs.firebase.bom)) - implementation(libs.firebase.messaging) - - implementation(libs.androidx.localbroadcastmanager) - implementation(libs.androidx.datastore) - implementation(libs.compose.material3) +kotlin { + android { + namespace = "${Gradle.flipcashNamespace}.core" + androidResources { + enable = true + } + } - api(libs.coil3) - api(libs.coil3.network) + sourceSets { + commonMain.dependencies { + implementation(libs.kotlinx.serialization.core) + implementation(libs.kotlinx.serialization.json) + implementation(libs.jetbrains.compose.runtime) - api(project(":services:flipcash-compose")) + api(project(":services:flipcash")) + api(project(":services:opencode")) + implementation(project(":libs:encryption:keys")) + } + androidMain.dependencies { + // What flipcash.android.feature supplied before the move to KMP. + implementation(libs.bundles.hilt) + implementation(project.dependencies.platform(libs.compose.bom)) + implementation(libs.bundles.compose) + implementation(libs.rinku.compose) + implementation(project(":libs:coroutines")) + implementation(project(":libs:logging")) + implementation(project(":ui:components")) + implementation(project(":ui:navigation")) + implementation(project(":ui:resources")) + implementation(project(":ui:theme")) - api(project(":libs:reporting")) - implementation(project(":libs:messaging")) - api(project(":libs:permissions:public")) - implementation(project(":libs:vibrator:public")) - - implementation(project(":apps:flipcash:shared:userflags")) - api(project(":apps:flipcash:shared:theme")) - - api(libs.sodium.bindings) - - api(project(":vendor:kik:scanner")) - - api(project(":ui:core")) - api(libs.navigation3.runtime) + implementation(libs.bundles.haze) + implementation(libs.zxing) + implementation(libs.androidx.browser) + implementation(project.dependencies.platform(libs.firebase.bom)) + implementation(libs.firebase.messaging) + implementation(libs.androidx.localbroadcastmanager) + implementation(libs.androidx.datastore) + implementation(libs.compose.material3) + api(libs.coil3) + api(libs.coil3.network) + api(project(":services:flipcash-compose")) + api(project(":libs:reporting")) + implementation(project(":libs:messaging")) + api(project(":libs:permissions:public")) + implementation(project(":libs:vibrator:public")) + implementation(project(":apps:flipcash:shared:userflags")) + api(project(":apps:flipcash:shared:theme")) + api(libs.sodium.bindings) + api(project(":vendor:kik:scanner")) + api(project(":ui:core")) + api(libs.navigation3.runtime) + api(project(":vendor:tipkit:tipkit-m2")) + } + getByName("androidHostTest").dependencies { + implementation(kotlin("test")) + implementation(libs.bundles.unit.testing) + implementation(libs.robolectric) + } + } +} - api(project(":vendor:tipkit:tipkit-m2")) +dependencies { + add("kspAndroid", libs.hilt.android.compiler) + add("kspAndroid", libs.hilt.compiler) } diff --git a/apps/flipcash/core/src/test/kotlin/com/flipcash/app/core/MainCoroutineRule.kt b/apps/flipcash/core/src/androidHostTest/kotlin/com/flipcash/app/core/MainCoroutineRule.kt similarity index 100% rename from apps/flipcash/core/src/test/kotlin/com/flipcash/app/core/MainCoroutineRule.kt rename to apps/flipcash/core/src/androidHostTest/kotlin/com/flipcash/app/core/MainCoroutineRule.kt diff --git a/apps/flipcash/core/src/test/kotlin/com/flipcash/app/core/bill/BillStateTest.kt b/apps/flipcash/core/src/androidHostTest/kotlin/com/flipcash/app/core/bill/BillStateTest.kt similarity index 100% rename from apps/flipcash/core/src/test/kotlin/com/flipcash/app/core/bill/BillStateTest.kt rename to apps/flipcash/core/src/androidHostTest/kotlin/com/flipcash/app/core/bill/BillStateTest.kt diff --git a/apps/flipcash/core/src/test/kotlin/com/flipcash/app/core/bill/ScannableTest.kt b/apps/flipcash/core/src/androidHostTest/kotlin/com/flipcash/app/core/bill/ScannableTest.kt similarity index 100% rename from apps/flipcash/core/src/test/kotlin/com/flipcash/app/core/bill/ScannableTest.kt rename to apps/flipcash/core/src/androidHostTest/kotlin/com/flipcash/app/core/bill/ScannableTest.kt diff --git a/apps/flipcash/core/src/test/kotlin/com/flipcash/app/core/cache/CachePolicyHandlerTest.kt b/apps/flipcash/core/src/androidHostTest/kotlin/com/flipcash/app/core/cache/CachePolicyHandlerTest.kt similarity index 100% rename from apps/flipcash/core/src/test/kotlin/com/flipcash/app/core/cache/CachePolicyHandlerTest.kt rename to apps/flipcash/core/src/androidHostTest/kotlin/com/flipcash/app/core/cache/CachePolicyHandlerTest.kt diff --git a/apps/flipcash/core/src/test/kotlin/com/flipcash/app/core/chat/ProfileOriginTest.kt b/apps/flipcash/core/src/androidHostTest/kotlin/com/flipcash/app/core/chat/ProfileOriginTest.kt similarity index 100% rename from apps/flipcash/core/src/test/kotlin/com/flipcash/app/core/chat/ProfileOriginTest.kt rename to apps/flipcash/core/src/androidHostTest/kotlin/com/flipcash/app/core/chat/ProfileOriginTest.kt diff --git a/apps/flipcash/core/src/test/kotlin/com/flipcash/app/core/data/LoadableTest.kt b/apps/flipcash/core/src/androidHostTest/kotlin/com/flipcash/app/core/data/LoadableTest.kt similarity index 100% rename from apps/flipcash/core/src/test/kotlin/com/flipcash/app/core/data/LoadableTest.kt rename to apps/flipcash/core/src/androidHostTest/kotlin/com/flipcash/app/core/data/LoadableTest.kt diff --git a/apps/flipcash/core/src/test/kotlin/com/flipcash/app/core/extensions/ListExtensionsTest.kt b/apps/flipcash/core/src/androidHostTest/kotlin/com/flipcash/app/core/extensions/ListExtensionsTest.kt similarity index 100% rename from apps/flipcash/core/src/test/kotlin/com/flipcash/app/core/extensions/ListExtensionsTest.kt rename to apps/flipcash/core/src/androidHostTest/kotlin/com/flipcash/app/core/extensions/ListExtensionsTest.kt diff --git a/apps/flipcash/core/src/test/kotlin/com/flipcash/app/core/feed/ActivityFeedMessageTest.kt b/apps/flipcash/core/src/androidHostTest/kotlin/com/flipcash/app/core/feed/ActivityFeedMessageTest.kt similarity index 100% rename from apps/flipcash/core/src/test/kotlin/com/flipcash/app/core/feed/ActivityFeedMessageTest.kt rename to apps/flipcash/core/src/androidHostTest/kotlin/com/flipcash/app/core/feed/ActivityFeedMessageTest.kt diff --git a/apps/flipcash/core/src/test/kotlin/com/flipcash/app/core/internal/bill/BillControllerTest.kt b/apps/flipcash/core/src/androidHostTest/kotlin/com/flipcash/app/core/internal/bill/BillControllerTest.kt similarity index 100% rename from apps/flipcash/core/src/test/kotlin/com/flipcash/app/core/internal/bill/BillControllerTest.kt rename to apps/flipcash/core/src/androidHostTest/kotlin/com/flipcash/app/core/internal/bill/BillControllerTest.kt diff --git a/apps/flipcash/core/src/test/kotlin/com/flipcash/app/core/internal/extensions/ResultExtensionsTest.kt b/apps/flipcash/core/src/androidHostTest/kotlin/com/flipcash/app/core/internal/extensions/ResultExtensionsTest.kt similarity index 100% rename from apps/flipcash/core/src/test/kotlin/com/flipcash/app/core/internal/extensions/ResultExtensionsTest.kt rename to apps/flipcash/core/src/androidHostTest/kotlin/com/flipcash/app/core/internal/extensions/ResultExtensionsTest.kt diff --git a/apps/flipcash/core/src/test/kotlin/com/flipcash/app/core/links/ExternalLinksTest.kt b/apps/flipcash/core/src/androidHostTest/kotlin/com/flipcash/app/core/links/ExternalLinksTest.kt similarity index 100% rename from apps/flipcash/core/src/test/kotlin/com/flipcash/app/core/links/ExternalLinksTest.kt rename to apps/flipcash/core/src/androidHostTest/kotlin/com/flipcash/app/core/links/ExternalLinksTest.kt diff --git a/apps/flipcash/core/src/test/kotlin/com/flipcash/app/core/links/TrustedLinksTest.kt b/apps/flipcash/core/src/androidHostTest/kotlin/com/flipcash/app/core/links/TrustedLinksTest.kt similarity index 100% rename from apps/flipcash/core/src/test/kotlin/com/flipcash/app/core/links/TrustedLinksTest.kt rename to apps/flipcash/core/src/androidHostTest/kotlin/com/flipcash/app/core/links/TrustedLinksTest.kt diff --git a/apps/flipcash/core/src/test/kotlin/com/flipcash/app/core/media/MediaUrlResolverTest.kt b/apps/flipcash/core/src/androidHostTest/kotlin/com/flipcash/app/core/media/MediaUrlResolverTest.kt similarity index 100% rename from apps/flipcash/core/src/test/kotlin/com/flipcash/app/core/media/MediaUrlResolverTest.kt rename to apps/flipcash/core/src/androidHostTest/kotlin/com/flipcash/app/core/media/MediaUrlResolverTest.kt diff --git a/apps/flipcash/core/src/test/kotlin/com/flipcash/app/core/money/FormatUtilsTest.kt b/apps/flipcash/core/src/androidHostTest/kotlin/com/flipcash/app/core/money/FormatUtilsTest.kt similarity index 100% rename from apps/flipcash/core/src/test/kotlin/com/flipcash/app/core/money/FormatUtilsTest.kt rename to apps/flipcash/core/src/androidHostTest/kotlin/com/flipcash/app/core/money/FormatUtilsTest.kt diff --git a/apps/flipcash/core/src/test/kotlin/com/flipcash/app/core/navigation/DeeplinkFragmentsTest.kt b/apps/flipcash/core/src/androidHostTest/kotlin/com/flipcash/app/core/navigation/DeeplinkFragmentsTest.kt similarity index 100% rename from apps/flipcash/core/src/test/kotlin/com/flipcash/app/core/navigation/DeeplinkFragmentsTest.kt rename to apps/flipcash/core/src/androidHostTest/kotlin/com/flipcash/app/core/navigation/DeeplinkFragmentsTest.kt diff --git a/apps/flipcash/core/src/test/kotlin/com/flipcash/app/core/navigation/DeeplinkScanPolicyTest.kt b/apps/flipcash/core/src/androidHostTest/kotlin/com/flipcash/app/core/navigation/DeeplinkScanPolicyTest.kt similarity index 100% rename from apps/flipcash/core/src/test/kotlin/com/flipcash/app/core/navigation/DeeplinkScanPolicyTest.kt rename to apps/flipcash/core/src/androidHostTest/kotlin/com/flipcash/app/core/navigation/DeeplinkScanPolicyTest.kt diff --git a/apps/flipcash/core/src/test/kotlin/com/flipcash/app/core/navigation/HomeRouteTest.kt b/apps/flipcash/core/src/androidHostTest/kotlin/com/flipcash/app/core/navigation/HomeRouteTest.kt similarity index 100% rename from apps/flipcash/core/src/test/kotlin/com/flipcash/app/core/navigation/HomeRouteTest.kt rename to apps/flipcash/core/src/androidHostTest/kotlin/com/flipcash/app/core/navigation/HomeRouteTest.kt diff --git a/apps/flipcash/core/src/test/kotlin/com/flipcash/app/core/navigation/NavBarRoutesTest.kt b/apps/flipcash/core/src/androidHostTest/kotlin/com/flipcash/app/core/navigation/NavBarRoutesTest.kt similarity index 100% rename from apps/flipcash/core/src/test/kotlin/com/flipcash/app/core/navigation/NavBarRoutesTest.kt rename to apps/flipcash/core/src/androidHostTest/kotlin/com/flipcash/app/core/navigation/NavBarRoutesTest.kt diff --git a/apps/flipcash/core/src/test/kotlin/com/flipcash/app/core/share/KikCodePainterTest.kt b/apps/flipcash/core/src/androidHostTest/kotlin/com/flipcash/app/core/share/KikCodePainterTest.kt similarity index 100% rename from apps/flipcash/core/src/test/kotlin/com/flipcash/app/core/share/KikCodePainterTest.kt rename to apps/flipcash/core/src/androidHostTest/kotlin/com/flipcash/app/core/share/KikCodePainterTest.kt diff --git a/apps/flipcash/core/src/test/kotlin/com/flipcash/app/core/share/TipCodeExportNameTest.kt b/apps/flipcash/core/src/androidHostTest/kotlin/com/flipcash/app/core/share/TipCodeExportNameTest.kt similarity index 100% rename from apps/flipcash/core/src/test/kotlin/com/flipcash/app/core/share/TipCodeExportNameTest.kt rename to apps/flipcash/core/src/androidHostTest/kotlin/com/flipcash/app/core/share/TipCodeExportNameTest.kt diff --git a/apps/flipcash/core/src/test/kotlin/com/flipcash/app/core/share/groupcard/GroupCardQrTest.kt b/apps/flipcash/core/src/androidHostTest/kotlin/com/flipcash/app/core/share/groupcard/GroupCardQrTest.kt similarity index 100% rename from apps/flipcash/core/src/test/kotlin/com/flipcash/app/core/share/groupcard/GroupCardQrTest.kt rename to apps/flipcash/core/src/androidHostTest/kotlin/com/flipcash/app/core/share/groupcard/GroupCardQrTest.kt diff --git a/apps/flipcash/core/src/test/kotlin/com/flipcash/app/core/time/FakeTimeProviderTest.kt b/apps/flipcash/core/src/androidHostTest/kotlin/com/flipcash/app/core/time/FakeTimeProviderTest.kt similarity index 100% rename from apps/flipcash/core/src/test/kotlin/com/flipcash/app/core/time/FakeTimeProviderTest.kt rename to apps/flipcash/core/src/androidHostTest/kotlin/com/flipcash/app/core/time/FakeTimeProviderTest.kt diff --git a/apps/flipcash/core/src/test/kotlin/com/flipcash/app/core/tokens/CompletedInPlaceTest.kt b/apps/flipcash/core/src/androidHostTest/kotlin/com/flipcash/app/core/tokens/CompletedInPlaceTest.kt similarity index 100% rename from apps/flipcash/core/src/test/kotlin/com/flipcash/app/core/tokens/CompletedInPlaceTest.kt rename to apps/flipcash/core/src/androidHostTest/kotlin/com/flipcash/app/core/tokens/CompletedInPlaceTest.kt diff --git a/apps/flipcash/core/src/test/kotlin/com/flipcash/app/core/tokens/TokenInfoEntryTest.kt b/apps/flipcash/core/src/androidHostTest/kotlin/com/flipcash/app/core/tokens/TokenInfoEntryTest.kt similarity index 100% rename from apps/flipcash/core/src/test/kotlin/com/flipcash/app/core/tokens/TokenInfoEntryTest.kt rename to apps/flipcash/core/src/androidHostTest/kotlin/com/flipcash/app/core/tokens/TokenInfoEntryTest.kt diff --git a/apps/flipcash/core/src/test/kotlin/com/flipcash/app/core/updater/NetworkUpdaterTest.kt b/apps/flipcash/core/src/androidHostTest/kotlin/com/flipcash/app/core/updater/NetworkUpdaterTest.kt similarity index 100% rename from apps/flipcash/core/src/test/kotlin/com/flipcash/app/core/updater/NetworkUpdaterTest.kt rename to apps/flipcash/core/src/androidHostTest/kotlin/com/flipcash/app/core/updater/NetworkUpdaterTest.kt diff --git a/apps/flipcash/core/src/test/kotlin/com/flipcash/app/core/util/AbbreviatedLinkTest.kt b/apps/flipcash/core/src/androidHostTest/kotlin/com/flipcash/app/core/util/AbbreviatedLinkTest.kt similarity index 100% rename from apps/flipcash/core/src/test/kotlin/com/flipcash/app/core/util/AbbreviatedLinkTest.kt rename to apps/flipcash/core/src/androidHostTest/kotlin/com/flipcash/app/core/util/AbbreviatedLinkTest.kt diff --git a/apps/flipcash/core/src/test/kotlin/com/flipcash/app/core/util/FiatTest.kt b/apps/flipcash/core/src/androidHostTest/kotlin/com/flipcash/app/core/util/FiatTest.kt similarity index 100% rename from apps/flipcash/core/src/test/kotlin/com/flipcash/app/core/util/FiatTest.kt rename to apps/flipcash/core/src/androidHostTest/kotlin/com/flipcash/app/core/util/FiatTest.kt diff --git a/apps/flipcash/core/src/test/kotlin/com/flipcash/app/core/util/NumberTest.kt b/apps/flipcash/core/src/androidHostTest/kotlin/com/flipcash/app/core/util/NumberTest.kt similarity index 100% rename from apps/flipcash/core/src/test/kotlin/com/flipcash/app/core/util/NumberTest.kt rename to apps/flipcash/core/src/androidHostTest/kotlin/com/flipcash/app/core/util/NumberTest.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/AppRoute.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/AppRoute.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/AppRoute.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/AppRoute.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/Locals.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/Locals.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/Locals.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/Locals.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/android/ActivityProvider.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/android/ActivityProvider.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/android/ActivityProvider.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/android/ActivityProvider.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/android/IntentLauncher.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/android/IntentLauncher.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/android/IntentLauncher.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/android/IntentLauncher.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/android/IntentUtils.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/android/IntentUtils.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/android/IntentUtils.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/android/IntentUtils.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/android/VersionInfo.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/android/VersionInfo.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/android/VersionInfo.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/android/VersionInfo.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/android/extensions/Context.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/android/extensions/Context.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/android/extensions/Context.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/android/extensions/Context.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/android/extensions/Uri.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/android/extensions/Uri.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/android/extensions/Uri.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/android/extensions/Uri.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/annotations/AccountType.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/annotations/AccountType.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/annotations/AccountType.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/annotations/AccountType.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/bill/BillState.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/bill/BillState.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/bill/BillState.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/bill/BillState.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/bill/PaymentRequest.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/bill/PaymentRequest.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/bill/PaymentRequest.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/bill/PaymentRequest.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/bill/Scannable.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/bill/Scannable.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/bill/Scannable.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/bill/Scannable.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/cache/CacheEntry.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/cache/CacheEntry.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/cache/CacheEntry.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/cache/CacheEntry.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/cache/CachePolicy.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/cache/CachePolicy.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/cache/CachePolicy.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/cache/CachePolicy.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/cache/CachePolicyHandler.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/cache/CachePolicyHandler.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/cache/CachePolicyHandler.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/cache/CachePolicyHandler.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/chat/ChatIdentifier.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/chat/ChatIdentifier.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/chat/ChatIdentifier.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/chat/ChatIdentifier.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/chat/ChatParticipant.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/chat/ChatParticipant.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/chat/ChatParticipant.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/chat/ChatParticipant.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/chat/ChatStep.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/chat/ChatStep.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/chat/ChatStep.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/chat/ChatStep.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/chat/DmDestination.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/chat/DmDestination.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/chat/DmDestination.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/chat/DmDestination.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/chat/NewGroupStep.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/chat/NewGroupStep.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/chat/NewGroupStep.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/chat/NewGroupStep.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/chat/ProfileAddress.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/chat/ProfileAddress.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/chat/ProfileAddress.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/chat/ProfileAddress.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/chat/ReportSubject.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/chat/ReportSubject.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/chat/ReportSubject.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/chat/ReportSubject.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/chrome/ChromeTabsUtils.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/chrome/ChromeTabsUtils.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/chrome/ChromeTabsUtils.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/chrome/ChromeTabsUtils.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/contacts/DeviceContact.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/contacts/DeviceContact.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/contacts/DeviceContact.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/contacts/DeviceContact.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/data/Loadable.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/data/Loadable.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/data/Loadable.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/data/Loadable.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/deposit/DepositResult.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/deposit/DepositResult.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/deposit/DepositResult.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/deposit/DepositResult.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/deposit/DepositStep.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/deposit/DepositStep.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/deposit/DepositStep.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/deposit/DepositStep.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/encryption/Sodium.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/encryption/Sodium.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/encryption/Sodium.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/encryption/Sodium.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/extensions/Boolean.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/extensions/Boolean.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/extensions/Boolean.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/extensions/Boolean.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/extensions/Clipboard.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/extensions/Clipboard.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/extensions/Clipboard.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/extensions/Clipboard.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/extensions/CodeNavigator.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/extensions/CodeNavigator.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/extensions/CodeNavigator.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/extensions/CodeNavigator.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/extensions/Flow.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/extensions/Flow.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/extensions/Flow.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/extensions/Flow.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/extensions/List.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/extensions/List.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/extensions/List.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/extensions/List.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/extensions/Pair.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/extensions/Pair.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/extensions/Pair.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/extensions/Pair.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/extensions/Result.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/extensions/Result.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/extensions/Result.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/extensions/Result.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/internal/bill/BillController.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/internal/bill/BillController.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/internal/bill/BillController.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/internal/bill/BillController.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/internal/errors/ErrorUtil.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/internal/errors/ErrorUtil.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/internal/errors/ErrorUtil.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/internal/errors/ErrorUtil.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/internal/extensions/Bitmap.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/internal/extensions/Bitmap.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/internal/extensions/Bitmap.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/internal/extensions/Bitmap.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/internal/extensions/Result.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/internal/extensions/Result.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/internal/extensions/Result.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/internal/extensions/Result.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/internal/updater/ProfileUpdater.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/internal/updater/ProfileUpdater.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/internal/updater/ProfileUpdater.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/internal/updater/ProfileUpdater.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/links/ExternalLinks.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/links/ExternalLinks.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/links/ExternalLinks.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/links/ExternalLinks.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/links/TrustedWebsites.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/links/TrustedWebsites.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/links/TrustedWebsites.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/links/TrustedWebsites.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/media/ImageCachePresence.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/media/ImageCachePresence.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/media/ImageCachePresence.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/media/ImageCachePresence.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/media/MediaUrlResolver.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/media/MediaUrlResolver.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/media/MediaUrlResolver.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/media/MediaUrlResolver.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/media/RememberMediaUrl.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/media/RememberMediaUrl.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/media/RememberMediaUrl.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/media/RememberMediaUrl.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/moderation/ModerationMessages.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/moderation/ModerationMessages.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/moderation/ModerationMessages.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/moderation/ModerationMessages.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/money/FormatUtils.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/money/FormatUtils.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/money/FormatUtils.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/money/FormatUtils.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/navigation/DeeplinkAction.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/navigation/DeeplinkAction.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/navigation/DeeplinkAction.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/navigation/DeeplinkAction.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/navigation/DeeplinkType.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/navigation/DeeplinkType.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/navigation/DeeplinkType.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/navigation/DeeplinkType.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/navigation/HomeRoute.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/navigation/HomeRoute.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/navigation/HomeRoute.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/navigation/HomeRoute.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/navigation/LocalTabBarPadding.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/navigation/LocalTabBarPadding.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/navigation/LocalTabBarPadding.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/navigation/LocalTabBarPadding.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/navigation/NavBarButton.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/navigation/NavBarButton.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/navigation/NavBarButton.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/navigation/NavBarButton.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/navigation/NavBarRoutes.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/navigation/NavBarRoutes.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/navigation/NavBarRoutes.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/navigation/NavBarRoutes.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/navigation/SteppedFlowRoute.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/navigation/SteppedFlowRoute.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/navigation/SteppedFlowRoute.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/navigation/SteppedFlowRoute.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/navigation/TabBarVisibility.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/navigation/TabBarVisibility.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/navigation/TabBarVisibility.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/navigation/TabBarVisibility.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/onboarding/OnboardingStep.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/onboarding/OnboardingStep.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/onboarding/OnboardingStep.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/onboarding/OnboardingStep.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/onramp/deeplinks/WalletDeeplinkConnectionResult.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/onramp/deeplinks/WalletDeeplinkConnectionResult.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/onramp/deeplinks/WalletDeeplinkConnectionResult.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/onramp/deeplinks/WalletDeeplinkConnectionResult.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/onramp/ui/ConfirmInWalletButtonLabel.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/onramp/ui/ConfirmInWalletButtonLabel.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/onramp/ui/ConfirmInWalletButtonLabel.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/onramp/ui/ConfirmInWalletButtonLabel.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/onramp/ui/PhantomLabel.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/onramp/ui/PhantomLabel.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/onramp/ui/PhantomLabel.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/onramp/ui/PhantomLabel.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/reporting/ReportStep.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/reporting/ReportStep.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/reporting/ReportStep.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/reporting/ReportStep.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/share/SharePreviewImage.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/share/SharePreviewImage.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/share/SharePreviewImage.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/share/SharePreviewImage.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/share/TipCodeExport.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/share/TipCodeExport.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/share/TipCodeExport.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/share/TipCodeExport.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/share/TipCodeExporter.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/share/TipCodeExporter.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/share/TipCodeExporter.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/share/TipCodeExporter.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/share/TipCodePreview.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/share/TipCodePreview.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/share/TipCodePreview.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/share/TipCodePreview.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/share/TipCodePreviewRenderer.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/share/TipCodePreviewRenderer.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/share/TipCodePreviewRenderer.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/share/TipCodePreviewRenderer.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/share/TipCodePreviewStorage.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/share/TipCodePreviewStorage.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/share/TipCodePreviewStorage.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/share/TipCodePreviewStorage.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/share/groupcard/GroupCardExporter.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/share/groupcard/GroupCardExporter.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/share/groupcard/GroupCardExporter.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/share/groupcard/GroupCardExporter.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/share/groupcard/QrMatrix.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/share/groupcard/QrMatrix.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/share/groupcard/QrMatrix.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/share/groupcard/QrMatrix.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/share/groupcard/StyledQrGeometry.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/share/groupcard/StyledQrGeometry.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/share/groupcard/StyledQrGeometry.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/share/groupcard/StyledQrGeometry.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/share/groupcard/StyledQrRenderer.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/share/groupcard/StyledQrRenderer.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/share/groupcard/StyledQrRenderer.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/share/groupcard/StyledQrRenderer.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/storage/MediaSaver.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/storage/MediaSaver.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/storage/MediaSaver.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/storage/MediaSaver.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/time/FakeTimeProvider.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/time/FakeTimeProvider.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/time/FakeTimeProvider.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/time/FakeTimeProvider.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/time/TimeProvider.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/time/TimeProvider.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/time/TimeProvider.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/time/TimeProvider.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/tipping/OwnTipCard.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/tipping/OwnTipCard.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/tipping/OwnTipCard.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/tipping/OwnTipCard.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/tipping/TipCardOwner.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/tipping/TipCardOwner.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/tipping/TipCardOwner.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/tipping/TipCardOwner.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/tipping/TipSelection.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/tipping/TipSelection.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/tipping/TipSelection.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/tipping/TipSelection.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/toast/SystemToastController.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/toast/SystemToastController.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/toast/SystemToastController.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/toast/SystemToastController.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/toast/ToastController.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/toast/ToastController.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/toast/ToastController.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/toast/ToastController.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/tokens/CurrencyCreatorDraft.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/tokens/CurrencyCreatorDraft.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/tokens/CurrencyCreatorDraft.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/tokens/CurrencyCreatorDraft.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/tokens/CurrencyCreatorResult.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/tokens/CurrencyCreatorResult.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/tokens/CurrencyCreatorResult.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/tokens/CurrencyCreatorResult.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/tokens/CurrencyCreatorStep.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/tokens/CurrencyCreatorStep.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/tokens/CurrencyCreatorStep.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/tokens/CurrencyCreatorStep.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/tokens/SwapResult.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/tokens/SwapResult.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/tokens/SwapResult.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/tokens/SwapResult.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/tokens/SwapStep.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/tokens/SwapStep.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/tokens/SwapStep.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/tokens/SwapStep.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/tokens/TokenDisplayName.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/tokens/TokenDisplayName.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/tokens/TokenDisplayName.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/tokens/TokenDisplayName.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/tokens/TokenInfoEntry.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/tokens/TokenInfoEntry.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/tokens/TokenInfoEntry.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/tokens/TokenInfoEntry.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/tokens/TokenPurpose.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/tokens/TokenPurpose.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/tokens/TokenPurpose.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/tokens/TokenPurpose.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/tokens/TokenSwapPurpose.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/tokens/TokenSwapPurpose.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/tokens/TokenSwapPurpose.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/tokens/TokenSwapPurpose.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/updater/NetworkUpdater.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/updater/NetworkUpdater.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/updater/NetworkUpdater.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/updater/NetworkUpdater.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/userprofile/UpdateProfileResult.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/userprofile/UpdateProfileResult.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/userprofile/UpdateProfileResult.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/userprofile/UpdateProfileResult.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/userprofile/UpdateProfileStep.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/userprofile/UpdateProfileStep.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/userprofile/UpdateProfileStep.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/userprofile/UpdateProfileStep.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/util/AbbreviatedLink.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/util/AbbreviatedLink.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/util/AbbreviatedLink.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/util/AbbreviatedLink.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/util/Fiat.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/util/Fiat.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/util/Fiat.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/util/Fiat.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/util/Linkify.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/util/Linkify.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/util/Linkify.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/util/Linkify.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/util/MessagingPackages.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/util/MessagingPackages.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/util/MessagingPackages.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/util/MessagingPackages.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/util/Number.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/util/Number.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/util/Number.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/util/Number.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/verification/VerificationResult.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/verification/VerificationResult.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/verification/VerificationResult.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/verification/VerificationResult.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/verification/VerificationStep.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/verification/VerificationStep.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/verification/VerificationStep.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/verification/VerificationStep.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/verification/email/EmailCodeChannel.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/verification/email/EmailCodeChannel.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/verification/email/EmailCodeChannel.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/verification/email/EmailCodeChannel.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/verification/email/EmailDeeplinkOrigin.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/verification/email/EmailDeeplinkOrigin.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/verification/email/EmailDeeplinkOrigin.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/verification/email/EmailDeeplinkOrigin.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/verification/email/LocalEmailCodeChannel.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/verification/email/LocalEmailCodeChannel.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/verification/email/LocalEmailCodeChannel.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/verification/email/LocalEmailCodeChannel.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/withdrawal/WithdrawalResult.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/withdrawal/WithdrawalResult.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/withdrawal/WithdrawalResult.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/withdrawal/WithdrawalResult.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/withdrawal/WithdrawalStep.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/withdrawal/WithdrawalStep.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/withdrawal/WithdrawalStep.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/withdrawal/WithdrawalStep.kt diff --git a/apps/flipcash/core/src/main/res/drawable-xxhdpi/ic_coin_dollars.webp b/apps/flipcash/core/src/androidMain/res/drawable-xxhdpi/ic_coin_dollars.webp similarity index 100% rename from apps/flipcash/core/src/main/res/drawable-xxhdpi/ic_coin_dollars.webp rename to apps/flipcash/core/src/androidMain/res/drawable-xxhdpi/ic_coin_dollars.webp diff --git a/apps/flipcash/core/src/main/res/drawable/bill_texture_1.webp b/apps/flipcash/core/src/androidMain/res/drawable/bill_texture_1.webp similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/bill_texture_1.webp rename to apps/flipcash/core/src/androidMain/res/drawable/bill_texture_1.webp diff --git a/apps/flipcash/core/src/main/res/drawable/bill_texture_2.webp b/apps/flipcash/core/src/androidMain/res/drawable/bill_texture_2.webp similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/bill_texture_2.webp rename to apps/flipcash/core/src/androidMain/res/drawable/bill_texture_2.webp diff --git a/apps/flipcash/core/src/main/res/drawable/bill_texture_3.webp b/apps/flipcash/core/src/androidMain/res/drawable/bill_texture_3.webp similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/bill_texture_3.webp rename to apps/flipcash/core/src/androidMain/res/drawable/bill_texture_3.webp diff --git a/apps/flipcash/core/src/main/res/drawable/bill_texture_4.webp b/apps/flipcash/core/src/androidMain/res/drawable/bill_texture_4.webp similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/bill_texture_4.webp rename to apps/flipcash/core/src/androidMain/res/drawable/bill_texture_4.webp diff --git a/apps/flipcash/core/src/main/res/drawable/bill_texture_5.webp b/apps/flipcash/core/src/androidMain/res/drawable/bill_texture_5.webp similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/bill_texture_5.webp rename to apps/flipcash/core/src/androidMain/res/drawable/bill_texture_5.webp diff --git a/apps/flipcash/core/src/main/res/drawable/bill_texture_6.webp b/apps/flipcash/core/src/androidMain/res/drawable/bill_texture_6.webp similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/bill_texture_6.webp rename to apps/flipcash/core/src/androidMain/res/drawable/bill_texture_6.webp diff --git a/apps/flipcash/core/src/main/res/drawable/bill_texture_7.webp b/apps/flipcash/core/src/androidMain/res/drawable/bill_texture_7.webp similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/bill_texture_7.webp rename to apps/flipcash/core/src/androidMain/res/drawable/bill_texture_7.webp diff --git a/apps/flipcash/core/src/main/res/drawable/bill_texture_8.webp b/apps/flipcash/core/src/androidMain/res/drawable/bill_texture_8.webp similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/bill_texture_8.webp rename to apps/flipcash/core/src/androidMain/res/drawable/bill_texture_8.webp diff --git a/apps/flipcash/core/src/main/res/drawable/close_right_arrow.xml b/apps/flipcash/core/src/androidMain/res/drawable/close_right_arrow.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/close_right_arrow.xml rename to apps/flipcash/core/src/androidMain/res/drawable/close_right_arrow.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_access_key_in_photos.webp b/apps/flipcash/core/src/androidMain/res/drawable/ic_access_key_in_photos.webp similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_access_key_in_photos.webp rename to apps/flipcash/core/src/androidMain/res/drawable/ic_access_key_in_photos.webp diff --git a/apps/flipcash/core/src/main/res/drawable/ic_advanced_features.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_advanced_features.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_advanced_features.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_advanced_features.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_app_update_required.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_app_update_required.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_app_update_required.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_app_update_required.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_arrow_down.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_arrow_down.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_arrow_down.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_arrow_down.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_arrow_right.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_arrow_right.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_arrow_right.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_arrow_right.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_arrow_up_large.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_arrow_up_large.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_arrow_up_large.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_arrow_up_large.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_at.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_at.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_at.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_at.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_backpack_wallet.webp b/apps/flipcash/core/src/androidMain/res/drawable/ic_backpack_wallet.webp similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_backpack_wallet.webp rename to apps/flipcash/core/src/androidMain/res/drawable/ic_backpack_wallet.webp diff --git a/apps/flipcash/core/src/main/res/drawable/ic_banknote.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_banknote.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_banknote.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_banknote.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_bill_previews.webp b/apps/flipcash/core/src/androidMain/res/drawable/ic_bill_previews.webp similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_bill_previews.webp rename to apps/flipcash/core/src/androidMain/res/drawable/ic_bill_previews.webp diff --git a/apps/flipcash/core/src/main/res/drawable/ic_biometrics.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_biometrics.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_biometrics.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_biometrics.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_bottom_navigation.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_bottom_navigation.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_bottom_navigation.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_bottom_navigation.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_bubble_outline.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_bubble_outline.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_bubble_outline.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_bubble_outline.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_buy_with_google_pay.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_buy_with_google_pay.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_buy_with_google_pay.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_buy_with_google_pay.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_callout_warning.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_callout_warning.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_callout_warning.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_callout_warning.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_camera.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_camera.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_camera.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_camera.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_camera_request.webp b/apps/flipcash/core/src/androidMain/res/drawable/ic_camera_request.webp similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_camera_request.webp rename to apps/flipcash/core/src/androidMain/res/drawable/ic_camera_request.webp diff --git a/apps/flipcash/core/src/main/res/drawable/ic_cash_bill.webp b/apps/flipcash/core/src/androidMain/res/drawable/ic_cash_bill.webp similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_cash_bill.webp rename to apps/flipcash/core/src/androidMain/res/drawable/ic_cash_bill.webp diff --git a/apps/flipcash/core/src/main/res/drawable/ic_checked.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_checked.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_checked.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_checked.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_checked_green.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_checked_green.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_checked_green.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_checked_green.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_checklist.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_checklist.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_checklist.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_checklist.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_chevron_down_small.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_chevron_down_small.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_chevron_down_small.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_chevron_down_small.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_circle_check_large.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_circle_check_large.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_circle_check_large.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_circle_check_large.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_circle_exclamation_large.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_circle_exclamation_large.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_circle_exclamation_large.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_circle_exclamation_large.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_coins.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_coins.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_coins.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_coins.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_coins_add.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_coins_add.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_coins_add.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_coins_add.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_color_tune_hsl.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_color_tune_hsl.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_color_tune_hsl.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_color_tune_hsl.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_contact_method_verification.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_contact_method_verification.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_contact_method_verification.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_contact_method_verification.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_convert.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_convert.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_convert.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_convert.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_currency_coin.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_currency_coin.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_currency_coin.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_currency_coin.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_currencycreator_cashbill.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_currencycreator_cashbill.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_currencycreator_cashbill.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_currencycreator_cashbill.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_currencycreator_description.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_currencycreator_description.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_currencycreator_description.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_currencycreator_description.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_currencycreator_gift.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_currencycreator_gift.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_currencycreator_gift.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_currencycreator_gift.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_currencycreator_icon.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_currencycreator_icon.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_currencycreator_icon.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_currencycreator_icon.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_currencycreator_name.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_currencycreator_name.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_currencycreator_name.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_currencycreator_name.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_currencycreator_purchase.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_currencycreator_purchase.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_currencycreator_purchase.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_currencycreator_purchase.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_debit_card.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_debit_card.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_debit_card.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_debit_card.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_device_frame.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_device_frame.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_device_frame.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_device_frame.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_existing_contact.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_existing_contact.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_existing_contact.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_existing_contact.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_flipcash_badge.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_flipcash_badge.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_flipcash_badge.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_flipcash_badge.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_flipcash_balance.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_flipcash_balance.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_flipcash_balance.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_flipcash_balance.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_flipcash_logo.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_flipcash_logo.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_flipcash_logo.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_flipcash_logo.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_flipcash_logo_offwhite_small.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_flipcash_logo_offwhite_small.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_flipcash_logo_offwhite_small.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_flipcash_logo_offwhite_small.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_flipcash_logo_w_name.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_flipcash_logo_w_name.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_flipcash_logo_w_name.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_flipcash_logo_w_name.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_flipcash_logo_w_name_large.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_flipcash_logo_w_name_large.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_flipcash_logo_w_name_large.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_flipcash_logo_w_name_large.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_flipcash_pools.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_flipcash_pools.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_flipcash_pools.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_flipcash_pools.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_globe.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_globe.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_globe.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_globe.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_google_pay.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_google_pay.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_google_pay.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_google_pay.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_google_pay_brand_mark.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_google_pay_brand_mark.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_google_pay_brand_mark.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_google_pay_brand_mark.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_group_3.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_group_3.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_group_3.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_group_3.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_hardware_security_key.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_hardware_security_key.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_hardware_security_key.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_hardware_security_key.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_home_options.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_home_options.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_home_options.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_home_options.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_host.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_host.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_host.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_host.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_info_bars.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_info_bars.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_info_bars.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_info_bars.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_linked_payment_method.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_linked_payment_method.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_linked_payment_method.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_linked_payment_method.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_lock.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_lock.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_lock.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_lock.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_logo_round_white.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_logo_round_white.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_logo_round_white.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_logo_round_white.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_market_cap_curve.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_market_cap_curve.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_market_cap_curve.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_market_cap_curve.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_menu_account.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_menu_account.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_menu_account.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_menu_account.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_menu_deposit.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_menu_deposit.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_menu_deposit.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_menu_deposit.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_menu_key.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_menu_key.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_menu_key.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_menu_key.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_menu_logout.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_menu_logout.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_menu_logout.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_menu_logout.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_menu_switchaccounts.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_menu_switchaccounts.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_menu_switchaccounts.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_menu_switchaccounts.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_menu_withdraw.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_menu_withdraw.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_menu_withdraw.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_menu_withdraw.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_minus.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_minus.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_minus.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_minus.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_nav_chat.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_nav_chat.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_nav_chat.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_nav_chat.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_nav_chat_selected.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_nav_chat_selected.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_nav_chat_selected.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_nav_chat_selected.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_nav_tipcard.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_nav_tipcard.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_nav_tipcard.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_nav_tipcard.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_nav_tipcard_selected.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_nav_tipcard_selected.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_nav_tipcard_selected.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_nav_tipcard_selected.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_nav_wallet.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_nav_wallet.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_nav_wallet.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_nav_wallet.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_nav_wallet_selected.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_nav_wallet_selected.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_nav_wallet_selected.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_nav_wallet_selected.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_new_email.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_new_email.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_new_email.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_new_email.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_notification_preview_icon.png b/apps/flipcash/core/src/androidMain/res/drawable/ic_notification_preview_icon.png similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_notification_preview_icon.png rename to apps/flipcash/core/src/androidMain/res/drawable/ic_notification_preview_icon.png diff --git a/apps/flipcash/core/src/main/res/drawable/ic_notification_request.webp b/apps/flipcash/core/src/androidMain/res/drawable/ic_notification_request.webp similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_notification_request.webp rename to apps/flipcash/core/src/androidMain/res/drawable/ic_notification_request.webp diff --git a/apps/flipcash/core/src/main/res/drawable/ic_pay_with_google_pay.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_pay_with_google_pay.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_pay_with_google_pay.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_pay_with_google_pay.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_people_circle.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_people_circle.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_people_circle.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_people_circle.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_people_gear.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_people_gear.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_people_gear.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_people_gear.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_phantom_buy_connect.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_phantom_buy_connect.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_phantom_buy_connect.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_phantom_buy_connect.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_phantom_connected.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_phantom_connected.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_phantom_connected.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_phantom_connected.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_phantom_wallet.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_phantom_wallet.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_phantom_wallet.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_phantom_wallet.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_plus.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_plus.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_plus.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_plus.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_qr_code.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_qr_code.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_qr_code.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_qr_code.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_screen_frame.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_screen_frame.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_screen_frame.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_screen_frame.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_send_large.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_send_large.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_send_large.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_send_large.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_send_outlined.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_send_outlined.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_send_outlined.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_send_outlined.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_social_discord.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_social_discord.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_social_discord.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_social_discord.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_social_tg.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_social_tg.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_social_tg.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_social_tg.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_social_web.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_social_web.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_social_web.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_social_web.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_social_x.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_social_x.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_social_x.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_social_x.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_solana_logo.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_solana_logo.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_solana_logo.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_solana_logo.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_solflare_wallet.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_solflare_wallet.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_solflare_wallet.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_solflare_wallet.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_tipcode.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_tipcode.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_tipcode.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_tipcode.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_tipping_hand.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_tipping_hand.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_tipping_hand.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_tipping_hand.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_transfer_deposit.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_transfer_deposit.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_transfer_deposit.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_transfer_deposit.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_transfer_withdraw.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_transfer_withdraw.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_transfer_withdraw.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_transfer_withdraw.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_trophy.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_trophy.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_trophy.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_trophy.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_unchecked.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_unchecked.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_unchecked.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_unchecked.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_undo.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_undo.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_undo.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_undo.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_unknown_contact.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_unknown_contact.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_unknown_contact.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_unknown_contact.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_usdc.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_usdc.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_usdc.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_usdc.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_usdc_on_solana.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_usdc_on_solana.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_usdc_on_solana.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_usdc_on_solana.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_wallet.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_wallet.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_wallet.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_wallet.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_warning_alert_large.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_warning_alert_large.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_warning_alert_large.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_warning_alert_large.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_withdraw_usdf_as_usdc.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_withdraw_usdf_as_usdc.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_withdraw_usdf_as_usdc.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_withdraw_usdf_as_usdc.xml diff --git a/apps/flipcash/core/src/main/res/values/strings-universal.xml b/apps/flipcash/core/src/androidMain/res/values/strings-universal.xml similarity index 100% rename from apps/flipcash/core/src/main/res/values/strings-universal.xml rename to apps/flipcash/core/src/androidMain/res/values/strings-universal.xml diff --git a/apps/flipcash/core/src/main/res/values/strings.xml b/apps/flipcash/core/src/androidMain/res/values/strings.xml similarity index 100% rename from apps/flipcash/core/src/main/res/values/strings.xml rename to apps/flipcash/core/src/androidMain/res/values/strings.xml diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/blocklist/BlockedUserProfile.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/blocklist/BlockedUserProfile.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/blocklist/BlockedUserProfile.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/blocklist/BlockedUserProfile.kt diff --git a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/feed/ActivityFeedMessage.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/feed/ActivityFeedMessage.kt similarity index 100% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/feed/ActivityFeedMessage.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/feed/ActivityFeedMessage.kt From 3f90e29b00129c7cb882e8cad4fd0058f8df06ee Mon Sep 17 00:00:00 2001 From: Brandon McAnsh Date: Fri, 23 Oct 2026 17:20:11 -0400 Subject: [PATCH 13/50] build(persistence): move persistence:sources to android+jvm KMP Data sources call a common inTransaction instead of room-ktx's withTransaction, which Room KMP only offers on Android. Android keeps withTransaction; the JVM runs the block on Room's writer connection. Token icons encode with java.util.Base64, which matches Android's NO_WRAP output. The draft data source and its mappers use Uri, so they stay in androidMain. --- .../app/persistence/Transactions.android.kt | 6 ++ .../flipcash/app/persistence/Transactions.kt | 9 +++ .../app/persistence/Transactions.jvm.kt | 8 +++ .../persistence/sources/build.gradle.kts | 62 +++++++++++-------- .../sources/ChatArchiveDataSourceTest.kt | 0 .../sources/ChatMetadataDataSourceTest.kt | 0 .../sources/IncomingMessageOpenerTest.kt | 0 .../sources/MessageDataSourceTest.kt | 0 .../sources/UnreadStreamReadinessTest.kt | 0 .../sources/UserProfileDataSourceTest.kt | 0 .../mapper/chat/ChatEntityMapperTest.kt | 0 .../MessageEntityToFeedMessageMapperTest.kt | 0 .../NotificationToEntityMapperTest.kt | 0 .../mediator/ChatFeedRemoteMediatorTest.kt | 0 .../mediator/ChatMessageRemoteMediatorTest.kt | 0 .../sources/mediator/FeedWatermarkTest.kt | 0 .../sources/CurrencyCreatorDraftDataSource.kt | 0 .../mapper/draft/DraftToEntityMapper.kt | 0 .../mapper/draft/EntityToDraftMapper.kt | 0 .../sources/BlockedUserDataSource.kt | 6 +- .../sources/ChatArchiveDataSource.kt | 0 .../sources/ChatDraftDataSource.kt | 0 .../app/persistence/sources/ChatFeedWriter.kt | 4 +- .../sources/ChatMemberDataSource.kt | 6 +- .../sources/ChatMessageDataSource.kt | 4 +- .../sources/ChatMetadataDataSource.kt | 0 .../persistence/sources/ContactDataSource.kt | 0 .../sources/IncomingMessageOpener.kt | 0 .../sources/LinkPreviewDataSource.kt | 0 .../persistence/sources/MessageDataSource.kt | 0 .../sources/PendingMediaDataSource.kt | 0 .../persistence/sources/TokenDataSource.kt | 0 .../sources/UserProfileDataSource.kt | 0 .../mapper/UserProfileDomainMappers.kt | 0 .../BlockedUserEntityToProfileMapper.kt | 0 .../blocklist/BlockedUserToEntityMapper.kt | 0 .../sources/mapper/chat/ChatEntityMapper.kt | 0 .../MessageEntityToFeedMessageMapper.kt | 0 .../NotificationToEntityMapper.kt | 0 .../mapper/tokens/EntityToTokenMapper.kt | 4 +- .../RelationToTokenWithBalanceMapper.kt | 0 .../mapper/tokens/TokenToEntityMapper.kt | 4 +- .../mediator/BlocklistRemoteMediator.kt | 0 .../mediator/ChatFeedRemoteMediator.kt | 0 .../mediator/ChatMessageRemoteMediator.kt | 0 .../sources/mediator/FeedRemoteMediator.kt | 0 .../sources/mediator/FeedWatermark.kt | 0 .../tokens/core/ReservesBalanceProvider.kt | 0 .../app/tokens/core/TotalBalanceProvider.kt | 0 49 files changed, 72 insertions(+), 41 deletions(-) create mode 100644 apps/flipcash/shared/persistence/db/src/androidMain/kotlin/com/flipcash/app/persistence/Transactions.android.kt create mode 100644 apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/Transactions.kt create mode 100644 apps/flipcash/shared/persistence/db/src/jvmMain/kotlin/com/flipcash/app/persistence/Transactions.jvm.kt rename apps/flipcash/shared/persistence/sources/src/{test => androidHostTest}/kotlin/com/flipcash/app/persistence/sources/ChatArchiveDataSourceTest.kt (100%) rename apps/flipcash/shared/persistence/sources/src/{test => androidHostTest}/kotlin/com/flipcash/app/persistence/sources/ChatMetadataDataSourceTest.kt (100%) rename apps/flipcash/shared/persistence/sources/src/{test => androidHostTest}/kotlin/com/flipcash/app/persistence/sources/IncomingMessageOpenerTest.kt (100%) rename apps/flipcash/shared/persistence/sources/src/{test => androidHostTest}/kotlin/com/flipcash/app/persistence/sources/MessageDataSourceTest.kt (100%) rename apps/flipcash/shared/persistence/sources/src/{test => androidHostTest}/kotlin/com/flipcash/app/persistence/sources/UnreadStreamReadinessTest.kt (100%) rename apps/flipcash/shared/persistence/sources/src/{test => androidHostTest}/kotlin/com/flipcash/app/persistence/sources/UserProfileDataSourceTest.kt (100%) rename apps/flipcash/shared/persistence/sources/src/{test => androidHostTest}/kotlin/com/flipcash/app/persistence/sources/mapper/chat/ChatEntityMapperTest.kt (100%) rename apps/flipcash/shared/persistence/sources/src/{test => androidHostTest}/kotlin/com/flipcash/app/persistence/sources/mapper/notifications/MessageEntityToFeedMessageMapperTest.kt (100%) rename apps/flipcash/shared/persistence/sources/src/{test => androidHostTest}/kotlin/com/flipcash/app/persistence/sources/mapper/notifications/NotificationToEntityMapperTest.kt (100%) rename apps/flipcash/shared/persistence/sources/src/{test => androidHostTest}/kotlin/com/flipcash/app/persistence/sources/mediator/ChatFeedRemoteMediatorTest.kt (100%) rename apps/flipcash/shared/persistence/sources/src/{test => androidHostTest}/kotlin/com/flipcash/app/persistence/sources/mediator/ChatMessageRemoteMediatorTest.kt (100%) rename apps/flipcash/shared/persistence/sources/src/{test => androidHostTest}/kotlin/com/flipcash/app/persistence/sources/mediator/FeedWatermarkTest.kt (100%) rename apps/flipcash/shared/persistence/sources/src/{main => androidMain}/kotlin/com/flipcash/app/persistence/sources/CurrencyCreatorDraftDataSource.kt (100%) rename apps/flipcash/shared/persistence/sources/src/{main => androidMain}/kotlin/com/flipcash/app/persistence/sources/mapper/draft/DraftToEntityMapper.kt (100%) rename apps/flipcash/shared/persistence/sources/src/{main => androidMain}/kotlin/com/flipcash/app/persistence/sources/mapper/draft/EntityToDraftMapper.kt (100%) rename apps/flipcash/shared/persistence/sources/src/{main => commonMain}/kotlin/com/flipcash/app/persistence/sources/BlockedUserDataSource.kt (97%) rename apps/flipcash/shared/persistence/sources/src/{main => commonMain}/kotlin/com/flipcash/app/persistence/sources/ChatArchiveDataSource.kt (100%) rename apps/flipcash/shared/persistence/sources/src/{main => commonMain}/kotlin/com/flipcash/app/persistence/sources/ChatDraftDataSource.kt (100%) rename apps/flipcash/shared/persistence/sources/src/{main => commonMain}/kotlin/com/flipcash/app/persistence/sources/ChatFeedWriter.kt (92%) rename apps/flipcash/shared/persistence/sources/src/{main => commonMain}/kotlin/com/flipcash/app/persistence/sources/ChatMemberDataSource.kt (98%) rename apps/flipcash/shared/persistence/sources/src/{main => commonMain}/kotlin/com/flipcash/app/persistence/sources/ChatMessageDataSource.kt (99%) rename apps/flipcash/shared/persistence/sources/src/{main => commonMain}/kotlin/com/flipcash/app/persistence/sources/ChatMetadataDataSource.kt (100%) rename apps/flipcash/shared/persistence/sources/src/{main => commonMain}/kotlin/com/flipcash/app/persistence/sources/ContactDataSource.kt (100%) rename apps/flipcash/shared/persistence/sources/src/{main => commonMain}/kotlin/com/flipcash/app/persistence/sources/IncomingMessageOpener.kt (100%) rename apps/flipcash/shared/persistence/sources/src/{main => commonMain}/kotlin/com/flipcash/app/persistence/sources/LinkPreviewDataSource.kt (100%) rename apps/flipcash/shared/persistence/sources/src/{main => commonMain}/kotlin/com/flipcash/app/persistence/sources/MessageDataSource.kt (100%) rename apps/flipcash/shared/persistence/sources/src/{main => commonMain}/kotlin/com/flipcash/app/persistence/sources/PendingMediaDataSource.kt (100%) rename apps/flipcash/shared/persistence/sources/src/{main => commonMain}/kotlin/com/flipcash/app/persistence/sources/TokenDataSource.kt (100%) rename apps/flipcash/shared/persistence/sources/src/{main => commonMain}/kotlin/com/flipcash/app/persistence/sources/UserProfileDataSource.kt (100%) rename apps/flipcash/shared/persistence/sources/src/{main => commonMain}/kotlin/com/flipcash/app/persistence/sources/mapper/UserProfileDomainMappers.kt (100%) rename apps/flipcash/shared/persistence/sources/src/{main => commonMain}/kotlin/com/flipcash/app/persistence/sources/mapper/blocklist/BlockedUserEntityToProfileMapper.kt (100%) rename apps/flipcash/shared/persistence/sources/src/{main => commonMain}/kotlin/com/flipcash/app/persistence/sources/mapper/blocklist/BlockedUserToEntityMapper.kt (100%) rename apps/flipcash/shared/persistence/sources/src/{main => commonMain}/kotlin/com/flipcash/app/persistence/sources/mapper/chat/ChatEntityMapper.kt (100%) rename apps/flipcash/shared/persistence/sources/src/{main => commonMain}/kotlin/com/flipcash/app/persistence/sources/mapper/notifications/MessageEntityToFeedMessageMapper.kt (100%) rename apps/flipcash/shared/persistence/sources/src/{main => commonMain}/kotlin/com/flipcash/app/persistence/sources/mapper/notifications/NotificationToEntityMapper.kt (100%) rename apps/flipcash/shared/persistence/sources/src/{main => commonMain}/kotlin/com/flipcash/app/persistence/sources/mapper/tokens/EntityToTokenMapper.kt (98%) rename apps/flipcash/shared/persistence/sources/src/{main => commonMain}/kotlin/com/flipcash/app/persistence/sources/mapper/tokens/RelationToTokenWithBalanceMapper.kt (100%) rename apps/flipcash/shared/persistence/sources/src/{main => commonMain}/kotlin/com/flipcash/app/persistence/sources/mapper/tokens/TokenToEntityMapper.kt (98%) rename apps/flipcash/shared/persistence/sources/src/{main => commonMain}/kotlin/com/flipcash/app/persistence/sources/mediator/BlocklistRemoteMediator.kt (100%) rename apps/flipcash/shared/persistence/sources/src/{main => commonMain}/kotlin/com/flipcash/app/persistence/sources/mediator/ChatFeedRemoteMediator.kt (100%) rename apps/flipcash/shared/persistence/sources/src/{main => commonMain}/kotlin/com/flipcash/app/persistence/sources/mediator/ChatMessageRemoteMediator.kt (100%) rename apps/flipcash/shared/persistence/sources/src/{main => commonMain}/kotlin/com/flipcash/app/persistence/sources/mediator/FeedRemoteMediator.kt (100%) rename apps/flipcash/shared/persistence/sources/src/{main => commonMain}/kotlin/com/flipcash/app/persistence/sources/mediator/FeedWatermark.kt (100%) rename apps/flipcash/shared/tokens/core/src/{main => commonMain}/kotlin/com/flipcash/app/tokens/core/ReservesBalanceProvider.kt (100%) rename apps/flipcash/shared/tokens/core/src/{main => commonMain}/kotlin/com/flipcash/app/tokens/core/TotalBalanceProvider.kt (100%) diff --git a/apps/flipcash/shared/persistence/db/src/androidMain/kotlin/com/flipcash/app/persistence/Transactions.android.kt b/apps/flipcash/shared/persistence/db/src/androidMain/kotlin/com/flipcash/app/persistence/Transactions.android.kt new file mode 100644 index 0000000000..0c24c16320 --- /dev/null +++ b/apps/flipcash/shared/persistence/db/src/androidMain/kotlin/com/flipcash/app/persistence/Transactions.android.kt @@ -0,0 +1,6 @@ +package com.flipcash.app.persistence + +import androidx.room.RoomDatabase +import androidx.room.withTransaction + +actual suspend fun RoomDatabase.inTransaction(block: suspend () -> R): R = withTransaction(block) diff --git a/apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/Transactions.kt b/apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/Transactions.kt new file mode 100644 index 0000000000..ee1763491c --- /dev/null +++ b/apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/Transactions.kt @@ -0,0 +1,9 @@ +package com.flipcash.app.persistence + +import androidx.room.RoomDatabase + +/** + * Runs [block] in a write transaction. Android keeps room-ktx's `withTransaction`; the desktop target + * has no SupportSQLite, so it takes Room's writer connection instead. + */ +expect suspend fun RoomDatabase.inTransaction(block: suspend () -> R): R diff --git a/apps/flipcash/shared/persistence/db/src/jvmMain/kotlin/com/flipcash/app/persistence/Transactions.jvm.kt b/apps/flipcash/shared/persistence/db/src/jvmMain/kotlin/com/flipcash/app/persistence/Transactions.jvm.kt new file mode 100644 index 0000000000..3d2bf9c68e --- /dev/null +++ b/apps/flipcash/shared/persistence/db/src/jvmMain/kotlin/com/flipcash/app/persistence/Transactions.jvm.kt @@ -0,0 +1,8 @@ +package com.flipcash.app.persistence + +import androidx.room.RoomDatabase +import androidx.room.immediateTransaction +import androidx.room.useWriterConnection + +actual suspend fun RoomDatabase.inTransaction(block: suspend () -> R): R = + useWriterConnection { connection -> connection.immediateTransaction { block() } } diff --git a/apps/flipcash/shared/persistence/sources/build.gradle.kts b/apps/flipcash/shared/persistence/sources/build.gradle.kts index ea4b055ca7..ccb56905b3 100644 --- a/apps/flipcash/shared/persistence/sources/build.gradle.kts +++ b/apps/flipcash/shared/persistence/sources/build.gradle.kts @@ -1,36 +1,44 @@ plugins { - alias(libs.plugins.flipcash.android.feature) + alias(libs.plugins.flipcash.kmp.app.library) + alias(libs.plugins.kotlin.ksp) } -android { - namespace = "${Gradle.flipcashNamespace}.shared.persistence.sources" - defaultConfig { - javaCompileOptions { - annotationProcessorOptions { - arguments += mapOf("room.schemaLocation" to "$projectDir/schemas") - } +kotlin { + android { + namespace = "${Gradle.flipcashNamespace}.shared.persistence.sources" + } + + sourceSets { + commonMain.dependencies { + implementation(libs.bundles.kotlinx.serialization) + implementation(libs.androidx.room.runtime) + implementation(libs.androidx.paging.common) + implementation(libs.javax.inject) + + implementation(project(":apps:flipcash:core")) + implementation(project(":apps:flipcash:shared:persistence:db")) + implementation(project(":libs:coroutines")) + implementation(project(":libs:logging")) + implementation(project(":libs:encryption:base58")) + implementation(project(":libs:encryption:keys")) + implementation(project(":libs:encryption:utils")) + implementation(project(":services:flipcash")) + } + androidMain.dependencies { + implementation(libs.bundles.hilt) + implementation(libs.androidx.room.ktx) + implementation(libs.androidx.paging.runtime) + } + getByName("androidHostTest").dependencies { + implementation(kotlin("test")) + implementation(libs.bundles.unit.testing) + implementation(libs.robolectric) + implementation(project(":services:flipcash:test-fixtures")) } } } dependencies { - testImplementation(kotlin("test")) - testImplementation(libs.bundles.unit.testing) - testImplementation(libs.robolectric) - testImplementation(project(":services:flipcash:test-fixtures")) - - implementation(libs.bundles.kotlinx.serialization) - - implementation(libs.bundles.room) - implementation(libs.androidx.paging.runtime) - - ksp(libs.androidx.room.compiler) - - implementation(project(":apps:flipcash:shared:persistence:db")) - - implementation(project(":libs:encryption:base58")) - implementation(project(":libs:encryption:keys")) - implementation(project(":libs:encryption:utils")) - - implementation(project(":services:flipcash")) + add("kspAndroid", libs.hilt.android.compiler) + add("kspAndroid", libs.hilt.compiler) } diff --git a/apps/flipcash/shared/persistence/sources/src/test/kotlin/com/flipcash/app/persistence/sources/ChatArchiveDataSourceTest.kt b/apps/flipcash/shared/persistence/sources/src/androidHostTest/kotlin/com/flipcash/app/persistence/sources/ChatArchiveDataSourceTest.kt similarity index 100% rename from apps/flipcash/shared/persistence/sources/src/test/kotlin/com/flipcash/app/persistence/sources/ChatArchiveDataSourceTest.kt rename to apps/flipcash/shared/persistence/sources/src/androidHostTest/kotlin/com/flipcash/app/persistence/sources/ChatArchiveDataSourceTest.kt diff --git a/apps/flipcash/shared/persistence/sources/src/test/kotlin/com/flipcash/app/persistence/sources/ChatMetadataDataSourceTest.kt b/apps/flipcash/shared/persistence/sources/src/androidHostTest/kotlin/com/flipcash/app/persistence/sources/ChatMetadataDataSourceTest.kt similarity index 100% rename from apps/flipcash/shared/persistence/sources/src/test/kotlin/com/flipcash/app/persistence/sources/ChatMetadataDataSourceTest.kt rename to apps/flipcash/shared/persistence/sources/src/androidHostTest/kotlin/com/flipcash/app/persistence/sources/ChatMetadataDataSourceTest.kt diff --git a/apps/flipcash/shared/persistence/sources/src/test/kotlin/com/flipcash/app/persistence/sources/IncomingMessageOpenerTest.kt b/apps/flipcash/shared/persistence/sources/src/androidHostTest/kotlin/com/flipcash/app/persistence/sources/IncomingMessageOpenerTest.kt similarity index 100% rename from apps/flipcash/shared/persistence/sources/src/test/kotlin/com/flipcash/app/persistence/sources/IncomingMessageOpenerTest.kt rename to apps/flipcash/shared/persistence/sources/src/androidHostTest/kotlin/com/flipcash/app/persistence/sources/IncomingMessageOpenerTest.kt diff --git a/apps/flipcash/shared/persistence/sources/src/test/kotlin/com/flipcash/app/persistence/sources/MessageDataSourceTest.kt b/apps/flipcash/shared/persistence/sources/src/androidHostTest/kotlin/com/flipcash/app/persistence/sources/MessageDataSourceTest.kt similarity index 100% rename from apps/flipcash/shared/persistence/sources/src/test/kotlin/com/flipcash/app/persistence/sources/MessageDataSourceTest.kt rename to apps/flipcash/shared/persistence/sources/src/androidHostTest/kotlin/com/flipcash/app/persistence/sources/MessageDataSourceTest.kt diff --git a/apps/flipcash/shared/persistence/sources/src/test/kotlin/com/flipcash/app/persistence/sources/UnreadStreamReadinessTest.kt b/apps/flipcash/shared/persistence/sources/src/androidHostTest/kotlin/com/flipcash/app/persistence/sources/UnreadStreamReadinessTest.kt similarity index 100% rename from apps/flipcash/shared/persistence/sources/src/test/kotlin/com/flipcash/app/persistence/sources/UnreadStreamReadinessTest.kt rename to apps/flipcash/shared/persistence/sources/src/androidHostTest/kotlin/com/flipcash/app/persistence/sources/UnreadStreamReadinessTest.kt diff --git a/apps/flipcash/shared/persistence/sources/src/test/kotlin/com/flipcash/app/persistence/sources/UserProfileDataSourceTest.kt b/apps/flipcash/shared/persistence/sources/src/androidHostTest/kotlin/com/flipcash/app/persistence/sources/UserProfileDataSourceTest.kt similarity index 100% rename from apps/flipcash/shared/persistence/sources/src/test/kotlin/com/flipcash/app/persistence/sources/UserProfileDataSourceTest.kt rename to apps/flipcash/shared/persistence/sources/src/androidHostTest/kotlin/com/flipcash/app/persistence/sources/UserProfileDataSourceTest.kt diff --git a/apps/flipcash/shared/persistence/sources/src/test/kotlin/com/flipcash/app/persistence/sources/mapper/chat/ChatEntityMapperTest.kt b/apps/flipcash/shared/persistence/sources/src/androidHostTest/kotlin/com/flipcash/app/persistence/sources/mapper/chat/ChatEntityMapperTest.kt similarity index 100% rename from apps/flipcash/shared/persistence/sources/src/test/kotlin/com/flipcash/app/persistence/sources/mapper/chat/ChatEntityMapperTest.kt rename to apps/flipcash/shared/persistence/sources/src/androidHostTest/kotlin/com/flipcash/app/persistence/sources/mapper/chat/ChatEntityMapperTest.kt diff --git a/apps/flipcash/shared/persistence/sources/src/test/kotlin/com/flipcash/app/persistence/sources/mapper/notifications/MessageEntityToFeedMessageMapperTest.kt b/apps/flipcash/shared/persistence/sources/src/androidHostTest/kotlin/com/flipcash/app/persistence/sources/mapper/notifications/MessageEntityToFeedMessageMapperTest.kt similarity index 100% rename from apps/flipcash/shared/persistence/sources/src/test/kotlin/com/flipcash/app/persistence/sources/mapper/notifications/MessageEntityToFeedMessageMapperTest.kt rename to apps/flipcash/shared/persistence/sources/src/androidHostTest/kotlin/com/flipcash/app/persistence/sources/mapper/notifications/MessageEntityToFeedMessageMapperTest.kt diff --git a/apps/flipcash/shared/persistence/sources/src/test/kotlin/com/flipcash/app/persistence/sources/mapper/notifications/NotificationToEntityMapperTest.kt b/apps/flipcash/shared/persistence/sources/src/androidHostTest/kotlin/com/flipcash/app/persistence/sources/mapper/notifications/NotificationToEntityMapperTest.kt similarity index 100% rename from apps/flipcash/shared/persistence/sources/src/test/kotlin/com/flipcash/app/persistence/sources/mapper/notifications/NotificationToEntityMapperTest.kt rename to apps/flipcash/shared/persistence/sources/src/androidHostTest/kotlin/com/flipcash/app/persistence/sources/mapper/notifications/NotificationToEntityMapperTest.kt diff --git a/apps/flipcash/shared/persistence/sources/src/test/kotlin/com/flipcash/app/persistence/sources/mediator/ChatFeedRemoteMediatorTest.kt b/apps/flipcash/shared/persistence/sources/src/androidHostTest/kotlin/com/flipcash/app/persistence/sources/mediator/ChatFeedRemoteMediatorTest.kt similarity index 100% rename from apps/flipcash/shared/persistence/sources/src/test/kotlin/com/flipcash/app/persistence/sources/mediator/ChatFeedRemoteMediatorTest.kt rename to apps/flipcash/shared/persistence/sources/src/androidHostTest/kotlin/com/flipcash/app/persistence/sources/mediator/ChatFeedRemoteMediatorTest.kt diff --git a/apps/flipcash/shared/persistence/sources/src/test/kotlin/com/flipcash/app/persistence/sources/mediator/ChatMessageRemoteMediatorTest.kt b/apps/flipcash/shared/persistence/sources/src/androidHostTest/kotlin/com/flipcash/app/persistence/sources/mediator/ChatMessageRemoteMediatorTest.kt similarity index 100% rename from apps/flipcash/shared/persistence/sources/src/test/kotlin/com/flipcash/app/persistence/sources/mediator/ChatMessageRemoteMediatorTest.kt rename to apps/flipcash/shared/persistence/sources/src/androidHostTest/kotlin/com/flipcash/app/persistence/sources/mediator/ChatMessageRemoteMediatorTest.kt diff --git a/apps/flipcash/shared/persistence/sources/src/test/kotlin/com/flipcash/app/persistence/sources/mediator/FeedWatermarkTest.kt b/apps/flipcash/shared/persistence/sources/src/androidHostTest/kotlin/com/flipcash/app/persistence/sources/mediator/FeedWatermarkTest.kt similarity index 100% rename from apps/flipcash/shared/persistence/sources/src/test/kotlin/com/flipcash/app/persistence/sources/mediator/FeedWatermarkTest.kt rename to apps/flipcash/shared/persistence/sources/src/androidHostTest/kotlin/com/flipcash/app/persistence/sources/mediator/FeedWatermarkTest.kt diff --git a/apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/CurrencyCreatorDraftDataSource.kt b/apps/flipcash/shared/persistence/sources/src/androidMain/kotlin/com/flipcash/app/persistence/sources/CurrencyCreatorDraftDataSource.kt similarity index 100% rename from apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/CurrencyCreatorDraftDataSource.kt rename to apps/flipcash/shared/persistence/sources/src/androidMain/kotlin/com/flipcash/app/persistence/sources/CurrencyCreatorDraftDataSource.kt diff --git a/apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/mapper/draft/DraftToEntityMapper.kt b/apps/flipcash/shared/persistence/sources/src/androidMain/kotlin/com/flipcash/app/persistence/sources/mapper/draft/DraftToEntityMapper.kt similarity index 100% rename from apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/mapper/draft/DraftToEntityMapper.kt rename to apps/flipcash/shared/persistence/sources/src/androidMain/kotlin/com/flipcash/app/persistence/sources/mapper/draft/DraftToEntityMapper.kt diff --git a/apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/mapper/draft/EntityToDraftMapper.kt b/apps/flipcash/shared/persistence/sources/src/androidMain/kotlin/com/flipcash/app/persistence/sources/mapper/draft/EntityToDraftMapper.kt similarity index 100% rename from apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/mapper/draft/EntityToDraftMapper.kt rename to apps/flipcash/shared/persistence/sources/src/androidMain/kotlin/com/flipcash/app/persistence/sources/mapper/draft/EntityToDraftMapper.kt diff --git a/apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/BlockedUserDataSource.kt b/apps/flipcash/shared/persistence/sources/src/commonMain/kotlin/com/flipcash/app/persistence/sources/BlockedUserDataSource.kt similarity index 97% rename from apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/BlockedUserDataSource.kt rename to apps/flipcash/shared/persistence/sources/src/commonMain/kotlin/com/flipcash/app/persistence/sources/BlockedUserDataSource.kt index 02443246a8..676c41d187 100644 --- a/apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/BlockedUserDataSource.kt +++ b/apps/flipcash/shared/persistence/sources/src/commonMain/kotlin/com/flipcash/app/persistence/sources/BlockedUserDataSource.kt @@ -2,7 +2,7 @@ package com.flipcash.app.persistence.sources import androidx.paging.PagingSource import androidx.paging.PagingState -import androidx.room.withTransaction +import com.flipcash.app.persistence.inTransaction import com.flipcash.app.persistence.FlipcashDatabase import com.flipcash.app.persistence.entities.BlockedUserEntity import com.flipcash.app.persistence.entities.BlockedUserWithProfile @@ -43,7 +43,7 @@ class BlockedUserDataSource @Inject constructor( suspend fun upsert(resolved: List) { val database = db ?: return - database.withTransaction { + database.inTransaction { database.blockedUserDao().upsert(resolved.map { toEntityMapper.map(it) }) resolved.forEach { database.writeProfile(it) } } @@ -52,7 +52,7 @@ class BlockedUserDataSource @Inject constructor( /** Atomically replaces the cached blocklist — a single Room invalidation, no empty flicker. */ suspend fun replaceAll(resolved: List) { val database = db ?: return - database.withTransaction { + database.inTransaction { database.blockedUserDao().replaceAll(resolved.map { toEntityMapper.map(it) }) resolved.forEach { database.writeProfile(it) } } diff --git a/apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/ChatArchiveDataSource.kt b/apps/flipcash/shared/persistence/sources/src/commonMain/kotlin/com/flipcash/app/persistence/sources/ChatArchiveDataSource.kt similarity index 100% rename from apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/ChatArchiveDataSource.kt rename to apps/flipcash/shared/persistence/sources/src/commonMain/kotlin/com/flipcash/app/persistence/sources/ChatArchiveDataSource.kt diff --git a/apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/ChatDraftDataSource.kt b/apps/flipcash/shared/persistence/sources/src/commonMain/kotlin/com/flipcash/app/persistence/sources/ChatDraftDataSource.kt similarity index 100% rename from apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/ChatDraftDataSource.kt rename to apps/flipcash/shared/persistence/sources/src/commonMain/kotlin/com/flipcash/app/persistence/sources/ChatDraftDataSource.kt diff --git a/apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/ChatFeedWriter.kt b/apps/flipcash/shared/persistence/sources/src/commonMain/kotlin/com/flipcash/app/persistence/sources/ChatFeedWriter.kt similarity index 92% rename from apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/ChatFeedWriter.kt rename to apps/flipcash/shared/persistence/sources/src/commonMain/kotlin/com/flipcash/app/persistence/sources/ChatFeedWriter.kt index 1c6b907771..e5cbb7e986 100644 --- a/apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/ChatFeedWriter.kt +++ b/apps/flipcash/shared/persistence/sources/src/commonMain/kotlin/com/flipcash/app/persistence/sources/ChatFeedWriter.kt @@ -1,6 +1,6 @@ package com.flipcash.app.persistence.sources -import androidx.room.withTransaction +import com.flipcash.app.persistence.inTransaction import com.flipcash.app.persistence.FlipcashDatabase import com.flipcash.services.models.chat.ChatMetadata import javax.inject.Inject @@ -31,7 +31,7 @@ class ChatFeedWriter @Inject constructor( messageDataSource.writePrepared(prepared) } val database = FlipcashDatabase.getInstance() - if (database != null) database.withTransaction { body() } else body() + if (database != null) database.inTransaction { body() } else body() messageDataSource.afterWrite(prepared) } } diff --git a/apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/ChatMemberDataSource.kt b/apps/flipcash/shared/persistence/sources/src/commonMain/kotlin/com/flipcash/app/persistence/sources/ChatMemberDataSource.kt similarity index 98% rename from apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/ChatMemberDataSource.kt rename to apps/flipcash/shared/persistence/sources/src/commonMain/kotlin/com/flipcash/app/persistence/sources/ChatMemberDataSource.kt index e11f9c44c3..42c74b8efc 100644 --- a/apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/ChatMemberDataSource.kt +++ b/apps/flipcash/shared/persistence/sources/src/commonMain/kotlin/com/flipcash/app/persistence/sources/ChatMemberDataSource.kt @@ -1,6 +1,6 @@ package com.flipcash.app.persistence.sources -import androidx.room.withTransaction +import com.flipcash.app.persistence.inTransaction import com.flipcash.app.persistence.FlipcashDatabase import com.flipcash.app.persistence.sources.mapper.chat.ChatEntityMapper import com.flipcash.services.models.chat.ChatId @@ -92,7 +92,7 @@ class ChatMemberDataSource @Inject constructor( // Member rows and their normalized profiles are written in one transaction so a // member never observes a missing profile mid-write. Profiles go first (the // @Relation reads them). - database.withTransaction { + database.inTransaction { database.userProfileDao().upsertMembers(profileRows(members)) database.chatMemberDao().upsert(members.map { mapper.toEntity(hex, it) }) } @@ -128,7 +128,7 @@ class ChatMemberDataSource @Inject constructor( val database = db ?: return val hex = mapper.chatIdHex(chatId) - database.withTransaction { + database.inTransaction { database.userProfileDao().upsertMembers(profileRows(members)) database.chatMemberDao().upsert(members.map { mapper.toEntity(hex, it) }) database.chatMemberDao().deleteMembersNotIn( diff --git a/apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/ChatMessageDataSource.kt b/apps/flipcash/shared/persistence/sources/src/commonMain/kotlin/com/flipcash/app/persistence/sources/ChatMessageDataSource.kt similarity index 99% rename from apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/ChatMessageDataSource.kt rename to apps/flipcash/shared/persistence/sources/src/commonMain/kotlin/com/flipcash/app/persistence/sources/ChatMessageDataSource.kt index 688e5339fc..9513162504 100644 --- a/apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/ChatMessageDataSource.kt +++ b/apps/flipcash/shared/persistence/sources/src/commonMain/kotlin/com/flipcash/app/persistence/sources/ChatMessageDataSource.kt @@ -1,7 +1,7 @@ package com.flipcash.app.persistence.sources import androidx.paging.PagingSource -import androidx.room.withTransaction +import com.flipcash.app.persistence.inTransaction import com.flipcash.app.persistence.FlipcashDatabase import com.flipcash.app.persistence.dao.ChatMessageDao import com.flipcash.app.persistence.entities.ChatMessageEntity @@ -366,7 +366,7 @@ class ChatMessageDataSource @Inject constructor( suspend fun writePrepared(prepared: PreparedMessages) { val database = db ?: return if (prepared.byChat.isEmpty()) return - database.withTransaction { + database.inTransaction { for ((chatId, messages) in prepared.byChat) write(mapper.chatIdHex(chatId), messages) } } diff --git a/apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/ChatMetadataDataSource.kt b/apps/flipcash/shared/persistence/sources/src/commonMain/kotlin/com/flipcash/app/persistence/sources/ChatMetadataDataSource.kt similarity index 100% rename from apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/ChatMetadataDataSource.kt rename to apps/flipcash/shared/persistence/sources/src/commonMain/kotlin/com/flipcash/app/persistence/sources/ChatMetadataDataSource.kt diff --git a/apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/ContactDataSource.kt b/apps/flipcash/shared/persistence/sources/src/commonMain/kotlin/com/flipcash/app/persistence/sources/ContactDataSource.kt similarity index 100% rename from apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/ContactDataSource.kt rename to apps/flipcash/shared/persistence/sources/src/commonMain/kotlin/com/flipcash/app/persistence/sources/ContactDataSource.kt diff --git a/apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/IncomingMessageOpener.kt b/apps/flipcash/shared/persistence/sources/src/commonMain/kotlin/com/flipcash/app/persistence/sources/IncomingMessageOpener.kt similarity index 100% rename from apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/IncomingMessageOpener.kt rename to apps/flipcash/shared/persistence/sources/src/commonMain/kotlin/com/flipcash/app/persistence/sources/IncomingMessageOpener.kt diff --git a/apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/LinkPreviewDataSource.kt b/apps/flipcash/shared/persistence/sources/src/commonMain/kotlin/com/flipcash/app/persistence/sources/LinkPreviewDataSource.kt similarity index 100% rename from apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/LinkPreviewDataSource.kt rename to apps/flipcash/shared/persistence/sources/src/commonMain/kotlin/com/flipcash/app/persistence/sources/LinkPreviewDataSource.kt diff --git a/apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/MessageDataSource.kt b/apps/flipcash/shared/persistence/sources/src/commonMain/kotlin/com/flipcash/app/persistence/sources/MessageDataSource.kt similarity index 100% rename from apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/MessageDataSource.kt rename to apps/flipcash/shared/persistence/sources/src/commonMain/kotlin/com/flipcash/app/persistence/sources/MessageDataSource.kt diff --git a/apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/PendingMediaDataSource.kt b/apps/flipcash/shared/persistence/sources/src/commonMain/kotlin/com/flipcash/app/persistence/sources/PendingMediaDataSource.kt similarity index 100% rename from apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/PendingMediaDataSource.kt rename to apps/flipcash/shared/persistence/sources/src/commonMain/kotlin/com/flipcash/app/persistence/sources/PendingMediaDataSource.kt diff --git a/apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/TokenDataSource.kt b/apps/flipcash/shared/persistence/sources/src/commonMain/kotlin/com/flipcash/app/persistence/sources/TokenDataSource.kt similarity index 100% rename from apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/TokenDataSource.kt rename to apps/flipcash/shared/persistence/sources/src/commonMain/kotlin/com/flipcash/app/persistence/sources/TokenDataSource.kt diff --git a/apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/UserProfileDataSource.kt b/apps/flipcash/shared/persistence/sources/src/commonMain/kotlin/com/flipcash/app/persistence/sources/UserProfileDataSource.kt similarity index 100% rename from apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/UserProfileDataSource.kt rename to apps/flipcash/shared/persistence/sources/src/commonMain/kotlin/com/flipcash/app/persistence/sources/UserProfileDataSource.kt diff --git a/apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/mapper/UserProfileDomainMappers.kt b/apps/flipcash/shared/persistence/sources/src/commonMain/kotlin/com/flipcash/app/persistence/sources/mapper/UserProfileDomainMappers.kt similarity index 100% rename from apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/mapper/UserProfileDomainMappers.kt rename to apps/flipcash/shared/persistence/sources/src/commonMain/kotlin/com/flipcash/app/persistence/sources/mapper/UserProfileDomainMappers.kt diff --git a/apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/mapper/blocklist/BlockedUserEntityToProfileMapper.kt b/apps/flipcash/shared/persistence/sources/src/commonMain/kotlin/com/flipcash/app/persistence/sources/mapper/blocklist/BlockedUserEntityToProfileMapper.kt similarity index 100% rename from apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/mapper/blocklist/BlockedUserEntityToProfileMapper.kt rename to apps/flipcash/shared/persistence/sources/src/commonMain/kotlin/com/flipcash/app/persistence/sources/mapper/blocklist/BlockedUserEntityToProfileMapper.kt diff --git a/apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/mapper/blocklist/BlockedUserToEntityMapper.kt b/apps/flipcash/shared/persistence/sources/src/commonMain/kotlin/com/flipcash/app/persistence/sources/mapper/blocklist/BlockedUserToEntityMapper.kt similarity index 100% rename from apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/mapper/blocklist/BlockedUserToEntityMapper.kt rename to apps/flipcash/shared/persistence/sources/src/commonMain/kotlin/com/flipcash/app/persistence/sources/mapper/blocklist/BlockedUserToEntityMapper.kt diff --git a/apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/mapper/chat/ChatEntityMapper.kt b/apps/flipcash/shared/persistence/sources/src/commonMain/kotlin/com/flipcash/app/persistence/sources/mapper/chat/ChatEntityMapper.kt similarity index 100% rename from apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/mapper/chat/ChatEntityMapper.kt rename to apps/flipcash/shared/persistence/sources/src/commonMain/kotlin/com/flipcash/app/persistence/sources/mapper/chat/ChatEntityMapper.kt diff --git a/apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/mapper/notifications/MessageEntityToFeedMessageMapper.kt b/apps/flipcash/shared/persistence/sources/src/commonMain/kotlin/com/flipcash/app/persistence/sources/mapper/notifications/MessageEntityToFeedMessageMapper.kt similarity index 100% rename from apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/mapper/notifications/MessageEntityToFeedMessageMapper.kt rename to apps/flipcash/shared/persistence/sources/src/commonMain/kotlin/com/flipcash/app/persistence/sources/mapper/notifications/MessageEntityToFeedMessageMapper.kt diff --git a/apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/mapper/notifications/NotificationToEntityMapper.kt b/apps/flipcash/shared/persistence/sources/src/commonMain/kotlin/com/flipcash/app/persistence/sources/mapper/notifications/NotificationToEntityMapper.kt similarity index 100% rename from apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/mapper/notifications/NotificationToEntityMapper.kt rename to apps/flipcash/shared/persistence/sources/src/commonMain/kotlin/com/flipcash/app/persistence/sources/mapper/notifications/NotificationToEntityMapper.kt diff --git a/apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/mapper/tokens/EntityToTokenMapper.kt b/apps/flipcash/shared/persistence/sources/src/commonMain/kotlin/com/flipcash/app/persistence/sources/mapper/tokens/EntityToTokenMapper.kt similarity index 98% rename from apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/mapper/tokens/EntityToTokenMapper.kt rename to apps/flipcash/shared/persistence/sources/src/commonMain/kotlin/com/flipcash/app/persistence/sources/mapper/tokens/EntityToTokenMapper.kt index 92b4ccfe96..69c6228baf 100644 --- a/apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/mapper/tokens/EntityToTokenMapper.kt +++ b/apps/flipcash/shared/persistence/sources/src/commonMain/kotlin/com/flipcash/app/persistence/sources/mapper/tokens/EntityToTokenMapper.kt @@ -1,6 +1,6 @@ package com.flipcash.app.persistence.sources.mapper.tokens -import android.util.Base64 +import java.util.Base64 import com.flipcash.app.persistence.converters.BillBackgroundSerialized import com.flipcash.app.persistence.converters.BillCustomizationsSerialized import com.flipcash.app.persistence.converters.HolderMetricsSerialized @@ -99,7 +99,7 @@ private fun BillCustomizationsSerialized.toDomain() = TokenBillCustomizations( strength = it.strength, ) }, - icon = icon?.let { Base64.decode(it, Base64.NO_WRAP) }, + icon = icon?.let { Base64.getDecoder().decode(it) }, ) private fun HolderMetricsSerialized.toDomain() = HolderMetrics( diff --git a/apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/mapper/tokens/RelationToTokenWithBalanceMapper.kt b/apps/flipcash/shared/persistence/sources/src/commonMain/kotlin/com/flipcash/app/persistence/sources/mapper/tokens/RelationToTokenWithBalanceMapper.kt similarity index 100% rename from apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/mapper/tokens/RelationToTokenWithBalanceMapper.kt rename to apps/flipcash/shared/persistence/sources/src/commonMain/kotlin/com/flipcash/app/persistence/sources/mapper/tokens/RelationToTokenWithBalanceMapper.kt diff --git a/apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/mapper/tokens/TokenToEntityMapper.kt b/apps/flipcash/shared/persistence/sources/src/commonMain/kotlin/com/flipcash/app/persistence/sources/mapper/tokens/TokenToEntityMapper.kt similarity index 98% rename from apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/mapper/tokens/TokenToEntityMapper.kt rename to apps/flipcash/shared/persistence/sources/src/commonMain/kotlin/com/flipcash/app/persistence/sources/mapper/tokens/TokenToEntityMapper.kt index eee1953820..54710f5007 100644 --- a/apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/mapper/tokens/TokenToEntityMapper.kt +++ b/apps/flipcash/shared/persistence/sources/src/commonMain/kotlin/com/flipcash/app/persistence/sources/mapper/tokens/TokenToEntityMapper.kt @@ -1,6 +1,6 @@ package com.flipcash.app.persistence.sources.mapper.tokens -import android.util.Base64 +import java.util.Base64 import com.flipcash.app.persistence.converters.BillBackgroundSerialized import com.flipcash.app.persistence.converters.BillCustomizationsSerialized import com.flipcash.app.persistence.converters.BillTextureSerialized @@ -95,7 +95,7 @@ private fun TokenBillCustomizations.toSerialized() = BillCustomizationsSerialize strength = it.strength, ) }, - icon = icon?.let { Base64.encodeToString(it, Base64.NO_WRAP) }, + icon = icon?.let { Base64.getEncoder().encodeToString(it) }, ) private fun HolderMetrics.toSerialized() = HolderMetricsSerialized( diff --git a/apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/mediator/BlocklistRemoteMediator.kt b/apps/flipcash/shared/persistence/sources/src/commonMain/kotlin/com/flipcash/app/persistence/sources/mediator/BlocklistRemoteMediator.kt similarity index 100% rename from apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/mediator/BlocklistRemoteMediator.kt rename to apps/flipcash/shared/persistence/sources/src/commonMain/kotlin/com/flipcash/app/persistence/sources/mediator/BlocklistRemoteMediator.kt diff --git a/apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/mediator/ChatFeedRemoteMediator.kt b/apps/flipcash/shared/persistence/sources/src/commonMain/kotlin/com/flipcash/app/persistence/sources/mediator/ChatFeedRemoteMediator.kt similarity index 100% rename from apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/mediator/ChatFeedRemoteMediator.kt rename to apps/flipcash/shared/persistence/sources/src/commonMain/kotlin/com/flipcash/app/persistence/sources/mediator/ChatFeedRemoteMediator.kt diff --git a/apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/mediator/ChatMessageRemoteMediator.kt b/apps/flipcash/shared/persistence/sources/src/commonMain/kotlin/com/flipcash/app/persistence/sources/mediator/ChatMessageRemoteMediator.kt similarity index 100% rename from apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/mediator/ChatMessageRemoteMediator.kt rename to apps/flipcash/shared/persistence/sources/src/commonMain/kotlin/com/flipcash/app/persistence/sources/mediator/ChatMessageRemoteMediator.kt diff --git a/apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/mediator/FeedRemoteMediator.kt b/apps/flipcash/shared/persistence/sources/src/commonMain/kotlin/com/flipcash/app/persistence/sources/mediator/FeedRemoteMediator.kt similarity index 100% rename from apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/mediator/FeedRemoteMediator.kt rename to apps/flipcash/shared/persistence/sources/src/commonMain/kotlin/com/flipcash/app/persistence/sources/mediator/FeedRemoteMediator.kt diff --git a/apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/mediator/FeedWatermark.kt b/apps/flipcash/shared/persistence/sources/src/commonMain/kotlin/com/flipcash/app/persistence/sources/mediator/FeedWatermark.kt similarity index 100% rename from apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/mediator/FeedWatermark.kt rename to apps/flipcash/shared/persistence/sources/src/commonMain/kotlin/com/flipcash/app/persistence/sources/mediator/FeedWatermark.kt diff --git a/apps/flipcash/shared/tokens/core/src/main/kotlin/com/flipcash/app/tokens/core/ReservesBalanceProvider.kt b/apps/flipcash/shared/tokens/core/src/commonMain/kotlin/com/flipcash/app/tokens/core/ReservesBalanceProvider.kt similarity index 100% rename from apps/flipcash/shared/tokens/core/src/main/kotlin/com/flipcash/app/tokens/core/ReservesBalanceProvider.kt rename to apps/flipcash/shared/tokens/core/src/commonMain/kotlin/com/flipcash/app/tokens/core/ReservesBalanceProvider.kt diff --git a/apps/flipcash/shared/tokens/core/src/main/kotlin/com/flipcash/app/tokens/core/TotalBalanceProvider.kt b/apps/flipcash/shared/tokens/core/src/commonMain/kotlin/com/flipcash/app/tokens/core/TotalBalanceProvider.kt similarity index 100% rename from apps/flipcash/shared/tokens/core/src/main/kotlin/com/flipcash/app/tokens/core/TotalBalanceProvider.kt rename to apps/flipcash/shared/tokens/core/src/commonMain/kotlin/com/flipcash/app/tokens/core/TotalBalanceProvider.kt From d24505921b66c3ea78031546b606f4cd522c39af Mon Sep 17 00:00:00 2001 From: Brandon McAnsh Date: Fri, 23 Oct 2026 17:20:11 -0400 Subject: [PATCH 14/50] build(tokens): move tokens:core to android+jvm KMP --- .../flipcash/shared/tokens/core/build.gradle.kts | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/apps/flipcash/shared/tokens/core/build.gradle.kts b/apps/flipcash/shared/tokens/core/build.gradle.kts index 7ab06290d4..1021b7e231 100644 --- a/apps/flipcash/shared/tokens/core/build.gradle.kts +++ b/apps/flipcash/shared/tokens/core/build.gradle.kts @@ -1,11 +1,15 @@ plugins { - alias(libs.plugins.flipcash.android.library) + alias(libs.plugins.flipcash.kmp.app.library) } -android { - namespace = "${Gradle.flipcashNamespace}.shared.tokens.core" -} +kotlin { + android { + namespace = "${Gradle.flipcashNamespace}.shared.tokens.core" + } -dependencies { - api(project(":services:opencode")) + sourceSets { + commonMain.dependencies { + api(project(":services:opencode")) + } + } } From d25809b87caae68843967bfc44c455d2ca52554f Mon Sep 17 00:00:00 2001 From: Brandon McAnsh Date: Fri, 23 Oct 2026 17:55:52 -0400 Subject: [PATCH 15/50] build(desktop): add the Compose Desktop shell and Android res as Compose resources :apps:desktop is a kotlin.jvm + compose.desktop app with an empty Metro graph. ui:resources now also generates a Compose Multiplatform Res class from its Android res/ through a Sync task, so common code can read the same strings and drawables without a second copy in the repo. --- apps/desktop/build.gradle.kts | 28 +++++++++++++++++++ .../com/flipcash/desktop/DesktopGraph.kt | 13 +++++++++ .../main/kotlin/com/flipcash/desktop/Main.kt | 25 +++++++++++++++++ .../resources/AndroidResAsComposeResources.kt | 27 ++++++++++++++++++ build.gradle.kts | 3 ++ gradle/libs.versions.toml | 12 ++++++++ settings.gradle.kts | 1 + ui/resources/build.gradle.kts | 13 +++++++++ 8 files changed, 122 insertions(+) create mode 100644 apps/desktop/build.gradle.kts create mode 100644 apps/desktop/src/main/kotlin/com/flipcash/desktop/DesktopGraph.kt create mode 100644 apps/desktop/src/main/kotlin/com/flipcash/desktop/Main.kt create mode 100644 build-logic/convention/src/main/kotlin/com/getcode/buildlogic/resources/AndroidResAsComposeResources.kt diff --git a/apps/desktop/build.gradle.kts b/apps/desktop/build.gradle.kts new file mode 100644 index 0000000000..2fc3dfc4c3 --- /dev/null +++ b/apps/desktop/build.gradle.kts @@ -0,0 +1,28 @@ +import org.jetbrains.compose.desktop.application.dsl.TargetFormat + +plugins { + alias(libs.plugins.kotlin.jvm) + alias(libs.plugins.compose.compiler) + alias(libs.plugins.jetbrains.compose) + alias(libs.plugins.metro) +} + +kotlin { + jvmToolchain(21) +} + +dependencies { + implementation(compose.desktop.currentOs) + implementation(libs.jetbrains.compose.material3) +} + +compose.desktop { + application { + mainClass = "com.flipcash.desktop.MainKt" + nativeDistributions { + targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb) + packageName = "Flipcash" + packageVersion = "1.0.0" + } + } +} diff --git a/apps/desktop/src/main/kotlin/com/flipcash/desktop/DesktopGraph.kt b/apps/desktop/src/main/kotlin/com/flipcash/desktop/DesktopGraph.kt new file mode 100644 index 0000000000..78b62aade5 --- /dev/null +++ b/apps/desktop/src/main/kotlin/com/flipcash/desktop/DesktopGraph.kt @@ -0,0 +1,13 @@ +package com.flipcash.desktop + +import dev.zacsweers.metro.AppScope +import dev.zacsweers.metro.DependencyGraph +import dev.zacsweers.metro.Provides + +@DependencyGraph(AppScope::class) +interface DesktopGraph { + val appName: String + + @Provides + fun provideAppName(): String = "Flipcash" +} diff --git a/apps/desktop/src/main/kotlin/com/flipcash/desktop/Main.kt b/apps/desktop/src/main/kotlin/com/flipcash/desktop/Main.kt new file mode 100644 index 0000000000..8f9fbed3a2 --- /dev/null +++ b/apps/desktop/src/main/kotlin/com/flipcash/desktop/Main.kt @@ -0,0 +1,25 @@ +package com.flipcash.desktop + +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.ui.window.Window +import androidx.compose.ui.window.application +import dev.zacsweers.metro.createGraph +import java.lang.management.ManagementFactory + +fun main() { + val graph = createGraph() + application { + Window(onCloseRequest = ::exitApplication, title = "Flipcash") { + MaterialTheme { + Text(graph.appName) + } + LaunchedEffect(Unit) { + val sinceJvmStart = System.currentTimeMillis() - + ManagementFactory.getRuntimeMXBean().startTime + println("startup: first composition ${sinceJvmStart}ms after JVM start") + } + } + } +} diff --git a/build-logic/convention/src/main/kotlin/com/getcode/buildlogic/resources/AndroidResAsComposeResources.kt b/build-logic/convention/src/main/kotlin/com/getcode/buildlogic/resources/AndroidResAsComposeResources.kt new file mode 100644 index 0000000000..aa98c13b88 --- /dev/null +++ b/build-logic/convention/src/main/kotlin/com/getcode/buildlogic/resources/AndroidResAsComposeResources.kt @@ -0,0 +1,27 @@ +package com.getcode.buildlogic.resources + +import org.gradle.api.Project +import org.gradle.api.file.Directory +import org.gradle.api.provider.Provider +import org.gradle.api.tasks.Sync + +/** + * Exposes a module's Android `res/` directory to Compose Multiplatform resources. + * + * Android keeps reading `res/` through `R`, so its behaviour does not change; common code reads + * the same strings and drawables through the generated `Res` class. The files stay in one place; + * this only maps the layout. Compose resources reject Android's `nodpi` qualifier, so + * `drawable-nodpi` is served as plain `drawable`. Pass the result to + * `compose.resources.customDirectory(sourceSetName = "commonMain", directoryProvider = ...)`. + */ +fun Project.androidResAsComposeResources(resDir: String = "src/androidMain/res"): Provider { + val sync = tasks.register("syncAndroidResForCompose", Sync::class.java) { + from(layout.projectDirectory.dir(resDir)) { + include("values/**", "drawable/**", "drawable-*/**", "font/**") + } + eachFile { path = path.replaceFirst("drawable-nodpi/", "drawable/") } + includeEmptyDirs = false + into(layout.buildDirectory.dir("generated/androidResForCompose")) + } + return layout.dir(sync.map { it.destinationDir }) +} diff --git a/build.gradle.kts b/build.gradle.kts index d9c3f8bee4..1033c682a0 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -31,6 +31,9 @@ plugins { alias(libs.plugins.kotlin.ksp) apply false alias(libs.plugins.hilt) apply false alias(libs.plugins.compose.compiler) apply false + alias(libs.plugins.jetbrains.compose) apply false + alias(libs.plugins.kotlin.jvm) apply false + alias(libs.plugins.metro) apply false alias(libs.plugins.google.services) apply false alias(libs.plugins.firebase.perf) apply false alias(libs.plugins.bugsnag.gradle) apply false diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b5f8ec6c08..0b98382696 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -7,6 +7,7 @@ android-java = "21" kotlin = "2.4.21" ksp = "2.3.12" +metro = "1.4.5" kotlinx-coroutines = "1.11.0" kotlinx-serialization = "1.11.0" kotlinx-datetime = "0.8.0" @@ -47,6 +48,9 @@ compose-coil = "3.6.3" hilt = "2.59.2" hilt-jetpack = "1.4.0" compose-multiplatform = "1.12.1" +# JetBrains publishes material3 and the extended icons on their own lines; the icons stopped at 1.7.3. +compose-multiplatform-material3 = "1.12.0-alpha03" +compose-multiplatform-icons = "1.7.3" okhttp = "5.5.0" retrofit = "3.0.0" kin-sdk = "2.1.2" @@ -341,6 +345,11 @@ jetbrains-compose-runtime = { module = "org.jetbrains.compose.runtime:runtime", # On Android these resolve to the androidx artifacts at the version the Compose BOM pins. jetbrains-compose-foundation = { module = "org.jetbrains.compose.foundation:foundation", version.ref = "compose-multiplatform" } jetbrains-compose-ui = { module = "org.jetbrains.compose.ui:ui", version.ref = "compose-multiplatform" } +jetbrains-compose-material = { module = "org.jetbrains.compose.material:material", version.ref = "compose-multiplatform" } +jetbrains-compose-material3 = { module = "org.jetbrains.compose.material3:material3", version.ref = "compose-multiplatform-material3" } +jetbrains-compose-material-icons-extended = { module = "org.jetbrains.compose.material:material-icons-extended", version.ref = "compose-multiplatform-icons" } +jetbrains-compose-components-preview = { module = "org.jetbrains.compose.components:components-ui-tooling-preview", version.ref = "compose-multiplatform" } +jetbrains-compose-components-resources = { module = "org.jetbrains.compose.components:components-resources", version.ref = "compose-multiplatform" } [bundles] compose = ["compose-ui", "compose-foundation", "compose-material", "compose-material-icons-extended", "compose-animation", "compose-activities"] @@ -383,4 +392,7 @@ screenshot = { id = "com.android.compose.screenshot", version.ref = "screenshot" kover = { id = "org.jetbrains.kotlinx.kover", version.ref = "kover" } kotlin-multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" } android-kotlin-multiplatform-library = { id = "com.android.kotlin.multiplatform.library", version.ref = "agp" } +jetbrains-compose = { id = "org.jetbrains.compose", version.ref = "compose-multiplatform" } +kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } +metro = { id = "dev.zacsweers.metro", version.ref = "metro" } kmmbridge = { id = "co.touchlab.kmmbridge.github", version.ref = "kmmbridge" } diff --git a/settings.gradle.kts b/settings.gradle.kts index 99cf20e5ba..6f3b8c4dee 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -111,6 +111,7 @@ rootProject.name = "Flipcash" include( // app containers + ":apps:desktop", ":apps:flipcash:app", ":apps:flipcash:benchmark", diff --git a/ui/resources/build.gradle.kts b/ui/resources/build.gradle.kts index 47fa09cfd2..2c59e04111 100644 --- a/ui/resources/build.gradle.kts +++ b/ui/resources/build.gradle.kts @@ -1,6 +1,9 @@ +import com.getcode.buildlogic.resources.androidResAsComposeResources + plugins { alias(libs.plugins.flipcash.kmp.app.library) alias(libs.plugins.compose.compiler) + alias(libs.plugins.jetbrains.compose) } kotlin { @@ -18,6 +21,7 @@ kotlin { api(libs.kotlinx.coroutines.core) api(libs.jetbrains.compose.runtime) api(libs.jetbrains.compose.ui) + api(libs.jetbrains.compose.components.resources) } androidMain.dependencies { api(libs.androidx.appcompat) @@ -27,3 +31,12 @@ kotlin { } } } + +compose.resources { + publicResClass = true + packageOfResClass = "${Gradle.codeNamespace}.util.resources" + customDirectory( + sourceSetName = "commonMain", + directoryProvider = androidResAsComposeResources(), + ) +} From ae1ec91bd5bafee985b60113d9d2d1d1541db196 Mon Sep 17 00:00:00 2001 From: Brandon McAnsh Date: Fri, 23 Oct 2026 18:06:17 -0400 Subject: [PATCH 16/50] build(theme): move ui:theme to android+jvm KMP Fonts load through an expect seam: Android keeps R.font, desktop reads the same files from the classpath. Dynamic color and the View helpers stay in androidMain. --- gradle/libs.versions.toml | 1 + ui/theme/build.gradle.kts | 45 +++++++----- .../kotlin/com/getcode/theme/DynamicColor.kt | 0 .../com/getcode/theme/Platform.android.kt | 66 ++++++++++++++++++ .../kotlin/com/getcode/ui/utils/View.kt | 0 .../res/font/avenir_next_demi.otf | Bin .../res/font/avenir_next_medium.otf | Bin .../res/font/avenir_next_regular.otf | Bin .../res/font/roboto_mono_variable.ttf | Bin .../animation/SharedTransitionScope.kt | 0 .../kotlin/com/getcode/theme/Color.kt | 4 +- .../kotlin/com/getcode/theme/Dimens.kt | 14 ++-- .../kotlin/com/getcode/theme/DropShadow.kt | 8 +-- .../kotlin/com/getcode/theme/Platform.kt | 20 ++++++ .../kotlin/com/getcode/theme/Shape.kt | 0 .../kotlin/com/getcode/theme/Theme.kt | 9 +-- .../kotlin/com/getcode/theme/Type.kt | 30 +------- .../com/getcode/theme/WindowSizeClass.kt | 16 ++--- .../getcode/view/shapes/TriangleCutShape.kt | 7 +- .../kotlin/com/getcode/theme/Platform.jvm.kt | 65 +++++++++++++++++ 20 files changed, 204 insertions(+), 81 deletions(-) rename ui/theme/src/{main => androidMain}/kotlin/com/getcode/theme/DynamicColor.kt (100%) create mode 100644 ui/theme/src/androidMain/kotlin/com/getcode/theme/Platform.android.kt rename ui/theme/src/{main => androidMain}/kotlin/com/getcode/ui/utils/View.kt (100%) rename ui/theme/src/{main => androidMain}/res/font/avenir_next_demi.otf (100%) rename ui/theme/src/{main => androidMain}/res/font/avenir_next_medium.otf (100%) rename ui/theme/src/{main => androidMain}/res/font/avenir_next_regular.otf (100%) rename ui/theme/src/{main => androidMain}/res/font/roboto_mono_variable.ttf (100%) rename ui/theme/src/{main => commonMain}/kotlin/com/getcode/animation/SharedTransitionScope.kt (100%) rename ui/theme/src/{main => commonMain}/kotlin/com/getcode/theme/Color.kt (96%) rename ui/theme/src/{main => commonMain}/kotlin/com/getcode/theme/Dimens.kt (92%) rename ui/theme/src/{main => commonMain}/kotlin/com/getcode/theme/DropShadow.kt (89%) create mode 100644 ui/theme/src/commonMain/kotlin/com/getcode/theme/Platform.kt rename ui/theme/src/{main => commonMain}/kotlin/com/getcode/theme/Shape.kt (100%) rename ui/theme/src/{main => commonMain}/kotlin/com/getcode/theme/Theme.kt (97%) rename ui/theme/src/{main => commonMain}/kotlin/com/getcode/theme/Type.kt (78%) rename ui/theme/src/{main => commonMain}/kotlin/com/getcode/theme/WindowSizeClass.kt (71%) rename ui/theme/src/{main => commonMain}/kotlin/com/getcode/view/shapes/TriangleCutShape.kt (93%) create mode 100644 ui/theme/src/jvmMain/kotlin/com/getcode/theme/Platform.jvm.kt diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 0b98382696..0c0ed05e95 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -349,6 +349,7 @@ jetbrains-compose-material = { module = "org.jetbrains.compose.material:material jetbrains-compose-material3 = { module = "org.jetbrains.compose.material3:material3", version.ref = "compose-multiplatform-material3" } jetbrains-compose-material-icons-extended = { module = "org.jetbrains.compose.material:material-icons-extended", version.ref = "compose-multiplatform-icons" } jetbrains-compose-components-preview = { module = "org.jetbrains.compose.components:components-ui-tooling-preview", version.ref = "compose-multiplatform" } +jetbrains-compose-ui-tooling-preview = { module = "org.jetbrains.compose.ui:ui-tooling-preview", version.ref = "compose-multiplatform" } jetbrains-compose-components-resources = { module = "org.jetbrains.compose.components:components-resources", version.ref = "compose-multiplatform" } [bundles] diff --git a/ui/theme/build.gradle.kts b/ui/theme/build.gradle.kts index 408c538682..f144579d0f 100644 --- a/ui/theme/build.gradle.kts +++ b/ui/theme/build.gradle.kts @@ -1,22 +1,35 @@ plugins { - alias(libs.plugins.flipcash.android.library.compose) + alias(libs.plugins.flipcash.kmp.app.library) + alias(libs.plugins.compose.compiler) } -android { - namespace = "com.getcode.theme" - - buildFeatures { - buildConfig = true +kotlin { + android { + namespace = "com.getcode.theme" + androidResources { + enable = true + } } -} -dependencies { debugImplementation(libs.compose.ui.tools) - implementation(libs.compose.ui.tools.preview) - implementation(libs.compose.material) - implementation(libs.compose.material3) - implementation(libs.compose.accompanist) - - implementation(libs.androidx.appcompat) - implementation(libs.androidx.core) - implementation(libs.androidx.activity) + sourceSets { + commonMain.dependencies { + implementation(project(":libs:logging")) + api(libs.jetbrains.compose.runtime) + api(libs.jetbrains.compose.foundation) + api(libs.jetbrains.compose.ui) + api(libs.jetbrains.compose.material) + implementation(libs.jetbrains.compose.ui.tooling.preview) + } + androidMain.dependencies { + implementation(project.dependencies.platform(libs.compose.bom)) + implementation(libs.compose.ui.tools.preview) + implementation(libs.compose.material3) + implementation(libs.compose.accompanist) + implementation(libs.androidx.appcompat) + implementation(libs.androidx.core) + implementation(libs.androidx.activity) + } + // Desktop reads the same font files Android packages from res/font. + jvmMain.get().resources.srcDir("src/androidMain/res") + } } diff --git a/ui/theme/src/main/kotlin/com/getcode/theme/DynamicColor.kt b/ui/theme/src/androidMain/kotlin/com/getcode/theme/DynamicColor.kt similarity index 100% rename from ui/theme/src/main/kotlin/com/getcode/theme/DynamicColor.kt rename to ui/theme/src/androidMain/kotlin/com/getcode/theme/DynamicColor.kt diff --git a/ui/theme/src/androidMain/kotlin/com/getcode/theme/Platform.android.kt b/ui/theme/src/androidMain/kotlin/com/getcode/theme/Platform.android.kt new file mode 100644 index 0000000000..92e8eacd8c --- /dev/null +++ b/ui/theme/src/androidMain/kotlin/com/getcode/theme/Platform.android.kt @@ -0,0 +1,66 @@ +package com.getcode.theme + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.SideEffect +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.Paint +import androidx.compose.ui.platform.LocalConfiguration +import androidx.compose.ui.text.font.Font +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import com.google.accompanist.systemuicontroller.rememberSystemUiController + +@Composable +actual fun currentScreenSizeDp(): ScreenSizeDp { + val configuration = LocalConfiguration.current + return ScreenSizeDp(configuration.screenWidthDp, configuration.screenHeightDp) +} + +@Composable +internal actual fun TransparentSystemBars() { + val sysUiController = rememberSystemUiController() + + SideEffect { + sysUiController.setStatusBarColor(color = Color(0x01000000)) + sysUiController.setNavigationBarColor(color = Color(0x01000000)) + } +} + +actual fun Paint.makeBlur(shadowBlurRadius: Float) { + this.asFrameworkPaint().apply { + maskFilter = + android.graphics.BlurMaskFilter( + shadowBlurRadius, android.graphics.BlurMaskFilter.Blur.NORMAL) + } +} + +internal actual object PlatformFonts { + actual val avenir = FontFamily( + Font(R.font.avenir_next_regular, FontWeight.Thin), + Font(R.font.avenir_next_regular, FontWeight.ExtraLight), + Font(R.font.avenir_next_regular, FontWeight.Light), + Font(R.font.avenir_next_regular, FontWeight.Normal), + Font(R.font.avenir_next_demi, FontWeight.Medium), // TODO: find a better medium OTF + Font(R.font.avenir_next_demi, FontWeight.SemiBold), + Font(R.font.avenir_next_demi, FontWeight.Bold), + Font(R.font.avenir_next_demi, FontWeight.ExtraBold), + Font(R.font.avenir_next_demi, FontWeight.Black) + ) + + actual val avenirMedium = FontFamily( + Font(R.font.avenir_next_medium, FontWeight.Normal), + Font(R.font.avenir_next_medium, FontWeight.Medium), + // Heavier overrides (e.g. caption.copy(fontWeight = Bold)) stay on Demi, as they did under Avenir. + Font(R.font.avenir_next_demi, FontWeight.SemiBold), + Font(R.font.avenir_next_demi, FontWeight.Bold), + Font(R.font.avenir_next_demi, FontWeight.ExtraBold), + Font(R.font.avenir_next_demi, FontWeight.Black), + ) + + actual val robotoMono = FontFamily( + Font(R.font.roboto_mono_variable, FontWeight.Light), + Font(R.font.roboto_mono_variable, FontWeight.Normal), + Font(R.font.roboto_mono_variable, FontWeight.Medium), + Font(R.font.roboto_mono_variable, FontWeight.SemiBold) + ) +} diff --git a/ui/theme/src/main/kotlin/com/getcode/ui/utils/View.kt b/ui/theme/src/androidMain/kotlin/com/getcode/ui/utils/View.kt similarity index 100% rename from ui/theme/src/main/kotlin/com/getcode/ui/utils/View.kt rename to ui/theme/src/androidMain/kotlin/com/getcode/ui/utils/View.kt diff --git a/ui/theme/src/main/res/font/avenir_next_demi.otf b/ui/theme/src/androidMain/res/font/avenir_next_demi.otf similarity index 100% rename from ui/theme/src/main/res/font/avenir_next_demi.otf rename to ui/theme/src/androidMain/res/font/avenir_next_demi.otf diff --git a/ui/theme/src/main/res/font/avenir_next_medium.otf b/ui/theme/src/androidMain/res/font/avenir_next_medium.otf similarity index 100% rename from ui/theme/src/main/res/font/avenir_next_medium.otf rename to ui/theme/src/androidMain/res/font/avenir_next_medium.otf diff --git a/ui/theme/src/main/res/font/avenir_next_regular.otf b/ui/theme/src/androidMain/res/font/avenir_next_regular.otf similarity index 100% rename from ui/theme/src/main/res/font/avenir_next_regular.otf rename to ui/theme/src/androidMain/res/font/avenir_next_regular.otf diff --git a/ui/theme/src/main/res/font/roboto_mono_variable.ttf b/ui/theme/src/androidMain/res/font/roboto_mono_variable.ttf similarity index 100% rename from ui/theme/src/main/res/font/roboto_mono_variable.ttf rename to ui/theme/src/androidMain/res/font/roboto_mono_variable.ttf diff --git a/ui/theme/src/main/kotlin/com/getcode/animation/SharedTransitionScope.kt b/ui/theme/src/commonMain/kotlin/com/getcode/animation/SharedTransitionScope.kt similarity index 100% rename from ui/theme/src/main/kotlin/com/getcode/animation/SharedTransitionScope.kt rename to ui/theme/src/commonMain/kotlin/com/getcode/animation/SharedTransitionScope.kt diff --git a/ui/theme/src/main/kotlin/com/getcode/theme/Color.kt b/ui/theme/src/commonMain/kotlin/com/getcode/theme/Color.kt similarity index 96% rename from ui/theme/src/main/kotlin/com/getcode/theme/Color.kt rename to ui/theme/src/commonMain/kotlin/com/getcode/theme/Color.kt index 5276f7edfe..53de9b8190 100644 --- a/ui/theme/src/main/kotlin/com/getcode/theme/Color.kt +++ b/ui/theme/src/commonMain/kotlin/com/getcode/theme/Color.kt @@ -2,7 +2,7 @@ package com.getcode.theme import androidx.compose.foundation.text.selection.TextSelectionColors import androidx.compose.ui.graphics.Color -import com.getcode.ui.utils.toAGColor +import androidx.compose.ui.graphics.toArgb val Brand = Color(0xFF0F0C1F) val BrandLight = Color(0xFF7379A0) @@ -85,7 +85,7 @@ data class GradientSpec( val borderColor: Color? = null, val borderWidth: Float = 0f, ) { - val colorsArray = colors.map { it.toAGColor() }.toIntArray() + val colorsArray = colors.map { it.toArgb() }.toIntArray() val stopsArray = stops.toFloatArray() override fun equals(other: Any?): Boolean { diff --git a/ui/theme/src/main/kotlin/com/getcode/theme/Dimens.kt b/ui/theme/src/commonMain/kotlin/com/getcode/theme/Dimens.kt similarity index 92% rename from ui/theme/src/main/kotlin/com/getcode/theme/Dimens.kt rename to ui/theme/src/commonMain/kotlin/com/getcode/theme/Dimens.kt index 303fc1b09b..ba3fce980f 100644 --- a/ui/theme/src/main/kotlin/com/getcode/theme/Dimens.kt +++ b/ui/theme/src/commonMain/kotlin/com/getcode/theme/Dimens.kt @@ -1,13 +1,11 @@ package com.getcode.theme -import android.content.res.Configuration import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.staticCompositionLocalOf -import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp -import com.getcode.theme.BuildConfig +import com.getcode.utils.BuildFlags val topBarHeight = 56.dp @@ -17,15 +15,15 @@ internal val LocalDimens = staticCompositionLocalOf { @Composable fun calculateDimensions( - logDimensions: Boolean = BuildConfig.DEBUG, - configuration: Configuration = LocalConfiguration.current + logDimensions: Boolean = BuildFlags.isDebug, + screenSizeDp: ScreenSizeDp = currentScreenSizeDp() ): Dimensions { - val screenWidthDp = configuration.screenWidthDp - val screenHeightDp = configuration.screenHeightDp + val screenWidthDp = screenSizeDp.widthDp + val screenHeightDp = screenSizeDp.heightDp val (widthSizeClass, heightSizeClass) = rememberWindowSizeClass( - logDimensions = logDimensions, configuration = configuration + logDimensions = logDimensions, screenSizeDp = screenSizeDp ) return Dimensions( diff --git a/ui/theme/src/main/kotlin/com/getcode/theme/DropShadow.kt b/ui/theme/src/commonMain/kotlin/com/getcode/theme/DropShadow.kt similarity index 89% rename from ui/theme/src/main/kotlin/com/getcode/theme/DropShadow.kt rename to ui/theme/src/commonMain/kotlin/com/getcode/theme/DropShadow.kt index 5a32981cbc..86b162ab5c 100644 --- a/ui/theme/src/main/kotlin/com/getcode/theme/DropShadow.kt +++ b/ui/theme/src/commonMain/kotlin/com/getcode/theme/DropShadow.kt @@ -17,13 +17,7 @@ data class DropShadow( val spread: Dp = 0.dp ) -fun Paint.makeBlur(shadowBlurRadius: Float) { - this.asFrameworkPaint().apply { - maskFilter = - android.graphics.BlurMaskFilter( - shadowBlurRadius, android.graphics.BlurMaskFilter.Blur.NORMAL) - } -} +expect fun Paint.makeBlur(shadowBlurRadius: Float) fun Modifier.dropShadow(shadow: DropShadow): Modifier { return this.then( diff --git a/ui/theme/src/commonMain/kotlin/com/getcode/theme/Platform.kt b/ui/theme/src/commonMain/kotlin/com/getcode/theme/Platform.kt new file mode 100644 index 0000000000..d402f00b24 --- /dev/null +++ b/ui/theme/src/commonMain/kotlin/com/getcode/theme/Platform.kt @@ -0,0 +1,20 @@ +package com.getcode.theme + +import androidx.compose.runtime.Composable +import androidx.compose.ui.text.font.FontFamily + +/** The current window's size in dp, as Android's `Configuration.screenWidthDp`/`screenHeightDp` report it. */ +data class ScreenSizeDp(val widthDp: Int, val heightDp: Int) + +@Composable +expect fun currentScreenSizeDp(): ScreenSizeDp + +/** Makes the status and navigation bars transparent where the platform has them. */ +@Composable +internal expect fun TransparentSystemBars() + +internal expect object PlatformFonts { + val avenir: FontFamily + val avenirMedium: FontFamily + val robotoMono: FontFamily +} diff --git a/ui/theme/src/main/kotlin/com/getcode/theme/Shape.kt b/ui/theme/src/commonMain/kotlin/com/getcode/theme/Shape.kt similarity index 100% rename from ui/theme/src/main/kotlin/com/getcode/theme/Shape.kt rename to ui/theme/src/commonMain/kotlin/com/getcode/theme/Shape.kt diff --git a/ui/theme/src/main/kotlin/com/getcode/theme/Theme.kt b/ui/theme/src/commonMain/kotlin/com/getcode/theme/Theme.kt similarity index 97% rename from ui/theme/src/main/kotlin/com/getcode/theme/Theme.kt rename to ui/theme/src/commonMain/kotlin/com/getcode/theme/Theme.kt index 64b1cdbede..e3930bd270 100644 --- a/ui/theme/src/main/kotlin/com/getcode/theme/Theme.kt +++ b/ui/theme/src/commonMain/kotlin/com/getcode/theme/Theme.kt @@ -8,7 +8,6 @@ import androidx.compose.material.Shapes import androidx.compose.material.TextFieldDefaults import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider -import androidx.compose.runtime.SideEffect import androidx.compose.runtime.Stable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -16,7 +15,6 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.runtime.staticCompositionLocalOf import androidx.compose.ui.graphics.Color -import com.google.accompanist.systemuicontroller.rememberSystemUiController internal val CodeDefaultColorScheme = ColorScheme( brand = Brand, @@ -80,12 +78,7 @@ fun DesignSystem( typography: CodeTypography = codeTypography, content: @Composable () -> Unit ) { - val sysUiController = rememberSystemUiController() - - SideEffect { - sysUiController.setStatusBarColor(color = Color(0x01000000)) - sysUiController.setNavigationBarColor(color = Color(0x01000000)) - } + TransparentSystemBars() val dimensions = calculateDimensions() diff --git a/ui/theme/src/main/kotlin/com/getcode/theme/Type.kt b/ui/theme/src/commonMain/kotlin/com/getcode/theme/Type.kt similarity index 78% rename from ui/theme/src/main/kotlin/com/getcode/theme/Type.kt rename to ui/theme/src/commonMain/kotlin/com/getcode/theme/Type.kt index ac44d6fff0..f6381fce91 100644 --- a/ui/theme/src/main/kotlin/com/getcode/theme/Type.kt +++ b/ui/theme/src/commonMain/kotlin/com/getcode/theme/Type.kt @@ -5,43 +5,19 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.staticCompositionLocalOf import androidx.compose.ui.text.TextStyle -import androidx.compose.ui.text.font.Font import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextDecoration import androidx.compose.ui.unit.sp -private val Avenir = FontFamily( - Font(R.font.avenir_next_regular, FontWeight.Thin), - Font(R.font.avenir_next_regular, FontWeight.ExtraLight), - Font(R.font.avenir_next_regular, FontWeight.Light), - Font(R.font.avenir_next_regular, FontWeight.Normal), - Font(R.font.avenir_next_demi, FontWeight.Medium), // TODO: find a better medium OTF - Font(R.font.avenir_next_demi, FontWeight.SemiBold), - Font(R.font.avenir_next_demi, FontWeight.Bold), - Font(R.font.avenir_next_demi, FontWeight.ExtraBold), - Font(R.font.avenir_next_demi, FontWeight.Black) -) +private val Avenir: FontFamily get() = PlatformFonts.avenir // The true Medium face. `Avenir` deliberately renders FontWeight.Medium as Demi (many call sites // depend on that), so styles that need iOS's real Medium use this family instead. -private val AvenirMedium = FontFamily( - Font(R.font.avenir_next_medium, FontWeight.Normal), - Font(R.font.avenir_next_medium, FontWeight.Medium), - // Heavier overrides (e.g. caption.copy(fontWeight = Bold)) stay on Demi, as they did under Avenir. - Font(R.font.avenir_next_demi, FontWeight.SemiBold), - Font(R.font.avenir_next_demi, FontWeight.Bold), - Font(R.font.avenir_next_demi, FontWeight.ExtraBold), - Font(R.font.avenir_next_demi, FontWeight.Black), -) +private val AvenirMedium: FontFamily get() = PlatformFonts.avenirMedium -private val RobotoMono = FontFamily( - Font(R.font.roboto_mono_variable, FontWeight.Light), - Font(R.font.roboto_mono_variable, FontWeight.Normal), - Font(R.font.roboto_mono_variable, FontWeight.Medium), - Font(R.font.roboto_mono_variable, FontWeight.SemiBold) -) +private val RobotoMono: FontFamily get() = PlatformFonts.robotoMono data class CodeTypography( val displayExtraLarge: TextStyle, diff --git a/ui/theme/src/main/kotlin/com/getcode/theme/WindowSizeClass.kt b/ui/theme/src/commonMain/kotlin/com/getcode/theme/WindowSizeClass.kt similarity index 71% rename from ui/theme/src/main/kotlin/com/getcode/theme/WindowSizeClass.kt rename to ui/theme/src/commonMain/kotlin/com/getcode/theme/WindowSizeClass.kt index 1068a1ca95..d839f0ba33 100644 --- a/ui/theme/src/main/kotlin/com/getcode/theme/WindowSizeClass.kt +++ b/ui/theme/src/commonMain/kotlin/com/getcode/theme/WindowSizeClass.kt @@ -1,11 +1,9 @@ package com.getcode.theme -import android.content.res.Configuration import androidx.compose.runtime.Composable import androidx.compose.runtime.remember -import androidx.compose.ui.platform.LocalConfiguration -import com.getcode.theme.BuildConfig -import timber.log.Timber +import com.getcode.utils.BuildFlags +import com.getcode.utils.Log data class DeviceWindowSizeClass internal constructor( val widthSizeClass: WindowSizeClass, @@ -14,11 +12,11 @@ data class DeviceWindowSizeClass internal constructor( @Composable fun rememberWindowSizeClass( - logDimensions: Boolean = BuildConfig.DEBUG, - configuration: Configuration = LocalConfiguration.current + logDimensions: Boolean = BuildFlags.isDebug, + screenSizeDp: ScreenSizeDp = currentScreenSizeDp() ): DeviceWindowSizeClass { - val screenWidthDp = configuration.screenWidthDp - val screenHeightDp = configuration.screenHeightDp + val screenWidthDp = screenSizeDp.widthDp + val screenHeightDp = screenSizeDp.heightDp return remember(screenWidthDp, screenHeightDp) { val screenWidthSizeClass = when { @@ -37,7 +35,7 @@ fun rememberWindowSizeClass( DeviceWindowSizeClass(screenWidthSizeClass, screenHeightSizeClass) }.also { if (logDimensions) { - Timber.d("dimens:: width = { dp: $screenWidthDp, class: ${it.widthSizeClass.name} }, height = { dp:$screenHeightDp, class: ${it.heightSizeClass.name} }") + Log.d("dimens:: width = { dp: $screenWidthDp, class: ${it.widthSizeClass.name} }, height = { dp:$screenHeightDp, class: ${it.heightSizeClass.name} }") } } } diff --git a/ui/theme/src/main/kotlin/com/getcode/view/shapes/TriangleCutShape.kt b/ui/theme/src/commonMain/kotlin/com/getcode/view/shapes/TriangleCutShape.kt similarity index 93% rename from ui/theme/src/main/kotlin/com/getcode/view/shapes/TriangleCutShape.kt rename to ui/theme/src/commonMain/kotlin/com/getcode/view/shapes/TriangleCutShape.kt index e29bf494f0..14ed6793f6 100644 --- a/ui/theme/src/main/kotlin/com/getcode/view/shapes/TriangleCutShape.kt +++ b/ui/theme/src/commonMain/kotlin/com/getcode/view/shapes/TriangleCutShape.kt @@ -1,6 +1,5 @@ package com.getcode.view.shapes -import android.graphics.PointF import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize @@ -29,9 +28,9 @@ class TriangleCutShape(private val cutStep: Dp = 10.dp) : androidx.compose.ui.gr private fun makeCutPath(size: Size, stepX: Float, height: Float, topClosed: Boolean): Path { val localHeight = if (topClosed) height else -height - val startPt = PointF(0f, if (topClosed) 0f else height) - val seq = listOf(PointF(0f, startPt.y)) + generateSequence(startPt) { - PointF(it.x.plus(stepX), if (it.y == startPt.y) startPt.y + localHeight else startPt.y) + val startPt = Offset(0f, if (topClosed) 0f else height) + val seq = listOf(Offset(0f, startPt.y)) + generateSequence(startPt) { + Offset(it.x.plus(stepX), if (it.y == startPt.y) startPt.y + localHeight else startPt.y) }.takeWhile { it.x <= (size.width + stepX) } return Path().apply { diff --git a/ui/theme/src/jvmMain/kotlin/com/getcode/theme/Platform.jvm.kt b/ui/theme/src/jvmMain/kotlin/com/getcode/theme/Platform.jvm.kt new file mode 100644 index 0000000000..3ea836657e --- /dev/null +++ b/ui/theme/src/jvmMain/kotlin/com/getcode/theme/Platform.jvm.kt @@ -0,0 +1,65 @@ +package com.getcode.theme + +import androidx.compose.runtime.Composable +import androidx.compose.ui.graphics.Paint +import androidx.compose.ui.graphics.skiaPaint +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.platform.LocalWindowInfo +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.platform.Font +import org.jetbrains.skia.FilterBlurMode +import org.jetbrains.skia.MaskFilter + +@Composable +actual fun currentScreenSizeDp(): ScreenSizeDp { + val size = LocalWindowInfo.current.containerSize + val density = LocalDensity.current.density + return ScreenSizeDp((size.width / density).toInt(), (size.height / density).toInt()) +} + +@Composable +internal actual fun TransparentSystemBars() = Unit + +actual fun Paint.makeBlur(shadowBlurRadius: Float) { + // Skia's own radius-to-sigma conversion, which Android's BlurMaskFilter applies internally. + val sigma = if (shadowBlurRadius > 0f) 0.57735f * shadowBlurRadius + 0.5f else 0f + skiaPaint.maskFilter = MaskFilter.makeBlur(FilterBlurMode.NORMAL, sigma) +} + +// The same font files Android packages from res/font, put on the classpath by this module's build. +private fun font(name: String, weight: FontWeight) = Font( + identity = "$name-${weight.weight}", + data = PlatformFonts::class.java.getResourceAsStream("/font/$name")!!.use { it.readBytes() }, + weight = weight, +) + +internal actual object PlatformFonts { + actual val avenir = FontFamily( + font("avenir_next_regular.otf", FontWeight.Thin), + font("avenir_next_regular.otf", FontWeight.ExtraLight), + font("avenir_next_regular.otf", FontWeight.Light), + font("avenir_next_regular.otf", FontWeight.Normal), + font("avenir_next_demi.otf", FontWeight.Medium), + font("avenir_next_demi.otf", FontWeight.SemiBold), + font("avenir_next_demi.otf", FontWeight.Bold), + font("avenir_next_demi.otf", FontWeight.ExtraBold), + font("avenir_next_demi.otf", FontWeight.Black), + ) + + actual val avenirMedium = FontFamily( + font("avenir_next_medium.otf", FontWeight.Normal), + font("avenir_next_medium.otf", FontWeight.Medium), + font("avenir_next_demi.otf", FontWeight.SemiBold), + font("avenir_next_demi.otf", FontWeight.Bold), + font("avenir_next_demi.otf", FontWeight.ExtraBold), + font("avenir_next_demi.otf", FontWeight.Black), + ) + + actual val robotoMono = FontFamily( + font("roboto_mono_variable.ttf", FontWeight.Light), + font("roboto_mono_variable.ttf", FontWeight.Normal), + font("roboto_mono_variable.ttf", FontWeight.Medium), + font("roboto_mono_variable.ttf", FontWeight.SemiBold), + ) +} From 82d26351735eb3ae1ab98ebee777e0c971dcd639 Mon Sep 17 00:00:00 2001 From: Brandon McAnsh Date: Fri, 23 Oct 2026 18:17:08 -0400 Subject: [PATCH 17/50] build(ui): move ui:core and ui:components to android+jvm KMP Only the files the balance screen reaches move to commonMain; the rest stay in androidMain unchanged. Drawable lookups by Android resource id go through painterForResId, with a desktop ResourceHelper over Compose resources. Blur support and hex colour parsing get small platform seams. --- gradle/libs.versions.toml | 1 + ui/components/build.gradle.kts | 93 +++++++++++-------- .../com/getcode/ui/components/BadgeTest.kt | 0 .../getcode/ui/components/FilterChipTest.kt | 0 .../components/chat/ComposerStackingTest.kt | 0 .../ui/components/chat/TypingIndicatorTest.kt | 0 .../components/text/AnimatedNumberTextTest.kt | 0 .../components/text/NumberInputHelperTest.kt | 0 .../components/text/NumberRollMotionTest.kt | 0 .../toast/FloatingToastHostStateTest.kt | 0 .../ui/core/ExpandedTouchTargetTest.kt | 0 .../ui/utils/KeyboardControllerTest.kt | 0 .../kotlin/com/getcode/ui/Locals.kt | 0 .../getcode/ui/components/BetaIndicator.kt | 0 .../getcode/ui/components/BlurredContent.kt | 0 .../getcode/ui/components/BottomScrollEdge.kt | 0 .../com/getcode/ui/components/BulletRow.kt | 0 .../ui/components/CapsuleProgressBar.kt | 0 .../kotlin/com/getcode/ui/components/Chip.kt | 0 .../com/getcode/ui/components/ChoiceRow.kt | 0 .../ui/components/CircularIconButton.kt | 0 .../ConnectionStatusPreview.android.kt | 13 +++ .../com/getcode/ui/components/FilterChip.kt | 0 .../com/getcode/ui/components/Flippable.kt | 0 .../components/FullWidthScrollableTabRow.kt | 0 .../com/getcode/ui/components/ListItem.kt | 0 .../kotlin/com/getcode/ui/components/Modal.kt | 0 .../getcode/ui/components/NotificationDot.kt | 0 .../getcode/ui/components/OnLifecycleEvent.kt | 0 .../ui/components/OnWindowFocusedRequester.kt | 0 .../kotlin/com/getcode/ui/components/Pill.kt | 0 .../getcode/ui/components/PriceWithFlag.kt | 0 .../com/getcode/ui/components/PullToReveal.kt | 0 .../com/getcode/ui/components/SearchInput.kt | 0 .../getcode/ui/components/SegmentedControl.kt | 0 .../ui/components/SelectionContainer.kt | 0 .../ui/components/SettingsSwitchRow.kt | 0 .../getcode/ui/components/SlideToConfirm.kt | 0 .../getcode/ui/components/SwipeActionRow.kt | 0 .../com/getcode/ui/components/TextInput.kt | 0 .../com/getcode/ui/components/TitleBar.kt | 0 .../getcode/ui/components/TopScrollEdge.kt | 0 .../getcode/ui/components/VerticalDivider.kt | 0 .../getcode/ui/components/bars/BarManager.kt | 0 .../getcode/ui/components/bars/BarMessages.kt | 0 .../ui/components/bars/BottomBarContainer.kt | 0 .../ui/components/bars/TopBarContainer.kt | 0 .../ui/components/charts/ChartPoint.kt | 0 .../getcode/ui/components/charts/Trends.kt | 0 .../ui/components/chat/AnonymousAvatar.kt | 0 .../getcode/ui/components/chat/ChatInput.kt | 0 .../getcode/ui/components/chat/DateBubble.kt | 0 .../ui/components/chat/HostableAvatar.kt | 0 .../ui/components/chat/MessageNodeDefaults.kt | 0 .../ui/components/chat/TypingIndicator.kt | 0 .../ui/components/chat/UnreadSeparator.kt | 0 .../getcode/ui/components/chat/UserAvatar.kt | 0 .../getcode/ui/components/picker/Picker.kt | 0 .../restrictions/RestrictionBlockingView.kt | 0 .../ui/components/text/AmountAreaPreviews.kt | 38 ++++++++ .../ui/components/text/BlurSupport.android.kt | 6 ++ .../ui/components/text/ExpandableText.kt | 0 .../ui/components/text/SectionHeader.kt | 0 .../text/animated/DigitContainer.kt | 0 .../ui/components/text/markup/Markup.kt | 0 .../text/markup/MarkupTextHelper.kt | 0 .../ui/components/toast/FloatingToast.kt | 0 .../ui/components/toast/FloatingToastHost.kt | 0 .../components/user/social/SocialUserTitle.kt | 0 .../ui/theme/CodeBillSwipeToDismiss.kt | 0 .../kotlin/com/getcode/ui/theme/CodeButton.kt | 0 .../com/getcode/ui/theme/CodeCheckbox.kt | 0 .../kotlin/com/getcode/ui/theme/CodeKeyPad.kt | 0 .../com/getcode/ui/theme/CodeRadioButton.kt | 0 .../com/getcode/ui/theme/CodeScaffold.kt | 0 .../com/getcode/ui/theme/CodeSeedView.kt | 0 .../getcode/ui/theme/CodeSegmentedControl.kt | 0 .../kotlin/com/getcode/ui/theme/CodeSwitch.kt | 0 .../com/getcode/ui/utils/AnimationUtils.kt | 0 .../getcode/ui/utils/ComplementaryGradient.kt | 0 .../com/getcode/ui/utils/EightBitGenerator.kt | 0 .../kotlin/com/getcode/ui/utils/Geometry.kt | 0 .../com/getcode/ui/utils/KeepScreenOn.kt | 0 .../kotlin/com/getcode/ui/utils/Keyboard.kt | 0 .../kotlin/com/getcode/ui/utils/LazyList.kt | 0 .../kotlin/com/getcode/ui/utils/Maps.kt | 0 .../com/getcode/ui/utils/MeasureScope.kt | 0 .../com/getcode/ui/utils/PaddingValues.kt | 0 .../getcode/ui/utils/ParseColor.android.kt | 5 + .../com/getcode/ui/utils/PreviewParameters.kt | 0 .../ui/utils/RecompositionHighlighter.kt | 0 .../kotlin/com/getcode/ui/utils/TextStyle.kt | 0 .../kotlin/com/getcode/ui/utils/Window.kt | 0 .../res/drawable/ic_arrow_up.xml | 0 .../drawable/ic_twitter_verified_badge.xml | 0 .../ic_twitter_verified_badge_gold.xml | 0 .../ic_twitter_verified_badge_gray.xml | 0 .../res/values/strings.xml | 0 .../kotlin/com/getcode/ui/components/Badge.kt | 0 .../components/ConnectionStatusComponent.kt | 10 -- .../ui/components/glass/FloatingGlass.kt | 0 .../getcode/ui/components/text/AmountArea.kt | 40 +------- .../getcode/ui/components/text/AmountText.kt | 10 +- .../ui/components/text/AmountTextAnimated.kt | 10 +- .../ui/components/text/AnimatedNumberText.kt | 3 +- .../getcode/ui/components/text/BlurSupport.kt | 4 + .../ui/components/text/NumberInputHelper.kt | 0 .../ui/components/text/NumberRollMotion.kt | 0 .../text/animated/AnimatedPlaceholderDigit.kt | 0 .../ui/components/text/animated/Digit.kt | 0 .../text/animated/DigitAnimations.kt | 0 .../text/animated/NormalizedPrefixText.kt | 0 .../ui/theme/CodeCircularProgressIndicator.kt | 0 .../com/getcode/ui/utils/AutoSizeText.kt | 0 .../getcode/ui/utils/AutoSizeTextMeasurer.kt | 0 .../getcode/ui/utils/ColorTransformations.kt | 3 +- .../kotlin/com/getcode/ui/utils/ParseColor.kt | 4 + .../kotlin/com/getcode/ui/utils/TextUnit.kt | 0 .../ui/components/text/BlurSupport.jvm.kt | 3 + .../com/getcode/ui/utils/ParseColor.jvm.kt | 11 +++ ui/core/build.gradle.kts | 37 +++++--- .../com/getcode/ui/core/AnimationScale.kt | 0 .../com/getcode/ui/core/ContextMenuAction.kt | 0 .../getcode/ui/core/ExpandedTouchTarget.kt | 0 .../com/getcode/ui/core/Modifier.android.kt | 15 +++ .../ui/core/StarMaskVisualTransformation.kt | 0 .../ui/core/visibility/VisibilityInfo.kt | 0 .../core/visibility/VisibilityTrackerNode.kt | 0 .../kotlin/com/getcode/ui/core/IntSize.kt | 0 .../kotlin/com/getcode/ui/core/Modifier.kt | 11 --- .../com/getcode/ui/core/RestrictionType.kt | 0 .../util/resources/PainterForResId.android.kt | 8 ++ .../getcode/util/resources/PainterForResId.kt | 14 +++ .../util/resources/ComposeResourceHelper.kt | 33 +++++++ .../util/resources/ComposeResourceIds.kt | 34 +++++++ .../util/resources/PainterForResId.jvm.kt | 8 ++ 136 files changed, 294 insertions(+), 120 deletions(-) rename ui/components/src/{test => androidHostTest}/kotlin/com/getcode/ui/components/BadgeTest.kt (100%) rename ui/components/src/{test => androidHostTest}/kotlin/com/getcode/ui/components/FilterChipTest.kt (100%) rename ui/components/src/{test => androidHostTest}/kotlin/com/getcode/ui/components/chat/ComposerStackingTest.kt (100%) rename ui/components/src/{test => androidHostTest}/kotlin/com/getcode/ui/components/chat/TypingIndicatorTest.kt (100%) rename ui/components/src/{test => androidHostTest}/kotlin/com/getcode/ui/components/text/AnimatedNumberTextTest.kt (100%) rename ui/components/src/{test => androidHostTest}/kotlin/com/getcode/ui/components/text/NumberInputHelperTest.kt (100%) rename ui/components/src/{test => androidHostTest}/kotlin/com/getcode/ui/components/text/NumberRollMotionTest.kt (100%) rename ui/components/src/{test => androidHostTest}/kotlin/com/getcode/ui/components/toast/FloatingToastHostStateTest.kt (100%) rename ui/components/src/{test => androidHostTest}/kotlin/com/getcode/ui/core/ExpandedTouchTargetTest.kt (100%) rename ui/components/src/{test => androidHostTest}/kotlin/com/getcode/ui/utils/KeyboardControllerTest.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/Locals.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/components/BetaIndicator.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/components/BlurredContent.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/components/BottomScrollEdge.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/components/BulletRow.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/components/CapsuleProgressBar.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/components/Chip.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/components/ChoiceRow.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/components/CircularIconButton.kt (100%) create mode 100644 ui/components/src/androidMain/kotlin/com/getcode/ui/components/ConnectionStatusPreview.android.kt rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/components/FilterChip.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/components/Flippable.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/components/FullWidthScrollableTabRow.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/components/ListItem.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/components/Modal.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/components/NotificationDot.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/components/OnLifecycleEvent.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/components/OnWindowFocusedRequester.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/components/Pill.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/components/PriceWithFlag.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/components/PullToReveal.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/components/SearchInput.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/components/SegmentedControl.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/components/SelectionContainer.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/components/SettingsSwitchRow.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/components/SlideToConfirm.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/components/SwipeActionRow.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/components/TextInput.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/components/TitleBar.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/components/TopScrollEdge.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/components/VerticalDivider.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/components/bars/BarManager.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/components/bars/BarMessages.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/components/bars/BottomBarContainer.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/components/bars/TopBarContainer.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/components/charts/ChartPoint.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/components/charts/Trends.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/components/chat/AnonymousAvatar.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/components/chat/ChatInput.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/components/chat/DateBubble.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/components/chat/HostableAvatar.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/components/chat/MessageNodeDefaults.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/components/chat/TypingIndicator.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/components/chat/UnreadSeparator.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/components/chat/UserAvatar.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/components/picker/Picker.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/components/restrictions/RestrictionBlockingView.kt (100%) create mode 100644 ui/components/src/androidMain/kotlin/com/getcode/ui/components/text/AmountAreaPreviews.kt create mode 100644 ui/components/src/androidMain/kotlin/com/getcode/ui/components/text/BlurSupport.android.kt rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/components/text/ExpandableText.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/components/text/SectionHeader.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/components/text/animated/DigitContainer.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/components/text/markup/Markup.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/components/text/markup/MarkupTextHelper.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/components/toast/FloatingToast.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/components/toast/FloatingToastHost.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/components/user/social/SocialUserTitle.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/theme/CodeBillSwipeToDismiss.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/theme/CodeButton.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/theme/CodeCheckbox.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/theme/CodeKeyPad.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/theme/CodeRadioButton.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/theme/CodeScaffold.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/theme/CodeSeedView.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/theme/CodeSegmentedControl.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/theme/CodeSwitch.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/utils/AnimationUtils.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/utils/ComplementaryGradient.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/utils/EightBitGenerator.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/utils/Geometry.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/utils/KeepScreenOn.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/utils/Keyboard.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/utils/LazyList.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/utils/Maps.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/utils/MeasureScope.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/utils/PaddingValues.kt (100%) create mode 100644 ui/components/src/androidMain/kotlin/com/getcode/ui/utils/ParseColor.android.kt rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/utils/PreviewParameters.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/utils/RecompositionHighlighter.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/utils/TextStyle.kt (100%) rename ui/components/src/{main => androidMain}/kotlin/com/getcode/ui/utils/Window.kt (100%) rename ui/components/src/{main => androidMain}/res/drawable/ic_arrow_up.xml (100%) rename ui/components/src/{main => androidMain}/res/drawable/ic_twitter_verified_badge.xml (100%) rename ui/components/src/{main => androidMain}/res/drawable/ic_twitter_verified_badge_gold.xml (100%) rename ui/components/src/{main => androidMain}/res/drawable/ic_twitter_verified_badge_gray.xml (100%) rename ui/components/src/{main => androidMain}/res/values/strings.xml (100%) rename ui/components/src/{main => commonMain}/kotlin/com/getcode/ui/components/Badge.kt (100%) rename ui/components/src/{main => commonMain}/kotlin/com/getcode/ui/components/ConnectionStatusComponent.kt (82%) rename ui/components/src/{main => commonMain}/kotlin/com/getcode/ui/components/glass/FloatingGlass.kt (100%) rename ui/components/src/{main => commonMain}/kotlin/com/getcode/ui/components/text/AmountArea.kt (86%) rename ui/components/src/{main => commonMain}/kotlin/com/getcode/ui/components/text/AmountText.kt (93%) rename ui/components/src/{main => commonMain}/kotlin/com/getcode/ui/components/text/AmountTextAnimated.kt (97%) rename ui/components/src/{main => commonMain}/kotlin/com/getcode/ui/components/text/AnimatedNumberText.kt (99%) create mode 100644 ui/components/src/commonMain/kotlin/com/getcode/ui/components/text/BlurSupport.kt rename ui/components/src/{main => commonMain}/kotlin/com/getcode/ui/components/text/NumberInputHelper.kt (100%) rename ui/components/src/{main => commonMain}/kotlin/com/getcode/ui/components/text/NumberRollMotion.kt (100%) rename ui/components/src/{main => commonMain}/kotlin/com/getcode/ui/components/text/animated/AnimatedPlaceholderDigit.kt (100%) rename ui/components/src/{main => commonMain}/kotlin/com/getcode/ui/components/text/animated/Digit.kt (100%) rename ui/components/src/{main => commonMain}/kotlin/com/getcode/ui/components/text/animated/DigitAnimations.kt (100%) rename ui/components/src/{main => commonMain}/kotlin/com/getcode/ui/components/text/animated/NormalizedPrefixText.kt (100%) rename ui/components/src/{main => commonMain}/kotlin/com/getcode/ui/theme/CodeCircularProgressIndicator.kt (100%) rename ui/components/src/{main => commonMain}/kotlin/com/getcode/ui/utils/AutoSizeText.kt (100%) rename ui/components/src/{main => commonMain}/kotlin/com/getcode/ui/utils/AutoSizeTextMeasurer.kt (100%) rename ui/components/src/{main => commonMain}/kotlin/com/getcode/ui/utils/ColorTransformations.kt (98%) create mode 100644 ui/components/src/commonMain/kotlin/com/getcode/ui/utils/ParseColor.kt rename ui/components/src/{main => commonMain}/kotlin/com/getcode/ui/utils/TextUnit.kt (100%) create mode 100644 ui/components/src/jvmMain/kotlin/com/getcode/ui/components/text/BlurSupport.jvm.kt create mode 100644 ui/components/src/jvmMain/kotlin/com/getcode/ui/utils/ParseColor.jvm.kt rename ui/core/src/{main => androidMain}/kotlin/com/getcode/ui/core/AnimationScale.kt (100%) rename ui/core/src/{main => androidMain}/kotlin/com/getcode/ui/core/ContextMenuAction.kt (100%) rename ui/core/src/{main => androidMain}/kotlin/com/getcode/ui/core/ExpandedTouchTarget.kt (100%) create mode 100644 ui/core/src/androidMain/kotlin/com/getcode/ui/core/Modifier.android.kt rename ui/core/src/{main => androidMain}/kotlin/com/getcode/ui/core/StarMaskVisualTransformation.kt (100%) rename ui/core/src/{main => androidMain}/kotlin/com/getcode/ui/core/visibility/VisibilityInfo.kt (100%) rename ui/core/src/{main => androidMain}/kotlin/com/getcode/ui/core/visibility/VisibilityTrackerNode.kt (100%) rename ui/core/src/{main => commonMain}/kotlin/com/getcode/ui/core/IntSize.kt (100%) rename ui/core/src/{main => commonMain}/kotlin/com/getcode/ui/core/Modifier.kt (98%) rename ui/core/src/{main => commonMain}/kotlin/com/getcode/ui/core/RestrictionType.kt (100%) create mode 100644 ui/resources/src/androidMain/kotlin/com/getcode/util/resources/PainterForResId.android.kt create mode 100644 ui/resources/src/commonMain/kotlin/com/getcode/util/resources/PainterForResId.kt create mode 100644 ui/resources/src/jvmMain/kotlin/com/getcode/util/resources/ComposeResourceHelper.kt create mode 100644 ui/resources/src/jvmMain/kotlin/com/getcode/util/resources/ComposeResourceIds.kt create mode 100644 ui/resources/src/jvmMain/kotlin/com/getcode/util/resources/PainterForResId.jvm.kt diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 0c0ed05e95..b8b9612939 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -344,6 +344,7 @@ androidx-foundation-layout = { group = "androidx.compose.foundation", name = "fo jetbrains-compose-runtime = { module = "org.jetbrains.compose.runtime:runtime", version.ref = "compose-multiplatform" } # On Android these resolve to the androidx artifacts at the version the Compose BOM pins. jetbrains-compose-foundation = { module = "org.jetbrains.compose.foundation:foundation", version.ref = "compose-multiplatform" } +jetbrains-compose-animation = { module = "org.jetbrains.compose.animation:animation", version.ref = "compose-multiplatform" } jetbrains-compose-ui = { module = "org.jetbrains.compose.ui:ui", version.ref = "compose-multiplatform" } jetbrains-compose-material = { module = "org.jetbrains.compose.material:material", version.ref = "compose-multiplatform" } jetbrains-compose-material3 = { module = "org.jetbrains.compose.material3:material3", version.ref = "compose-multiplatform-material3" } diff --git a/ui/components/build.gradle.kts b/ui/components/build.gradle.kts index b66710c0a1..d578f47feb 100644 --- a/ui/components/build.gradle.kts +++ b/ui/components/build.gradle.kts @@ -1,48 +1,61 @@ plugins { - alias(libs.plugins.flipcash.android.library.compose) + alias(libs.plugins.flipcash.kmp.app.library) + alias(libs.plugins.compose.compiler) id("org.jetbrains.kotlin.plugin.parcelize") } -android { - namespace = "com.getcode.ui.components" +kotlin { + android { + namespace = "com.getcode.ui.components" + androidResources { enable = true } + } - buildFeatures { - buildConfig = true + sourceSets { + commonMain.dependencies { + implementation(libs.jetbrains.compose.runtime) + implementation(libs.jetbrains.compose.foundation) + implementation(libs.jetbrains.compose.ui) + implementation(libs.jetbrains.compose.animation) + implementation(libs.jetbrains.compose.material) + api(libs.jetbrains.compose.material3) + implementation(libs.jetbrains.compose.components.resources) + api(libs.jetbrains.compose.ui.tooling.preview) + // api: TopScrollEdge and the app bar take a HazeState, so callers need the type. + api(libs.bundles.haze) + api(project(":ui:core")) + implementation(project(":ui:theme")) + implementation(project(":ui:resources")) + implementation(project(":libs:network:connectivity:public")) + } + androidMain.dependencies { + implementation(project.dependencies.platform(libs.compose.bom)) + implementation(project(":libs:datetime")) + implementation(project(":libs:encryption:ed25519")) + implementation(project(":libs:encryption:utils")) + implementation(project(":libs:currency")) + implementation(project(":libs:messaging")) + implementation(project(":libs:models")) + implementation(project(":libs:vibrator:public")) + implementation(project(":ui:navigation")) + implementation(libs.coil3) + implementation(libs.coil3.network) + implementation(libs.kotlinx.datetime) + implementation(libs.compose.animation) + implementation(libs.compose.ui.text) + implementation(libs.compose.activities) + implementation(libs.compose.material) + api(libs.compose.material3) + api(libs.compose.ui.tools.preview) + implementation(libs.compose.material.icons.extended) + implementation(libs.compose.accompanist) + implementation(libs.compose.paging) + api(libs.vico.compose) + } + getByName("androidHostTest").dependencies { + implementation(kotlin("test")) + implementation(libs.bundles.unit.testing) + implementation(libs.bundles.compose.ui.testing) + } } } -dependencies { - testImplementation(kotlin("test")) - testImplementation(libs.bundles.unit.testing) - testImplementation(libs.bundles.compose.ui.testing) - - implementation(project(":libs:datetime")) - implementation(project(":libs:encryption:ed25519")) - implementation(project(":libs:encryption:utils")) - implementation(project(":libs:currency")) - implementation(project(":libs:messaging")) - implementation(project(":libs:models")) - implementation(project(":libs:network:connectivity:public")) - implementation(project(":libs:vibrator:public")) - api(project(":ui:core")) - implementation(project(":ui:theme")) - implementation(project(":ui:resources")) - - implementation(libs.coil3) - implementation(libs.coil3.network) - implementation(libs.kotlinx.datetime) - implementation(libs.compose.animation) - implementation(libs.compose.ui.text) - implementation(libs.compose.activities) - implementation(project(":ui:navigation")) - debugApi(libs.compose.ui.tools) - api(libs.compose.ui.tools.preview) - implementation(libs.compose.material) - api(libs.compose.material3) - implementation(libs.compose.material.icons.extended) - implementation(libs.compose.accompanist) - implementation(libs.compose.paging) - api(libs.vico.compose) - // api: TopScrollEdge and the app bar take a HazeState, so callers need the type. - api(libs.bundles.haze) -} diff --git a/ui/components/src/test/kotlin/com/getcode/ui/components/BadgeTest.kt b/ui/components/src/androidHostTest/kotlin/com/getcode/ui/components/BadgeTest.kt similarity index 100% rename from ui/components/src/test/kotlin/com/getcode/ui/components/BadgeTest.kt rename to ui/components/src/androidHostTest/kotlin/com/getcode/ui/components/BadgeTest.kt diff --git a/ui/components/src/test/kotlin/com/getcode/ui/components/FilterChipTest.kt b/ui/components/src/androidHostTest/kotlin/com/getcode/ui/components/FilterChipTest.kt similarity index 100% rename from ui/components/src/test/kotlin/com/getcode/ui/components/FilterChipTest.kt rename to ui/components/src/androidHostTest/kotlin/com/getcode/ui/components/FilterChipTest.kt diff --git a/ui/components/src/test/kotlin/com/getcode/ui/components/chat/ComposerStackingTest.kt b/ui/components/src/androidHostTest/kotlin/com/getcode/ui/components/chat/ComposerStackingTest.kt similarity index 100% rename from ui/components/src/test/kotlin/com/getcode/ui/components/chat/ComposerStackingTest.kt rename to ui/components/src/androidHostTest/kotlin/com/getcode/ui/components/chat/ComposerStackingTest.kt diff --git a/ui/components/src/test/kotlin/com/getcode/ui/components/chat/TypingIndicatorTest.kt b/ui/components/src/androidHostTest/kotlin/com/getcode/ui/components/chat/TypingIndicatorTest.kt similarity index 100% rename from ui/components/src/test/kotlin/com/getcode/ui/components/chat/TypingIndicatorTest.kt rename to ui/components/src/androidHostTest/kotlin/com/getcode/ui/components/chat/TypingIndicatorTest.kt diff --git a/ui/components/src/test/kotlin/com/getcode/ui/components/text/AnimatedNumberTextTest.kt b/ui/components/src/androidHostTest/kotlin/com/getcode/ui/components/text/AnimatedNumberTextTest.kt similarity index 100% rename from ui/components/src/test/kotlin/com/getcode/ui/components/text/AnimatedNumberTextTest.kt rename to ui/components/src/androidHostTest/kotlin/com/getcode/ui/components/text/AnimatedNumberTextTest.kt diff --git a/ui/components/src/test/kotlin/com/getcode/ui/components/text/NumberInputHelperTest.kt b/ui/components/src/androidHostTest/kotlin/com/getcode/ui/components/text/NumberInputHelperTest.kt similarity index 100% rename from ui/components/src/test/kotlin/com/getcode/ui/components/text/NumberInputHelperTest.kt rename to ui/components/src/androidHostTest/kotlin/com/getcode/ui/components/text/NumberInputHelperTest.kt diff --git a/ui/components/src/test/kotlin/com/getcode/ui/components/text/NumberRollMotionTest.kt b/ui/components/src/androidHostTest/kotlin/com/getcode/ui/components/text/NumberRollMotionTest.kt similarity index 100% rename from ui/components/src/test/kotlin/com/getcode/ui/components/text/NumberRollMotionTest.kt rename to ui/components/src/androidHostTest/kotlin/com/getcode/ui/components/text/NumberRollMotionTest.kt diff --git a/ui/components/src/test/kotlin/com/getcode/ui/components/toast/FloatingToastHostStateTest.kt b/ui/components/src/androidHostTest/kotlin/com/getcode/ui/components/toast/FloatingToastHostStateTest.kt similarity index 100% rename from ui/components/src/test/kotlin/com/getcode/ui/components/toast/FloatingToastHostStateTest.kt rename to ui/components/src/androidHostTest/kotlin/com/getcode/ui/components/toast/FloatingToastHostStateTest.kt diff --git a/ui/components/src/test/kotlin/com/getcode/ui/core/ExpandedTouchTargetTest.kt b/ui/components/src/androidHostTest/kotlin/com/getcode/ui/core/ExpandedTouchTargetTest.kt similarity index 100% rename from ui/components/src/test/kotlin/com/getcode/ui/core/ExpandedTouchTargetTest.kt rename to ui/components/src/androidHostTest/kotlin/com/getcode/ui/core/ExpandedTouchTargetTest.kt diff --git a/ui/components/src/test/kotlin/com/getcode/ui/utils/KeyboardControllerTest.kt b/ui/components/src/androidHostTest/kotlin/com/getcode/ui/utils/KeyboardControllerTest.kt similarity index 100% rename from ui/components/src/test/kotlin/com/getcode/ui/utils/KeyboardControllerTest.kt rename to ui/components/src/androidHostTest/kotlin/com/getcode/ui/utils/KeyboardControllerTest.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/Locals.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/Locals.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/Locals.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/Locals.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/components/BetaIndicator.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/components/BetaIndicator.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/components/BetaIndicator.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/components/BetaIndicator.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/components/BlurredContent.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/components/BlurredContent.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/components/BlurredContent.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/components/BlurredContent.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/components/BottomScrollEdge.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/components/BottomScrollEdge.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/components/BottomScrollEdge.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/components/BottomScrollEdge.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/components/BulletRow.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/components/BulletRow.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/components/BulletRow.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/components/BulletRow.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/components/CapsuleProgressBar.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/components/CapsuleProgressBar.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/components/CapsuleProgressBar.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/components/CapsuleProgressBar.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/components/Chip.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/components/Chip.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/components/Chip.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/components/Chip.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/components/ChoiceRow.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/components/ChoiceRow.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/components/ChoiceRow.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/components/ChoiceRow.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/components/CircularIconButton.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/components/CircularIconButton.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/components/CircularIconButton.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/components/CircularIconButton.kt diff --git a/ui/components/src/androidMain/kotlin/com/getcode/ui/components/ConnectionStatusPreview.android.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/components/ConnectionStatusPreview.android.kt new file mode 100644 index 0000000000..3a68e98ba8 --- /dev/null +++ b/ui/components/src/androidMain/kotlin/com/getcode/ui/components/ConnectionStatusPreview.android.kt @@ -0,0 +1,13 @@ +package com.getcode.ui.components + +import androidx.compose.runtime.Composable +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.tooling.preview.PreviewParameter +import com.getcode.utils.network.NetworkState +import com.getcode.utils.network.connectivity.NetworkStateProvider + +@Preview +@Composable +fun ConnectionReconnectingPreview(@PreviewParameter(NetworkStateProvider::class) state: NetworkState) { + ConnectionStatus(state) +} diff --git a/ui/components/src/main/kotlin/com/getcode/ui/components/FilterChip.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/components/FilterChip.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/components/FilterChip.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/components/FilterChip.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/components/Flippable.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/components/Flippable.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/components/Flippable.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/components/Flippable.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/components/FullWidthScrollableTabRow.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/components/FullWidthScrollableTabRow.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/components/FullWidthScrollableTabRow.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/components/FullWidthScrollableTabRow.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/components/ListItem.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/components/ListItem.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/components/ListItem.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/components/ListItem.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/components/Modal.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/components/Modal.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/components/Modal.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/components/Modal.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/components/NotificationDot.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/components/NotificationDot.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/components/NotificationDot.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/components/NotificationDot.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/components/OnLifecycleEvent.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/components/OnLifecycleEvent.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/components/OnLifecycleEvent.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/components/OnLifecycleEvent.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/components/OnWindowFocusedRequester.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/components/OnWindowFocusedRequester.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/components/OnWindowFocusedRequester.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/components/OnWindowFocusedRequester.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/components/Pill.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/components/Pill.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/components/Pill.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/components/Pill.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/components/PriceWithFlag.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/components/PriceWithFlag.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/components/PriceWithFlag.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/components/PriceWithFlag.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/components/PullToReveal.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/components/PullToReveal.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/components/PullToReveal.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/components/PullToReveal.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/components/SearchInput.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/components/SearchInput.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/components/SearchInput.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/components/SearchInput.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/components/SegmentedControl.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/components/SegmentedControl.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/components/SegmentedControl.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/components/SegmentedControl.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/components/SelectionContainer.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/components/SelectionContainer.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/components/SelectionContainer.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/components/SelectionContainer.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/components/SettingsSwitchRow.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/components/SettingsSwitchRow.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/components/SettingsSwitchRow.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/components/SettingsSwitchRow.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/components/SlideToConfirm.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/components/SlideToConfirm.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/components/SlideToConfirm.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/components/SlideToConfirm.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/components/SwipeActionRow.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/components/SwipeActionRow.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/components/SwipeActionRow.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/components/SwipeActionRow.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/components/TextInput.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/components/TextInput.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/components/TextInput.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/components/TextInput.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/components/TitleBar.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/components/TitleBar.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/components/TitleBar.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/components/TitleBar.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/components/TopScrollEdge.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/components/TopScrollEdge.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/components/TopScrollEdge.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/components/TopScrollEdge.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/components/VerticalDivider.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/components/VerticalDivider.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/components/VerticalDivider.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/components/VerticalDivider.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/components/bars/BarManager.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/components/bars/BarManager.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/components/bars/BarManager.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/components/bars/BarManager.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/components/bars/BarMessages.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/components/bars/BarMessages.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/components/bars/BarMessages.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/components/bars/BarMessages.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/components/bars/BottomBarContainer.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/components/bars/BottomBarContainer.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/components/bars/BottomBarContainer.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/components/bars/BottomBarContainer.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/components/bars/TopBarContainer.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/components/bars/TopBarContainer.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/components/bars/TopBarContainer.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/components/bars/TopBarContainer.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/components/charts/ChartPoint.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/components/charts/ChartPoint.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/components/charts/ChartPoint.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/components/charts/ChartPoint.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/components/charts/Trends.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/components/charts/Trends.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/components/charts/Trends.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/components/charts/Trends.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/components/chat/AnonymousAvatar.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/components/chat/AnonymousAvatar.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/components/chat/AnonymousAvatar.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/components/chat/AnonymousAvatar.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/components/chat/ChatInput.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/components/chat/ChatInput.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/components/chat/ChatInput.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/components/chat/ChatInput.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/components/chat/DateBubble.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/components/chat/DateBubble.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/components/chat/DateBubble.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/components/chat/DateBubble.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/components/chat/HostableAvatar.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/components/chat/HostableAvatar.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/components/chat/HostableAvatar.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/components/chat/HostableAvatar.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/components/chat/MessageNodeDefaults.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/components/chat/MessageNodeDefaults.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/components/chat/MessageNodeDefaults.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/components/chat/MessageNodeDefaults.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/components/chat/TypingIndicator.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/components/chat/TypingIndicator.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/components/chat/TypingIndicator.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/components/chat/TypingIndicator.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/components/chat/UnreadSeparator.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/components/chat/UnreadSeparator.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/components/chat/UnreadSeparator.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/components/chat/UnreadSeparator.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/components/chat/UserAvatar.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/components/chat/UserAvatar.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/components/chat/UserAvatar.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/components/chat/UserAvatar.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/components/picker/Picker.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/components/picker/Picker.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/components/picker/Picker.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/components/picker/Picker.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/components/restrictions/RestrictionBlockingView.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/components/restrictions/RestrictionBlockingView.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/components/restrictions/RestrictionBlockingView.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/components/restrictions/RestrictionBlockingView.kt diff --git a/ui/components/src/androidMain/kotlin/com/getcode/ui/components/text/AmountAreaPreviews.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/components/text/AmountAreaPreviews.kt new file mode 100644 index 0000000000..2dd329962c --- /dev/null +++ b/ui/components/src/androidMain/kotlin/com/getcode/ui/components/text/AmountAreaPreviews.kt @@ -0,0 +1,38 @@ +package com.getcode.ui.components.text + +import androidx.compose.runtime.Composable +import androidx.compose.ui.tooling.preview.Preview +import com.getcode.theme.DesignSystem +import com.getcode.ui.components.R +import com.getcode.utils.network.connectivity.NetworkStateProvider + +private val networkStateValues = NetworkStateProvider().values +@Preview +@Composable +fun AmountPreview() { + DesignSystem { + AmountArea( + amountPrefix = "prefix", + amountText = "$12.34 of Kin", + amountSuffix = "suffix", + captionText = "The value of kin fluctuates", + currencyResId = R.drawable.ic_flag_ca, + networkState = networkStateValues.last(), + ) + } +} + +@Preview +@Composable +fun AmountPreviewDisconnected() { + DesignSystem { + AmountArea( + amountPrefix = "prefix", + amountText = "$12.34 of Kin", + amountSuffix = "suffix", + captionText = "The value of kin fluctuates", + currencyResId = R.drawable.ic_flag_ca, + networkState = networkStateValues.first(), + ) + } +} \ No newline at end of file diff --git a/ui/components/src/androidMain/kotlin/com/getcode/ui/components/text/BlurSupport.android.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/components/text/BlurSupport.android.kt new file mode 100644 index 0000000000..bc14dc1fbc --- /dev/null +++ b/ui/components/src/androidMain/kotlin/com/getcode/ui/components/text/BlurSupport.android.kt @@ -0,0 +1,6 @@ +package com.getcode.ui.components.text + +import android.os.Build + +internal actual val SupportsBlurEffect: Boolean + get() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S diff --git a/ui/components/src/main/kotlin/com/getcode/ui/components/text/ExpandableText.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/components/text/ExpandableText.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/components/text/ExpandableText.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/components/text/ExpandableText.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/components/text/SectionHeader.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/components/text/SectionHeader.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/components/text/SectionHeader.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/components/text/SectionHeader.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/components/text/animated/DigitContainer.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/components/text/animated/DigitContainer.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/components/text/animated/DigitContainer.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/components/text/animated/DigitContainer.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/components/text/markup/Markup.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/components/text/markup/Markup.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/components/text/markup/Markup.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/components/text/markup/Markup.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/components/text/markup/MarkupTextHelper.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/components/text/markup/MarkupTextHelper.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/components/text/markup/MarkupTextHelper.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/components/text/markup/MarkupTextHelper.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/components/toast/FloatingToast.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/components/toast/FloatingToast.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/components/toast/FloatingToast.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/components/toast/FloatingToast.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/components/toast/FloatingToastHost.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/components/toast/FloatingToastHost.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/components/toast/FloatingToastHost.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/components/toast/FloatingToastHost.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/components/user/social/SocialUserTitle.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/components/user/social/SocialUserTitle.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/components/user/social/SocialUserTitle.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/components/user/social/SocialUserTitle.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/theme/CodeBillSwipeToDismiss.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/theme/CodeBillSwipeToDismiss.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/theme/CodeBillSwipeToDismiss.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/theme/CodeBillSwipeToDismiss.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/theme/CodeButton.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/theme/CodeButton.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/theme/CodeButton.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/theme/CodeButton.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/theme/CodeCheckbox.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/theme/CodeCheckbox.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/theme/CodeCheckbox.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/theme/CodeCheckbox.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/theme/CodeKeyPad.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/theme/CodeKeyPad.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/theme/CodeKeyPad.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/theme/CodeKeyPad.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/theme/CodeRadioButton.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/theme/CodeRadioButton.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/theme/CodeRadioButton.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/theme/CodeRadioButton.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/theme/CodeScaffold.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/theme/CodeScaffold.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/theme/CodeScaffold.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/theme/CodeScaffold.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/theme/CodeSeedView.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/theme/CodeSeedView.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/theme/CodeSeedView.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/theme/CodeSeedView.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/theme/CodeSegmentedControl.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/theme/CodeSegmentedControl.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/theme/CodeSegmentedControl.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/theme/CodeSegmentedControl.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/theme/CodeSwitch.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/theme/CodeSwitch.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/theme/CodeSwitch.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/theme/CodeSwitch.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/utils/AnimationUtils.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/utils/AnimationUtils.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/utils/AnimationUtils.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/utils/AnimationUtils.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/utils/ComplementaryGradient.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/utils/ComplementaryGradient.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/utils/ComplementaryGradient.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/utils/ComplementaryGradient.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/utils/EightBitGenerator.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/utils/EightBitGenerator.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/utils/EightBitGenerator.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/utils/EightBitGenerator.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/utils/Geometry.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/utils/Geometry.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/utils/Geometry.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/utils/Geometry.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/utils/KeepScreenOn.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/utils/KeepScreenOn.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/utils/KeepScreenOn.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/utils/KeepScreenOn.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/utils/Keyboard.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/utils/Keyboard.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/utils/Keyboard.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/utils/Keyboard.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/utils/LazyList.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/utils/LazyList.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/utils/LazyList.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/utils/LazyList.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/utils/Maps.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/utils/Maps.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/utils/Maps.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/utils/Maps.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/utils/MeasureScope.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/utils/MeasureScope.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/utils/MeasureScope.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/utils/MeasureScope.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/utils/PaddingValues.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/utils/PaddingValues.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/utils/PaddingValues.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/utils/PaddingValues.kt diff --git a/ui/components/src/androidMain/kotlin/com/getcode/ui/utils/ParseColor.android.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/utils/ParseColor.android.kt new file mode 100644 index 0000000000..8a25261061 --- /dev/null +++ b/ui/components/src/androidMain/kotlin/com/getcode/ui/utils/ParseColor.android.kt @@ -0,0 +1,5 @@ +package com.getcode.ui.utils + +import androidx.core.graphics.toColorInt + +internal actual fun parseColorInt(hex: String): Int = hex.toColorInt() diff --git a/ui/components/src/main/kotlin/com/getcode/ui/utils/PreviewParameters.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/utils/PreviewParameters.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/utils/PreviewParameters.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/utils/PreviewParameters.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/utils/RecompositionHighlighter.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/utils/RecompositionHighlighter.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/utils/RecompositionHighlighter.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/utils/RecompositionHighlighter.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/utils/TextStyle.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/utils/TextStyle.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/utils/TextStyle.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/utils/TextStyle.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/utils/Window.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/utils/Window.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/utils/Window.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/utils/Window.kt diff --git a/ui/components/src/main/res/drawable/ic_arrow_up.xml b/ui/components/src/androidMain/res/drawable/ic_arrow_up.xml similarity index 100% rename from ui/components/src/main/res/drawable/ic_arrow_up.xml rename to ui/components/src/androidMain/res/drawable/ic_arrow_up.xml diff --git a/ui/components/src/main/res/drawable/ic_twitter_verified_badge.xml b/ui/components/src/androidMain/res/drawable/ic_twitter_verified_badge.xml similarity index 100% rename from ui/components/src/main/res/drawable/ic_twitter_verified_badge.xml rename to ui/components/src/androidMain/res/drawable/ic_twitter_verified_badge.xml diff --git a/ui/components/src/main/res/drawable/ic_twitter_verified_badge_gold.xml b/ui/components/src/androidMain/res/drawable/ic_twitter_verified_badge_gold.xml similarity index 100% rename from ui/components/src/main/res/drawable/ic_twitter_verified_badge_gold.xml rename to ui/components/src/androidMain/res/drawable/ic_twitter_verified_badge_gold.xml diff --git a/ui/components/src/main/res/drawable/ic_twitter_verified_badge_gray.xml b/ui/components/src/androidMain/res/drawable/ic_twitter_verified_badge_gray.xml similarity index 100% rename from ui/components/src/main/res/drawable/ic_twitter_verified_badge_gray.xml rename to ui/components/src/androidMain/res/drawable/ic_twitter_verified_badge_gray.xml diff --git a/ui/components/src/main/res/values/strings.xml b/ui/components/src/androidMain/res/values/strings.xml similarity index 100% rename from ui/components/src/main/res/values/strings.xml rename to ui/components/src/androidMain/res/values/strings.xml diff --git a/ui/components/src/main/kotlin/com/getcode/ui/components/Badge.kt b/ui/components/src/commonMain/kotlin/com/getcode/ui/components/Badge.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/components/Badge.kt rename to ui/components/src/commonMain/kotlin/com/getcode/ui/components/Badge.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/components/ConnectionStatusComponent.kt b/ui/components/src/commonMain/kotlin/com/getcode/ui/components/ConnectionStatusComponent.kt similarity index 82% rename from ui/components/src/main/kotlin/com/getcode/ui/components/ConnectionStatusComponent.kt rename to ui/components/src/commonMain/kotlin/com/getcode/ui/components/ConnectionStatusComponent.kt index 20d932c5cd..1f2dc307b3 100644 --- a/ui/components/src/main/kotlin/com/getcode/ui/components/ConnectionStatusComponent.kt +++ b/ui/components/src/commonMain/kotlin/com/getcode/ui/components/ConnectionStatusComponent.kt @@ -7,13 +7,10 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.tooling.preview.PreviewParameter import com.getcode.theme.CodeTheme import com.getcode.ui.theme.CodeCircularProgressIndicator import com.getcode.utils.network.ConnectionType import com.getcode.utils.network.NetworkState -import com.getcode.utils.network.connectivity.NetworkStateProvider @Composable fun ConnectionStatus(state: NetworkState, modifier: Modifier = Modifier) { @@ -42,10 +39,3 @@ fun ConnectionStatus(state: NetworkState, modifier: Modifier = Modifier) { } } } - - -@Preview -@Composable -fun ConnectionReconnectingPreview(@PreviewParameter(NetworkStateProvider::class) state: NetworkState) { - ConnectionStatus(state) -} \ No newline at end of file diff --git a/ui/components/src/main/kotlin/com/getcode/ui/components/glass/FloatingGlass.kt b/ui/components/src/commonMain/kotlin/com/getcode/ui/components/glass/FloatingGlass.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/components/glass/FloatingGlass.kt rename to ui/components/src/commonMain/kotlin/com/getcode/ui/components/glass/FloatingGlass.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/components/text/AmountArea.kt b/ui/components/src/commonMain/kotlin/com/getcode/ui/components/text/AmountArea.kt similarity index 86% rename from ui/components/src/main/kotlin/com/getcode/ui/components/text/AmountArea.kt rename to ui/components/src/commonMain/kotlin/com/getcode/ui/components/text/AmountArea.kt index 90127a695d..a104709340 100644 --- a/ui/components/src/main/kotlin/com/getcode/ui/components/text/AmountArea.kt +++ b/ui/components/src/commonMain/kotlin/com/getcode/ui/components/text/AmountArea.kt @@ -17,7 +17,10 @@ import androidx.compose.ui.Alignment.Companion.CenterVertically import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.ColorFilter -import androidx.compose.ui.res.painterResource +import org.jetbrains.compose.resources.painterResource +import com.getcode.util.resources.Res +import com.getcode.util.resources.painterForResId +import com.getcode.util.resources.ic_kin_brand import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview @@ -26,12 +29,10 @@ import com.getcode.theme.DesignSystem import com.getcode.theme.White import com.getcode.theme.bolded import com.getcode.ui.components.ConnectionStatus -import com.getcode.ui.components.R import androidx.compose.foundation.clickable import com.getcode.ui.utils.ConstraintMode import com.getcode.utils.network.LocalNetworkObserver import com.getcode.utils.network.NetworkState -import com.getcode.utils.network.connectivity.NetworkStateProvider @OptIn(ExperimentalAnimationApi::class) @Composable @@ -145,7 +146,7 @@ private fun ValueHint( modifier = Modifier .padding(end = CodeTheme.dimens.staticGrid.x1) .requiredSize(CodeTheme.dimens.staticGrid.x2), - painter = painterResource(R.drawable.ic_kin_brand), + painter = painterResource(Res.drawable.ic_kin_brand), colorFilter = ColorFilter.tint(iconColor), contentDescription = "" ) @@ -163,34 +164,3 @@ private fun ValueHint( } } } - -private val networkStateValues = NetworkStateProvider().values -@Preview -@Composable -fun AmountPreview() { - DesignSystem { - AmountArea( - amountPrefix = "prefix", - amountText = "$12.34 of Kin", - amountSuffix = "suffix", - captionText = "The value of kin fluctuates", - currencyResId = R.drawable.ic_flag_ca, - networkState = networkStateValues.last(), - ) - } -} - -@Preview -@Composable -fun AmountPreviewDisconnected() { - DesignSystem { - AmountArea( - amountPrefix = "prefix", - amountText = "$12.34 of Kin", - amountSuffix = "suffix", - captionText = "The value of kin fluctuates", - currencyResId = R.drawable.ic_flag_ca, - networkState = networkStateValues.first(), - ) - } -} \ No newline at end of file diff --git a/ui/components/src/main/kotlin/com/getcode/ui/components/text/AmountText.kt b/ui/components/src/commonMain/kotlin/com/getcode/ui/components/text/AmountText.kt similarity index 93% rename from ui/components/src/main/kotlin/com/getcode/ui/components/text/AmountText.kt rename to ui/components/src/commonMain/kotlin/com/getcode/ui/components/text/AmountText.kt index b2813fb856..e1b98f70b2 100644 --- a/ui/components/src/main/kotlin/com/getcode/ui/components/text/AmountText.kt +++ b/ui/components/src/commonMain/kotlin/com/getcode/ui/components/text/AmountText.kt @@ -23,7 +23,10 @@ import androidx.compose.ui.Alignment.Companion.CenterVertically import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.drawWithCache -import androidx.compose.ui.res.painterResource +import org.jetbrains.compose.resources.painterResource +import com.getcode.util.resources.Res +import com.getcode.util.resources.painterForResId +import com.getcode.util.resources.ic_dropdown import androidx.compose.ui.text.TextLayoutResult import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.style.TextAlign @@ -31,7 +34,6 @@ import androidx.compose.ui.unit.TextUnit import com.getcode.theme.CodeTheme import com.getcode.theme.White import com.getcode.theme.bolded -import com.getcode.ui.components.R @Composable internal fun RowScope.AmountLeadingIcons( @@ -44,7 +46,7 @@ internal fun RowScope.AmountLeadingIcons( .align(CenterVertically) .requiredSize(CodeTheme.dimens.staticGrid.x7) .clip(CircleShape), - painter = painterResource(currencyResId), + painter = painterForResId(currencyResId), contentDescription = "" ) } @@ -54,7 +56,7 @@ internal fun RowScope.AmountLeadingIcons( .padding(end = CodeTheme.dimens.grid.x2) .requiredSize(CodeTheme.dimens.grid.x5) .align(CenterVertically), - painter = painterResource(R.drawable.ic_dropdown), + painter = painterResource(Res.drawable.ic_dropdown), contentDescription = "" ) } else { diff --git a/ui/components/src/main/kotlin/com/getcode/ui/components/text/AmountTextAnimated.kt b/ui/components/src/commonMain/kotlin/com/getcode/ui/components/text/AmountTextAnimated.kt similarity index 97% rename from ui/components/src/main/kotlin/com/getcode/ui/components/text/AmountTextAnimated.kt rename to ui/components/src/commonMain/kotlin/com/getcode/ui/components/text/AmountTextAnimated.kt index 4ef661fbc5..4e1ffb9c01 100644 --- a/ui/components/src/main/kotlin/com/getcode/ui/components/text/AmountTextAnimated.kt +++ b/ui/components/src/commonMain/kotlin/com/getcode/ui/components/text/AmountTextAnimated.kt @@ -40,7 +40,10 @@ import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.Layout import androidx.compose.ui.platform.LocalDensity -import androidx.compose.ui.res.painterResource +import org.jetbrains.compose.resources.painterResource +import com.getcode.util.resources.Res +import com.getcode.util.resources.painterForResId +import com.getcode.util.resources.ic_dropdown import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.font.FontWeight @@ -50,7 +53,6 @@ import androidx.compose.ui.unit.TextUnit import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.getcode.theme.CodeTheme -import com.getcode.ui.components.R import com.getcode.ui.components.text.NumberInputHelper.Companion.DECIMAL_SEPARATOR import com.getcode.ui.components.text.NumberInputHelper.Companion.GROUPING_SEPARATOR import com.getcode.ui.components.text.animated.AnimatedPlaceholderDigit @@ -310,14 +312,14 @@ internal fun AmountTextAnimated( modifier = Modifier .requiredSize(CodeTheme.dimens.grid.x7) .clip(CircleShape), - painter = painterResource(currencyResId), + painter = painterForResId(currencyResId), contentDescription = "" ) if (isClickable) { Image( modifier = Modifier .width(CodeTheme.dimens.grid.x4), - painter = painterResource(R.drawable.ic_dropdown), + painter = painterResource(Res.drawable.ic_dropdown), contentDescription = "" ) } else { diff --git a/ui/components/src/main/kotlin/com/getcode/ui/components/text/AnimatedNumberText.kt b/ui/components/src/commonMain/kotlin/com/getcode/ui/components/text/AnimatedNumberText.kt similarity index 99% rename from ui/components/src/main/kotlin/com/getcode/ui/components/text/AnimatedNumberText.kt rename to ui/components/src/commonMain/kotlin/com/getcode/ui/components/text/AnimatedNumberText.kt index 775b476850..b1f20c6b5c 100644 --- a/ui/components/src/main/kotlin/com/getcode/ui/components/text/AnimatedNumberText.kt +++ b/ui/components/src/commonMain/kotlin/com/getcode/ui/components/text/AnimatedNumberText.kt @@ -1,6 +1,5 @@ package com.getcode.ui.components.text -import android.os.Build import androidx.compose.animation.core.Animatable import androidx.compose.animation.core.FloatSpringSpec import androidx.compose.animation.core.tween @@ -418,7 +417,7 @@ private fun GraphicsLayerScope.applyGlyphMotion(d: Float, fade: Float, p: Float, // The layer carries [MaxBlur] of padding on each side; travel is in heights of the glyph itself. translationY = motion.travel * (size.height - 2 * MaxBlur.toPx()) alpha = motion.alpha - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + if (SupportsBlurEffect) { val radius = MaxBlur.toPx() * motion.blur renderEffect = if (radius > 0.5f) BlurEffect(radius, radius, TileMode.Decal) else null } diff --git a/ui/components/src/commonMain/kotlin/com/getcode/ui/components/text/BlurSupport.kt b/ui/components/src/commonMain/kotlin/com/getcode/ui/components/text/BlurSupport.kt new file mode 100644 index 0000000000..607ca47c5e --- /dev/null +++ b/ui/components/src/commonMain/kotlin/com/getcode/ui/components/text/BlurSupport.kt @@ -0,0 +1,4 @@ +package com.getcode.ui.components.text + +/** Whether a graphics layer can take a blur `RenderEffect` (API 31+ on Android). */ +internal expect val SupportsBlurEffect: Boolean diff --git a/ui/components/src/main/kotlin/com/getcode/ui/components/text/NumberInputHelper.kt b/ui/components/src/commonMain/kotlin/com/getcode/ui/components/text/NumberInputHelper.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/components/text/NumberInputHelper.kt rename to ui/components/src/commonMain/kotlin/com/getcode/ui/components/text/NumberInputHelper.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/components/text/NumberRollMotion.kt b/ui/components/src/commonMain/kotlin/com/getcode/ui/components/text/NumberRollMotion.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/components/text/NumberRollMotion.kt rename to ui/components/src/commonMain/kotlin/com/getcode/ui/components/text/NumberRollMotion.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/components/text/animated/AnimatedPlaceholderDigit.kt b/ui/components/src/commonMain/kotlin/com/getcode/ui/components/text/animated/AnimatedPlaceholderDigit.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/components/text/animated/AnimatedPlaceholderDigit.kt rename to ui/components/src/commonMain/kotlin/com/getcode/ui/components/text/animated/AnimatedPlaceholderDigit.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/components/text/animated/Digit.kt b/ui/components/src/commonMain/kotlin/com/getcode/ui/components/text/animated/Digit.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/components/text/animated/Digit.kt rename to ui/components/src/commonMain/kotlin/com/getcode/ui/components/text/animated/Digit.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/components/text/animated/DigitAnimations.kt b/ui/components/src/commonMain/kotlin/com/getcode/ui/components/text/animated/DigitAnimations.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/components/text/animated/DigitAnimations.kt rename to ui/components/src/commonMain/kotlin/com/getcode/ui/components/text/animated/DigitAnimations.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/components/text/animated/NormalizedPrefixText.kt b/ui/components/src/commonMain/kotlin/com/getcode/ui/components/text/animated/NormalizedPrefixText.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/components/text/animated/NormalizedPrefixText.kt rename to ui/components/src/commonMain/kotlin/com/getcode/ui/components/text/animated/NormalizedPrefixText.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/theme/CodeCircularProgressIndicator.kt b/ui/components/src/commonMain/kotlin/com/getcode/ui/theme/CodeCircularProgressIndicator.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/theme/CodeCircularProgressIndicator.kt rename to ui/components/src/commonMain/kotlin/com/getcode/ui/theme/CodeCircularProgressIndicator.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/utils/AutoSizeText.kt b/ui/components/src/commonMain/kotlin/com/getcode/ui/utils/AutoSizeText.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/utils/AutoSizeText.kt rename to ui/components/src/commonMain/kotlin/com/getcode/ui/utils/AutoSizeText.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/utils/AutoSizeTextMeasurer.kt b/ui/components/src/commonMain/kotlin/com/getcode/ui/utils/AutoSizeTextMeasurer.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/utils/AutoSizeTextMeasurer.kt rename to ui/components/src/commonMain/kotlin/com/getcode/ui/utils/AutoSizeTextMeasurer.kt diff --git a/ui/components/src/main/kotlin/com/getcode/ui/utils/ColorTransformations.kt b/ui/components/src/commonMain/kotlin/com/getcode/ui/utils/ColorTransformations.kt similarity index 98% rename from ui/components/src/main/kotlin/com/getcode/ui/utils/ColorTransformations.kt rename to ui/components/src/commonMain/kotlin/com/getcode/ui/utils/ColorTransformations.kt index 53871673e6..7cc6c3371c 100644 --- a/ui/components/src/main/kotlin/com/getcode/ui/utils/ColorTransformations.kt +++ b/ui/components/src/commonMain/kotlin/com/getcode/ui/utils/ColorTransformations.kt @@ -2,7 +2,6 @@ package com.getcode.ui.utils import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.toArgb -import androidx.core.graphics.toColorInt import kotlin.math.abs import kotlin.math.roundToInt @@ -178,7 +177,7 @@ private fun invertColor(color: Color): Color { } fun hexToColor(hex: String): Color { - return Color(hex.toColorInt()) + return Color(parseColorInt(hex)) } fun adjustBrightness(color: Color, factor: Float): Color { diff --git a/ui/components/src/commonMain/kotlin/com/getcode/ui/utils/ParseColor.kt b/ui/components/src/commonMain/kotlin/com/getcode/ui/utils/ParseColor.kt new file mode 100644 index 0000000000..4328c1ddb2 --- /dev/null +++ b/ui/components/src/commonMain/kotlin/com/getcode/ui/utils/ParseColor.kt @@ -0,0 +1,4 @@ +package com.getcode.ui.utils + +/** Parses a `#RRGGBB` or `#AARRGGBB` color string into an ARGB int. */ +internal expect fun parseColorInt(hex: String): Int diff --git a/ui/components/src/main/kotlin/com/getcode/ui/utils/TextUnit.kt b/ui/components/src/commonMain/kotlin/com/getcode/ui/utils/TextUnit.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/utils/TextUnit.kt rename to ui/components/src/commonMain/kotlin/com/getcode/ui/utils/TextUnit.kt diff --git a/ui/components/src/jvmMain/kotlin/com/getcode/ui/components/text/BlurSupport.jvm.kt b/ui/components/src/jvmMain/kotlin/com/getcode/ui/components/text/BlurSupport.jvm.kt new file mode 100644 index 0000000000..4a97f4bd15 --- /dev/null +++ b/ui/components/src/jvmMain/kotlin/com/getcode/ui/components/text/BlurSupport.jvm.kt @@ -0,0 +1,3 @@ +package com.getcode.ui.components.text + +internal actual val SupportsBlurEffect: Boolean = true diff --git a/ui/components/src/jvmMain/kotlin/com/getcode/ui/utils/ParseColor.jvm.kt b/ui/components/src/jvmMain/kotlin/com/getcode/ui/utils/ParseColor.jvm.kt new file mode 100644 index 0000000000..27901571c4 --- /dev/null +++ b/ui/components/src/jvmMain/kotlin/com/getcode/ui/utils/ParseColor.jvm.kt @@ -0,0 +1,11 @@ +package com.getcode.ui.utils + +internal actual fun parseColorInt(hex: String): Int { + require(hex.startsWith("#")) { "Unknown color: $hex" } + val value = hex.substring(1).toLong(16) + return when (hex.length) { + 7 -> (value or 0xFF000000).toInt() + 9 -> value.toInt() + else -> throw IllegalArgumentException("Unknown color: $hex") + } +} diff --git a/ui/core/build.gradle.kts b/ui/core/build.gradle.kts index 127ea489a5..5e0a924f9d 100644 --- a/ui/core/build.gradle.kts +++ b/ui/core/build.gradle.kts @@ -1,17 +1,30 @@ plugins { - alias(libs.plugins.flipcash.android.library.compose) + alias(libs.plugins.flipcash.kmp.app.library) + alias(libs.plugins.compose.compiler) } -android { - namespace = "${Gradle.codeNamespace}.ui.core" -} +kotlin { + android { + namespace = "${Gradle.codeNamespace}.ui.core" + androidResources { enable = true } + } -dependencies { - implementation(libs.compose.animation) - implementation(libs.compose.activities) - implementation(libs.compose.material) - implementation(libs.kotlinx.serialization.core) - api(project(":ui:resources")) - api(project(":ui:testing")) - implementation(project(":ui:theme")) + sourceSets { + commonMain.dependencies { + implementation(libs.jetbrains.compose.runtime) + implementation(libs.jetbrains.compose.foundation) + implementation(libs.jetbrains.compose.ui) + implementation(libs.jetbrains.compose.material) + implementation(libs.kotlinx.serialization.core) + api(project(":ui:resources")) + implementation(project(":ui:theme")) + } + androidMain.dependencies { + implementation(project.dependencies.platform(libs.compose.bom)) + implementation(libs.compose.animation) + implementation(libs.compose.activities) + implementation(libs.compose.material) + api(project(":ui:testing")) + } + } } diff --git a/ui/core/src/main/kotlin/com/getcode/ui/core/AnimationScale.kt b/ui/core/src/androidMain/kotlin/com/getcode/ui/core/AnimationScale.kt similarity index 100% rename from ui/core/src/main/kotlin/com/getcode/ui/core/AnimationScale.kt rename to ui/core/src/androidMain/kotlin/com/getcode/ui/core/AnimationScale.kt diff --git a/ui/core/src/main/kotlin/com/getcode/ui/core/ContextMenuAction.kt b/ui/core/src/androidMain/kotlin/com/getcode/ui/core/ContextMenuAction.kt similarity index 100% rename from ui/core/src/main/kotlin/com/getcode/ui/core/ContextMenuAction.kt rename to ui/core/src/androidMain/kotlin/com/getcode/ui/core/ContextMenuAction.kt diff --git a/ui/core/src/main/kotlin/com/getcode/ui/core/ExpandedTouchTarget.kt b/ui/core/src/androidMain/kotlin/com/getcode/ui/core/ExpandedTouchTarget.kt similarity index 100% rename from ui/core/src/main/kotlin/com/getcode/ui/core/ExpandedTouchTarget.kt rename to ui/core/src/androidMain/kotlin/com/getcode/ui/core/ExpandedTouchTarget.kt diff --git a/ui/core/src/androidMain/kotlin/com/getcode/ui/core/Modifier.android.kt b/ui/core/src/androidMain/kotlin/com/getcode/ui/core/Modifier.android.kt new file mode 100644 index 0000000000..ff66150c23 --- /dev/null +++ b/ui/core/src/androidMain/kotlin/com/getcode/ui/core/Modifier.android.kt @@ -0,0 +1,15 @@ +package com.getcode.ui.core + +import android.view.MotionEvent +import androidx.compose.ui.ExperimentalComposeUiApi +import androidx.compose.ui.Modifier +import androidx.compose.ui.input.pointer.pointerInteropFilter + +@OptIn(ExperimentalComposeUiApi::class) +fun Modifier.swallowClicks(onClick: () -> Unit = { }): Modifier = + this.pointerInteropFilter { + if (it.actionMasked == MotionEvent.ACTION_UP) { + onClick() + } + true + } diff --git a/ui/core/src/main/kotlin/com/getcode/ui/core/StarMaskVisualTransformation.kt b/ui/core/src/androidMain/kotlin/com/getcode/ui/core/StarMaskVisualTransformation.kt similarity index 100% rename from ui/core/src/main/kotlin/com/getcode/ui/core/StarMaskVisualTransformation.kt rename to ui/core/src/androidMain/kotlin/com/getcode/ui/core/StarMaskVisualTransformation.kt diff --git a/ui/core/src/main/kotlin/com/getcode/ui/core/visibility/VisibilityInfo.kt b/ui/core/src/androidMain/kotlin/com/getcode/ui/core/visibility/VisibilityInfo.kt similarity index 100% rename from ui/core/src/main/kotlin/com/getcode/ui/core/visibility/VisibilityInfo.kt rename to ui/core/src/androidMain/kotlin/com/getcode/ui/core/visibility/VisibilityInfo.kt diff --git a/ui/core/src/main/kotlin/com/getcode/ui/core/visibility/VisibilityTrackerNode.kt b/ui/core/src/androidMain/kotlin/com/getcode/ui/core/visibility/VisibilityTrackerNode.kt similarity index 100% rename from ui/core/src/main/kotlin/com/getcode/ui/core/visibility/VisibilityTrackerNode.kt rename to ui/core/src/androidMain/kotlin/com/getcode/ui/core/visibility/VisibilityTrackerNode.kt diff --git a/ui/core/src/main/kotlin/com/getcode/ui/core/IntSize.kt b/ui/core/src/commonMain/kotlin/com/getcode/ui/core/IntSize.kt similarity index 100% rename from ui/core/src/main/kotlin/com/getcode/ui/core/IntSize.kt rename to ui/core/src/commonMain/kotlin/com/getcode/ui/core/IntSize.kt diff --git a/ui/core/src/main/kotlin/com/getcode/ui/core/Modifier.kt b/ui/core/src/commonMain/kotlin/com/getcode/ui/core/Modifier.kt similarity index 98% rename from ui/core/src/main/kotlin/com/getcode/ui/core/Modifier.kt rename to ui/core/src/commonMain/kotlin/com/getcode/ui/core/Modifier.kt index b4f1e39ebe..70b3cf176c 100644 --- a/ui/core/src/main/kotlin/com/getcode/ui/core/Modifier.kt +++ b/ui/core/src/commonMain/kotlin/com/getcode/ui/core/Modifier.kt @@ -1,6 +1,5 @@ package com.getcode.ui.core -import android.view.MotionEvent import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.Indication import androidx.compose.foundation.border @@ -42,7 +41,6 @@ import androidx.compose.ui.graphics.drawscope.Stroke import androidx.compose.ui.graphics.drawscope.clipPath import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.graphics.takeOrElse -import androidx.compose.ui.input.pointer.pointerInteropFilter import androidx.compose.ui.layout.layout import androidx.compose.ui.layout.onPlaced import androidx.compose.ui.platform.LocalDensity @@ -139,15 +137,6 @@ fun Modifier.measured(block: (DpSize) -> Unit): Modifier = composed { fun Modifier.measuredIntSize(block: (IntSize) -> Unit): Modifier = onPlaced { block(it.size) } -@OptIn(ExperimentalComposeUiApi::class) -fun Modifier.swallowClicks(onClick: () -> Unit = { }): Modifier = - this.pointerInteropFilter { - if (it.actionMasked == MotionEvent.ACTION_UP) { - onClick() - } - true - } - /** * Draws circle with a solid [color] behind the content. * diff --git a/ui/core/src/main/kotlin/com/getcode/ui/core/RestrictionType.kt b/ui/core/src/commonMain/kotlin/com/getcode/ui/core/RestrictionType.kt similarity index 100% rename from ui/core/src/main/kotlin/com/getcode/ui/core/RestrictionType.kt rename to ui/core/src/commonMain/kotlin/com/getcode/ui/core/RestrictionType.kt diff --git a/ui/resources/src/androidMain/kotlin/com/getcode/util/resources/PainterForResId.android.kt b/ui/resources/src/androidMain/kotlin/com/getcode/util/resources/PainterForResId.android.kt new file mode 100644 index 0000000000..f64906572b --- /dev/null +++ b/ui/resources/src/androidMain/kotlin/com/getcode/util/resources/PainterForResId.android.kt @@ -0,0 +1,8 @@ +package com.getcode.util.resources + +import androidx.compose.runtime.Composable +import androidx.compose.ui.graphics.painter.Painter +import androidx.compose.ui.res.painterResource + +@Composable +actual fun painterForResId(id: Int): Painter = painterResource(id) diff --git a/ui/resources/src/commonMain/kotlin/com/getcode/util/resources/PainterForResId.kt b/ui/resources/src/commonMain/kotlin/com/getcode/util/resources/PainterForResId.kt new file mode 100644 index 0000000000..25cd6a885d --- /dev/null +++ b/ui/resources/src/commonMain/kotlin/com/getcode/util/resources/PainterForResId.kt @@ -0,0 +1,14 @@ +package com.getcode.util.resources + +import androidx.annotation.DrawableRes +import androidx.compose.runtime.Composable +import androidx.compose.ui.graphics.painter.Painter + +/** + * Loads the drawable behind a resource ID handed out by [ResourceHelper.getIdentifier]. + * + * Shared components take currency and flag icons as `Int` IDs; on Android these are `R.drawable` + * values, on desktop they index the generated Compose resources. + */ +@Composable +expect fun painterForResId(@DrawableRes id: Int): Painter diff --git a/ui/resources/src/jvmMain/kotlin/com/getcode/util/resources/ComposeResourceHelper.kt b/ui/resources/src/jvmMain/kotlin/com/getcode/util/resources/ComposeResourceHelper.kt new file mode 100644 index 0000000000..c55ed631b5 --- /dev/null +++ b/ui/resources/src/jvmMain/kotlin/com/getcode/util/resources/ComposeResourceHelper.kt @@ -0,0 +1,33 @@ +package com.getcode.util.resources + +import kotlinx.coroutines.runBlocking +import org.jetbrains.compose.resources.getPluralString +import org.jetbrains.compose.resources.getString + +/** + * Desktop [ResourceHelper] over the Compose resources generated from `ui:resources`' Android + * `res/`. IDs come from [ComposeResourceIds]; dimensions and raw resources are not mapped. + */ +class ComposeResourceHelper : ResourceHelper { + override fun getString(resourceId: Int): String = + runBlocking { getString(ComposeResourceIds.string(resourceId)) } + + override fun getString(resourceId: Int, vararg formatArgs: Any): String = + runBlocking { getString(ComposeResourceIds.string(resourceId), *formatArgs) } + + override fun getRawResource(resourceId: Int): String = "" + + override fun getQuantityString(id: Int, quantity: Int, vararg formatArgs: Any, default: String): String = + runCatching { + runBlocking { getPluralString(ComposeResourceIds.plural(id), quantity, *formatArgs) } + }.getOrDefault(default) + + override fun getDimension(dimenId: Int, default: Float): Float = default + + override fun getDimensionPixelSize(dimenId: Int, default: Int): Int = default + + override fun getIdentifier(name: String, type: ResourceType): Int? = when (type) { + ResourceType.Drawable -> ComposeResourceIds.drawableId(name) + ResourceType.String -> ComposeResourceIds.stringId(name) + } +} diff --git a/ui/resources/src/jvmMain/kotlin/com/getcode/util/resources/ComposeResourceIds.kt b/ui/resources/src/jvmMain/kotlin/com/getcode/util/resources/ComposeResourceIds.kt new file mode 100644 index 0000000000..898ed8033f --- /dev/null +++ b/ui/resources/src/jvmMain/kotlin/com/getcode/util/resources/ComposeResourceIds.kt @@ -0,0 +1,34 @@ +package com.getcode.util.resources + +import org.jetbrains.compose.resources.DrawableResource +import org.jetbrains.compose.resources.PluralStringResource +import org.jetbrains.compose.resources.StringResource + +/** + * Stable `Int` IDs for the generated Compose resources, so desktop can serve the `Int`-keyed + * [ResourceHelper] API. Each resource type gets its own range, ordered by resource name. + */ +object ComposeResourceIds { + private const val DRAWABLE_BASE = 0x7f010000 + private const val STRING_BASE = 0x7f020000 + private const val PLURAL_BASE = 0x7f030000 + + private val drawables: List> by lazy { Res.allDrawableResources.toSortedList() } + private val strings: List> by lazy { Res.allStringResources.toSortedList() } + private val plurals: List> by lazy { Res.allPluralStringResources.toSortedList() } + + fun drawableId(name: String): Int? = drawables.indexOfName(name)?.plus(DRAWABLE_BASE) + fun stringId(name: String): Int? = strings.indexOfName(name)?.plus(STRING_BASE) + + fun drawable(id: Int): DrawableResource = drawables.at(id - DRAWABLE_BASE, id) + fun string(id: Int): StringResource = strings.at(id - STRING_BASE, id) + fun plural(id: Int): PluralStringResource = plurals.at(id - PLURAL_BASE, id) + + private fun Map.toSortedList() = entries.sortedBy { it.key }.map { it.key to it.value } + + private fun List>.indexOfName(name: String): Int? = + indexOfFirst { it.first == name }.takeIf { it >= 0 } + + private fun List>.at(index: Int, id: Int): T = + getOrNull(index)?.second ?: throw IllegalArgumentException("No Compose resource for ID 0x${id.toString(16)}") +} diff --git a/ui/resources/src/jvmMain/kotlin/com/getcode/util/resources/PainterForResId.jvm.kt b/ui/resources/src/jvmMain/kotlin/com/getcode/util/resources/PainterForResId.jvm.kt new file mode 100644 index 0000000000..0076b5a5dd --- /dev/null +++ b/ui/resources/src/jvmMain/kotlin/com/getcode/util/resources/PainterForResId.jvm.kt @@ -0,0 +1,8 @@ +package com.getcode.util.resources + +import androidx.compose.runtime.Composable +import androidx.compose.ui.graphics.painter.Painter +import org.jetbrains.compose.resources.painterResource + +@Composable +actual fun painterForResId(id: Int): Painter = painterResource(ComposeResourceIds.drawable(id)) From 80adf96d5c011520fd4e5c4049db73ae90121628 Mon Sep 17 00:00:00 2001 From: Brandon McAnsh Date: Fri, 23 Oct 2026 18:23:31 -0400 Subject: [PATCH 18/50] build(navigation): move ui:navigation to android+jvm KMP CodeNavigator, its options, flow scope and the nav-result types move to commonMain; navigation3 1.1.4 publishes a desktop variant, so the back stack type is the same artifact on both platforms. Scenes, flow hosts and AppNavHost stay in androidMain. RepeatOnLifecycle reads LocalLifecycleOwner from lifecycle-runtime-compose, the class the old androidx.compose.ui.platform one already aliases on Android. --- gradle/libs.versions.toml | 3 + ui/navigation/build.gradle.kts | 77 +++++++++++-------- .../kotlin/com/getcode/navigation/TestNav.kt | 0 .../core/CodeNavigatorDispatchTest.kt | 0 .../core/CodeNavigatorHarnessTest.kt | 0 .../core/CodeNavigatorIntentTest.kt | 0 .../decorators/RetentionLedgerTest.kt | 0 .../navigation/flow/InnerFlowNavigatorTest.kt | 0 .../scenes/ModalBottomSheetSceneTest.kt | 0 .../com/getcode/navigation/AppNavHost.kt | 0 .../com/getcode/navigation/NavMetadata.kt | 2 +- .../NavResultScopeEntryDecorator.kt | 0 .../decorators/RetainedEntryState.kt | 0 .../extensions/ViewModelExtensions.kt | 0 .../navigation/flow/FlowDismissStyle.kt | 0 .../com/getcode/navigation/flow/FlowHost.kt | 2 +- .../getcode/navigation/flow/FlowNavigator.kt | 2 +- .../com/getcode/navigation/flow/FlowRoute.kt | 2 +- .../getcode/navigation/flow/FlowViewModel.kt | 0 .../scenes/FullscreenOverlaySceneStrategy.kt | 0 .../scenes/ModalBottomSheetSceneStrategy.kt | 2 +- .../com/getcode/navigation/scrim/Scrim.kt | 0 .../getcode/ui/utils/DisableSheetGestures.kt | 0 .../com/getcode/ui/utils/SheetExpansion.kt | 0 .../ui/utils/SheetResignmentModifierNode.kt | 0 .../kotlin/com/getcode/view/BaseViewModel.kt | 0 .../com/getcode/navigation/NavContentKey.kt | 0 .../kotlin/com/getcode/navigation/Types.kt | 0 .../getcode/navigation/core/CodeNavigator.kt | 6 +- .../com/getcode/navigation/core/FlowScope.kt | 2 +- .../com/getcode/navigation/core/NavOptions.kt | 4 +- .../com/getcode/navigation/flow/FlowStep.kt | 0 .../getcode/navigation/results/NavResult.kt | 4 +- .../navigation/results/NavResultController.kt | 2 +- .../navigation/results/NavResultKey.kt | 2 +- .../navigation/results/NavResultStore.kt | 2 +- .../com/getcode/navigation/results/RetVal.kt | 2 +- .../navigation/utils/KClassSerializer.kt | 0 .../utils/lifecycle/RepeatOnLifecycle.kt | 2 +- 39 files changed, 67 insertions(+), 49 deletions(-) rename ui/navigation/src/{test => androidHostTest}/kotlin/com/getcode/navigation/TestNav.kt (100%) rename ui/navigation/src/{test => androidHostTest}/kotlin/com/getcode/navigation/core/CodeNavigatorDispatchTest.kt (100%) rename ui/navigation/src/{test => androidHostTest}/kotlin/com/getcode/navigation/core/CodeNavigatorHarnessTest.kt (100%) rename ui/navigation/src/{test => androidHostTest}/kotlin/com/getcode/navigation/core/CodeNavigatorIntentTest.kt (100%) rename ui/navigation/src/{test => androidHostTest}/kotlin/com/getcode/navigation/decorators/RetentionLedgerTest.kt (100%) rename ui/navigation/src/{test => androidHostTest}/kotlin/com/getcode/navigation/flow/InnerFlowNavigatorTest.kt (100%) rename ui/navigation/src/{test => androidHostTest}/kotlin/com/getcode/navigation/scenes/ModalBottomSheetSceneTest.kt (100%) rename ui/navigation/src/{main => androidMain}/kotlin/com/getcode/navigation/AppNavHost.kt (100%) rename ui/navigation/src/{main => androidMain}/kotlin/com/getcode/navigation/NavMetadata.kt (99%) rename ui/navigation/src/{main => androidMain}/kotlin/com/getcode/navigation/decorators/NavResultScopeEntryDecorator.kt (100%) rename ui/navigation/src/{main => androidMain}/kotlin/com/getcode/navigation/decorators/RetainedEntryState.kt (100%) rename ui/navigation/src/{main => androidMain}/kotlin/com/getcode/navigation/extensions/ViewModelExtensions.kt (100%) rename ui/navigation/src/{main => androidMain}/kotlin/com/getcode/navigation/flow/FlowDismissStyle.kt (100%) rename ui/navigation/src/{main => androidMain}/kotlin/com/getcode/navigation/flow/FlowHost.kt (99%) rename ui/navigation/src/{main => androidMain}/kotlin/com/getcode/navigation/flow/FlowNavigator.kt (98%) rename ui/navigation/src/{main => androidMain}/kotlin/com/getcode/navigation/flow/FlowRoute.kt (97%) rename ui/navigation/src/{main => androidMain}/kotlin/com/getcode/navigation/flow/FlowViewModel.kt (100%) rename ui/navigation/src/{main => androidMain}/kotlin/com/getcode/navigation/scenes/FullscreenOverlaySceneStrategy.kt (100%) rename ui/navigation/src/{main => androidMain}/kotlin/com/getcode/navigation/scenes/ModalBottomSheetSceneStrategy.kt (99%) rename ui/navigation/src/{main => androidMain}/kotlin/com/getcode/navigation/scrim/Scrim.kt (100%) rename ui/navigation/src/{main => androidMain}/kotlin/com/getcode/ui/utils/DisableSheetGestures.kt (100%) rename ui/navigation/src/{main => androidMain}/kotlin/com/getcode/ui/utils/SheetExpansion.kt (100%) rename ui/navigation/src/{main => androidMain}/kotlin/com/getcode/ui/utils/SheetResignmentModifierNode.kt (100%) rename ui/navigation/src/{main => androidMain}/kotlin/com/getcode/view/BaseViewModel.kt (100%) rename ui/navigation/src/{main => commonMain}/kotlin/com/getcode/navigation/NavContentKey.kt (100%) rename ui/navigation/src/{main => commonMain}/kotlin/com/getcode/navigation/Types.kt (100%) rename ui/navigation/src/{main => commonMain}/kotlin/com/getcode/navigation/core/CodeNavigator.kt (98%) rename ui/navigation/src/{main => commonMain}/kotlin/com/getcode/navigation/core/FlowScope.kt (96%) rename ui/navigation/src/{main => commonMain}/kotlin/com/getcode/navigation/core/NavOptions.kt (89%) rename ui/navigation/src/{main => commonMain}/kotlin/com/getcode/navigation/flow/FlowStep.kt (100%) rename ui/navigation/src/{main => commonMain}/kotlin/com/getcode/navigation/results/NavResult.kt (90%) rename ui/navigation/src/{main => commonMain}/kotlin/com/getcode/navigation/results/NavResultController.kt (98%) rename ui/navigation/src/{main => commonMain}/kotlin/com/getcode/navigation/results/NavResultKey.kt (94%) rename ui/navigation/src/{main => commonMain}/kotlin/com/getcode/navigation/results/NavResultStore.kt (99%) rename ui/navigation/src/{main => commonMain}/kotlin/com/getcode/navigation/results/RetVal.kt (91%) rename ui/navigation/src/{main => commonMain}/kotlin/com/getcode/navigation/utils/KClassSerializer.kt (100%) rename ui/navigation/src/{main => commonMain}/kotlin/com/getcode/navigation/utils/lifecycle/RepeatOnLifecycle.kt (94%) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b8b9612939..a21628234f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -148,6 +148,9 @@ androidx-exifinterface = { module = "androidx.exifinterface:exifinterface", vers androidx-lifecycle-process = { module = "androidx.lifecycle:lifecycle-process", version.ref = "androidx-lifecycle" } androidx-lifecycle-runtime = { module = "androidx.lifecycle:lifecycle-runtime-ktx", version.ref = "androidx-lifecycle" } androidx-lifecycle-viewmodel = { module = "androidx.lifecycle:lifecycle-viewmodel-ktx", version.ref = "androidx-lifecycle" } +androidx-lifecycle-runtime-common = { module = "androidx.lifecycle:lifecycle-runtime", version.ref = "androidx-lifecycle" } +androidx-lifecycle-runtime-compose = { module = "androidx.lifecycle:lifecycle-runtime-compose", version.ref = "androidx-lifecycle" } +androidx-lifecycle-viewmodel-savedstate = { module = "androidx.lifecycle:lifecycle-viewmodel-savedstate", version.ref = "androidx-lifecycle" } navigation3-runtime = { module = "androidx.navigation3:navigation3-runtime", version.ref = "navigation3" } navigation3-ui = { module = "androidx.navigation3:navigation3-ui", version.ref = "navigation3" } lifecycle-viewmodel-navigation3 = { module = "androidx.lifecycle:lifecycle-viewmodel-navigation3", version.ref = "navigation3-lifecycle" } diff --git a/ui/navigation/build.gradle.kts b/ui/navigation/build.gradle.kts index 6e8e974f1f..b124afb989 100644 --- a/ui/navigation/build.gradle.kts +++ b/ui/navigation/build.gradle.kts @@ -1,40 +1,55 @@ plugins { - alias(libs.plugins.flipcash.android.library.compose) - alias(libs.plugins.kotlin.serialization) + alias(libs.plugins.flipcash.kmp.app.library) + alias(libs.plugins.compose.compiler) alias(libs.plugins.kotlin.ksp) - alias(libs.plugins.hilt) id("org.jetbrains.kotlin.plugin.parcelize") } -android { - namespace = "${Gradle.codeNamespace}.navigation" - buildFeatures { buildConfig = true } -} - -dependencies { - api(project(":libs:coroutines")) - implementation(project(":libs:logging")) - implementation(project(":ui:core")) - api(project(":ui:resources")) - implementation(project(":ui:theme")) +kotlin { + android { + namespace = "${Gradle.codeNamespace}.navigation" + } - implementation(libs.compose.material3) - implementation(libs.compose.unstyled.bottom.sheet) - implementation(libs.compose.activities) - implementation(libs.bundles.kotlinx.serialization) - implementation(libs.kotlin.reflect) + sourceSets { + commonMain.dependencies { + api(project(":libs:coroutines")) + implementation(project(":libs:logging")) + implementation(project(":libs:parcelable")) + implementation(project(":ui:core")) + api(project(":ui:resources")) + implementation(project(":ui:theme")) - implementation(libs.bundles.hilt) - ksp(libs.bundles.hilt.compiler) - - api(libs.compose.view.models) - api(libs.navigation3.runtime) - api(libs.navigation3.ui) - api(libs.lifecycle.viewmodel.navigation3) - api(libs.hilt.nav.compose) - api(libs.rinku) + implementation(libs.jetbrains.compose.runtime) + implementation(libs.jetbrains.compose.foundation) + implementation(libs.jetbrains.compose.ui) + implementation(libs.bundles.kotlinx.serialization) + implementation(libs.kotlin.reflect) + implementation(libs.androidx.lifecycle.runtime.common) + implementation(libs.androidx.lifecycle.runtime.compose) + implementation(libs.androidx.lifecycle.viewmodel.savedstate) + api(libs.compose.view.models) + api(libs.navigation3.runtime) + } + androidMain.dependencies { + implementation(project.dependencies.platform(libs.compose.bom)) + implementation(libs.compose.material3) + implementation(libs.compose.unstyled.bottom.sheet) + implementation(libs.compose.activities) + implementation(libs.bundles.hilt) + api(libs.navigation3.ui) + api(libs.lifecycle.viewmodel.navigation3) + api(libs.hilt.nav.compose) + api(libs.rinku) + } + getByName("androidHostTest").dependencies { + implementation(kotlin("test")) + implementation(libs.bundles.unit.testing) + implementation(libs.bundles.compose.ui.testing) + } + } +} - testImplementation(kotlin("test")) - testImplementation(libs.bundles.unit.testing) - testImplementation(libs.bundles.compose.ui.testing) +dependencies { + add("kspAndroid", libs.hilt.android.compiler) + add("kspAndroid", libs.hilt.compiler) } diff --git a/ui/navigation/src/test/kotlin/com/getcode/navigation/TestNav.kt b/ui/navigation/src/androidHostTest/kotlin/com/getcode/navigation/TestNav.kt similarity index 100% rename from ui/navigation/src/test/kotlin/com/getcode/navigation/TestNav.kt rename to ui/navigation/src/androidHostTest/kotlin/com/getcode/navigation/TestNav.kt diff --git a/ui/navigation/src/test/kotlin/com/getcode/navigation/core/CodeNavigatorDispatchTest.kt b/ui/navigation/src/androidHostTest/kotlin/com/getcode/navigation/core/CodeNavigatorDispatchTest.kt similarity index 100% rename from ui/navigation/src/test/kotlin/com/getcode/navigation/core/CodeNavigatorDispatchTest.kt rename to ui/navigation/src/androidHostTest/kotlin/com/getcode/navigation/core/CodeNavigatorDispatchTest.kt diff --git a/ui/navigation/src/test/kotlin/com/getcode/navigation/core/CodeNavigatorHarnessTest.kt b/ui/navigation/src/androidHostTest/kotlin/com/getcode/navigation/core/CodeNavigatorHarnessTest.kt similarity index 100% rename from ui/navigation/src/test/kotlin/com/getcode/navigation/core/CodeNavigatorHarnessTest.kt rename to ui/navigation/src/androidHostTest/kotlin/com/getcode/navigation/core/CodeNavigatorHarnessTest.kt diff --git a/ui/navigation/src/test/kotlin/com/getcode/navigation/core/CodeNavigatorIntentTest.kt b/ui/navigation/src/androidHostTest/kotlin/com/getcode/navigation/core/CodeNavigatorIntentTest.kt similarity index 100% rename from ui/navigation/src/test/kotlin/com/getcode/navigation/core/CodeNavigatorIntentTest.kt rename to ui/navigation/src/androidHostTest/kotlin/com/getcode/navigation/core/CodeNavigatorIntentTest.kt diff --git a/ui/navigation/src/test/kotlin/com/getcode/navigation/decorators/RetentionLedgerTest.kt b/ui/navigation/src/androidHostTest/kotlin/com/getcode/navigation/decorators/RetentionLedgerTest.kt similarity index 100% rename from ui/navigation/src/test/kotlin/com/getcode/navigation/decorators/RetentionLedgerTest.kt rename to ui/navigation/src/androidHostTest/kotlin/com/getcode/navigation/decorators/RetentionLedgerTest.kt diff --git a/ui/navigation/src/test/kotlin/com/getcode/navigation/flow/InnerFlowNavigatorTest.kt b/ui/navigation/src/androidHostTest/kotlin/com/getcode/navigation/flow/InnerFlowNavigatorTest.kt similarity index 100% rename from ui/navigation/src/test/kotlin/com/getcode/navigation/flow/InnerFlowNavigatorTest.kt rename to ui/navigation/src/androidHostTest/kotlin/com/getcode/navigation/flow/InnerFlowNavigatorTest.kt diff --git a/ui/navigation/src/test/kotlin/com/getcode/navigation/scenes/ModalBottomSheetSceneTest.kt b/ui/navigation/src/androidHostTest/kotlin/com/getcode/navigation/scenes/ModalBottomSheetSceneTest.kt similarity index 100% rename from ui/navigation/src/test/kotlin/com/getcode/navigation/scenes/ModalBottomSheetSceneTest.kt rename to ui/navigation/src/androidHostTest/kotlin/com/getcode/navigation/scenes/ModalBottomSheetSceneTest.kt diff --git a/ui/navigation/src/main/kotlin/com/getcode/navigation/AppNavHost.kt b/ui/navigation/src/androidMain/kotlin/com/getcode/navigation/AppNavHost.kt similarity index 100% rename from ui/navigation/src/main/kotlin/com/getcode/navigation/AppNavHost.kt rename to ui/navigation/src/androidMain/kotlin/com/getcode/navigation/AppNavHost.kt diff --git a/ui/navigation/src/main/kotlin/com/getcode/navigation/NavMetadata.kt b/ui/navigation/src/androidMain/kotlin/com/getcode/navigation/NavMetadata.kt similarity index 99% rename from ui/navigation/src/main/kotlin/com/getcode/navigation/NavMetadata.kt rename to ui/navigation/src/androidMain/kotlin/com/getcode/navigation/NavMetadata.kt index 1718fc1334..cda74df70b 100644 --- a/ui/navigation/src/main/kotlin/com/getcode/navigation/NavMetadata.kt +++ b/ui/navigation/src/androidMain/kotlin/com/getcode/navigation/NavMetadata.kt @@ -1,6 +1,6 @@ package com.getcode.navigation -import android.os.Parcelable +import com.getcode.libs.parcelable.Parcelable import androidx.compose.foundation.layout.Box import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier diff --git a/ui/navigation/src/main/kotlin/com/getcode/navigation/decorators/NavResultScopeEntryDecorator.kt b/ui/navigation/src/androidMain/kotlin/com/getcode/navigation/decorators/NavResultScopeEntryDecorator.kt similarity index 100% rename from ui/navigation/src/main/kotlin/com/getcode/navigation/decorators/NavResultScopeEntryDecorator.kt rename to ui/navigation/src/androidMain/kotlin/com/getcode/navigation/decorators/NavResultScopeEntryDecorator.kt diff --git a/ui/navigation/src/main/kotlin/com/getcode/navigation/decorators/RetainedEntryState.kt b/ui/navigation/src/androidMain/kotlin/com/getcode/navigation/decorators/RetainedEntryState.kt similarity index 100% rename from ui/navigation/src/main/kotlin/com/getcode/navigation/decorators/RetainedEntryState.kt rename to ui/navigation/src/androidMain/kotlin/com/getcode/navigation/decorators/RetainedEntryState.kt diff --git a/ui/navigation/src/main/kotlin/com/getcode/navigation/extensions/ViewModelExtensions.kt b/ui/navigation/src/androidMain/kotlin/com/getcode/navigation/extensions/ViewModelExtensions.kt similarity index 100% rename from ui/navigation/src/main/kotlin/com/getcode/navigation/extensions/ViewModelExtensions.kt rename to ui/navigation/src/androidMain/kotlin/com/getcode/navigation/extensions/ViewModelExtensions.kt diff --git a/ui/navigation/src/main/kotlin/com/getcode/navigation/flow/FlowDismissStyle.kt b/ui/navigation/src/androidMain/kotlin/com/getcode/navigation/flow/FlowDismissStyle.kt similarity index 100% rename from ui/navigation/src/main/kotlin/com/getcode/navigation/flow/FlowDismissStyle.kt rename to ui/navigation/src/androidMain/kotlin/com/getcode/navigation/flow/FlowDismissStyle.kt diff --git a/ui/navigation/src/main/kotlin/com/getcode/navigation/flow/FlowHost.kt b/ui/navigation/src/androidMain/kotlin/com/getcode/navigation/flow/FlowHost.kt similarity index 99% rename from ui/navigation/src/main/kotlin/com/getcode/navigation/flow/FlowHost.kt rename to ui/navigation/src/androidMain/kotlin/com/getcode/navigation/flow/FlowHost.kt index 13bb0ed33f..e589b0f90c 100644 --- a/ui/navigation/src/main/kotlin/com/getcode/navigation/flow/FlowHost.kt +++ b/ui/navigation/src/androidMain/kotlin/com/getcode/navigation/flow/FlowHost.kt @@ -1,6 +1,6 @@ package com.getcode.navigation.flow -import android.os.Parcelable +import com.getcode.libs.parcelable.Parcelable import androidx.compose.animation.AnimatedContentTransitionScope import androidx.compose.animation.ContentTransform import androidx.compose.animation.EnterTransition diff --git a/ui/navigation/src/main/kotlin/com/getcode/navigation/flow/FlowNavigator.kt b/ui/navigation/src/androidMain/kotlin/com/getcode/navigation/flow/FlowNavigator.kt similarity index 98% rename from ui/navigation/src/main/kotlin/com/getcode/navigation/flow/FlowNavigator.kt rename to ui/navigation/src/androidMain/kotlin/com/getcode/navigation/flow/FlowNavigator.kt index 0f493b9796..ceb3485c13 100644 --- a/ui/navigation/src/main/kotlin/com/getcode/navigation/flow/FlowNavigator.kt +++ b/ui/navigation/src/androidMain/kotlin/com/getcode/navigation/flow/FlowNavigator.kt @@ -1,6 +1,6 @@ package com.getcode.navigation.flow -import android.os.Parcelable +import com.getcode.libs.parcelable.Parcelable import androidx.compose.runtime.Composable import androidx.compose.runtime.staticCompositionLocalOf import androidx.navigation3.runtime.NavKey diff --git a/ui/navigation/src/main/kotlin/com/getcode/navigation/flow/FlowRoute.kt b/ui/navigation/src/androidMain/kotlin/com/getcode/navigation/flow/FlowRoute.kt similarity index 97% rename from ui/navigation/src/main/kotlin/com/getcode/navigation/flow/FlowRoute.kt rename to ui/navigation/src/androidMain/kotlin/com/getcode/navigation/flow/FlowRoute.kt index a3fab98589..49bee9ba82 100644 --- a/ui/navigation/src/main/kotlin/com/getcode/navigation/flow/FlowRoute.kt +++ b/ui/navigation/src/androidMain/kotlin/com/getcode/navigation/flow/FlowRoute.kt @@ -1,6 +1,6 @@ package com.getcode.navigation.flow -import android.os.Parcelable +import com.getcode.libs.parcelable.Parcelable import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.navigation3.runtime.NavKey diff --git a/ui/navigation/src/main/kotlin/com/getcode/navigation/flow/FlowViewModel.kt b/ui/navigation/src/androidMain/kotlin/com/getcode/navigation/flow/FlowViewModel.kt similarity index 100% rename from ui/navigation/src/main/kotlin/com/getcode/navigation/flow/FlowViewModel.kt rename to ui/navigation/src/androidMain/kotlin/com/getcode/navigation/flow/FlowViewModel.kt diff --git a/ui/navigation/src/main/kotlin/com/getcode/navigation/scenes/FullscreenOverlaySceneStrategy.kt b/ui/navigation/src/androidMain/kotlin/com/getcode/navigation/scenes/FullscreenOverlaySceneStrategy.kt similarity index 100% rename from ui/navigation/src/main/kotlin/com/getcode/navigation/scenes/FullscreenOverlaySceneStrategy.kt rename to ui/navigation/src/androidMain/kotlin/com/getcode/navigation/scenes/FullscreenOverlaySceneStrategy.kt diff --git a/ui/navigation/src/main/kotlin/com/getcode/navigation/scenes/ModalBottomSheetSceneStrategy.kt b/ui/navigation/src/androidMain/kotlin/com/getcode/navigation/scenes/ModalBottomSheetSceneStrategy.kt similarity index 99% rename from ui/navigation/src/main/kotlin/com/getcode/navigation/scenes/ModalBottomSheetSceneStrategy.kt rename to ui/navigation/src/androidMain/kotlin/com/getcode/navigation/scenes/ModalBottomSheetSceneStrategy.kt index c792fd1e50..d9ce8f8b86 100644 --- a/ui/navigation/src/main/kotlin/com/getcode/navigation/scenes/ModalBottomSheetSceneStrategy.kt +++ b/ui/navigation/src/androidMain/kotlin/com/getcode/navigation/scenes/ModalBottomSheetSceneStrategy.kt @@ -1,7 +1,7 @@ package com.getcode.navigation.scenes import android.os.Build -import android.os.Parcelable +import com.getcode.libs.parcelable.Parcelable import androidx.activity.compose.BackHandler import androidx.compose.animation.SharedTransitionLayout import androidx.compose.foundation.background diff --git a/ui/navigation/src/main/kotlin/com/getcode/navigation/scrim/Scrim.kt b/ui/navigation/src/androidMain/kotlin/com/getcode/navigation/scrim/Scrim.kt similarity index 100% rename from ui/navigation/src/main/kotlin/com/getcode/navigation/scrim/Scrim.kt rename to ui/navigation/src/androidMain/kotlin/com/getcode/navigation/scrim/Scrim.kt diff --git a/ui/navigation/src/main/kotlin/com/getcode/ui/utils/DisableSheetGestures.kt b/ui/navigation/src/androidMain/kotlin/com/getcode/ui/utils/DisableSheetGestures.kt similarity index 100% rename from ui/navigation/src/main/kotlin/com/getcode/ui/utils/DisableSheetGestures.kt rename to ui/navigation/src/androidMain/kotlin/com/getcode/ui/utils/DisableSheetGestures.kt diff --git a/ui/navigation/src/main/kotlin/com/getcode/ui/utils/SheetExpansion.kt b/ui/navigation/src/androidMain/kotlin/com/getcode/ui/utils/SheetExpansion.kt similarity index 100% rename from ui/navigation/src/main/kotlin/com/getcode/ui/utils/SheetExpansion.kt rename to ui/navigation/src/androidMain/kotlin/com/getcode/ui/utils/SheetExpansion.kt diff --git a/ui/navigation/src/main/kotlin/com/getcode/ui/utils/SheetResignmentModifierNode.kt b/ui/navigation/src/androidMain/kotlin/com/getcode/ui/utils/SheetResignmentModifierNode.kt similarity index 100% rename from ui/navigation/src/main/kotlin/com/getcode/ui/utils/SheetResignmentModifierNode.kt rename to ui/navigation/src/androidMain/kotlin/com/getcode/ui/utils/SheetResignmentModifierNode.kt diff --git a/ui/navigation/src/main/kotlin/com/getcode/view/BaseViewModel.kt b/ui/navigation/src/androidMain/kotlin/com/getcode/view/BaseViewModel.kt similarity index 100% rename from ui/navigation/src/main/kotlin/com/getcode/view/BaseViewModel.kt rename to ui/navigation/src/androidMain/kotlin/com/getcode/view/BaseViewModel.kt diff --git a/ui/navigation/src/main/kotlin/com/getcode/navigation/NavContentKey.kt b/ui/navigation/src/commonMain/kotlin/com/getcode/navigation/NavContentKey.kt similarity index 100% rename from ui/navigation/src/main/kotlin/com/getcode/navigation/NavContentKey.kt rename to ui/navigation/src/commonMain/kotlin/com/getcode/navigation/NavContentKey.kt diff --git a/ui/navigation/src/main/kotlin/com/getcode/navigation/Types.kt b/ui/navigation/src/commonMain/kotlin/com/getcode/navigation/Types.kt similarity index 100% rename from ui/navigation/src/main/kotlin/com/getcode/navigation/Types.kt rename to ui/navigation/src/commonMain/kotlin/com/getcode/navigation/Types.kt diff --git a/ui/navigation/src/main/kotlin/com/getcode/navigation/core/CodeNavigator.kt b/ui/navigation/src/commonMain/kotlin/com/getcode/navigation/core/CodeNavigator.kt similarity index 98% rename from ui/navigation/src/main/kotlin/com/getcode/navigation/core/CodeNavigator.kt rename to ui/navigation/src/commonMain/kotlin/com/getcode/navigation/core/CodeNavigator.kt index e609baf033..9f29459ee3 100644 --- a/ui/navigation/src/main/kotlin/com/getcode/navigation/core/CodeNavigator.kt +++ b/ui/navigation/src/commonMain/kotlin/com/getcode/navigation/core/CodeNavigator.kt @@ -21,7 +21,7 @@ import com.getcode.navigation.results.SavedStateHandleNavResultController import com.getcode.navigation.results.rememberNavResultStore import com.getcode.utils.TraceType import com.getcode.utils.trace -import timber.log.Timber +import com.getcode.utils.Log import kotlin.reflect.KClass val LocalCodeNavigator: ProvidableCompositionLocal = @@ -240,7 +240,7 @@ class CodeNavigator( * The flow host tears down the flow after receiving this signal. * No-op (with a trace) when called outside a flow — there is no caller to return to. */ - fun navigateBackWithResult(result: android.os.Parcelable) { + fun navigateBackWithResult(result: com.getcode.libs.parcelable.Parcelable) { val scope = flowScope if (scope != null) { scope.exitWithResult(result) @@ -271,7 +271,7 @@ class CodeNavigator( } fun clearToFirst(routeClass: KClass): Boolean { - Timber.d("Clearing backstack to first instance of $routeClass") + Log.d("Clearing backstack to first instance of $routeClass") var routeFound = false Snapshot.withMutableSnapshot { val first = backStack.indexOfFirst { it::class == routeClass } diff --git a/ui/navigation/src/main/kotlin/com/getcode/navigation/core/FlowScope.kt b/ui/navigation/src/commonMain/kotlin/com/getcode/navigation/core/FlowScope.kt similarity index 96% rename from ui/navigation/src/main/kotlin/com/getcode/navigation/core/FlowScope.kt rename to ui/navigation/src/commonMain/kotlin/com/getcode/navigation/core/FlowScope.kt index 4fb06fdfc7..cf8a63f55a 100644 --- a/ui/navigation/src/main/kotlin/com/getcode/navigation/core/FlowScope.kt +++ b/ui/navigation/src/commonMain/kotlin/com/getcode/navigation/core/FlowScope.kt @@ -1,6 +1,6 @@ package com.getcode.navigation.core -import android.os.Parcelable +import com.getcode.libs.parcelable.Parcelable /** * The bounded navigation scope a [CodeNavigator] belongs to when it is a flow's inner navigator. diff --git a/ui/navigation/src/main/kotlin/com/getcode/navigation/core/NavOptions.kt b/ui/navigation/src/commonMain/kotlin/com/getcode/navigation/core/NavOptions.kt similarity index 89% rename from ui/navigation/src/main/kotlin/com/getcode/navigation/core/NavOptions.kt rename to ui/navigation/src/commonMain/kotlin/com/getcode/navigation/core/NavOptions.kt index bf63f4fd67..77307e4aaf 100644 --- a/ui/navigation/src/main/kotlin/com/getcode/navigation/core/NavOptions.kt +++ b/ui/navigation/src/commonMain/kotlin/com/getcode/navigation/core/NavOptions.kt @@ -1,7 +1,7 @@ package com.getcode.navigation.core import androidx.navigation3.runtime.NavKey -import com.getcode.navigation.BuildConfig +import com.getcode.utils.BuildFlags import kotlin.reflect.KClass /** @@ -14,7 +14,7 @@ import kotlin.reflect.KClass data class NavOptions( val popUpTo: PopUpTo = PopUpTo.None, val navigatingForResult: Boolean = false, - val debugRouting: Boolean = BuildConfig.DEBUG, + val debugRouting: Boolean = BuildFlags.isDebug, ) { sealed interface PopUpTo { data object ClearAll : PopUpTo diff --git a/ui/navigation/src/main/kotlin/com/getcode/navigation/flow/FlowStep.kt b/ui/navigation/src/commonMain/kotlin/com/getcode/navigation/flow/FlowStep.kt similarity index 100% rename from ui/navigation/src/main/kotlin/com/getcode/navigation/flow/FlowStep.kt rename to ui/navigation/src/commonMain/kotlin/com/getcode/navigation/flow/FlowStep.kt diff --git a/ui/navigation/src/main/kotlin/com/getcode/navigation/results/NavResult.kt b/ui/navigation/src/commonMain/kotlin/com/getcode/navigation/results/NavResult.kt similarity index 90% rename from ui/navigation/src/main/kotlin/com/getcode/navigation/results/NavResult.kt rename to ui/navigation/src/commonMain/kotlin/com/getcode/navigation/results/NavResult.kt index ee6401cd63..7568854130 100644 --- a/ui/navigation/src/main/kotlin/com/getcode/navigation/results/NavResult.kt +++ b/ui/navigation/src/commonMain/kotlin/com/getcode/navigation/results/NavResult.kt @@ -1,7 +1,7 @@ package com.getcode.navigation.results -import android.os.Parcelable -import kotlinx.parcelize.Parcelize +import com.getcode.libs.parcelable.Parcelable +import com.getcode.libs.parcelable.Parcelize /** * NavResultStore value diff --git a/ui/navigation/src/main/kotlin/com/getcode/navigation/results/NavResultController.kt b/ui/navigation/src/commonMain/kotlin/com/getcode/navigation/results/NavResultController.kt similarity index 98% rename from ui/navigation/src/main/kotlin/com/getcode/navigation/results/NavResultController.kt rename to ui/navigation/src/commonMain/kotlin/com/getcode/navigation/results/NavResultController.kt index d89ea1e356..dcac76fe7f 100644 --- a/ui/navigation/src/main/kotlin/com/getcode/navigation/results/NavResultController.kt +++ b/ui/navigation/src/commonMain/kotlin/com/getcode/navigation/results/NavResultController.kt @@ -1,6 +1,6 @@ package com.getcode.navigation.results -import android.os.Parcelable +import com.getcode.libs.parcelable.Parcelable import androidx.navigation3.runtime.NavKey import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableSharedFlow diff --git a/ui/navigation/src/main/kotlin/com/getcode/navigation/results/NavResultKey.kt b/ui/navigation/src/commonMain/kotlin/com/getcode/navigation/results/NavResultKey.kt similarity index 94% rename from ui/navigation/src/main/kotlin/com/getcode/navigation/results/NavResultKey.kt rename to ui/navigation/src/commonMain/kotlin/com/getcode/navigation/results/NavResultKey.kt index fe56fbaa2b..34118fc54c 100644 --- a/ui/navigation/src/main/kotlin/com/getcode/navigation/results/NavResultKey.kt +++ b/ui/navigation/src/commonMain/kotlin/com/getcode/navigation/results/NavResultKey.kt @@ -1,6 +1,6 @@ package com.getcode.navigation.results -import android.os.Parcelable +import com.getcode.libs.parcelable.Parcelable import com.getcode.navigation.utils.KClassSerializer import kotlinx.serialization.Serializable import kotlin.reflect.KClass diff --git a/ui/navigation/src/main/kotlin/com/getcode/navigation/results/NavResultStore.kt b/ui/navigation/src/commonMain/kotlin/com/getcode/navigation/results/NavResultStore.kt similarity index 99% rename from ui/navigation/src/main/kotlin/com/getcode/navigation/results/NavResultStore.kt rename to ui/navigation/src/commonMain/kotlin/com/getcode/navigation/results/NavResultStore.kt index f7c82f0a8f..c668a711ab 100644 --- a/ui/navigation/src/main/kotlin/com/getcode/navigation/results/NavResultStore.kt +++ b/ui/navigation/src/commonMain/kotlin/com/getcode/navigation/results/NavResultStore.kt @@ -1,6 +1,6 @@ package com.getcode.navigation.results -import android.os.Parcelable +import com.getcode.libs.parcelable.Parcelable import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.mutableStateMapOf diff --git a/ui/navigation/src/main/kotlin/com/getcode/navigation/results/RetVal.kt b/ui/navigation/src/commonMain/kotlin/com/getcode/navigation/results/RetVal.kt similarity index 91% rename from ui/navigation/src/main/kotlin/com/getcode/navigation/results/RetVal.kt rename to ui/navigation/src/commonMain/kotlin/com/getcode/navigation/results/RetVal.kt index 79eded14d1..62e2df54fa 100644 --- a/ui/navigation/src/main/kotlin/com/getcode/navigation/results/RetVal.kt +++ b/ui/navigation/src/commonMain/kotlin/com/getcode/navigation/results/RetVal.kt @@ -1,6 +1,6 @@ package com.getcode.navigation.results -import android.os.Parcelable +import com.getcode.libs.parcelable.Parcelable import androidx.navigation3.runtime.NavKey import kotlin.reflect.KClass diff --git a/ui/navigation/src/main/kotlin/com/getcode/navigation/utils/KClassSerializer.kt b/ui/navigation/src/commonMain/kotlin/com/getcode/navigation/utils/KClassSerializer.kt similarity index 100% rename from ui/navigation/src/main/kotlin/com/getcode/navigation/utils/KClassSerializer.kt rename to ui/navigation/src/commonMain/kotlin/com/getcode/navigation/utils/KClassSerializer.kt diff --git a/ui/navigation/src/main/kotlin/com/getcode/navigation/utils/lifecycle/RepeatOnLifecycle.kt b/ui/navigation/src/commonMain/kotlin/com/getcode/navigation/utils/lifecycle/RepeatOnLifecycle.kt similarity index 94% rename from ui/navigation/src/main/kotlin/com/getcode/navigation/utils/lifecycle/RepeatOnLifecycle.kt rename to ui/navigation/src/commonMain/kotlin/com/getcode/navigation/utils/lifecycle/RepeatOnLifecycle.kt index 3343f78ee3..973409de01 100644 --- a/ui/navigation/src/main/kotlin/com/getcode/navigation/utils/lifecycle/RepeatOnLifecycle.kt +++ b/ui/navigation/src/commonMain/kotlin/com/getcode/navigation/utils/lifecycle/RepeatOnLifecycle.kt @@ -2,7 +2,7 @@ package com.getcode.navigation.utils.lifecycle import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect -import androidx.compose.ui.platform.LocalLifecycleOwner +import androidx.lifecycle.compose.LocalLifecycleOwner import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.lifecycleScope From 6672b93e2c3af795ed55500ead403321f3cc9ba8 Mon Sep 17 00:00:00 2001 From: Brandon McAnsh Date: Fri, 23 Oct 2026 18:27:07 -0400 Subject: [PATCH 19/50] build(analytics): move shared:analytics to android+jvm KMP The FlipcashAnalytics interface, the token symbol resolver and the CompositionLocal move to common code. Conversions (toUri and app:core's DeeplinkType) and the Mixpanel delegate stay Android. RecordingAnalytics moves to a :test-fixtures module, since the KMP Android target has no testFixtures; its 10 consumers point at that module. Also moves ui:navigation's BaseViewModel to common code; it uses only lifecycle and coroutines. --- .../features/balance/build.gradle.kts | 2 +- apps/flipcash/features/cash/build.gradle.kts | 2 +- apps/flipcash/features/login/build.gradle.kts | 2 +- .../features/messenger/build.gradle.kts | 2 +- .../features/tipping/build.gradle.kts | 2 +- .../flipcash/features/tokens/build.gradle.kts | 2 +- .../features/user-profile/build.gradle.kts | 2 +- .../shared/analytics/build.gradle.kts | 56 +++++++++++-------- .../flipcash/app/analytics/ConversionsTest.kt | 0 .../app/analytics/MixpanelTrackTest.kt | 0 .../com/flipcash/app/analytics/Conversions.kt | 0 .../app/analytics/inject/AnalyticsModule.kt | 0 .../internal/MixpanelAnalyticsDelegate.kt | 0 .../com/flipcash/app/analytics/Analytics.kt | 0 .../app/analytics/FlipcashAnalytics.kt | 0 .../app/analytics/TokenSymbolResolver.kt | 0 .../analytics/test-fixtures/build.gradle.kts | 15 +++++ .../app/analytics/RecordingAnalytics.kt | 0 apps/flipcash/shared/chat/build.gradle.kts | 2 +- apps/flipcash/shared/session/build.gradle.kts | 2 +- apps/flipcash/shared/tokens/build.gradle.kts | 2 +- .../app/userflags/FieldOverrideTest.kt | 0 .../app/userflags/ResolvedFlagTest.kt | 0 .../app/userflags/ResolvedUserFlagsTest.kt | 0 .../app/userflags/UsernameGateTest.kt | 0 .../res/values/strings.xml | 0 .../com/flipcash/app/userflags/Field.kt | 0 .../com/flipcash/app/userflags/FieldEditor.kt | 0 .../flipcash/app/userflags/FieldOverride.kt | 0 .../app/userflags/ResolvedUserFlags.kt | 0 .../app/userflags/UserFlagsCoordinator.kt | 0 .../flipcash/app/userflags/UsernameGate.kt | 0 settings.gradle.kts | 1 + .../kotlin/com/getcode/view/BaseViewModel.kt | 0 34 files changed, 58 insertions(+), 34 deletions(-) rename apps/flipcash/shared/analytics/src/{test => androidHostTest}/kotlin/com/flipcash/app/analytics/ConversionsTest.kt (100%) rename apps/flipcash/shared/analytics/src/{test => androidHostTest}/kotlin/com/flipcash/app/analytics/MixpanelTrackTest.kt (100%) rename apps/flipcash/shared/analytics/src/{main => androidMain}/kotlin/com/flipcash/app/analytics/Conversions.kt (100%) rename apps/flipcash/shared/analytics/src/{main => androidMain}/kotlin/com/flipcash/app/analytics/inject/AnalyticsModule.kt (100%) rename apps/flipcash/shared/analytics/src/{main => androidMain}/kotlin/com/flipcash/app/analytics/internal/MixpanelAnalyticsDelegate.kt (100%) rename apps/flipcash/shared/analytics/src/{main => commonMain}/kotlin/com/flipcash/app/analytics/Analytics.kt (100%) rename apps/flipcash/shared/analytics/src/{main => commonMain}/kotlin/com/flipcash/app/analytics/FlipcashAnalytics.kt (100%) rename apps/flipcash/shared/analytics/src/{main => commonMain}/kotlin/com/flipcash/app/analytics/TokenSymbolResolver.kt (100%) create mode 100644 apps/flipcash/shared/analytics/test-fixtures/build.gradle.kts rename apps/flipcash/shared/analytics/{src/testFixtures => test-fixtures/src/commonMain}/kotlin/com/flipcash/app/analytics/RecordingAnalytics.kt (100%) rename apps/flipcash/shared/userflags/src/{test => androidHostTest}/kotlin/com/flipcash/app/userflags/FieldOverrideTest.kt (100%) rename apps/flipcash/shared/userflags/src/{test => androidHostTest}/kotlin/com/flipcash/app/userflags/ResolvedFlagTest.kt (100%) rename apps/flipcash/shared/userflags/src/{test => androidHostTest}/kotlin/com/flipcash/app/userflags/ResolvedUserFlagsTest.kt (100%) rename apps/flipcash/shared/userflags/src/{test => androidHostTest}/kotlin/com/flipcash/app/userflags/UsernameGateTest.kt (100%) rename apps/flipcash/shared/userflags/src/{main => androidMain}/res/values/strings.xml (100%) rename apps/flipcash/shared/userflags/src/{main => commonMain}/kotlin/com/flipcash/app/userflags/Field.kt (100%) rename apps/flipcash/shared/userflags/src/{main => commonMain}/kotlin/com/flipcash/app/userflags/FieldEditor.kt (100%) rename apps/flipcash/shared/userflags/src/{main => commonMain}/kotlin/com/flipcash/app/userflags/FieldOverride.kt (100%) rename apps/flipcash/shared/userflags/src/{main => commonMain}/kotlin/com/flipcash/app/userflags/ResolvedUserFlags.kt (100%) rename apps/flipcash/shared/userflags/src/{main => commonMain}/kotlin/com/flipcash/app/userflags/UserFlagsCoordinator.kt (100%) rename apps/flipcash/shared/userflags/src/{main => commonMain}/kotlin/com/flipcash/app/userflags/UsernameGate.kt (100%) rename ui/navigation/src/{androidMain => commonMain}/kotlin/com/getcode/view/BaseViewModel.kt (100%) diff --git a/apps/flipcash/features/balance/build.gradle.kts b/apps/flipcash/features/balance/build.gradle.kts index 35b9361647..3c7e428cd6 100644 --- a/apps/flipcash/features/balance/build.gradle.kts +++ b/apps/flipcash/features/balance/build.gradle.kts @@ -15,7 +15,7 @@ dependencies { implementation(project(":apps:flipcash:shared:transaction-history")) implementation(project(":apps:flipcash:shared:analytics")) - testImplementation(testFixtures(project(":apps:flipcash:shared:analytics"))) + testImplementation(project(":apps:flipcash:shared:analytics:test-fixtures")) implementation(project(":apps:flipcash:shared:chat")) implementation(project(":apps:flipcash:shared:featureflags")) implementation(project(":apps:flipcash:shared:funding")) diff --git a/apps/flipcash/features/cash/build.gradle.kts b/apps/flipcash/features/cash/build.gradle.kts index 748344538f..6faa79e880 100644 --- a/apps/flipcash/features/cash/build.gradle.kts +++ b/apps/flipcash/features/cash/build.gradle.kts @@ -16,7 +16,7 @@ dependencies { implementation(libs.kotlin.stdlib) implementation(project(":apps:flipcash:shared:amount-entry")) implementation(project(":apps:flipcash:shared:analytics")) - testImplementation(testFixtures(project(":apps:flipcash:shared:analytics"))) + testImplementation(project(":apps:flipcash:shared:analytics:test-fixtures")) implementation(project(":apps:flipcash:shared:featureflags")) implementation(project(":apps:flipcash:shared:session")) implementation(project(":apps:flipcash:shared:tokens")) diff --git a/apps/flipcash/features/login/build.gradle.kts b/apps/flipcash/features/login/build.gradle.kts index fdc0140b53..0fffe64486 100644 --- a/apps/flipcash/features/login/build.gradle.kts +++ b/apps/flipcash/features/login/build.gradle.kts @@ -15,7 +15,7 @@ dependencies { implementation(project(":apps:flipcash:shared:accesskey")) implementation(project(":apps:flipcash:shared:analytics")) - testImplementation(testFixtures(project(":apps:flipcash:shared:analytics"))) + testImplementation(project(":apps:flipcash:shared:analytics:test-fixtures")) implementation(project(":apps:flipcash:shared:authentication")) implementation(project(":apps:flipcash:shared:contacts")) implementation(project(":apps:flipcash:shared:featureflags")) diff --git a/apps/flipcash/features/messenger/build.gradle.kts b/apps/flipcash/features/messenger/build.gradle.kts index db75e306bb..1db86fa31d 100644 --- a/apps/flipcash/features/messenger/build.gradle.kts +++ b/apps/flipcash/features/messenger/build.gradle.kts @@ -8,7 +8,7 @@ android { dependencies { implementation(project(":apps:flipcash:shared:analytics")) - testImplementation(testFixtures(project(":apps:flipcash:shared:analytics"))) + testImplementation(project(":apps:flipcash:shared:analytics:test-fixtures")) testImplementation(project(":libs:coroutines:test-fixtures")) implementation(project(":apps:flipcash:shared:blob")) implementation(project(":apps:flipcash:shared:bills")) diff --git a/apps/flipcash/features/tipping/build.gradle.kts b/apps/flipcash/features/tipping/build.gradle.kts index 2c4f4a7910..9af93ef91c 100644 --- a/apps/flipcash/features/tipping/build.gradle.kts +++ b/apps/flipcash/features/tipping/build.gradle.kts @@ -10,7 +10,7 @@ dependencies { testImplementation(kotlin("test")) testImplementation(libs.bundles.unit.testing) testImplementation(project(":ui:resources:test-fixtures")) - testImplementation(testFixtures(project(":apps:flipcash:shared:analytics"))) + testImplementation(project(":apps:flipcash:shared:analytics:test-fixtures")) testImplementation(libs.robolectric) implementation(project(":apps:flipcash:shared:analytics")) diff --git a/apps/flipcash/features/tokens/build.gradle.kts b/apps/flipcash/features/tokens/build.gradle.kts index e5739b5cb4..de0f8983bc 100644 --- a/apps/flipcash/features/tokens/build.gradle.kts +++ b/apps/flipcash/features/tokens/build.gradle.kts @@ -10,7 +10,7 @@ dependencies { implementation(project(":apps:flipcash:card-expand")) implementation(project(":apps:flipcash:shared:amount-entry")) implementation(project(":apps:flipcash:shared:analytics")) - testImplementation(testFixtures(project(":apps:flipcash:shared:analytics"))) + testImplementation(project(":apps:flipcash:shared:analytics:test-fixtures")) implementation(project(":apps:flipcash:shared:onramp:coinbase")) implementation(project(":apps:flipcash:shared:onramp:deeplinks")) implementation(project(":apps:flipcash:shared:featureflags")) diff --git a/apps/flipcash/features/user-profile/build.gradle.kts b/apps/flipcash/features/user-profile/build.gradle.kts index e82b55b0a1..1ae121ea60 100644 --- a/apps/flipcash/features/user-profile/build.gradle.kts +++ b/apps/flipcash/features/user-profile/build.gradle.kts @@ -17,7 +17,7 @@ dependencies { implementation(project(":apps:flipcash:shared:amount-entry")) implementation(project(":apps:flipcash:shared:analytics")) - testImplementation(testFixtures(project(":apps:flipcash:shared:analytics"))) + testImplementation(project(":apps:flipcash:shared:analytics:test-fixtures")) implementation(project(":apps:flipcash:shared:blob")) implementation(project(":apps:flipcash:shared:chat")) implementation(project(":apps:flipcash:shared:common-ui")) diff --git a/apps/flipcash/shared/analytics/build.gradle.kts b/apps/flipcash/shared/analytics/build.gradle.kts index c17b1a59e6..af3b9fdf86 100644 --- a/apps/flipcash/shared/analytics/build.gradle.kts +++ b/apps/flipcash/shared/analytics/build.gradle.kts @@ -1,32 +1,40 @@ plugins { - alias(libs.plugins.flipcash.android.feature) + alias(libs.plugins.flipcash.kmp.app.library) + alias(libs.plugins.compose.compiler) + alias(libs.plugins.kotlin.ksp) } -android { - namespace = "${Gradle.flipcashNamespace}.shared.anaylytics" - testFixtures { - enable = true +kotlin { + android { + namespace = "${Gradle.flipcashNamespace}.shared.anaylytics" + } + + sourceSets { + commonMain.dependencies { + api(project(":libs:analytics-events")) + implementation(libs.jetbrains.compose.runtime) + } + androidMain.dependencies { + implementation(project(":apps:flipcash:core")) + implementation(project(":libs:logging")) + implementation(project(":libs:currency-math")) + implementation(project(":libs:encryption:keys")) + implementation(project(":services:flipcash")) + implementation(project(":services:opencode")) + implementation(libs.androidx.core) + implementation(libs.mixpanel) + implementation(libs.bundles.hilt) + } + getByName("androidHostTest").dependencies { + implementation(project(":apps:flipcash:shared:analytics:test-fixtures")) + implementation(kotlin("test")) + implementation(libs.bundles.unit.testing) + implementation(libs.robolectric) + } } } dependencies { - testFixturesImplementation(platform(libs.compose.bom)) - testFixturesImplementation(libs.compose.ui) - - testImplementation(kotlin("test")) - testImplementation(libs.bundles.unit.testing) - testImplementation(libs.robolectric) - - implementation(platform(libs.firebase.bom)) - implementation(libs.firebase.messaging) - implementation(libs.bugsnag) - - api(project(":libs:analytics-events")) - implementation(project(":libs:logging")) - implementation(project(":services:flipcash")) - implementation(project(":services:opencode")) - - implementation(libs.mixpanel) - - implementation(libs.androidx.datastore) + add("kspAndroid", libs.hilt.android.compiler) + add("kspAndroid", libs.hilt.compiler) } diff --git a/apps/flipcash/shared/analytics/src/test/kotlin/com/flipcash/app/analytics/ConversionsTest.kt b/apps/flipcash/shared/analytics/src/androidHostTest/kotlin/com/flipcash/app/analytics/ConversionsTest.kt similarity index 100% rename from apps/flipcash/shared/analytics/src/test/kotlin/com/flipcash/app/analytics/ConversionsTest.kt rename to apps/flipcash/shared/analytics/src/androidHostTest/kotlin/com/flipcash/app/analytics/ConversionsTest.kt diff --git a/apps/flipcash/shared/analytics/src/test/kotlin/com/flipcash/app/analytics/MixpanelTrackTest.kt b/apps/flipcash/shared/analytics/src/androidHostTest/kotlin/com/flipcash/app/analytics/MixpanelTrackTest.kt similarity index 100% rename from apps/flipcash/shared/analytics/src/test/kotlin/com/flipcash/app/analytics/MixpanelTrackTest.kt rename to apps/flipcash/shared/analytics/src/androidHostTest/kotlin/com/flipcash/app/analytics/MixpanelTrackTest.kt diff --git a/apps/flipcash/shared/analytics/src/main/kotlin/com/flipcash/app/analytics/Conversions.kt b/apps/flipcash/shared/analytics/src/androidMain/kotlin/com/flipcash/app/analytics/Conversions.kt similarity index 100% rename from apps/flipcash/shared/analytics/src/main/kotlin/com/flipcash/app/analytics/Conversions.kt rename to apps/flipcash/shared/analytics/src/androidMain/kotlin/com/flipcash/app/analytics/Conversions.kt diff --git a/apps/flipcash/shared/analytics/src/main/kotlin/com/flipcash/app/analytics/inject/AnalyticsModule.kt b/apps/flipcash/shared/analytics/src/androidMain/kotlin/com/flipcash/app/analytics/inject/AnalyticsModule.kt similarity index 100% rename from apps/flipcash/shared/analytics/src/main/kotlin/com/flipcash/app/analytics/inject/AnalyticsModule.kt rename to apps/flipcash/shared/analytics/src/androidMain/kotlin/com/flipcash/app/analytics/inject/AnalyticsModule.kt diff --git a/apps/flipcash/shared/analytics/src/main/kotlin/com/flipcash/app/analytics/internal/MixpanelAnalyticsDelegate.kt b/apps/flipcash/shared/analytics/src/androidMain/kotlin/com/flipcash/app/analytics/internal/MixpanelAnalyticsDelegate.kt similarity index 100% rename from apps/flipcash/shared/analytics/src/main/kotlin/com/flipcash/app/analytics/internal/MixpanelAnalyticsDelegate.kt rename to apps/flipcash/shared/analytics/src/androidMain/kotlin/com/flipcash/app/analytics/internal/MixpanelAnalyticsDelegate.kt diff --git a/apps/flipcash/shared/analytics/src/main/kotlin/com/flipcash/app/analytics/Analytics.kt b/apps/flipcash/shared/analytics/src/commonMain/kotlin/com/flipcash/app/analytics/Analytics.kt similarity index 100% rename from apps/flipcash/shared/analytics/src/main/kotlin/com/flipcash/app/analytics/Analytics.kt rename to apps/flipcash/shared/analytics/src/commonMain/kotlin/com/flipcash/app/analytics/Analytics.kt diff --git a/apps/flipcash/shared/analytics/src/main/kotlin/com/flipcash/app/analytics/FlipcashAnalytics.kt b/apps/flipcash/shared/analytics/src/commonMain/kotlin/com/flipcash/app/analytics/FlipcashAnalytics.kt similarity index 100% rename from apps/flipcash/shared/analytics/src/main/kotlin/com/flipcash/app/analytics/FlipcashAnalytics.kt rename to apps/flipcash/shared/analytics/src/commonMain/kotlin/com/flipcash/app/analytics/FlipcashAnalytics.kt diff --git a/apps/flipcash/shared/analytics/src/main/kotlin/com/flipcash/app/analytics/TokenSymbolResolver.kt b/apps/flipcash/shared/analytics/src/commonMain/kotlin/com/flipcash/app/analytics/TokenSymbolResolver.kt similarity index 100% rename from apps/flipcash/shared/analytics/src/main/kotlin/com/flipcash/app/analytics/TokenSymbolResolver.kt rename to apps/flipcash/shared/analytics/src/commonMain/kotlin/com/flipcash/app/analytics/TokenSymbolResolver.kt diff --git a/apps/flipcash/shared/analytics/test-fixtures/build.gradle.kts b/apps/flipcash/shared/analytics/test-fixtures/build.gradle.kts new file mode 100644 index 0000000000..a2e8c1b43e --- /dev/null +++ b/apps/flipcash/shared/analytics/test-fixtures/build.gradle.kts @@ -0,0 +1,15 @@ +plugins { + alias(libs.plugins.flipcash.kmp.app.library) +} + +kotlin { + android { + namespace = "${Gradle.flipcashNamespace}.shared.analytics.testfixtures" + } + + sourceSets { + commonMain.dependencies { + api(project(":apps:flipcash:shared:analytics")) + } + } +} diff --git a/apps/flipcash/shared/analytics/src/testFixtures/kotlin/com/flipcash/app/analytics/RecordingAnalytics.kt b/apps/flipcash/shared/analytics/test-fixtures/src/commonMain/kotlin/com/flipcash/app/analytics/RecordingAnalytics.kt similarity index 100% rename from apps/flipcash/shared/analytics/src/testFixtures/kotlin/com/flipcash/app/analytics/RecordingAnalytics.kt rename to apps/flipcash/shared/analytics/test-fixtures/src/commonMain/kotlin/com/flipcash/app/analytics/RecordingAnalytics.kt diff --git a/apps/flipcash/shared/chat/build.gradle.kts b/apps/flipcash/shared/chat/build.gradle.kts index a21772a251..2bf81627f5 100644 --- a/apps/flipcash/shared/chat/build.gradle.kts +++ b/apps/flipcash/shared/chat/build.gradle.kts @@ -33,7 +33,7 @@ dependencies { // so this module's public surface names a type from it. api(project(":apps:flipcash:shared:tokens")) implementation(project(":apps:flipcash:shared:analytics")) - testImplementation(testFixtures(project(":apps:flipcash:shared:analytics"))) + testImplementation(project(":apps:flipcash:shared:analytics:test-fixtures")) implementation(project(":services:flipcash")) testImplementation(project(":services:flipcash:test-fixtures")) implementation(project(":libs:network:connectivity:public")) diff --git a/apps/flipcash/shared/session/build.gradle.kts b/apps/flipcash/shared/session/build.gradle.kts index 9fb357fa99..fe5f4fd58d 100644 --- a/apps/flipcash/shared/session/build.gradle.kts +++ b/apps/flipcash/shared/session/build.gradle.kts @@ -18,7 +18,7 @@ dependencies { implementation(project(":apps:flipcash:shared:contacts")) implementation(project(":apps:flipcash:shared:transaction-history")) implementation(project(":apps:flipcash:shared:analytics")) - testImplementation(testFixtures(project(":apps:flipcash:shared:analytics"))) + testImplementation(project(":apps:flipcash:shared:analytics:test-fixtures")) implementation(project(":apps:flipcash:shared:appsettings")) implementation(project(":apps:flipcash:shared:google-play-billing")) implementation(project(":apps:flipcash:shared:featureflags")) diff --git a/apps/flipcash/shared/tokens/build.gradle.kts b/apps/flipcash/shared/tokens/build.gradle.kts index e7825e9269..18842e020e 100644 --- a/apps/flipcash/shared/tokens/build.gradle.kts +++ b/apps/flipcash/shared/tokens/build.gradle.kts @@ -25,7 +25,7 @@ dependencies { implementation(project(":apps:flipcash:shared:funding")) implementation(project(":apps:flipcash:shared:transaction-history")) implementation(project(":apps:flipcash:shared:analytics")) - testImplementation(testFixtures(project(":apps:flipcash:shared:analytics"))) + testImplementation(project(":apps:flipcash:shared:analytics:test-fixtures")) implementation(project(":apps:flipcash:shared:featureflags")) implementation(project(":apps:flipcash:shared:onramp:coinbase")) implementation(project(":apps:flipcash:shared:onramp:deeplinks")) diff --git a/apps/flipcash/shared/userflags/src/test/kotlin/com/flipcash/app/userflags/FieldOverrideTest.kt b/apps/flipcash/shared/userflags/src/androidHostTest/kotlin/com/flipcash/app/userflags/FieldOverrideTest.kt similarity index 100% rename from apps/flipcash/shared/userflags/src/test/kotlin/com/flipcash/app/userflags/FieldOverrideTest.kt rename to apps/flipcash/shared/userflags/src/androidHostTest/kotlin/com/flipcash/app/userflags/FieldOverrideTest.kt diff --git a/apps/flipcash/shared/userflags/src/test/kotlin/com/flipcash/app/userflags/ResolvedFlagTest.kt b/apps/flipcash/shared/userflags/src/androidHostTest/kotlin/com/flipcash/app/userflags/ResolvedFlagTest.kt similarity index 100% rename from apps/flipcash/shared/userflags/src/test/kotlin/com/flipcash/app/userflags/ResolvedFlagTest.kt rename to apps/flipcash/shared/userflags/src/androidHostTest/kotlin/com/flipcash/app/userflags/ResolvedFlagTest.kt diff --git a/apps/flipcash/shared/userflags/src/test/kotlin/com/flipcash/app/userflags/ResolvedUserFlagsTest.kt b/apps/flipcash/shared/userflags/src/androidHostTest/kotlin/com/flipcash/app/userflags/ResolvedUserFlagsTest.kt similarity index 100% rename from apps/flipcash/shared/userflags/src/test/kotlin/com/flipcash/app/userflags/ResolvedUserFlagsTest.kt rename to apps/flipcash/shared/userflags/src/androidHostTest/kotlin/com/flipcash/app/userflags/ResolvedUserFlagsTest.kt diff --git a/apps/flipcash/shared/userflags/src/test/kotlin/com/flipcash/app/userflags/UsernameGateTest.kt b/apps/flipcash/shared/userflags/src/androidHostTest/kotlin/com/flipcash/app/userflags/UsernameGateTest.kt similarity index 100% rename from apps/flipcash/shared/userflags/src/test/kotlin/com/flipcash/app/userflags/UsernameGateTest.kt rename to apps/flipcash/shared/userflags/src/androidHostTest/kotlin/com/flipcash/app/userflags/UsernameGateTest.kt diff --git a/apps/flipcash/shared/userflags/src/main/res/values/strings.xml b/apps/flipcash/shared/userflags/src/androidMain/res/values/strings.xml similarity index 100% rename from apps/flipcash/shared/userflags/src/main/res/values/strings.xml rename to apps/flipcash/shared/userflags/src/androidMain/res/values/strings.xml diff --git a/apps/flipcash/shared/userflags/src/main/kotlin/com/flipcash/app/userflags/Field.kt b/apps/flipcash/shared/userflags/src/commonMain/kotlin/com/flipcash/app/userflags/Field.kt similarity index 100% rename from apps/flipcash/shared/userflags/src/main/kotlin/com/flipcash/app/userflags/Field.kt rename to apps/flipcash/shared/userflags/src/commonMain/kotlin/com/flipcash/app/userflags/Field.kt diff --git a/apps/flipcash/shared/userflags/src/main/kotlin/com/flipcash/app/userflags/FieldEditor.kt b/apps/flipcash/shared/userflags/src/commonMain/kotlin/com/flipcash/app/userflags/FieldEditor.kt similarity index 100% rename from apps/flipcash/shared/userflags/src/main/kotlin/com/flipcash/app/userflags/FieldEditor.kt rename to apps/flipcash/shared/userflags/src/commonMain/kotlin/com/flipcash/app/userflags/FieldEditor.kt diff --git a/apps/flipcash/shared/userflags/src/main/kotlin/com/flipcash/app/userflags/FieldOverride.kt b/apps/flipcash/shared/userflags/src/commonMain/kotlin/com/flipcash/app/userflags/FieldOverride.kt similarity index 100% rename from apps/flipcash/shared/userflags/src/main/kotlin/com/flipcash/app/userflags/FieldOverride.kt rename to apps/flipcash/shared/userflags/src/commonMain/kotlin/com/flipcash/app/userflags/FieldOverride.kt diff --git a/apps/flipcash/shared/userflags/src/main/kotlin/com/flipcash/app/userflags/ResolvedUserFlags.kt b/apps/flipcash/shared/userflags/src/commonMain/kotlin/com/flipcash/app/userflags/ResolvedUserFlags.kt similarity index 100% rename from apps/flipcash/shared/userflags/src/main/kotlin/com/flipcash/app/userflags/ResolvedUserFlags.kt rename to apps/flipcash/shared/userflags/src/commonMain/kotlin/com/flipcash/app/userflags/ResolvedUserFlags.kt diff --git a/apps/flipcash/shared/userflags/src/main/kotlin/com/flipcash/app/userflags/UserFlagsCoordinator.kt b/apps/flipcash/shared/userflags/src/commonMain/kotlin/com/flipcash/app/userflags/UserFlagsCoordinator.kt similarity index 100% rename from apps/flipcash/shared/userflags/src/main/kotlin/com/flipcash/app/userflags/UserFlagsCoordinator.kt rename to apps/flipcash/shared/userflags/src/commonMain/kotlin/com/flipcash/app/userflags/UserFlagsCoordinator.kt diff --git a/apps/flipcash/shared/userflags/src/main/kotlin/com/flipcash/app/userflags/UsernameGate.kt b/apps/flipcash/shared/userflags/src/commonMain/kotlin/com/flipcash/app/userflags/UsernameGate.kt similarity index 100% rename from apps/flipcash/shared/userflags/src/main/kotlin/com/flipcash/app/userflags/UsernameGate.kt rename to apps/flipcash/shared/userflags/src/commonMain/kotlin/com/flipcash/app/userflags/UsernameGate.kt diff --git a/settings.gradle.kts b/settings.gradle.kts index 6f3b8c4dee..593daac175 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -124,6 +124,7 @@ include( ":apps:flipcash:shared:amount-entry", ":apps:flipcash:shared:accesskey", ":apps:flipcash:shared:analytics", + ":apps:flipcash:shared:analytics:test-fixtures", ":apps:flipcash:shared:appsettings", ":apps:flipcash:shared:authentication", ":apps:flipcash:shared:activityfeed", diff --git a/ui/navigation/src/androidMain/kotlin/com/getcode/view/BaseViewModel.kt b/ui/navigation/src/commonMain/kotlin/com/getcode/view/BaseViewModel.kt similarity index 100% rename from ui/navigation/src/androidMain/kotlin/com/getcode/view/BaseViewModel.kt rename to ui/navigation/src/commonMain/kotlin/com/getcode/view/BaseViewModel.kt From 924470c4aee896a4be61b6564d9c8434f8f4b9bb Mon Sep 17 00:00:00 2001 From: Brandon McAnsh Date: Fri, 23 Oct 2026 18:30:49 -0400 Subject: [PATCH 20/50] build(userflags): move shared:userflags to android+jvm KMP Flag labels sit behind a FlagStrings expect object (Android keeps the R.string ids; desktop has no flag editor). UserFlagsFiles replaces the Context parameter so the DataStore file comes from the platform. --- .../shared/userflags/build.gradle.kts | 56 ++++++++++++------- .../app/userflags/AndroidUserFlagsFiles.kt | 14 +++++ .../app/userflags/FlagStrings.android.kt | 26 +++++++++ .../app/userflags/inject/UserFlagsModule.kt | 15 +++++ .../com/flipcash/app/userflags/Field.kt | 41 +++++++------- .../com/flipcash/app/userflags/FlagStrings.kt | 28 ++++++++++ .../app/userflags/UserFlagsCoordinator.kt | 13 ++--- .../flipcash/app/userflags/UserFlagsFiles.kt | 12 ++++ .../flipcash/app/userflags/FlagStrings.jvm.kt | 24 ++++++++ gradle/libs.versions.toml | 1 + 10 files changed, 182 insertions(+), 48 deletions(-) create mode 100644 apps/flipcash/shared/userflags/src/androidMain/kotlin/com/flipcash/app/userflags/AndroidUserFlagsFiles.kt create mode 100644 apps/flipcash/shared/userflags/src/androidMain/kotlin/com/flipcash/app/userflags/FlagStrings.android.kt create mode 100644 apps/flipcash/shared/userflags/src/androidMain/kotlin/com/flipcash/app/userflags/inject/UserFlagsModule.kt create mode 100644 apps/flipcash/shared/userflags/src/commonMain/kotlin/com/flipcash/app/userflags/FlagStrings.kt create mode 100644 apps/flipcash/shared/userflags/src/commonMain/kotlin/com/flipcash/app/userflags/UserFlagsFiles.kt create mode 100644 apps/flipcash/shared/userflags/src/jvmMain/kotlin/com/flipcash/app/userflags/FlagStrings.jvm.kt diff --git a/apps/flipcash/shared/userflags/build.gradle.kts b/apps/flipcash/shared/userflags/build.gradle.kts index 38e90ecf0e..365a0bfbf0 100644 --- a/apps/flipcash/shared/userflags/build.gradle.kts +++ b/apps/flipcash/shared/userflags/build.gradle.kts @@ -1,27 +1,45 @@ plugins { - alias(libs.plugins.flipcash.android.library.compose) - alias(libs.plugins.kotlin.serialization) + alias(libs.plugins.flipcash.kmp.app.library) + alias(libs.plugins.compose.compiler) + alias(libs.plugins.kotlin.ksp) } -android { - namespace = "${Gradle.flipcashNamespace}.shared.userflags" -} +kotlin { + android { + namespace = "${Gradle.flipcashNamespace}.shared.userflags" + androidResources { enable = true } + } -dependencies { - implementation(libs.bundles.hilt) - implementation(libs.androidx.datastore) - implementation(libs.compose.foundation) - implementation(libs.compose.ui.text) - implementation(libs.kotlinx.serialization.json) + sourceSets { + commonMain.dependencies { + implementation(libs.jetbrains.compose.runtime) + implementation(libs.jetbrains.compose.foundation) + implementation(libs.androidx.annotation) + implementation(libs.androidx.datastore.preferences.core) + implementation(libs.javax.inject) + implementation(libs.kotlinx.serialization.json) - implementation(project(":libs:coroutines")) - implementation(project(":libs:datetime")) - implementation(project(":libs:messaging")) + implementation(project(":libs:coroutines")) + implementation(project(":libs:datetime")) + implementation(project(":libs:messaging")) + implementation(project(":libs:currency-math")) - implementation(project(":services:flipcash")) - implementation(project(":services:opencode")) + implementation(project(":services:flipcash")) + implementation(project(":services:opencode")) + } + androidMain.dependencies { + implementation(libs.bundles.hilt) + implementation(libs.androidx.datastore) + } + getByName("androidHostTest").dependencies { + implementation(kotlin("test")) + implementation(libs.bundles.unit.testing) + implementation(libs.mockito.kotlin) + } + } +} - testImplementation(kotlin("test")) - testImplementation(libs.bundles.unit.testing) - testImplementation(libs.mockito.kotlin) +dependencies { + add("kspAndroid", libs.hilt.android.compiler) + add("kspAndroid", libs.hilt.compiler) } diff --git a/apps/flipcash/shared/userflags/src/androidMain/kotlin/com/flipcash/app/userflags/AndroidUserFlagsFiles.kt b/apps/flipcash/shared/userflags/src/androidMain/kotlin/com/flipcash/app/userflags/AndroidUserFlagsFiles.kt new file mode 100644 index 0000000000..af9e6aad23 --- /dev/null +++ b/apps/flipcash/shared/userflags/src/androidMain/kotlin/com/flipcash/app/userflags/AndroidUserFlagsFiles.kt @@ -0,0 +1,14 @@ +package com.flipcash.app.userflags + +import android.content.Context +import androidx.datastore.preferences.preferencesDataStoreFile +import dagger.hilt.android.qualifiers.ApplicationContext +import java.io.File +import javax.inject.Inject + +internal class AndroidUserFlagsFiles @Inject constructor( + @param:ApplicationContext private val context: Context, +) : UserFlagsFiles { + override val noBackupDir: File get() = context.noBackupFilesDir + override fun dataStoreFile(name: String): File = context.preferencesDataStoreFile(name) +} diff --git a/apps/flipcash/shared/userflags/src/androidMain/kotlin/com/flipcash/app/userflags/FlagStrings.android.kt b/apps/flipcash/shared/userflags/src/androidMain/kotlin/com/flipcash/app/userflags/FlagStrings.android.kt new file mode 100644 index 0000000000..bf9407fcfc --- /dev/null +++ b/apps/flipcash/shared/userflags/src/androidMain/kotlin/com/flipcash/app/userflags/FlagStrings.android.kt @@ -0,0 +1,26 @@ +package com.flipcash.app.userflags + +import com.flipcash.shared.userflags.R + +internal actual object FlagStrings { + actual val hint_flag_billExchangeDataTimeout: Int = R.string.hint_flag_billExchangeDataTimeout + actual val hint_flag_messageDeleteWindow: Int = R.string.hint_flag_messageDeleteWindow + actual val hint_flag_messageEditWindow: Int = R.string.hint_flag_messageEditWindow + actual val hint_flag_minHolderAmount: Int = R.string.hint_flag_minHolderAmount + actual val hint_flag_minimumVersion: Int = R.string.hint_flag_minimumVersion + actual val hint_flag_newCurrencyFeeAmount: Int = R.string.hint_flag_newCurrencyFeeAmount + actual val hint_flag_newCurrencyPurchaseAmount: Int = R.string.hint_flag_newCurrencyPurchaseAmount + actual val hint_flag_withdrawalFeeAmount: Int = R.string.hint_flag_withdrawalFeeAmount + actual val label_flag_billExchangeDataTimeout: Int = R.string.label_flag_billExchangeDataTimeout + actual val label_flag_messageDeleteWindow: Int = R.string.label_flag_messageDeleteWindow + actual val label_flag_messageEditWindow: Int = R.string.label_flag_messageEditWindow + actual val label_flag_minHolderAmount: Int = R.string.label_flag_minHolderAmount + actual val label_flag_minimumVersion: Int = R.string.label_flag_minimumVersion + actual val label_flag_newCurrencyFeeAmount: Int = R.string.label_flag_newCurrencyFeeAmount + actual val label_flag_newCurrencyPurchaseAmount: Int = R.string.label_flag_newCurrencyPurchaseAmount + actual val label_flag_preferredProvider: Int = R.string.label_flag_preferredProvider + actual val label_flag_preferredUsdcLiquidityPool: Int = R.string.label_flag_preferredUsdcLiquidityPool + actual val label_flag_requireCoinbaseEmailVerification: Int = R.string.label_flag_requireCoinbaseEmailVerification + actual val label_flag_supportedOnRampProviders: Int = R.string.label_flag_supportedOnRampProviders + actual val label_flag_withdrawalFeeAmount: Int = R.string.label_flag_withdrawalFeeAmount +} diff --git a/apps/flipcash/shared/userflags/src/androidMain/kotlin/com/flipcash/app/userflags/inject/UserFlagsModule.kt b/apps/flipcash/shared/userflags/src/androidMain/kotlin/com/flipcash/app/userflags/inject/UserFlagsModule.kt new file mode 100644 index 0000000000..bbceea8a1e --- /dev/null +++ b/apps/flipcash/shared/userflags/src/androidMain/kotlin/com/flipcash/app/userflags/inject/UserFlagsModule.kt @@ -0,0 +1,15 @@ +package com.flipcash.app.userflags.inject + +import com.flipcash.app.userflags.AndroidUserFlagsFiles +import com.flipcash.app.userflags.UserFlagsFiles +import dagger.Binds +import dagger.Module +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent + +@Module +@InstallIn(SingletonComponent::class) +internal abstract class UserFlagsModule { + @Binds + abstract fun bindUserFlagsFiles(impl: AndroidUserFlagsFiles): UserFlagsFiles +} diff --git a/apps/flipcash/shared/userflags/src/commonMain/kotlin/com/flipcash/app/userflags/Field.kt b/apps/flipcash/shared/userflags/src/commonMain/kotlin/com/flipcash/app/userflags/Field.kt index 833a8bf162..6f94b50caa 100644 --- a/apps/flipcash/shared/userflags/src/commonMain/kotlin/com/flipcash/app/userflags/Field.kt +++ b/apps/flipcash/shared/userflags/src/commonMain/kotlin/com/flipcash/app/userflags/Field.kt @@ -14,7 +14,6 @@ import androidx.datastore.preferences.core.stringSetPreferencesKey import com.flipcash.services.internal.model.thirdparty.OnRampProvider import com.flipcash.services.internal.model.thirdparty.OnRampType import com.flipcash.services.internal.model.thirdparty.UsdcLiquidtyPool -import com.flipcash.shared.userflags.R import com.getcode.opencode.model.financial.Fiat import kotlin.time.Duration import kotlin.time.Duration.Companion.milliseconds @@ -35,7 +34,7 @@ sealed class Field( stringPreferencesKey("override_preferred_provider"), encode = { it?.encode() ?: "None" }, decode = { decodeOnRampProvider(it) }, - label = R.string.label_flag_preferredProvider, + label = FlagStrings.label_flag_preferredProvider, format = { provider -> provider?.displayName() ?: "None" }, editor = FieldEditor.SingleSelect( options = listOf( @@ -57,7 +56,7 @@ sealed class Field( else -> "${providers.size} selected" } }, - label = R.string.label_flag_supportedOnRampProviders, + label = FlagStrings.label_flag_supportedOnRampProviders, editor = FieldEditor.MultiSelect( options = listOf( "Manual Deposit" to OnRampProvider.ManualDeposit, @@ -71,8 +70,8 @@ sealed class Field( intPreferencesKey("override_min_version"), encode = { it ?: 0 }, decode = { it }, - label = R.string.label_flag_minimumVersion, - hint = R.string.hint_flag_minimumVersion, + label = FlagStrings.label_flag_minimumVersion, + hint = FlagStrings.hint_flag_minimumVersion, format = { it.toString() }, editor = FieldEditor.TextInput( keyboard = KeyboardType.Number, @@ -87,8 +86,8 @@ sealed class Field( longPreferencesKey("override_bill_timeout"), encode = { it?.inWholeMilliseconds ?: -1L }, decode = { if (it < 0) null else it.milliseconds }, - label = R.string.label_flag_billExchangeDataTimeout, - hint = R.string.hint_flag_billExchangeDataTimeout, + label = FlagStrings.label_flag_billExchangeDataTimeout, + hint = FlagStrings.hint_flag_billExchangeDataTimeout, format = { it?.let { "${it.inWholeSeconds}s" } ?: "None" }, editFormat = { it?.inWholeSeconds?.toString() ?: "" }, editor = FieldEditor.TextInput( @@ -109,8 +108,8 @@ sealed class Field( longPreferencesKey("override_message_edit_window"), encode = { it?.inWholeMilliseconds ?: -1L }, decode = { if (it < 0) null else it.milliseconds }, - label = R.string.label_flag_messageEditWindow, - hint = R.string.hint_flag_messageEditWindow, + label = FlagStrings.label_flag_messageEditWindow, + hint = FlagStrings.hint_flag_messageEditWindow, format = { it?.let { "${it.inWholeSeconds}s" } ?: "None" }, editFormat = { it?.inWholeSeconds?.toString() ?: "" }, editor = FieldEditor.TextInput( @@ -126,8 +125,8 @@ sealed class Field( longPreferencesKey("override_message_delete_window"), encode = { it?.inWholeMilliseconds ?: -1L }, decode = { if (it < 0) null else it.milliseconds }, - label = R.string.label_flag_messageDeleteWindow, - hint = R.string.hint_flag_messageDeleteWindow, + label = FlagStrings.label_flag_messageDeleteWindow, + hint = FlagStrings.hint_flag_messageDeleteWindow, format = { it?.let { "${it.inWholeSeconds}s" } ?: "None" }, editFormat = { it?.inWholeSeconds?.toString() ?: "" }, editor = FieldEditor.TextInput( @@ -143,8 +142,8 @@ sealed class Field( longPreferencesKey("override_new_currency_amount"), encode = { it.quarks }, decode = { Fiat(quarks = it) }, - label = R.string.label_flag_newCurrencyPurchaseAmount, - hint = R.string.hint_flag_newCurrencyPurchaseAmount, + label = FlagStrings.label_flag_newCurrencyPurchaseAmount, + hint = FlagStrings.hint_flag_newCurrencyPurchaseAmount, format = { it.formatted(rule = Fiat.FormattingRule.Truncated) }, editFormat = { it.formatted(showPrefix = false, rule = Fiat.FormattingRule.Truncated) }, editor = FieldEditor.TextInput( @@ -162,8 +161,8 @@ sealed class Field( longPreferencesKey("override_new_fee_amount"), encode = { it.quarks }, decode = { Fiat(quarks = it) }, - label = R.string.label_flag_newCurrencyFeeAmount, - hint = R.string.hint_flag_newCurrencyFeeAmount, + label = FlagStrings.label_flag_newCurrencyFeeAmount, + hint = FlagStrings.hint_flag_newCurrencyFeeAmount, format = { it.formatted(rule = Fiat.FormattingRule.Truncated) }, editFormat = { it.formatted(showPrefix = false, rule = Fiat.FormattingRule.Truncated) }, editor = FieldEditor.TextInput( @@ -181,8 +180,8 @@ sealed class Field( longPreferencesKey("override_withdrawal_fee_amount"), encode = { it.quarks }, decode = { Fiat(quarks = it) }, - label = R.string.label_flag_withdrawalFeeAmount, - hint = R.string.hint_flag_withdrawalFeeAmount, + label = FlagStrings.label_flag_withdrawalFeeAmount, + hint = FlagStrings.hint_flag_withdrawalFeeAmount, format = { it.formatted(rule = Fiat.FormattingRule.Truncated) }, editFormat = { it.formatted(showPrefix = false, rule = Fiat.FormattingRule.Truncated) }, editor = FieldEditor.TextInput( @@ -200,7 +199,7 @@ sealed class Field( stringPreferencesKey("override_preferred_liquidity_pool"), encode = { it.name }, decode = { runCatching { UsdcLiquidtyPool.valueOf(it) }.getOrNull() }, - label = R.string.label_flag_preferredUsdcLiquidityPool, + label = FlagStrings.label_flag_preferredUsdcLiquidityPool, format = { provider -> provider.displayName() }, editor = FieldEditor.SingleSelect( options = listOf( @@ -214,7 +213,7 @@ sealed class Field( booleanPreferencesKey("override_require_coinbase_email_verification"), encode = { it }, decode = { it }, - label = R.string.label_flag_requireCoinbaseEmailVerification, + label = FlagStrings.label_flag_requireCoinbaseEmailVerification, format = { if (it) "Yes" else "No" }, editor = FieldEditor.SingleSelect( options = listOf("Yes" to true, "No" to false) @@ -225,8 +224,8 @@ sealed class Field( longPreferencesKey("override_min_holder_amount"), encode = { it.quarks }, decode = { Fiat(quarks = it) }, - label = R.string.label_flag_minHolderAmount, - hint = R.string.hint_flag_minHolderAmount, + label = FlagStrings.label_flag_minHolderAmount, + hint = FlagStrings.hint_flag_minHolderAmount, format = { it.formatted(rule = Fiat.FormattingRule.Truncated) }, editFormat = { it.formatted(showPrefix = false, rule = Fiat.FormattingRule.Truncated) }, editor = FieldEditor.TextInput( diff --git a/apps/flipcash/shared/userflags/src/commonMain/kotlin/com/flipcash/app/userflags/FlagStrings.kt b/apps/flipcash/shared/userflags/src/commonMain/kotlin/com/flipcash/app/userflags/FlagStrings.kt new file mode 100644 index 0000000000..f7923bed81 --- /dev/null +++ b/apps/flipcash/shared/userflags/src/commonMain/kotlin/com/flipcash/app/userflags/FlagStrings.kt @@ -0,0 +1,28 @@ +package com.flipcash.app.userflags + +/** + * String resource ids for the debug flag editor's labels and hints. Android reads them from + * this module's `R`; desktop has no flag editor, so its ids are 0. + */ +internal expect object FlagStrings { + val hint_flag_billExchangeDataTimeout: Int + val hint_flag_messageDeleteWindow: Int + val hint_flag_messageEditWindow: Int + val hint_flag_minHolderAmount: Int + val hint_flag_minimumVersion: Int + val hint_flag_newCurrencyFeeAmount: Int + val hint_flag_newCurrencyPurchaseAmount: Int + val hint_flag_withdrawalFeeAmount: Int + val label_flag_billExchangeDataTimeout: Int + val label_flag_messageDeleteWindow: Int + val label_flag_messageEditWindow: Int + val label_flag_minHolderAmount: Int + val label_flag_minimumVersion: Int + val label_flag_newCurrencyFeeAmount: Int + val label_flag_newCurrencyPurchaseAmount: Int + val label_flag_preferredProvider: Int + val label_flag_preferredUsdcLiquidityPool: Int + val label_flag_requireCoinbaseEmailVerification: Int + val label_flag_supportedOnRampProviders: Int + val label_flag_withdrawalFeeAmount: Int +} diff --git a/apps/flipcash/shared/userflags/src/commonMain/kotlin/com/flipcash/app/userflags/UserFlagsCoordinator.kt b/apps/flipcash/shared/userflags/src/commonMain/kotlin/com/flipcash/app/userflags/UserFlagsCoordinator.kt index 04a5c91e03..fb9bb49c9c 100644 --- a/apps/flipcash/shared/userflags/src/commonMain/kotlin/com/flipcash/app/userflags/UserFlagsCoordinator.kt +++ b/apps/flipcash/shared/userflags/src/commonMain/kotlin/com/flipcash/app/userflags/UserFlagsCoordinator.kt @@ -1,12 +1,10 @@ package com.flipcash.app.userflags -import android.content.Context import androidx.datastore.core.handlers.ReplaceFileCorruptionHandler import androidx.datastore.preferences.core.PreferenceDataStoreFactory import androidx.datastore.preferences.core.edit import androidx.datastore.preferences.core.emptyPreferences import androidx.datastore.preferences.core.stringPreferencesKey -import androidx.datastore.preferences.preferencesDataStoreFile import com.flipcash.libs.coroutines.DispatcherProvider import com.flipcash.services.internal.model.thirdparty.OnRampProvider import com.flipcash.services.internal.model.thirdparty.OnRampType @@ -16,7 +14,6 @@ import com.flipcash.services.models.UserFlags import com.flipcash.services.user.UserManager import com.getcode.opencode.model.financial.CurrencyCode import com.getcode.opencode.model.financial.Fiat -import dagger.hilt.android.qualifiers.ApplicationContext import java.io.File import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.SupervisorJob @@ -38,7 +35,7 @@ import kotlin.time.Duration.Companion.milliseconds @Singleton class UserFlagsCoordinator @Inject constructor( - @param:ApplicationContext private val context: Context, + private val files: UserFlagsFiles, private val userManager: UserManager, dispatchers: DispatcherProvider, ) { @@ -80,9 +77,9 @@ class UserFlagsCoordinator @Inject constructor( init { // Delete the backing file before DataStore reads it to avoid a race // where stale overrides restored from backup are briefly visible. - val marker = File(context.noBackupFilesDir, "user-flag-overrides-initialized") + val marker = File(files.noBackupDir, "user-flag-overrides-initialized") if (!marker.exists()) { - context.preferencesDataStoreFile("user-flag-overrides").delete() + files.dataStoreFile("user-flag-overrides").delete() marker.createNewFile() } @@ -98,7 +95,7 @@ class UserFlagsCoordinator @Inject constructor( private val dataStore = PreferenceDataStoreFactory.create( corruptionHandler = ReplaceFileCorruptionHandler { emptyPreferences() }, scope = scope, - produceFile = { context.preferencesDataStoreFile("user-flag-overrides") } + produceFile = { files.dataStoreFile("user-flag-overrides") } ) // Parse DataStore prefs → Overrides @@ -145,7 +142,7 @@ class UserFlagsCoordinator @Inject constructor( private val cacheDataStore = PreferenceDataStoreFactory.create( corruptionHandler = ReplaceFileCorruptionHandler { emptyPreferences() }, scope = scope, - produceFile = { context.preferencesDataStoreFile("cached-user-flags") } + produceFile = { files.dataStoreFile("cached-user-flags") } ) suspend fun restoreFlags() { diff --git a/apps/flipcash/shared/userflags/src/commonMain/kotlin/com/flipcash/app/userflags/UserFlagsFiles.kt b/apps/flipcash/shared/userflags/src/commonMain/kotlin/com/flipcash/app/userflags/UserFlagsFiles.kt new file mode 100644 index 0000000000..b61b3e6949 --- /dev/null +++ b/apps/flipcash/shared/userflags/src/commonMain/kotlin/com/flipcash/app/userflags/UserFlagsFiles.kt @@ -0,0 +1,12 @@ +package com.flipcash.app.userflags + +import java.io.File + +/** Where [UserFlagsCoordinator] keeps its DataStore files and its first-run marker. */ +interface UserFlagsFiles { + /** Directory excluded from backup, for the first-run marker. */ + val noBackupDir: File + + /** The file backing the preferences DataStore called [name]. */ + fun dataStoreFile(name: String): File +} diff --git a/apps/flipcash/shared/userflags/src/jvmMain/kotlin/com/flipcash/app/userflags/FlagStrings.jvm.kt b/apps/flipcash/shared/userflags/src/jvmMain/kotlin/com/flipcash/app/userflags/FlagStrings.jvm.kt new file mode 100644 index 0000000000..5e9c5fbd6d --- /dev/null +++ b/apps/flipcash/shared/userflags/src/jvmMain/kotlin/com/flipcash/app/userflags/FlagStrings.jvm.kt @@ -0,0 +1,24 @@ +package com.flipcash.app.userflags + +internal actual object FlagStrings { + actual val hint_flag_billExchangeDataTimeout: Int = 0 + actual val hint_flag_messageDeleteWindow: Int = 0 + actual val hint_flag_messageEditWindow: Int = 0 + actual val hint_flag_minHolderAmount: Int = 0 + actual val hint_flag_minimumVersion: Int = 0 + actual val hint_flag_newCurrencyFeeAmount: Int = 0 + actual val hint_flag_newCurrencyPurchaseAmount: Int = 0 + actual val hint_flag_withdrawalFeeAmount: Int = 0 + actual val label_flag_billExchangeDataTimeout: Int = 0 + actual val label_flag_messageDeleteWindow: Int = 0 + actual val label_flag_messageEditWindow: Int = 0 + actual val label_flag_minHolderAmount: Int = 0 + actual val label_flag_minimumVersion: Int = 0 + actual val label_flag_newCurrencyFeeAmount: Int = 0 + actual val label_flag_newCurrencyPurchaseAmount: Int = 0 + actual val label_flag_preferredProvider: Int = 0 + actual val label_flag_preferredUsdcLiquidityPool: Int = 0 + actual val label_flag_requireCoinbaseEmailVerification: Int = 0 + actual val label_flag_supportedOnRampProviders: Int = 0 + actual val label_flag_withdrawalFeeAmount: Int = 0 +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index a21628234f..f9356a8896 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -167,6 +167,7 @@ androidx-sqlite-bundled = { module = "androidx.sqlite:sqlite-bundled", version.r androidx-work = { module = "androidx.work:work-runtime", version.ref = "androidx-work" } androidx-work-testing = { module = "androidx.work:work-testing", version.ref = "androidx-work" } androidx-datastore = { module = "androidx.datastore:datastore-preferences", version.ref = "androidx-datastore" } +androidx-datastore-preferences-core = { module = "androidx.datastore:datastore-preferences-core", version.ref = "androidx-datastore" } androidx-webkit = { module = "androidx.webkit:webkit", version.ref = "androidx-webkit" } sqlcipher = { module = "net.zetetic:android-database-sqlcipher", version.ref = "sqlcipher" } From 90afa5e6438c72dd8ad9dd670b0b478bf5cbbd6a Mon Sep 17 00:00:00 2001 From: Brandon McAnsh Date: Fri, 23 Oct 2026 18:37:16 -0400 Subject: [PATCH 21/50] build(core): lift AppRoute and flow step types to common AppRoute, its step and result types, DeviceContact and TipCardOwner move to app:core's commonMain with the shared Parcelable aliases. The three files that use Uri or R (CurrencyCreatorDraft, TokenDisplayName, DeeplinkType) stay in androidMain. FlowRoute moves to ui:navigation's commonMain. ui:resources adds stringRes/pluralStringRes for composables that hold an Int resource ID, and lets other modules register their own Compose resources with ComposeResourceIds to get an Int ID on desktop. --- apps/flipcash/core/build.gradle.kts | 6 +++ .../kotlin/com/flipcash/app/core/AppRoute.kt | 4 +- .../flipcash/app/core/chat/ChatIdentifier.kt | 4 +- .../flipcash/app/core/chat/ChatParticipant.kt | 4 +- .../com/flipcash/app/core/chat/ChatStep.kt | 4 +- .../flipcash/app/core/chat/DmDestination.kt | 0 .../flipcash/app/core/chat/NewGroupStep.kt | 4 +- .../flipcash/app/core/chat/ProfileAddress.kt | 4 +- .../flipcash/app/core/chat/ReportSubject.kt | 4 +- .../app/core/contacts/DeviceContact.kt | 4 +- .../app/core/deposit/DepositResult.kt | 4 +- .../flipcash/app/core/deposit/DepositStep.kt | 4 +- .../app/core/extensions/CodeNavigator.kt | 0 .../app/core/navigation/DeeplinkAction.kt | 0 .../flipcash/app/core/navigation/HomeRoute.kt | 0 .../app/core/navigation/LocalTabBarPadding.kt | 0 .../app/core/navigation/NavBarButton.kt | 0 .../app/core/navigation/NavBarRoutes.kt | 0 .../app/core/navigation/SteppedFlowRoute.kt | 2 +- .../app/core/navigation/TabBarVisibility.kt | 0 .../app/core/onboarding/OnboardingStep.kt | 4 +- .../flipcash/app/core/reporting/ReportStep.kt | 4 +- .../flipcash/app/core/tipping/TipCardOwner.kt | 0 .../app/core/tokens/CurrencyCreatorResult.kt | 4 +- .../app/core/tokens/CurrencyCreatorStep.kt | 4 +- .../flipcash/app/core/tokens/SwapResult.kt | 4 +- .../com/flipcash/app/core/tokens/SwapStep.kt | 4 +- .../app/core/tokens/TokenInfoEntry.kt | 4 +- .../flipcash/app/core/tokens/TokenPurpose.kt | 4 +- .../app/core/tokens/TokenSwapPurpose.kt | 4 +- .../core/userprofile/UpdateProfileResult.kt | 4 +- .../app/core/userprofile/UpdateProfileStep.kt | 4 +- .../core/verification/VerificationResult.kt | 4 +- .../app/core/verification/VerificationStep.kt | 4 +- .../app/core/withdrawal/WithdrawalResult.kt | 4 +- .../app/core/withdrawal/WithdrawalStep.kt | 4 +- .../com/getcode/navigation/flow/FlowRoute.kt | 0 .../util/resources/StringRes.android.kt | 15 +++++++ .../com/getcode/util/resources/StringRes.kt | 18 ++++++++ .../util/resources/ComposeResourceIds.kt | 45 +++++++++++++++++-- .../getcode/util/resources/StringRes.jvm.kt | 16 +++++++ 41 files changed, 147 insertions(+), 55 deletions(-) rename apps/flipcash/core/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/AppRoute.kt (99%) rename apps/flipcash/core/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/chat/ChatIdentifier.kt (93%) rename apps/flipcash/core/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/chat/ChatParticipant.kt (95%) rename apps/flipcash/core/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/chat/ChatStep.kt (99%) rename apps/flipcash/core/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/chat/DmDestination.kt (100%) rename apps/flipcash/core/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/chat/NewGroupStep.kt (95%) rename apps/flipcash/core/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/chat/ProfileAddress.kt (94%) rename apps/flipcash/core/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/chat/ReportSubject.kt (93%) rename apps/flipcash/core/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/contacts/DeviceContact.kt (89%) rename apps/flipcash/core/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/deposit/DepositResult.kt (76%) rename apps/flipcash/core/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/deposit/DepositStep.kt (87%) rename apps/flipcash/core/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/extensions/CodeNavigator.kt (100%) rename apps/flipcash/core/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/navigation/DeeplinkAction.kt (100%) rename apps/flipcash/core/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/navigation/HomeRoute.kt (100%) rename apps/flipcash/core/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/navigation/LocalTabBarPadding.kt (100%) rename apps/flipcash/core/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/navigation/NavBarButton.kt (100%) rename apps/flipcash/core/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/navigation/NavBarRoutes.kt (100%) rename apps/flipcash/core/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/navigation/SteppedFlowRoute.kt (93%) rename apps/flipcash/core/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/navigation/TabBarVisibility.kt (100%) rename apps/flipcash/core/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/onboarding/OnboardingStep.kt (94%) rename apps/flipcash/core/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/reporting/ReportStep.kt (94%) rename apps/flipcash/core/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/tipping/TipCardOwner.kt (100%) rename apps/flipcash/core/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/tokens/CurrencyCreatorResult.kt (83%) rename apps/flipcash/core/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/tokens/CurrencyCreatorStep.kt (94%) rename apps/flipcash/core/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/tokens/SwapResult.kt (86%) rename apps/flipcash/core/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/tokens/SwapStep.kt (95%) rename apps/flipcash/core/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/tokens/TokenInfoEntry.kt (97%) rename apps/flipcash/core/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/tokens/TokenPurpose.kt (93%) rename apps/flipcash/core/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/tokens/TokenSwapPurpose.kt (94%) rename apps/flipcash/core/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/userprofile/UpdateProfileResult.kt (80%) rename apps/flipcash/core/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/userprofile/UpdateProfileStep.kt (94%) rename apps/flipcash/core/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/verification/VerificationResult.kt (80%) rename apps/flipcash/core/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/verification/VerificationStep.kt (91%) rename apps/flipcash/core/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/withdrawal/WithdrawalResult.kt (76%) rename apps/flipcash/core/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/withdrawal/WithdrawalStep.kt (90%) rename ui/navigation/src/{androidMain => commonMain}/kotlin/com/getcode/navigation/flow/FlowRoute.kt (100%) create mode 100644 ui/resources/src/androidMain/kotlin/com/getcode/util/resources/StringRes.android.kt create mode 100644 ui/resources/src/commonMain/kotlin/com/getcode/util/resources/StringRes.kt create mode 100644 ui/resources/src/jvmMain/kotlin/com/getcode/util/resources/StringRes.jvm.kt diff --git a/apps/flipcash/core/build.gradle.kts b/apps/flipcash/core/build.gradle.kts index 0967c1843a..3deb1a4c65 100644 --- a/apps/flipcash/core/build.gradle.kts +++ b/apps/flipcash/core/build.gradle.kts @@ -14,9 +14,15 @@ kotlin { sourceSets { commonMain.dependencies { + implementation(project(":libs:parcelable")) + api(project(":ui:navigation")) + api(project(":ui:core")) + api(libs.navigation3.runtime) implementation(libs.kotlinx.serialization.core) implementation(libs.kotlinx.serialization.json) implementation(libs.jetbrains.compose.runtime) + implementation(libs.jetbrains.compose.foundation) + api(project(":libs:reporting")) api(project(":services:flipcash")) api(project(":services:opencode")) diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/AppRoute.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/AppRoute.kt similarity index 99% rename from apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/AppRoute.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/AppRoute.kt index 03254b422e..52b268b1d9 100644 --- a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/AppRoute.kt +++ b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/AppRoute.kt @@ -1,6 +1,6 @@ package com.flipcash.app.core -import android.os.Parcelable +import com.getcode.libs.parcelable.Parcelable import androidx.navigation3.runtime.NavKey import com.flipcash.app.core.chat.ChatIdentifier import com.flipcash.app.core.chat.ChatStep @@ -36,7 +36,7 @@ import com.getcode.opencode.model.core.ID import com.getcode.opencode.model.financial.Fiat import com.getcode.solana.keys.Mint import com.getcode.ui.core.RestrictionType -import kotlinx.parcelize.Parcelize +import com.getcode.libs.parcelable.Parcelize import kotlinx.serialization.Serializable import kotlin.reflect.KClass diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/chat/ChatIdentifier.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/chat/ChatIdentifier.kt similarity index 93% rename from apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/chat/ChatIdentifier.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/chat/ChatIdentifier.kt index d6dfd7347d..fac5c262f2 100644 --- a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/chat/ChatIdentifier.kt +++ b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/chat/ChatIdentifier.kt @@ -1,12 +1,12 @@ package com.flipcash.app.core.chat -import android.os.Parcelable +import com.getcode.libs.parcelable.Parcelable import com.flipcash.app.core.contacts.DeviceContact import com.flipcash.services.models.UserProfile import com.flipcash.services.models.chat.ChatId import com.getcode.opencode.model.core.ID import com.getcode.utils.hexEncodedString -import kotlinx.parcelize.Parcelize +import com.getcode.libs.parcelable.Parcelize import kotlinx.serialization.Serializable @Serializable diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/chat/ChatParticipant.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/chat/ChatParticipant.kt similarity index 95% rename from apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/chat/ChatParticipant.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/chat/ChatParticipant.kt index 930ebb662f..3ada98b8a7 100644 --- a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/chat/ChatParticipant.kt +++ b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/chat/ChatParticipant.kt @@ -1,12 +1,12 @@ package com.flipcash.app.core.chat -import android.os.Parcelable +import com.getcode.libs.parcelable.Parcelable import com.flipcash.app.core.contacts.DeviceContact import com.flipcash.services.models.UserProfile import com.flipcash.services.models.handle import com.flipcash.services.models.nameOrHandle import com.getcode.opencode.model.core.ID -import kotlinx.parcelize.Parcelize +import com.getcode.libs.parcelable.Parcelize /** * The counterparty a DM header and info card renders. diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/chat/ChatStep.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/chat/ChatStep.kt similarity index 99% rename from apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/chat/ChatStep.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/chat/ChatStep.kt index 4cdc7d4694..40fc67cfff 100644 --- a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/chat/ChatStep.kt +++ b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/chat/ChatStep.kt @@ -1,13 +1,13 @@ package com.flipcash.app.core.chat -import android.os.Parcelable +import com.getcode.libs.parcelable.Parcelable import com.flipcash.services.models.chat.ChatId import com.getcode.navigation.HalfSheet import com.getcode.navigation.Sheet import com.getcode.navigation.WrapContentSheet import com.getcode.navigation.flow.FlowStep import com.getcode.navigation.results.NavigationRetVal -import kotlinx.parcelize.Parcelize +import com.getcode.libs.parcelable.Parcelize import kotlinx.serialization.Serializable @Parcelize diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/chat/DmDestination.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/chat/DmDestination.kt similarity index 100% rename from apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/chat/DmDestination.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/chat/DmDestination.kt diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/chat/NewGroupStep.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/chat/NewGroupStep.kt similarity index 95% rename from apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/chat/NewGroupStep.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/chat/NewGroupStep.kt index 99cf40f50b..121789a5fb 100644 --- a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/chat/NewGroupStep.kt +++ b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/chat/NewGroupStep.kt @@ -1,9 +1,9 @@ package com.flipcash.app.core.chat -import android.os.Parcelable +import com.getcode.libs.parcelable.Parcelable import com.getcode.navigation.Sheet import com.getcode.navigation.flow.FlowStep -import kotlinx.parcelize.Parcelize +import com.getcode.libs.parcelable.Parcelize import kotlinx.serialization.Serializable /** diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/chat/ProfileAddress.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/chat/ProfileAddress.kt similarity index 94% rename from apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/chat/ProfileAddress.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/chat/ProfileAddress.kt index 810aac7056..9b87c95d4c 100644 --- a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/chat/ProfileAddress.kt +++ b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/chat/ProfileAddress.kt @@ -1,9 +1,9 @@ package com.flipcash.app.core.chat -import android.os.Parcelable +import com.getcode.libs.parcelable.Parcelable import com.flipcash.app.core.tipping.TipCardOwner import com.getcode.opencode.model.core.ID -import kotlinx.parcelize.Parcelize +import com.getcode.libs.parcelable.Parcelize import kotlinx.serialization.Serializable /** diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/chat/ReportSubject.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/chat/ReportSubject.kt similarity index 93% rename from apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/chat/ReportSubject.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/chat/ReportSubject.kt index 3a11b14a5d..434f8e5f97 100644 --- a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/chat/ReportSubject.kt +++ b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/chat/ReportSubject.kt @@ -1,9 +1,9 @@ package com.flipcash.app.core.chat -import android.os.Parcelable +import com.getcode.libs.parcelable.Parcelable import com.flipcash.services.models.chat.ChatId import com.getcode.opencode.model.core.ID -import kotlinx.parcelize.Parcelize +import com.getcode.libs.parcelable.Parcelize import kotlinx.serialization.Serializable /** diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/contacts/DeviceContact.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/contacts/DeviceContact.kt similarity index 89% rename from apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/contacts/DeviceContact.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/contacts/DeviceContact.kt index fa7f12aafa..2cfcbe5268 100644 --- a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/contacts/DeviceContact.kt +++ b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/contacts/DeviceContact.kt @@ -1,7 +1,7 @@ package com.flipcash.app.core.contacts -import android.os.Parcelable -import kotlinx.parcelize.Parcelize +import com.getcode.libs.parcelable.Parcelable +import com.getcode.libs.parcelable.Parcelize import kotlinx.serialization.Serializable @Serializable diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/deposit/DepositResult.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/deposit/DepositResult.kt similarity index 76% rename from apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/deposit/DepositResult.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/deposit/DepositResult.kt index 87010430d3..e9b5764cf6 100644 --- a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/deposit/DepositResult.kt +++ b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/deposit/DepositResult.kt @@ -1,7 +1,7 @@ package com.flipcash.app.core.deposit -import android.os.Parcelable -import kotlinx.parcelize.Parcelize +import com.getcode.libs.parcelable.Parcelable +import com.getcode.libs.parcelable.Parcelize import kotlinx.serialization.Serializable @Serializable diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/deposit/DepositStep.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/deposit/DepositStep.kt similarity index 87% rename from apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/deposit/DepositStep.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/deposit/DepositStep.kt index 8cb18871f2..1e5bfb56d7 100644 --- a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/deposit/DepositStep.kt +++ b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/deposit/DepositStep.kt @@ -1,9 +1,9 @@ package com.flipcash.app.core.deposit -import android.os.Parcelable +import com.getcode.libs.parcelable.Parcelable import com.getcode.navigation.flow.FlowStep import com.getcode.solana.keys.Mint -import kotlinx.parcelize.Parcelize +import com.getcode.libs.parcelable.Parcelize import kotlinx.serialization.Serializable /** diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/extensions/CodeNavigator.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/extensions/CodeNavigator.kt similarity index 100% rename from apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/extensions/CodeNavigator.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/extensions/CodeNavigator.kt diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/navigation/DeeplinkAction.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/navigation/DeeplinkAction.kt similarity index 100% rename from apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/navigation/DeeplinkAction.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/navigation/DeeplinkAction.kt diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/navigation/HomeRoute.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/navigation/HomeRoute.kt similarity index 100% rename from apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/navigation/HomeRoute.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/navigation/HomeRoute.kt diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/navigation/LocalTabBarPadding.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/navigation/LocalTabBarPadding.kt similarity index 100% rename from apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/navigation/LocalTabBarPadding.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/navigation/LocalTabBarPadding.kt diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/navigation/NavBarButton.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/navigation/NavBarButton.kt similarity index 100% rename from apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/navigation/NavBarButton.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/navigation/NavBarButton.kt diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/navigation/NavBarRoutes.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/navigation/NavBarRoutes.kt similarity index 100% rename from apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/navigation/NavBarRoutes.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/navigation/NavBarRoutes.kt diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/navigation/SteppedFlowRoute.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/navigation/SteppedFlowRoute.kt similarity index 93% rename from apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/navigation/SteppedFlowRoute.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/navigation/SteppedFlowRoute.kt index 9e08de1e33..df3248c1cb 100644 --- a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/navigation/SteppedFlowRoute.kt +++ b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/navigation/SteppedFlowRoute.kt @@ -1,6 +1,6 @@ package com.flipcash.app.core.navigation -import android.os.Parcelable +import com.getcode.libs.parcelable.Parcelable import com.getcode.navigation.flow.FlowRouteWithResult import com.getcode.navigation.flow.FlowStep import kotlin.reflect.KClass diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/navigation/TabBarVisibility.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/navigation/TabBarVisibility.kt similarity index 100% rename from apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/navigation/TabBarVisibility.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/navigation/TabBarVisibility.kt diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/onboarding/OnboardingStep.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/onboarding/OnboardingStep.kt similarity index 94% rename from apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/onboarding/OnboardingStep.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/onboarding/OnboardingStep.kt index 318fcaf3f0..6b1a657c25 100644 --- a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/onboarding/OnboardingStep.kt +++ b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/onboarding/OnboardingStep.kt @@ -1,9 +1,9 @@ package com.flipcash.app.core.onboarding -import android.os.Parcelable +import com.getcode.libs.parcelable.Parcelable import com.getcode.navigation.NonDismissableRoute import com.getcode.navigation.flow.FlowStep -import kotlinx.parcelize.Parcelize +import com.getcode.libs.parcelable.Parcelize import kotlinx.serialization.Serializable /** diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/reporting/ReportStep.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/reporting/ReportStep.kt similarity index 94% rename from apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/reporting/ReportStep.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/reporting/ReportStep.kt index 3e09d6d291..af5b1ab24f 100644 --- a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/reporting/ReportStep.kt +++ b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/reporting/ReportStep.kt @@ -1,10 +1,10 @@ package com.flipcash.app.core.reporting -import android.os.Parcelable +import com.getcode.libs.parcelable.Parcelable import com.flipcash.reporting.ReportReason import com.getcode.navigation.NonDraggableRoute import com.getcode.navigation.flow.FlowStep -import kotlinx.parcelize.Parcelize +import com.getcode.libs.parcelable.Parcelize import kotlinx.serialization.Serializable /** diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/tipping/TipCardOwner.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/tipping/TipCardOwner.kt similarity index 100% rename from apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/tipping/TipCardOwner.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/tipping/TipCardOwner.kt diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/tokens/CurrencyCreatorResult.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/tokens/CurrencyCreatorResult.kt similarity index 83% rename from apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/tokens/CurrencyCreatorResult.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/tokens/CurrencyCreatorResult.kt index 6c52cc5465..4a6593d935 100644 --- a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/tokens/CurrencyCreatorResult.kt +++ b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/tokens/CurrencyCreatorResult.kt @@ -1,7 +1,7 @@ package com.flipcash.app.core.tokens -import android.os.Parcelable -import kotlinx.parcelize.Parcelize +import com.getcode.libs.parcelable.Parcelable +import com.getcode.libs.parcelable.Parcelize import kotlinx.serialization.Serializable @Serializable diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/tokens/CurrencyCreatorStep.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/tokens/CurrencyCreatorStep.kt similarity index 94% rename from apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/tokens/CurrencyCreatorStep.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/tokens/CurrencyCreatorStep.kt index eaa999df84..54b83cc212 100644 --- a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/tokens/CurrencyCreatorStep.kt +++ b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/tokens/CurrencyCreatorStep.kt @@ -1,12 +1,12 @@ package com.flipcash.app.core.tokens -import android.os.Parcelable +import com.getcode.libs.parcelable.Parcelable import com.getcode.navigation.NonDismissableRoute import com.getcode.navigation.NonDraggableRoute import com.getcode.navigation.flow.FlowStep import com.getcode.opencode.model.financial.Fiat import com.getcode.opencode.model.ui.TokenBillCustomizations -import kotlinx.parcelize.Parcelize +import com.getcode.libs.parcelable.Parcelize import kotlinx.serialization.Serializable @Serializable diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/tokens/SwapResult.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/tokens/SwapResult.kt similarity index 86% rename from apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/tokens/SwapResult.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/tokens/SwapResult.kt index bd1d82c74f..daedc148d2 100644 --- a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/tokens/SwapResult.kt +++ b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/tokens/SwapResult.kt @@ -1,8 +1,8 @@ package com.flipcash.app.core.tokens -import android.os.Parcelable +import com.getcode.libs.parcelable.Parcelable import com.getcode.opencode.model.financial.Fiat -import kotlinx.parcelize.Parcelize +import com.getcode.libs.parcelable.Parcelize import kotlinx.serialization.Serializable @Serializable diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/tokens/SwapStep.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/tokens/SwapStep.kt similarity index 95% rename from apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/tokens/SwapStep.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/tokens/SwapStep.kt index bc29cc68c1..4bfd249cd5 100644 --- a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/tokens/SwapStep.kt +++ b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/tokens/SwapStep.kt @@ -1,6 +1,6 @@ package com.flipcash.app.core.tokens -import android.os.Parcelable +import com.getcode.libs.parcelable.Parcelable import com.getcode.navigation.HalfSheet import com.getcode.navigation.NonDismissableRoute import com.getcode.navigation.NonDraggableRoute @@ -9,7 +9,7 @@ import com.getcode.navigation.WrapContentSheet import com.getcode.navigation.flow.FlowStep import com.getcode.opencode.internal.solana.model.SwapId import com.getcode.opencode.model.financial.Fiat -import kotlinx.parcelize.Parcelize +import com.getcode.libs.parcelable.Parcelize import kotlinx.serialization.Serializable @Serializable diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/tokens/TokenInfoEntry.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/tokens/TokenInfoEntry.kt similarity index 97% rename from apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/tokens/TokenInfoEntry.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/tokens/TokenInfoEntry.kt index 3fcc0b9cde..8cda25dec3 100644 --- a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/tokens/TokenInfoEntry.kt +++ b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/tokens/TokenInfoEntry.kt @@ -1,8 +1,8 @@ package com.flipcash.app.core.tokens -import android.os.Parcelable +import com.getcode.libs.parcelable.Parcelable import com.getcode.solana.keys.Mint -import kotlinx.parcelize.Parcelize +import com.getcode.libs.parcelable.Parcelize import kotlinx.serialization.Serializable /** diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/tokens/TokenPurpose.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/tokens/TokenPurpose.kt similarity index 93% rename from apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/tokens/TokenPurpose.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/tokens/TokenPurpose.kt index ad73d2af65..ba0d49364b 100644 --- a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/tokens/TokenPurpose.kt +++ b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/tokens/TokenPurpose.kt @@ -1,9 +1,9 @@ package com.flipcash.app.core.tokens -import android.os.Parcelable +import com.getcode.libs.parcelable.Parcelable import com.getcode.opencode.model.financial.Fiat import com.getcode.solana.keys.Mint -import kotlinx.parcelize.Parcelize +import com.getcode.libs.parcelable.Parcelize import kotlinx.serialization.Serializable @Serializable diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/tokens/TokenSwapPurpose.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/tokens/TokenSwapPurpose.kt similarity index 94% rename from apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/tokens/TokenSwapPurpose.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/tokens/TokenSwapPurpose.kt index d45cae9721..46241a1aa2 100644 --- a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/tokens/TokenSwapPurpose.kt +++ b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/tokens/TokenSwapPurpose.kt @@ -1,8 +1,8 @@ package com.flipcash.app.core.tokens -import android.os.Parcelable +import com.getcode.libs.parcelable.Parcelable import com.getcode.solana.keys.Mint -import kotlinx.parcelize.Parcelize +import com.getcode.libs.parcelable.Parcelize import kotlinx.serialization.Serializable /** diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/userprofile/UpdateProfileResult.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/userprofile/UpdateProfileResult.kt similarity index 80% rename from apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/userprofile/UpdateProfileResult.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/userprofile/UpdateProfileResult.kt index ecbd0ce6c7..86c2968f8a 100644 --- a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/userprofile/UpdateProfileResult.kt +++ b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/userprofile/UpdateProfileResult.kt @@ -1,7 +1,7 @@ package com.flipcash.app.core.userprofile -import android.os.Parcelable -import kotlinx.parcelize.Parcelize +import com.getcode.libs.parcelable.Parcelable +import com.getcode.libs.parcelable.Parcelize import kotlinx.serialization.Serializable /** diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/userprofile/UpdateProfileStep.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/userprofile/UpdateProfileStep.kt similarity index 94% rename from apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/userprofile/UpdateProfileStep.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/userprofile/UpdateProfileStep.kt index f355f0592e..850d354f29 100644 --- a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/userprofile/UpdateProfileStep.kt +++ b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/userprofile/UpdateProfileStep.kt @@ -1,9 +1,9 @@ package com.flipcash.app.core.userprofile -import android.os.Parcelable +import com.getcode.libs.parcelable.Parcelable import com.flipcash.app.core.DisplayNameSource import com.getcode.navigation.flow.FlowStep -import kotlinx.parcelize.Parcelize +import com.getcode.libs.parcelable.Parcelize import kotlinx.serialization.Serializable /** diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/verification/VerificationResult.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/verification/VerificationResult.kt similarity index 80% rename from apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/verification/VerificationResult.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/verification/VerificationResult.kt index dbe23df81c..7b921f846f 100644 --- a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/verification/VerificationResult.kt +++ b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/verification/VerificationResult.kt @@ -1,7 +1,7 @@ package com.flipcash.app.core.verification -import android.os.Parcelable -import kotlinx.parcelize.Parcelize +import com.getcode.libs.parcelable.Parcelable +import com.getcode.libs.parcelable.Parcelize import kotlinx.serialization.Serializable /** diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/verification/VerificationStep.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/verification/VerificationStep.kt similarity index 91% rename from apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/verification/VerificationStep.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/verification/VerificationStep.kt index 76e85dd9e0..a3053071ea 100644 --- a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/verification/VerificationStep.kt +++ b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/verification/VerificationStep.kt @@ -1,8 +1,8 @@ package com.flipcash.app.core.verification -import android.os.Parcelable +import com.getcode.libs.parcelable.Parcelable import com.getcode.navigation.flow.FlowStep -import kotlinx.parcelize.Parcelize +import com.getcode.libs.parcelable.Parcelize import kotlinx.serialization.Serializable /** diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/withdrawal/WithdrawalResult.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/withdrawal/WithdrawalResult.kt similarity index 76% rename from apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/withdrawal/WithdrawalResult.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/withdrawal/WithdrawalResult.kt index 951379a37f..f7ca5b6492 100644 --- a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/withdrawal/WithdrawalResult.kt +++ b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/withdrawal/WithdrawalResult.kt @@ -1,7 +1,7 @@ package com.flipcash.app.core.withdrawal -import android.os.Parcelable -import kotlinx.parcelize.Parcelize +import com.getcode.libs.parcelable.Parcelable +import com.getcode.libs.parcelable.Parcelize import kotlinx.serialization.Serializable @Serializable diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/withdrawal/WithdrawalStep.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/withdrawal/WithdrawalStep.kt similarity index 90% rename from apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/withdrawal/WithdrawalStep.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/withdrawal/WithdrawalStep.kt index 2500725704..c9fb525778 100644 --- a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/withdrawal/WithdrawalStep.kt +++ b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/withdrawal/WithdrawalStep.kt @@ -1,10 +1,10 @@ package com.flipcash.app.core.withdrawal -import android.os.Parcelable +import com.getcode.libs.parcelable.Parcelable import com.getcode.navigation.flow.FlowStep import com.getcode.opencode.internal.solana.model.SwapId import com.getcode.solana.keys.Mint -import kotlinx.parcelize.Parcelize +import com.getcode.libs.parcelable.Parcelize import kotlinx.serialization.Serializable /** diff --git a/ui/navigation/src/androidMain/kotlin/com/getcode/navigation/flow/FlowRoute.kt b/ui/navigation/src/commonMain/kotlin/com/getcode/navigation/flow/FlowRoute.kt similarity index 100% rename from ui/navigation/src/androidMain/kotlin/com/getcode/navigation/flow/FlowRoute.kt rename to ui/navigation/src/commonMain/kotlin/com/getcode/navigation/flow/FlowRoute.kt diff --git a/ui/resources/src/androidMain/kotlin/com/getcode/util/resources/StringRes.android.kt b/ui/resources/src/androidMain/kotlin/com/getcode/util/resources/StringRes.android.kt new file mode 100644 index 0000000000..5819f8d2f9 --- /dev/null +++ b/ui/resources/src/androidMain/kotlin/com/getcode/util/resources/StringRes.android.kt @@ -0,0 +1,15 @@ +package com.getcode.util.resources + +import androidx.compose.runtime.Composable +import androidx.compose.ui.res.pluralStringResource +import androidx.compose.ui.res.stringResource + +@Composable +actual fun stringRes(id: Int): String = stringResource(id) + +@Composable +actual fun stringRes(id: Int, vararg formatArgs: Any): String = stringResource(id, *formatArgs) + +@Composable +actual fun pluralStringRes(id: Int, count: Int, vararg formatArgs: Any): String = + pluralStringResource(id, count, *formatArgs) diff --git a/ui/resources/src/commonMain/kotlin/com/getcode/util/resources/StringRes.kt b/ui/resources/src/commonMain/kotlin/com/getcode/util/resources/StringRes.kt new file mode 100644 index 0000000000..5bb17bec3e --- /dev/null +++ b/ui/resources/src/commonMain/kotlin/com/getcode/util/resources/StringRes.kt @@ -0,0 +1,18 @@ +package com.getcode.util.resources + +import androidx.annotation.PluralsRes +import androidx.annotation.StringRes +import androidx.compose.runtime.Composable + +/** + * Reads the string behind a resource ID in composition. On Android these are `R.string` values; + * on desktop they come from [ResourceHelper.getIdentifier] or a module's string table. + */ +@Composable +expect fun stringRes(@StringRes id: Int): String + +@Composable +expect fun stringRes(@StringRes id: Int, vararg formatArgs: Any): String + +@Composable +expect fun pluralStringRes(@PluralsRes id: Int, count: Int, vararg formatArgs: Any): String diff --git a/ui/resources/src/jvmMain/kotlin/com/getcode/util/resources/ComposeResourceIds.kt b/ui/resources/src/jvmMain/kotlin/com/getcode/util/resources/ComposeResourceIds.kt index 898ed8033f..9a15779c2c 100644 --- a/ui/resources/src/jvmMain/kotlin/com/getcode/util/resources/ComposeResourceIds.kt +++ b/ui/resources/src/jvmMain/kotlin/com/getcode/util/resources/ComposeResourceIds.kt @@ -6,23 +6,60 @@ import org.jetbrains.compose.resources.StringResource /** * Stable `Int` IDs for the generated Compose resources, so desktop can serve the `Int`-keyed - * [ResourceHelper] API. Each resource type gets its own range, ordered by resource name. + * [ResourceHelper] API. + * + * `ui:resources`' own resources get fixed ranges ordered by name. Other modules keep their own + * `Res` class and register each resource they hand out, getting an ID from a separate range. */ object ComposeResourceIds { private const val DRAWABLE_BASE = 0x7f010000 private const val STRING_BASE = 0x7f020000 private const val PLURAL_BASE = 0x7f030000 + private const val REGISTERED_DRAWABLE_BASE = 0x7f040000 + private const val REGISTERED_STRING_BASE = 0x7f050000 + private const val REGISTERED_PLURAL_BASE = 0x7f060000 + private const val RANGE = 0x10000 private val drawables: List> by lazy { Res.allDrawableResources.toSortedList() } private val strings: List> by lazy { Res.allStringResources.toSortedList() } private val plurals: List> by lazy { Res.allPluralStringResources.toSortedList() } + private val registeredDrawables = Registry(REGISTERED_DRAWABLE_BASE) + private val registeredStrings = Registry(REGISTERED_STRING_BASE) + private val registeredPlurals = Registry(REGISTERED_PLURAL_BASE) + fun drawableId(name: String): Int? = drawables.indexOfName(name)?.plus(DRAWABLE_BASE) fun stringId(name: String): Int? = strings.indexOfName(name)?.plus(STRING_BASE) - fun drawable(id: Int): DrawableResource = drawables.at(id - DRAWABLE_BASE, id) - fun string(id: Int): StringResource = strings.at(id - STRING_BASE, id) - fun plural(id: Int): PluralStringResource = plurals.at(id - PLURAL_BASE, id) + fun register(resource: DrawableResource): Int = registeredDrawables.idOf(resource) + fun register(resource: StringResource): Int = registeredStrings.idOf(resource) + fun register(resource: PluralStringResource): Int = registeredPlurals.idOf(resource) + + fun drawable(id: Int): DrawableResource = + if (id.inRange(REGISTERED_DRAWABLE_BASE)) registeredDrawables[id] else drawables.at(id - DRAWABLE_BASE, id) + + fun string(id: Int): StringResource = + if (id.inRange(REGISTERED_STRING_BASE)) registeredStrings[id] else strings.at(id - STRING_BASE, id) + + fun plural(id: Int): PluralStringResource = + if (id.inRange(REGISTERED_PLURAL_BASE)) registeredPlurals[id] else plurals.at(id - PLURAL_BASE, id) + + private fun Int.inRange(base: Int) = this >= base && this < base + RANGE + + private class Registry(private val base: Int) { + private val ids = HashMap() + private val resources = ArrayList() + + @Synchronized + fun idOf(resource: T): Int = ids.getOrPut(resource) { + resources.add(resource) + base + resources.size - 1 + } + + @Synchronized + operator fun get(id: Int): T = resources.getOrNull(id - base) + ?: throw IllegalArgumentException("No Compose resource for ID 0x${id.toString(16)}") + } private fun Map.toSortedList() = entries.sortedBy { it.key }.map { it.key to it.value } diff --git a/ui/resources/src/jvmMain/kotlin/com/getcode/util/resources/StringRes.jvm.kt b/ui/resources/src/jvmMain/kotlin/com/getcode/util/resources/StringRes.jvm.kt new file mode 100644 index 0000000000..6e9a8f1313 --- /dev/null +++ b/ui/resources/src/jvmMain/kotlin/com/getcode/util/resources/StringRes.jvm.kt @@ -0,0 +1,16 @@ +package com.getcode.util.resources + +import androidx.compose.runtime.Composable +import org.jetbrains.compose.resources.pluralStringResource +import org.jetbrains.compose.resources.stringResource + +@Composable +actual fun stringRes(id: Int): String = stringResource(ComposeResourceIds.string(id)) + +@Composable +actual fun stringRes(id: Int, vararg formatArgs: Any): String = + stringResource(ComposeResourceIds.string(id), *formatArgs) + +@Composable +actual fun pluralStringRes(id: Int, count: Int, vararg formatArgs: Any): String = + pluralStringResource(ComposeResourceIds.plural(id), count, *formatArgs) From 57f1d91cdc085e17d80b8898a9f508ff9b886737 Mon Sep 17 00:00:00 2001 From: Brandon McAnsh Date: Fri, 23 Oct 2026 18:46:50 -0400 Subject: [PATCH 22/50] build(core-ui): move core-ui to android+jvm KMP and lift balance-path composables Lifts the nine composables the balance screen and activity feed render (TileButton, TokenCard, TokenCardStack, TokenImageWithName, ViewerAmount, ActivityAmount, CurrencyAppreciationLabel, FlagWithFiat, NewUserTutorial) to commonMain. Everything else stays in androidMain unchanged. Seams: screenHeightPx (Configuration on Android, window container on desktop) and ImageRequestPlaceholders for Coil placeholders. Flags load through painterForResId. app:core exposes its res/ as Compose resources and gains CoreStrings/CoreDrawables id objects for the lifted files. opencode-compose moves to KMP with LocalExchange in commonMain. --- apps/flipcash/core-ui/build.gradle.kts | 62 +++++++++++++++---- .../ui/NavigationBarAvatarScreenshotTest.kt | 0 .../app/core/ui/NavigationBarLongPressTest.kt | 0 .../core/ui/TokenCardStackPlacementTest.kt | 0 .../ui/TokenCardWatermarkScreenshotTest.kt | 0 .../flipcash/app/core/ui/ViewerAmountTest.kt | 0 .../app/core/ui/flow/FlowProgressTest.kt | 0 .../ui/previews/AppBarTitlePreviews.kt | 0 .../internal/ui/previews/ButtonPreviews.kt | 0 .../internal/ui/previews/CalloutPreviews.kt | 0 .../flipcash/app/core/ui/AmountWithKeypad.kt | 0 .../app/core/ui/BrandedGradientIcon.kt | 0 .../com/flipcash/app/core/ui/Callout.kt | 0 .../flipcash/app/core/ui/ConfirmationStyle.kt | 0 .../flipcash/app/core/ui/ConversionGraphic.kt | 0 .../flipcash/app/core/ui/CurrencyHolder.kt | 0 .../com/flipcash/app/core/ui/DeviceFrame.kt | 0 .../flipcash/app/core/ui/DisplayTextInput.kt | 0 .../ui/ImageRequestPlaceholders.android.kt | 8 +++ .../com/flipcash/app/core/ui/NavigationBar.kt | 0 .../app/core/ui/NotificationPreview.kt | 0 .../flipcash/app/core/ui/NotifyButtonLabel.kt | 0 .../flipcash/app/core/ui/ReceiptLineItem.kt | 0 .../app/core/ui/ScreenHeight.android.kt | 11 ++++ .../com/flipcash/app/core/ui/Skeleton.kt | 0 .../com/flipcash/app/core/ui/SwitchPreview.kt | 0 .../flipcash/app/core/ui/TokenBalanceRow.kt | 0 .../app/core/ui/TokenSelectionPill.kt | 0 .../flipcash/app/core/ui/flow/FlowProgress.kt | 0 .../flipcash/app/core/ui/flow/FlowStepBar.kt | 0 .../app/core/ui/flow/FlowStepBarController.kt | 0 .../flipcash/app/core/ui/flow/FlowStepper.kt | 0 .../app/core/ui/flow/SteppedFlowScaffold.kt | 2 +- .../ui/processing/FlowProcessingScreen.kt | 0 .../processing/ProcessingLoadingIndicator.kt | 0 .../ui/transitions/CardExpandTransition.kt | 0 .../core/ui/transitions/FocusWhenSettled.kt | 0 .../core/ui/transitions/SharedTransitions.kt | 0 .../flipcash/app/core/ui/ActivityAmount.kt | 0 .../app/core/ui/CurrencyAppreciationLabel.kt | 12 ++-- .../com/flipcash/app/core/ui/FlagWithFiat.kt | 4 +- .../app/core/ui/ImageRequestPlaceholders.kt | 6 ++ .../com/flipcash/app/core/ui/ScreenHeight.kt | 7 +++ .../com/flipcash/app/core/ui/TileButton.kt | 0 .../com/flipcash/app/core/ui/TokenCard.kt | 0 .../flipcash/app/core/ui/TokenCardStack.kt | 5 +- .../app/core/ui/TokenImageWithName.kt | 4 +- .../com/flipcash/app/core/ui/ViewerAmount.kt | 0 .../app/core/ui/onboarding/NewUserTutorial.kt | 21 ++++--- .../core/ui/ImageRequestPlaceholders.jvm.kt | 6 ++ .../flipcash/app/core/ui/ScreenHeight.jvm.kt | 7 +++ apps/flipcash/core/build.gradle.kts | 14 +++++ .../core/resources/CoreResources.android.kt | 22 +++++++ .../flipcash/app/core/money/FormatUtils.kt | 0 .../app/core/resources/CoreResources.kt | 25 ++++++++ .../app/core/resources/CoreResources.jvm.kt | 33 ++++++++++ services/opencode-compose/build.gradle.kts | 29 +++------ .../getcode/opencode/compose/ExchangeStub.kt | 0 .../com/getcode/opencode/compose/Exchange.kt | 0 59 files changed, 222 insertions(+), 56 deletions(-) rename apps/flipcash/core-ui/src/{test => androidHostTest}/kotlin/com/flipcash/app/core/ui/NavigationBarAvatarScreenshotTest.kt (100%) rename apps/flipcash/core-ui/src/{test => androidHostTest}/kotlin/com/flipcash/app/core/ui/NavigationBarLongPressTest.kt (100%) rename apps/flipcash/core-ui/src/{test => androidHostTest}/kotlin/com/flipcash/app/core/ui/TokenCardStackPlacementTest.kt (100%) rename apps/flipcash/core-ui/src/{test => androidHostTest}/kotlin/com/flipcash/app/core/ui/TokenCardWatermarkScreenshotTest.kt (100%) rename apps/flipcash/core-ui/src/{test => androidHostTest}/kotlin/com/flipcash/app/core/ui/ViewerAmountTest.kt (100%) rename apps/flipcash/core-ui/src/{test => androidHostTest}/kotlin/com/flipcash/app/core/ui/flow/FlowProgressTest.kt (100%) rename apps/flipcash/core-ui/src/{main => androidMain}/kotlin/com/flipcash/app/core/internal/ui/previews/AppBarTitlePreviews.kt (100%) rename apps/flipcash/core-ui/src/{main => androidMain}/kotlin/com/flipcash/app/core/internal/ui/previews/ButtonPreviews.kt (100%) rename apps/flipcash/core-ui/src/{main => androidMain}/kotlin/com/flipcash/app/core/internal/ui/previews/CalloutPreviews.kt (100%) rename apps/flipcash/core-ui/src/{main => androidMain}/kotlin/com/flipcash/app/core/ui/AmountWithKeypad.kt (100%) rename apps/flipcash/core-ui/src/{main => androidMain}/kotlin/com/flipcash/app/core/ui/BrandedGradientIcon.kt (100%) rename apps/flipcash/core-ui/src/{main => androidMain}/kotlin/com/flipcash/app/core/ui/Callout.kt (100%) rename apps/flipcash/core-ui/src/{main => androidMain}/kotlin/com/flipcash/app/core/ui/ConfirmationStyle.kt (100%) rename apps/flipcash/core-ui/src/{main => androidMain}/kotlin/com/flipcash/app/core/ui/ConversionGraphic.kt (100%) rename apps/flipcash/core-ui/src/{main => androidMain}/kotlin/com/flipcash/app/core/ui/CurrencyHolder.kt (100%) rename apps/flipcash/core-ui/src/{main => androidMain}/kotlin/com/flipcash/app/core/ui/DeviceFrame.kt (100%) rename apps/flipcash/core-ui/src/{main => androidMain}/kotlin/com/flipcash/app/core/ui/DisplayTextInput.kt (100%) create mode 100644 apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/ImageRequestPlaceholders.android.kt rename apps/flipcash/core-ui/src/{main => androidMain}/kotlin/com/flipcash/app/core/ui/NavigationBar.kt (100%) rename apps/flipcash/core-ui/src/{main => androidMain}/kotlin/com/flipcash/app/core/ui/NotificationPreview.kt (100%) rename apps/flipcash/core-ui/src/{main => androidMain}/kotlin/com/flipcash/app/core/ui/NotifyButtonLabel.kt (100%) rename apps/flipcash/core-ui/src/{main => androidMain}/kotlin/com/flipcash/app/core/ui/ReceiptLineItem.kt (100%) create mode 100644 apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/ScreenHeight.android.kt rename apps/flipcash/core-ui/src/{main => androidMain}/kotlin/com/flipcash/app/core/ui/Skeleton.kt (100%) rename apps/flipcash/core-ui/src/{main => androidMain}/kotlin/com/flipcash/app/core/ui/SwitchPreview.kt (100%) rename apps/flipcash/core-ui/src/{main => androidMain}/kotlin/com/flipcash/app/core/ui/TokenBalanceRow.kt (100%) rename apps/flipcash/core-ui/src/{main => androidMain}/kotlin/com/flipcash/app/core/ui/TokenSelectionPill.kt (100%) rename apps/flipcash/core-ui/src/{main => androidMain}/kotlin/com/flipcash/app/core/ui/flow/FlowProgress.kt (100%) rename apps/flipcash/core-ui/src/{main => androidMain}/kotlin/com/flipcash/app/core/ui/flow/FlowStepBar.kt (100%) rename apps/flipcash/core-ui/src/{main => androidMain}/kotlin/com/flipcash/app/core/ui/flow/FlowStepBarController.kt (100%) rename apps/flipcash/core-ui/src/{main => androidMain}/kotlin/com/flipcash/app/core/ui/flow/FlowStepper.kt (100%) rename apps/flipcash/core-ui/src/{main => androidMain}/kotlin/com/flipcash/app/core/ui/flow/SteppedFlowScaffold.kt (98%) rename apps/flipcash/core-ui/src/{main => androidMain}/kotlin/com/flipcash/app/core/ui/processing/FlowProcessingScreen.kt (100%) rename apps/flipcash/core-ui/src/{main => androidMain}/kotlin/com/flipcash/app/core/ui/processing/ProcessingLoadingIndicator.kt (100%) rename apps/flipcash/core-ui/src/{main => androidMain}/kotlin/com/flipcash/app/core/ui/transitions/CardExpandTransition.kt (100%) rename apps/flipcash/core-ui/src/{main => androidMain}/kotlin/com/flipcash/app/core/ui/transitions/FocusWhenSettled.kt (100%) rename apps/flipcash/core-ui/src/{main => androidMain}/kotlin/com/flipcash/app/core/ui/transitions/SharedTransitions.kt (100%) rename apps/flipcash/core-ui/src/{main => commonMain}/kotlin/com/flipcash/app/core/ui/ActivityAmount.kt (100%) rename apps/flipcash/core-ui/src/{main => commonMain}/kotlin/com/flipcash/app/core/ui/CurrencyAppreciationLabel.kt (90%) rename apps/flipcash/core-ui/src/{main => commonMain}/kotlin/com/flipcash/app/core/ui/FlagWithFiat.kt (95%) create mode 100644 apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/ImageRequestPlaceholders.kt create mode 100644 apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/ScreenHeight.kt rename apps/flipcash/core-ui/src/{main => commonMain}/kotlin/com/flipcash/app/core/ui/TileButton.kt (100%) rename apps/flipcash/core-ui/src/{main => commonMain}/kotlin/com/flipcash/app/core/ui/TokenCard.kt (100%) rename apps/flipcash/core-ui/src/{main => commonMain}/kotlin/com/flipcash/app/core/ui/TokenCardStack.kt (98%) rename apps/flipcash/core-ui/src/{main => commonMain}/kotlin/com/flipcash/app/core/ui/TokenImageWithName.kt (96%) rename apps/flipcash/core-ui/src/{main => commonMain}/kotlin/com/flipcash/app/core/ui/ViewerAmount.kt (100%) rename apps/flipcash/core-ui/src/{main => commonMain}/kotlin/com/flipcash/app/core/ui/onboarding/NewUserTutorial.kt (88%) create mode 100644 apps/flipcash/core-ui/src/jvmMain/kotlin/com/flipcash/app/core/ui/ImageRequestPlaceholders.jvm.kt create mode 100644 apps/flipcash/core-ui/src/jvmMain/kotlin/com/flipcash/app/core/ui/ScreenHeight.jvm.kt create mode 100644 apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/resources/CoreResources.android.kt rename apps/flipcash/core/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/money/FormatUtils.kt (100%) create mode 100644 apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/resources/CoreResources.kt create mode 100644 apps/flipcash/core/src/jvmMain/kotlin/com/flipcash/app/core/resources/CoreResources.jvm.kt rename services/opencode-compose/src/{main => androidMain}/kotlin/com/getcode/opencode/compose/ExchangeStub.kt (100%) rename services/opencode-compose/src/{main => commonMain}/kotlin/com/getcode/opencode/compose/Exchange.kt (100%) diff --git a/apps/flipcash/core-ui/build.gradle.kts b/apps/flipcash/core-ui/build.gradle.kts index 8e3f3d0dff..f457abba5f 100644 --- a/apps/flipcash/core-ui/build.gradle.kts +++ b/apps/flipcash/core-ui/build.gradle.kts @@ -1,18 +1,58 @@ plugins { - alias(libs.plugins.flipcash.android.feature) + alias(libs.plugins.flipcash.kmp.app.library) + alias(libs.plugins.compose.compiler) + alias(libs.plugins.kotlin.ksp) } -android { - namespace = "${Gradle.flipcashNamespace}.core.ui" -} +kotlin { + android { + namespace = "${Gradle.flipcashNamespace}.core.ui" + androidResources { + enable = true + } + } -dependencies { - implementation(project(":apps:flipcash:shared:featureflags")) + sourceSets { + commonMain.dependencies { + implementation(project(":apps:flipcash:core")) + implementation(project(":services:opencode")) + implementation(project(":services:opencode-compose")) + implementation(project(":libs:encryption:keys")) + implementation(project(":ui:components")) + implementation(project(":ui:resources")) + implementation(project(":ui:theme")) - implementation(libs.compose.material3) - implementation(libs.bundles.haze) + implementation(libs.jetbrains.compose.runtime) + implementation(libs.jetbrains.compose.foundation) + implementation(libs.jetbrains.compose.ui) + implementation(libs.jetbrains.compose.material) + implementation(libs.jetbrains.compose.material3) + implementation(libs.jetbrains.compose.material.icons.extended) + implementation(libs.coil3) + } + androidMain.dependencies { + // What flipcash.android.feature supplied before the move to KMP. + implementation(libs.bundles.hilt) + implementation(project.dependencies.platform(libs.compose.bom)) + implementation(libs.bundles.compose) + implementation(libs.rinku.compose) + implementation(project(":libs:coroutines")) + implementation(project(":libs:logging")) + implementation(project(":ui:navigation")) + implementation(project(":apps:flipcash:shared:featureflags")) - testImplementation(kotlin("test")) - testImplementation(libs.bundles.unit.testing) - testImplementation(libs.robolectric) + implementation(libs.compose.material3) + implementation(libs.bundles.haze) + } + getByName("androidHostTest").dependencies { + implementation(kotlin("test")) + implementation(libs.bundles.unit.testing) + implementation(libs.robolectric) + } + } +} + +dependencies { + add("kspAndroid", libs.hilt.android.compiler) + add("kspAndroid", libs.hilt.compiler) } diff --git a/apps/flipcash/core-ui/src/test/kotlin/com/flipcash/app/core/ui/NavigationBarAvatarScreenshotTest.kt b/apps/flipcash/core-ui/src/androidHostTest/kotlin/com/flipcash/app/core/ui/NavigationBarAvatarScreenshotTest.kt similarity index 100% rename from apps/flipcash/core-ui/src/test/kotlin/com/flipcash/app/core/ui/NavigationBarAvatarScreenshotTest.kt rename to apps/flipcash/core-ui/src/androidHostTest/kotlin/com/flipcash/app/core/ui/NavigationBarAvatarScreenshotTest.kt diff --git a/apps/flipcash/core-ui/src/test/kotlin/com/flipcash/app/core/ui/NavigationBarLongPressTest.kt b/apps/flipcash/core-ui/src/androidHostTest/kotlin/com/flipcash/app/core/ui/NavigationBarLongPressTest.kt similarity index 100% rename from apps/flipcash/core-ui/src/test/kotlin/com/flipcash/app/core/ui/NavigationBarLongPressTest.kt rename to apps/flipcash/core-ui/src/androidHostTest/kotlin/com/flipcash/app/core/ui/NavigationBarLongPressTest.kt diff --git a/apps/flipcash/core-ui/src/test/kotlin/com/flipcash/app/core/ui/TokenCardStackPlacementTest.kt b/apps/flipcash/core-ui/src/androidHostTest/kotlin/com/flipcash/app/core/ui/TokenCardStackPlacementTest.kt similarity index 100% rename from apps/flipcash/core-ui/src/test/kotlin/com/flipcash/app/core/ui/TokenCardStackPlacementTest.kt rename to apps/flipcash/core-ui/src/androidHostTest/kotlin/com/flipcash/app/core/ui/TokenCardStackPlacementTest.kt diff --git a/apps/flipcash/core-ui/src/test/kotlin/com/flipcash/app/core/ui/TokenCardWatermarkScreenshotTest.kt b/apps/flipcash/core-ui/src/androidHostTest/kotlin/com/flipcash/app/core/ui/TokenCardWatermarkScreenshotTest.kt similarity index 100% rename from apps/flipcash/core-ui/src/test/kotlin/com/flipcash/app/core/ui/TokenCardWatermarkScreenshotTest.kt rename to apps/flipcash/core-ui/src/androidHostTest/kotlin/com/flipcash/app/core/ui/TokenCardWatermarkScreenshotTest.kt diff --git a/apps/flipcash/core-ui/src/test/kotlin/com/flipcash/app/core/ui/ViewerAmountTest.kt b/apps/flipcash/core-ui/src/androidHostTest/kotlin/com/flipcash/app/core/ui/ViewerAmountTest.kt similarity index 100% rename from apps/flipcash/core-ui/src/test/kotlin/com/flipcash/app/core/ui/ViewerAmountTest.kt rename to apps/flipcash/core-ui/src/androidHostTest/kotlin/com/flipcash/app/core/ui/ViewerAmountTest.kt diff --git a/apps/flipcash/core-ui/src/test/kotlin/com/flipcash/app/core/ui/flow/FlowProgressTest.kt b/apps/flipcash/core-ui/src/androidHostTest/kotlin/com/flipcash/app/core/ui/flow/FlowProgressTest.kt similarity index 100% rename from apps/flipcash/core-ui/src/test/kotlin/com/flipcash/app/core/ui/flow/FlowProgressTest.kt rename to apps/flipcash/core-ui/src/androidHostTest/kotlin/com/flipcash/app/core/ui/flow/FlowProgressTest.kt diff --git a/apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/internal/ui/previews/AppBarTitlePreviews.kt b/apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/internal/ui/previews/AppBarTitlePreviews.kt similarity index 100% rename from apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/internal/ui/previews/AppBarTitlePreviews.kt rename to apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/internal/ui/previews/AppBarTitlePreviews.kt diff --git a/apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/internal/ui/previews/ButtonPreviews.kt b/apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/internal/ui/previews/ButtonPreviews.kt similarity index 100% rename from apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/internal/ui/previews/ButtonPreviews.kt rename to apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/internal/ui/previews/ButtonPreviews.kt diff --git a/apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/internal/ui/previews/CalloutPreviews.kt b/apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/internal/ui/previews/CalloutPreviews.kt similarity index 100% rename from apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/internal/ui/previews/CalloutPreviews.kt rename to apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/internal/ui/previews/CalloutPreviews.kt diff --git a/apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/AmountWithKeypad.kt b/apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/AmountWithKeypad.kt similarity index 100% rename from apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/AmountWithKeypad.kt rename to apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/AmountWithKeypad.kt diff --git a/apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/BrandedGradientIcon.kt b/apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/BrandedGradientIcon.kt similarity index 100% rename from apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/BrandedGradientIcon.kt rename to apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/BrandedGradientIcon.kt diff --git a/apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/Callout.kt b/apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/Callout.kt similarity index 100% rename from apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/Callout.kt rename to apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/Callout.kt diff --git a/apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/ConfirmationStyle.kt b/apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/ConfirmationStyle.kt similarity index 100% rename from apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/ConfirmationStyle.kt rename to apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/ConfirmationStyle.kt diff --git a/apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/ConversionGraphic.kt b/apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/ConversionGraphic.kt similarity index 100% rename from apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/ConversionGraphic.kt rename to apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/ConversionGraphic.kt diff --git a/apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/CurrencyHolder.kt b/apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/CurrencyHolder.kt similarity index 100% rename from apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/CurrencyHolder.kt rename to apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/CurrencyHolder.kt diff --git a/apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/DeviceFrame.kt b/apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/DeviceFrame.kt similarity index 100% rename from apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/DeviceFrame.kt rename to apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/DeviceFrame.kt diff --git a/apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/DisplayTextInput.kt b/apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/DisplayTextInput.kt similarity index 100% rename from apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/DisplayTextInput.kt rename to apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/DisplayTextInput.kt diff --git a/apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/ImageRequestPlaceholders.android.kt b/apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/ImageRequestPlaceholders.android.kt new file mode 100644 index 0000000000..89d57a79c8 --- /dev/null +++ b/apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/ImageRequestPlaceholders.android.kt @@ -0,0 +1,8 @@ +package com.flipcash.app.core.ui + +import coil3.request.ImageRequest +import coil3.request.error +import com.getcode.ui.components.R + +internal actual fun ImageRequest.Builder.errorPlaceholderUser(): ImageRequest.Builder = + error(R.drawable.ic_placeholder_user) diff --git a/apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/NavigationBar.kt b/apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/NavigationBar.kt similarity index 100% rename from apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/NavigationBar.kt rename to apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/NavigationBar.kt diff --git a/apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/NotificationPreview.kt b/apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/NotificationPreview.kt similarity index 100% rename from apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/NotificationPreview.kt rename to apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/NotificationPreview.kt diff --git a/apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/NotifyButtonLabel.kt b/apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/NotifyButtonLabel.kt similarity index 100% rename from apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/NotifyButtonLabel.kt rename to apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/NotifyButtonLabel.kt diff --git a/apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/ReceiptLineItem.kt b/apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/ReceiptLineItem.kt similarity index 100% rename from apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/ReceiptLineItem.kt rename to apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/ReceiptLineItem.kt diff --git a/apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/ScreenHeight.android.kt b/apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/ScreenHeight.android.kt new file mode 100644 index 0000000000..5ec54fe231 --- /dev/null +++ b/apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/ScreenHeight.android.kt @@ -0,0 +1,11 @@ +package com.flipcash.app.core.ui + +import androidx.compose.runtime.Composable +import androidx.compose.ui.platform.LocalConfiguration +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.unit.dp + +@Composable +internal actual fun screenHeightPx(): Float = with(LocalDensity.current) { + LocalConfiguration.current.screenHeightDp.dp.toPx() +} diff --git a/apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/Skeleton.kt b/apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/Skeleton.kt similarity index 100% rename from apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/Skeleton.kt rename to apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/Skeleton.kt diff --git a/apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/SwitchPreview.kt b/apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/SwitchPreview.kt similarity index 100% rename from apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/SwitchPreview.kt rename to apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/SwitchPreview.kt diff --git a/apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/TokenBalanceRow.kt b/apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/TokenBalanceRow.kt similarity index 100% rename from apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/TokenBalanceRow.kt rename to apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/TokenBalanceRow.kt diff --git a/apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/TokenSelectionPill.kt b/apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/TokenSelectionPill.kt similarity index 100% rename from apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/TokenSelectionPill.kt rename to apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/TokenSelectionPill.kt diff --git a/apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/flow/FlowProgress.kt b/apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/flow/FlowProgress.kt similarity index 100% rename from apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/flow/FlowProgress.kt rename to apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/flow/FlowProgress.kt diff --git a/apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/flow/FlowStepBar.kt b/apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/flow/FlowStepBar.kt similarity index 100% rename from apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/flow/FlowStepBar.kt rename to apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/flow/FlowStepBar.kt diff --git a/apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/flow/FlowStepBarController.kt b/apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/flow/FlowStepBarController.kt similarity index 100% rename from apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/flow/FlowStepBarController.kt rename to apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/flow/FlowStepBarController.kt diff --git a/apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/flow/FlowStepper.kt b/apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/flow/FlowStepper.kt similarity index 100% rename from apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/flow/FlowStepper.kt rename to apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/flow/FlowStepper.kt diff --git a/apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/flow/SteppedFlowScaffold.kt b/apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/flow/SteppedFlowScaffold.kt similarity index 98% rename from apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/flow/SteppedFlowScaffold.kt rename to apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/flow/SteppedFlowScaffold.kt index 2f84fd1be8..e1b07675dd 100644 --- a/apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/flow/SteppedFlowScaffold.kt +++ b/apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/flow/SteppedFlowScaffold.kt @@ -1,6 +1,6 @@ package com.flipcash.app.core.ui.flow -import android.os.Parcelable +import com.getcode.libs.parcelable.Parcelable import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.runtime.Composable diff --git a/apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/processing/FlowProcessingScreen.kt b/apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/processing/FlowProcessingScreen.kt similarity index 100% rename from apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/processing/FlowProcessingScreen.kt rename to apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/processing/FlowProcessingScreen.kt diff --git a/apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/processing/ProcessingLoadingIndicator.kt b/apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/processing/ProcessingLoadingIndicator.kt similarity index 100% rename from apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/processing/ProcessingLoadingIndicator.kt rename to apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/processing/ProcessingLoadingIndicator.kt diff --git a/apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/transitions/CardExpandTransition.kt b/apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/transitions/CardExpandTransition.kt similarity index 100% rename from apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/transitions/CardExpandTransition.kt rename to apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/transitions/CardExpandTransition.kt diff --git a/apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/transitions/FocusWhenSettled.kt b/apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/transitions/FocusWhenSettled.kt similarity index 100% rename from apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/transitions/FocusWhenSettled.kt rename to apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/transitions/FocusWhenSettled.kt diff --git a/apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/transitions/SharedTransitions.kt b/apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/transitions/SharedTransitions.kt similarity index 100% rename from apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/transitions/SharedTransitions.kt rename to apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/transitions/SharedTransitions.kt diff --git a/apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/ActivityAmount.kt b/apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/ActivityAmount.kt similarity index 100% rename from apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/ActivityAmount.kt rename to apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/ActivityAmount.kt diff --git a/apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/CurrencyAppreciationLabel.kt b/apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/CurrencyAppreciationLabel.kt similarity index 90% rename from apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/CurrencyAppreciationLabel.kt rename to apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/CurrencyAppreciationLabel.kt index c2ad4f5574..bc05434934 100644 --- a/apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/CurrencyAppreciationLabel.kt +++ b/apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/CurrencyAppreciationLabel.kt @@ -10,15 +10,15 @@ import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import com.flipcash.app.core.money.formattedAppreciation -import com.flipcash.core.R +import com.flipcash.app.core.resources.CoreStrings import com.getcode.opencode.model.financial.Fiat import com.getcode.theme.CodeTheme import com.getcode.theme.White20 import com.getcode.theme.extraSmall import com.getcode.ui.components.text.AnimatedNumberText +import com.getcode.util.resources.stringRes /** Controls the visual treatment of the appreciation badge. */ enum class AppreciationStyle { @@ -88,15 +88,15 @@ fun CurrencyAppreciationLabel( val label = when (style) { AppreciationStyle.Pill -> if (hasAppreciation) { - stringResource(R.string.label_fromAppreciation) + stringRes(CoreStrings.label_fromAppreciation) } else { - stringResource(R.string.label_fromDepreciation) + stringRes(CoreStrings.label_fromDepreciation) } AppreciationStyle.Classic -> if (hasAppreciation) { - stringResource(R.string.label_fromCurrencyAppreciation) + stringRes(CoreStrings.label_fromCurrencyAppreciation) } else { - stringResource(R.string.label_fromCurrencyDepreciation) + stringRes(CoreStrings.label_fromCurrencyDepreciation) } } Text( diff --git a/apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/FlagWithFiat.kt b/apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/FlagWithFiat.kt similarity index 95% rename from apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/FlagWithFiat.kt rename to apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/FlagWithFiat.kt index 83d0712e1b..fe0b57434a 100644 --- a/apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/FlagWithFiat.kt +++ b/apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/FlagWithFiat.kt @@ -12,7 +12,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color -import androidx.compose.ui.res.painterResource +import com.getcode.util.resources.painterForResId import androidx.compose.ui.text.TextStyle import androidx.compose.ui.unit.Dp import com.getcode.opencode.compose.LocalExchange @@ -45,7 +45,7 @@ fun FlagWithFiat( .height(iconSize) .width(iconSize) .clip(CircleShape), - painter = painterResource(it), + painter = painterForResId(it), contentDescription = "" ) } diff --git a/apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/ImageRequestPlaceholders.kt b/apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/ImageRequestPlaceholders.kt new file mode 100644 index 0000000000..204448d2a8 --- /dev/null +++ b/apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/ImageRequestPlaceholders.kt @@ -0,0 +1,6 @@ +package com.flipcash.app.core.ui + +import coil3.request.ImageRequest + +/** Shows the user placeholder when the request fails. Coil's `error(Int)` overload is Android-only. */ +internal expect fun ImageRequest.Builder.errorPlaceholderUser(): ImageRequest.Builder diff --git a/apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/ScreenHeight.kt b/apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/ScreenHeight.kt new file mode 100644 index 0000000000..b56fa9b7c1 --- /dev/null +++ b/apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/ScreenHeight.kt @@ -0,0 +1,7 @@ +package com.flipcash.app.core.ui + +import androidx.compose.runtime.Composable + +/** Screen height in pixels: `Configuration.screenHeightDp` on Android, the window's container height on desktop. */ +@Composable +internal expect fun screenHeightPx(): Float diff --git a/apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/TileButton.kt b/apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/TileButton.kt similarity index 100% rename from apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/TileButton.kt rename to apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/TileButton.kt diff --git a/apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/TokenCard.kt b/apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/TokenCard.kt similarity index 100% rename from apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/TokenCard.kt rename to apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/TokenCard.kt diff --git a/apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/TokenCardStack.kt b/apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/TokenCardStack.kt similarity index 98% rename from apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/TokenCardStack.kt rename to apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/TokenCardStack.kt index 0bde9a7353..7446efcdcf 100644 --- a/apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/TokenCardStack.kt +++ b/apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/TokenCardStack.kt @@ -15,7 +15,6 @@ import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.layout.Layout import androidx.compose.ui.layout.boundsInWindow import androidx.compose.ui.layout.onGloballyPositioned -import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.util.lerp import androidx.compose.ui.unit.Dp @@ -132,9 +131,7 @@ fun TokenCardStack( // Screen height, so cards below the selected one travel off the bottom edge (read live in the reorg // layer; changes rarely). - val windowHeightPx = with(LocalDensity.current) { - LocalConfiguration.current.screenHeightDp.dp.toPx() - } + val windowHeightPx = screenHeightPx() Layout( modifier = modifier diff --git a/apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/TokenImageWithName.kt b/apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/TokenImageWithName.kt similarity index 96% rename from apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/TokenImageWithName.kt rename to apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/TokenImageWithName.kt index 9425ab32c6..dee6f64aef 100644 --- a/apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/TokenImageWithName.kt +++ b/apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/TokenImageWithName.kt @@ -19,10 +19,8 @@ import coil3.compose.AsyncImage import coil3.compose.LocalPlatformContext import coil3.request.ImageRequest import coil3.request.crossfade -import coil3.request.error import com.getcode.opencode.model.financial.Token import com.getcode.theme.CodeTheme -import com.getcode.ui.components.R @Composable fun TokenIconWithName( @@ -106,7 +104,7 @@ fun TokenIcon( model = ImageRequest.Builder(LocalPlatformContext.current) .data(image) .crossfade(false) - .error(R.drawable.ic_placeholder_user) + .errorPlaceholderUser() .build(), contentDescription = null, contentScale = ContentScale.Crop, diff --git a/apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/ViewerAmount.kt b/apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/ViewerAmount.kt similarity index 100% rename from apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/ViewerAmount.kt rename to apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/ViewerAmount.kt diff --git a/apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/onboarding/NewUserTutorial.kt b/apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/onboarding/NewUserTutorial.kt similarity index 88% rename from apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/onboarding/NewUserTutorial.kt rename to apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/onboarding/NewUserTutorial.kt index cb9c858261..cb1a56b6c8 100644 --- a/apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/onboarding/NewUserTutorial.kt +++ b/apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/onboarding/NewUserTutorial.kt @@ -23,14 +23,15 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.ColorFilter import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.graphics.vector.rememberVectorPainter -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.compose.ui.util.fastForEach -import com.flipcash.core.R +import com.flipcash.app.core.resources.CoreDrawables +import com.flipcash.app.core.resources.CoreStrings import com.getcode.theme.CodeTheme import com.getcode.theme.extraSmall +import com.getcode.util.resources.painterForResId +import com.getcode.util.resources.stringRes /** * A row in a "what's left to do" checklist. @@ -52,20 +53,20 @@ sealed interface TutorialItem { class AddMoney(override val isCompleted: Boolean) : Wallet { override val title: String - @Composable get() = stringResource(R.string.title_addMoney) + @Composable get() = stringRes(CoreStrings.title_addMoney) override val description: String - @Composable get() = stringResource(R.string.subtitle_addMoney) + @Composable get() = stringRes(CoreStrings.subtitle_addMoney) override val icon: Painter @Composable get() = rememberVectorPainter(Icons.Outlined.AddCircleOutline) } class ScanTipCard(override val isCompleted: Boolean) : Wallet { override val title: String - @Composable get() = stringResource(R.string.title_scanTipCard) + @Composable get() = stringRes(CoreStrings.title_scanTipCard) override val description: String - @Composable get() = stringResource(R.string.subtitle_scanTipCard) + @Composable get() = stringRes(CoreStrings.subtitle_scanTipCard) override val icon: Painter - @Composable get() = painterResource(R.drawable.ic_nav_tipcard) + @Composable get() = painterForResId(CoreDrawables.ic_nav_tipcard) } } @@ -136,7 +137,7 @@ private fun OnboardingItemRow( Image( modifier = Modifier.align(Alignment.Top).size(24.dp), painter = if (item.isCompleted) { - painterResource(R.drawable.ic_checked_green) + painterForResId(CoreDrawables.ic_checked_green) } else { item.icon }, @@ -161,7 +162,7 @@ private fun OnboardingItemRow( } Icon( modifier = Modifier.align(Alignment.CenterVertically).size(16.dp), - painter = painterResource(R.drawable.ic_chevron_right), + painter = painterForResId(CoreDrawables.ic_chevron_right), tint = CodeTheme.colors.textSecondary, contentDescription = null ) diff --git a/apps/flipcash/core-ui/src/jvmMain/kotlin/com/flipcash/app/core/ui/ImageRequestPlaceholders.jvm.kt b/apps/flipcash/core-ui/src/jvmMain/kotlin/com/flipcash/app/core/ui/ImageRequestPlaceholders.jvm.kt new file mode 100644 index 0000000000..5023301a00 --- /dev/null +++ b/apps/flipcash/core-ui/src/jvmMain/kotlin/com/flipcash/app/core/ui/ImageRequestPlaceholders.jvm.kt @@ -0,0 +1,6 @@ +package com.flipcash.app.core.ui + +import coil3.request.ImageRequest + +// TODO(desktop): decode ic_placeholder_user from Compose resources into a coil Image. +internal actual fun ImageRequest.Builder.errorPlaceholderUser(): ImageRequest.Builder = this diff --git a/apps/flipcash/core-ui/src/jvmMain/kotlin/com/flipcash/app/core/ui/ScreenHeight.jvm.kt b/apps/flipcash/core-ui/src/jvmMain/kotlin/com/flipcash/app/core/ui/ScreenHeight.jvm.kt new file mode 100644 index 0000000000..9246aacac8 --- /dev/null +++ b/apps/flipcash/core-ui/src/jvmMain/kotlin/com/flipcash/app/core/ui/ScreenHeight.jvm.kt @@ -0,0 +1,7 @@ +package com.flipcash.app.core.ui + +import androidx.compose.runtime.Composable +import androidx.compose.ui.platform.LocalWindowInfo + +@Composable +internal actual fun screenHeightPx(): Float = LocalWindowInfo.current.containerSize.height.toFloat() diff --git a/apps/flipcash/core/build.gradle.kts b/apps/flipcash/core/build.gradle.kts index 3deb1a4c65..52a65baa26 100644 --- a/apps/flipcash/core/build.gradle.kts +++ b/apps/flipcash/core/build.gradle.kts @@ -1,6 +1,9 @@ +import com.getcode.buildlogic.resources.androidResAsComposeResources + plugins { alias(libs.plugins.flipcash.kmp.app.library) alias(libs.plugins.compose.compiler) + alias(libs.plugins.jetbrains.compose) alias(libs.plugins.kotlin.ksp) } @@ -22,6 +25,8 @@ kotlin { implementation(libs.kotlinx.serialization.json) implementation(libs.jetbrains.compose.runtime) implementation(libs.jetbrains.compose.foundation) + implementation(libs.jetbrains.compose.components.resources) + implementation(project(":ui:resources")) api(project(":libs:reporting")) api(project(":services:flipcash")) @@ -72,6 +77,15 @@ kotlin { } } +compose.resources { + publicResClass = true + packageOfResClass = "${Gradle.flipcashNamespace}.core.resources" + customDirectory( + sourceSetName = "commonMain", + directoryProvider = androidResAsComposeResources(), + ) +} + dependencies { add("kspAndroid", libs.hilt.android.compiler) add("kspAndroid", libs.hilt.compiler) diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/resources/CoreResources.android.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/resources/CoreResources.android.kt new file mode 100644 index 0000000000..945ba5768c --- /dev/null +++ b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/resources/CoreResources.android.kt @@ -0,0 +1,22 @@ +package com.flipcash.app.core.resources + +import com.flipcash.core.R + +@Suppress("PropertyName") +actual object CoreStrings { + actual val title_addMoney: Int = R.string.title_addMoney + actual val subtitle_addMoney: Int = R.string.subtitle_addMoney + actual val title_scanTipCard: Int = R.string.title_scanTipCard + actual val subtitle_scanTipCard: Int = R.string.subtitle_scanTipCard + actual val label_fromAppreciation: Int = R.string.label_fromAppreciation + actual val label_fromDepreciation: Int = R.string.label_fromDepreciation + actual val label_fromCurrencyAppreciation: Int = R.string.label_fromCurrencyAppreciation + actual val label_fromCurrencyDepreciation: Int = R.string.label_fromCurrencyDepreciation +} + +@Suppress("PropertyName") +actual object CoreDrawables { + actual val ic_nav_tipcard: Int = R.drawable.ic_nav_tipcard + actual val ic_checked_green: Int = R.drawable.ic_checked_green + actual val ic_chevron_right: Int = R.drawable.ic_chevron_right +} diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/money/FormatUtils.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/money/FormatUtils.kt similarity index 100% rename from apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/money/FormatUtils.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/money/FormatUtils.kt diff --git a/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/resources/CoreResources.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/resources/CoreResources.kt new file mode 100644 index 0000000000..61f1fda6ba --- /dev/null +++ b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/resources/CoreResources.kt @@ -0,0 +1,25 @@ +package com.flipcash.app.core.resources + +/** + * `Int` IDs for the `app:core` resources that common UI hands to [com.getcode.util.resources.stringRes] + * and [com.getcode.util.resources.painterForResId]. Android returns the `R` IDs; desktop registers the + * generated Compose resources. + */ +@Suppress("PropertyName") +expect object CoreStrings { + val title_addMoney: Int + val subtitle_addMoney: Int + val title_scanTipCard: Int + val subtitle_scanTipCard: Int + val label_fromAppreciation: Int + val label_fromDepreciation: Int + val label_fromCurrencyAppreciation: Int + val label_fromCurrencyDepreciation: Int +} + +@Suppress("PropertyName") +expect object CoreDrawables { + val ic_nav_tipcard: Int + val ic_checked_green: Int + val ic_chevron_right: Int +} diff --git a/apps/flipcash/core/src/jvmMain/kotlin/com/flipcash/app/core/resources/CoreResources.jvm.kt b/apps/flipcash/core/src/jvmMain/kotlin/com/flipcash/app/core/resources/CoreResources.jvm.kt new file mode 100644 index 0000000000..0861caa072 --- /dev/null +++ b/apps/flipcash/core/src/jvmMain/kotlin/com/flipcash/app/core/resources/CoreResources.jvm.kt @@ -0,0 +1,33 @@ +package com.flipcash.app.core.resources + +import com.flipcash.core.resources.Res +import com.flipcash.core.resources.ic_checked_green +import com.flipcash.core.resources.ic_nav_tipcard +import com.flipcash.core.resources.label_fromAppreciation +import com.flipcash.core.resources.label_fromCurrencyAppreciation +import com.flipcash.core.resources.label_fromCurrencyDepreciation +import com.flipcash.core.resources.label_fromDepreciation +import com.flipcash.core.resources.subtitle_addMoney +import com.flipcash.core.resources.subtitle_scanTipCard +import com.flipcash.core.resources.title_addMoney +import com.flipcash.core.resources.title_scanTipCard +import com.getcode.util.resources.ComposeResourceIds + +@Suppress("PropertyName") +actual object CoreStrings { + actual val title_addMoney: Int = ComposeResourceIds.register(Res.string.title_addMoney) + actual val subtitle_addMoney: Int = ComposeResourceIds.register(Res.string.subtitle_addMoney) + actual val title_scanTipCard: Int = ComposeResourceIds.register(Res.string.title_scanTipCard) + actual val subtitle_scanTipCard: Int = ComposeResourceIds.register(Res.string.subtitle_scanTipCard) + actual val label_fromAppreciation: Int = ComposeResourceIds.register(Res.string.label_fromAppreciation) + actual val label_fromDepreciation: Int = ComposeResourceIds.register(Res.string.label_fromDepreciation) + actual val label_fromCurrencyAppreciation: Int = ComposeResourceIds.register(Res.string.label_fromCurrencyAppreciation) + actual val label_fromCurrencyDepreciation: Int = ComposeResourceIds.register(Res.string.label_fromCurrencyDepreciation) +} + +@Suppress("PropertyName") +actual object CoreDrawables { + actual val ic_nav_tipcard: Int = ComposeResourceIds.register(Res.drawable.ic_nav_tipcard) + actual val ic_checked_green: Int = ComposeResourceIds.register(Res.drawable.ic_checked_green) + actual val ic_chevron_right: Int = checkNotNull(ComposeResourceIds.drawableId("ic_chevron_right")) +} diff --git a/services/opencode-compose/build.gradle.kts b/services/opencode-compose/build.gradle.kts index f3c32e5221..fb22ba0b69 100644 --- a/services/opencode-compose/build.gradle.kts +++ b/services/opencode-compose/build.gradle.kts @@ -1,26 +1,17 @@ plugins { - alias(libs.plugins.flipcash.android.library.compose) + alias(libs.plugins.flipcash.kmp.app.library) + alias(libs.plugins.compose.compiler) } -android { - namespace = "${Gradle.codeNamespace}.services.opencode.compose" - - defaultConfig { - consumerProguardFiles("consumer-rules.pro") - - buildConfigField("Boolean", "NOTIFY_ERRORS", "false") - buildConfigField( - "String", - "GOOGLE_CLOUD_PROJECT_NUMBER", - "\"${tryReadProperty(rootProject.rootDir, "GOOGLE_CLOUD_PROJECT_NUMBER", "-1L")}\"" - ) +kotlin { + android { + namespace = "${Gradle.codeNamespace}.services.opencode.compose" } - buildFeatures { - buildConfig = true + sourceSets { + commonMain.dependencies { + api(project(":services:opencode")) + implementation(libs.jetbrains.compose.runtime) + } } } - -dependencies { - api(project(":services:opencode")) -} diff --git a/services/opencode-compose/src/main/kotlin/com/getcode/opencode/compose/ExchangeStub.kt b/services/opencode-compose/src/androidMain/kotlin/com/getcode/opencode/compose/ExchangeStub.kt similarity index 100% rename from services/opencode-compose/src/main/kotlin/com/getcode/opencode/compose/ExchangeStub.kt rename to services/opencode-compose/src/androidMain/kotlin/com/getcode/opencode/compose/ExchangeStub.kt diff --git a/services/opencode-compose/src/main/kotlin/com/getcode/opencode/compose/Exchange.kt b/services/opencode-compose/src/commonMain/kotlin/com/getcode/opencode/compose/Exchange.kt similarity index 100% rename from services/opencode-compose/src/main/kotlin/com/getcode/opencode/compose/Exchange.kt rename to services/opencode-compose/src/commonMain/kotlin/com/getcode/opencode/compose/Exchange.kt From 61c39c8c5f588091e39fd92262c016aa507843cf Mon Sep 17 00:00:00 2001 From: Brandon McAnsh Date: Fri, 23 Oct 2026 18:52:19 -0400 Subject: [PATCH 23/50] build(common-ui): move common-ui to android+jvm KMP and lift ContactAvatar BlurHash decodes to pixels in common code; each platform wraps them (Android still builds the same ARGB_8888 Bitmap, and keeps BlurHash.decode as an extension). ContactAvatar uses Coil's LocalPlatformContext and passes the URL string to Coil, which maps it as it did the Uri. app:core's media resolver and TimeProvider move to common; the Coil-backed ImageCachePresence stays Android. --- apps/flipcash/core/build.gradle.kts | 1 + ...ePresence.kt => CoilImageCachePresence.kt} | 9 --- .../app/core/media/ImageCachePresence.kt | 10 ++++ .../app/core/media/MediaUrlResolver.kt | 0 .../app/core/media/RememberMediaUrl.kt | 0 .../app/core/time/FakeTimeProvider.kt | 0 .../flipcash/app/core/time/TimeProvider.kt | 0 .../flipcash/app/blob/BlurHashEncoderTest.kt | 1 + .../shared/common-ui/build.gradle.kts | 58 +++++++++++++------ .../ui/BlurHashAverageColorVectorTest.kt | 0 .../flipcash/shared/common/ui/BlurHashTest.kt | 0 .../common/ui/profile/JoinedLabelTest.kt | 0 .../resources/blurhash_average.json | 0 .../shared/common/ui/ImageBitmaps.android.kt | 16 +++++ .../shared/common/ui/amount/AmountChip.kt | 0 .../ui/profile/BalanceRequirementsCard.kt | 0 .../ui/profile/FeaturedGroupsSection.kt | 0 .../common/ui/profile/GroupChattingGrid.kt | 0 .../shared/common/ui/profile/JoinedLabel.kt | 0 .../common/ui/profile/ProfileActionButton.kt | 0 .../shared/common/ui/profile/ProfileCover.kt | 0 .../common/ui/profile/ProfileEditFields.kt | 0 .../shared/common/ui/profile/ProfileHeader.kt | 0 .../ui/profile/ProfilePinnedActionBar.kt | 0 .../common/ui/profile/ProfileStatsCard.kt | 0 .../common/ui/profile/ProfileStatusChip.kt | 0 .../common/ui/profile/ProfileTopScrollEdge.kt | 0 .../res/values/strings.xml | 0 .../com/flipcash/shared/common/ui/BlurHash.kt | 31 ++++++---- .../shared/common/ui/ContactAvatar.kt | 34 +++++------ .../shared/common/ui/ImageBitmaps.jvm.kt | 26 +++++++++ 31 files changed, 129 insertions(+), 57 deletions(-) rename apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/media/{ImageCachePresence.kt => CoilImageCachePresence.kt} (78%) create mode 100644 apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/media/ImageCachePresence.kt rename apps/flipcash/core/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/media/MediaUrlResolver.kt (100%) rename apps/flipcash/core/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/media/RememberMediaUrl.kt (100%) rename apps/flipcash/core/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/time/FakeTimeProvider.kt (100%) rename apps/flipcash/core/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/time/TimeProvider.kt (100%) rename apps/flipcash/shared/common-ui/src/{test => androidHostTest}/kotlin/com/flipcash/shared/common/ui/BlurHashAverageColorVectorTest.kt (100%) rename apps/flipcash/shared/common-ui/src/{test => androidHostTest}/kotlin/com/flipcash/shared/common/ui/BlurHashTest.kt (100%) rename apps/flipcash/shared/common-ui/src/{test => androidHostTest}/kotlin/com/flipcash/shared/common/ui/profile/JoinedLabelTest.kt (100%) rename apps/flipcash/shared/common-ui/src/{test => androidHostTest}/resources/blurhash_average.json (100%) create mode 100644 apps/flipcash/shared/common-ui/src/androidMain/kotlin/com/flipcash/shared/common/ui/ImageBitmaps.android.kt rename apps/flipcash/shared/common-ui/src/{main => androidMain}/kotlin/com/flipcash/shared/common/ui/amount/AmountChip.kt (100%) rename apps/flipcash/shared/common-ui/src/{main => androidMain}/kotlin/com/flipcash/shared/common/ui/profile/BalanceRequirementsCard.kt (100%) rename apps/flipcash/shared/common-ui/src/{main => androidMain}/kotlin/com/flipcash/shared/common/ui/profile/FeaturedGroupsSection.kt (100%) rename apps/flipcash/shared/common-ui/src/{main => androidMain}/kotlin/com/flipcash/shared/common/ui/profile/GroupChattingGrid.kt (100%) rename apps/flipcash/shared/common-ui/src/{main => androidMain}/kotlin/com/flipcash/shared/common/ui/profile/JoinedLabel.kt (100%) rename apps/flipcash/shared/common-ui/src/{main => androidMain}/kotlin/com/flipcash/shared/common/ui/profile/ProfileActionButton.kt (100%) rename apps/flipcash/shared/common-ui/src/{main => androidMain}/kotlin/com/flipcash/shared/common/ui/profile/ProfileCover.kt (100%) rename apps/flipcash/shared/common-ui/src/{main => androidMain}/kotlin/com/flipcash/shared/common/ui/profile/ProfileEditFields.kt (100%) rename apps/flipcash/shared/common-ui/src/{main => androidMain}/kotlin/com/flipcash/shared/common/ui/profile/ProfileHeader.kt (100%) rename apps/flipcash/shared/common-ui/src/{main => androidMain}/kotlin/com/flipcash/shared/common/ui/profile/ProfilePinnedActionBar.kt (100%) rename apps/flipcash/shared/common-ui/src/{main => androidMain}/kotlin/com/flipcash/shared/common/ui/profile/ProfileStatsCard.kt (100%) rename apps/flipcash/shared/common-ui/src/{main => androidMain}/kotlin/com/flipcash/shared/common/ui/profile/ProfileStatusChip.kt (100%) rename apps/flipcash/shared/common-ui/src/{main => androidMain}/kotlin/com/flipcash/shared/common/ui/profile/ProfileTopScrollEdge.kt (100%) rename apps/flipcash/shared/common-ui/src/{main => androidMain}/res/values/strings.xml (100%) rename apps/flipcash/shared/common-ui/src/{main => commonMain}/kotlin/com/flipcash/shared/common/ui/BlurHash.kt (83%) rename apps/flipcash/shared/common-ui/src/{main => commonMain}/kotlin/com/flipcash/shared/common/ui/ContactAvatar.kt (94%) create mode 100644 apps/flipcash/shared/common-ui/src/jvmMain/kotlin/com/flipcash/shared/common/ui/ImageBitmaps.jvm.kt diff --git a/apps/flipcash/core/build.gradle.kts b/apps/flipcash/core/build.gradle.kts index 52a65baa26..d28cbdf678 100644 --- a/apps/flipcash/core/build.gradle.kts +++ b/apps/flipcash/core/build.gradle.kts @@ -18,6 +18,7 @@ kotlin { sourceSets { commonMain.dependencies { implementation(project(":libs:parcelable")) + implementation(libs.javax.inject) api(project(":ui:navigation")) api(project(":ui:core")) api(libs.navigation3.runtime) diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/media/ImageCachePresence.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/media/CoilImageCachePresence.kt similarity index 78% rename from apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/media/ImageCachePresence.kt rename to apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/media/CoilImageCachePresence.kt index 8c8dcff514..daa966423c 100644 --- a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/media/ImageCachePresence.kt +++ b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/media/CoilImageCachePresence.kt @@ -12,15 +12,6 @@ import kotlinx.coroutines.withContext import javax.inject.Inject import javax.inject.Singleton -/** - * Whether the image loader already holds the bytes filed under a stable cache key. Blob renditions - * are cached by their durable blob id rather than their download URL, so a hit here means the URL - * will never be dereferenced — and an expired one costs nothing. - */ -interface ImageCachePresence { - suspend fun holds(cacheKey: String): Boolean -} - @Singleton class CoilImageCachePresence @Inject constructor( @param:ApplicationContext private val context: Context, diff --git a/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/media/ImageCachePresence.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/media/ImageCachePresence.kt new file mode 100644 index 0000000000..89f0bb336b --- /dev/null +++ b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/media/ImageCachePresence.kt @@ -0,0 +1,10 @@ +package com.flipcash.app.core.media + +/** + * Whether the image loader already holds the bytes filed under a stable cache key. Blob renditions + * are cached by their durable blob id rather than their download URL, so a hit here means the URL + * will never be dereferenced — and an expired one costs nothing. + */ +interface ImageCachePresence { + suspend fun holds(cacheKey: String): Boolean +} diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/media/MediaUrlResolver.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/media/MediaUrlResolver.kt similarity index 100% rename from apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/media/MediaUrlResolver.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/media/MediaUrlResolver.kt diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/media/RememberMediaUrl.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/media/RememberMediaUrl.kt similarity index 100% rename from apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/media/RememberMediaUrl.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/media/RememberMediaUrl.kt diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/time/FakeTimeProvider.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/time/FakeTimeProvider.kt similarity index 100% rename from apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/time/FakeTimeProvider.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/time/FakeTimeProvider.kt diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/time/TimeProvider.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/time/TimeProvider.kt similarity index 100% rename from apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/time/TimeProvider.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/time/TimeProvider.kt diff --git a/apps/flipcash/shared/blob/src/test/kotlin/com/flipcash/app/blob/BlurHashEncoderTest.kt b/apps/flipcash/shared/blob/src/test/kotlin/com/flipcash/app/blob/BlurHashEncoderTest.kt index 7d91d6b3da..bca2e93d68 100644 --- a/apps/flipcash/shared/blob/src/test/kotlin/com/flipcash/app/blob/BlurHashEncoderTest.kt +++ b/apps/flipcash/shared/blob/src/test/kotlin/com/flipcash/app/blob/BlurHashEncoderTest.kt @@ -2,6 +2,7 @@ package com.flipcash.app.blob import android.graphics.Bitmap import com.flipcash.shared.common.ui.BlurHash +import com.flipcash.shared.common.ui.decode import org.junit.runner.RunWith import org.robolectric.RobolectricTestRunner import kotlin.math.abs diff --git a/apps/flipcash/shared/common-ui/build.gradle.kts b/apps/flipcash/shared/common-ui/build.gradle.kts index a55a5b8f81..afa584a830 100644 --- a/apps/flipcash/shared/common-ui/build.gradle.kts +++ b/apps/flipcash/shared/common-ui/build.gradle.kts @@ -1,24 +1,46 @@ plugins { - alias(libs.plugins.flipcash.android.library.compose) + alias(libs.plugins.flipcash.kmp.app.library) + alias(libs.plugins.compose.compiler) } -android { - namespace = "${Gradle.flipcashNamespace}.shared.common.ui" -} +kotlin { + android { + namespace = "${Gradle.flipcashNamespace}.shared.common.ui" + androidResources { + enable = true + } + } -dependencies { - implementation(project(":apps:flipcash:core")) - implementation(project(":ui:core")) - implementation(project(":ui:components")) - implementation(project(":ui:theme")) - implementation(project(":ui:resources")) - implementation(project(":services:flipcash")) - implementation(project(":libs:datetime")) - implementation(project(":apps:flipcash:shared:theme")) + sourceSets { + commonMain.dependencies { + implementation(project(":apps:flipcash:core")) + implementation(project(":ui:core")) + implementation(project(":ui:theme")) + implementation(project(":services:flipcash")) + implementation(project(":services:opencode")) - implementation(libs.bundles.haze) - implementation(libs.compose.material) - implementation(libs.bundles.haze) - api(libs.compose.material.icons.extended) - testImplementation(libs.robolectric) + implementation(libs.jetbrains.compose.runtime) + implementation(libs.jetbrains.compose.foundation) + implementation(libs.jetbrains.compose.ui) + implementation(libs.jetbrains.compose.material3) + api(libs.jetbrains.compose.material.icons.extended) + implementation(libs.coil3) + } + androidMain.dependencies { + implementation(project(":ui:components")) + implementation(project(":ui:resources")) + implementation(project(":libs:datetime")) + implementation(project(":apps:flipcash:shared:theme")) + implementation(project.dependencies.platform(libs.compose.bom)) + implementation(libs.bundles.compose) + implementation(libs.bundles.haze) + implementation(libs.compose.material) + api(libs.compose.material.icons.extended) + } + getByName("androidHostTest").dependencies { + implementation(kotlin("test")) + implementation(libs.bundles.unit.testing) + implementation(libs.robolectric) + } + } } diff --git a/apps/flipcash/shared/common-ui/src/test/kotlin/com/flipcash/shared/common/ui/BlurHashAverageColorVectorTest.kt b/apps/flipcash/shared/common-ui/src/androidHostTest/kotlin/com/flipcash/shared/common/ui/BlurHashAverageColorVectorTest.kt similarity index 100% rename from apps/flipcash/shared/common-ui/src/test/kotlin/com/flipcash/shared/common/ui/BlurHashAverageColorVectorTest.kt rename to apps/flipcash/shared/common-ui/src/androidHostTest/kotlin/com/flipcash/shared/common/ui/BlurHashAverageColorVectorTest.kt diff --git a/apps/flipcash/shared/common-ui/src/test/kotlin/com/flipcash/shared/common/ui/BlurHashTest.kt b/apps/flipcash/shared/common-ui/src/androidHostTest/kotlin/com/flipcash/shared/common/ui/BlurHashTest.kt similarity index 100% rename from apps/flipcash/shared/common-ui/src/test/kotlin/com/flipcash/shared/common/ui/BlurHashTest.kt rename to apps/flipcash/shared/common-ui/src/androidHostTest/kotlin/com/flipcash/shared/common/ui/BlurHashTest.kt diff --git a/apps/flipcash/shared/common-ui/src/test/kotlin/com/flipcash/shared/common/ui/profile/JoinedLabelTest.kt b/apps/flipcash/shared/common-ui/src/androidHostTest/kotlin/com/flipcash/shared/common/ui/profile/JoinedLabelTest.kt similarity index 100% rename from apps/flipcash/shared/common-ui/src/test/kotlin/com/flipcash/shared/common/ui/profile/JoinedLabelTest.kt rename to apps/flipcash/shared/common-ui/src/androidHostTest/kotlin/com/flipcash/shared/common/ui/profile/JoinedLabelTest.kt diff --git a/apps/flipcash/shared/common-ui/src/test/resources/blurhash_average.json b/apps/flipcash/shared/common-ui/src/androidHostTest/resources/blurhash_average.json similarity index 100% rename from apps/flipcash/shared/common-ui/src/test/resources/blurhash_average.json rename to apps/flipcash/shared/common-ui/src/androidHostTest/resources/blurhash_average.json diff --git a/apps/flipcash/shared/common-ui/src/androidMain/kotlin/com/flipcash/shared/common/ui/ImageBitmaps.android.kt b/apps/flipcash/shared/common-ui/src/androidMain/kotlin/com/flipcash/shared/common/ui/ImageBitmaps.android.kt new file mode 100644 index 0000000000..95c2962d21 --- /dev/null +++ b/apps/flipcash/shared/common-ui/src/androidMain/kotlin/com/flipcash/shared/common/ui/ImageBitmaps.android.kt @@ -0,0 +1,16 @@ +package com.flipcash.shared.common.ui + +import android.graphics.Bitmap +import androidx.compose.ui.graphics.ImageBitmap +import androidx.compose.ui.graphics.asAndroidBitmap +import androidx.compose.ui.graphics.asImageBitmap +import coil3.asImage + +internal actual fun argbToImageBitmap(pixels: IntArray, width: Int, height: Int): ImageBitmap = + Bitmap.createBitmap(pixels, width, height, Bitmap.Config.ARGB_8888).asImageBitmap() + +internal actual fun ImageBitmap.asCoilImage(): coil3.Image = asAndroidBitmap().asImage() + +/** Decodes [blurHash] into an Android [Bitmap]; kept for Android callers of the old API. */ +fun BlurHash.decode(blurHash: String?, width: Int, height: Int, punch: Float = 1f): Bitmap? = + decodeImage(blurHash, width, height, punch)?.asAndroidBitmap() diff --git a/apps/flipcash/shared/common-ui/src/main/kotlin/com/flipcash/shared/common/ui/amount/AmountChip.kt b/apps/flipcash/shared/common-ui/src/androidMain/kotlin/com/flipcash/shared/common/ui/amount/AmountChip.kt similarity index 100% rename from apps/flipcash/shared/common-ui/src/main/kotlin/com/flipcash/shared/common/ui/amount/AmountChip.kt rename to apps/flipcash/shared/common-ui/src/androidMain/kotlin/com/flipcash/shared/common/ui/amount/AmountChip.kt diff --git a/apps/flipcash/shared/common-ui/src/main/kotlin/com/flipcash/shared/common/ui/profile/BalanceRequirementsCard.kt b/apps/flipcash/shared/common-ui/src/androidMain/kotlin/com/flipcash/shared/common/ui/profile/BalanceRequirementsCard.kt similarity index 100% rename from apps/flipcash/shared/common-ui/src/main/kotlin/com/flipcash/shared/common/ui/profile/BalanceRequirementsCard.kt rename to apps/flipcash/shared/common-ui/src/androidMain/kotlin/com/flipcash/shared/common/ui/profile/BalanceRequirementsCard.kt diff --git a/apps/flipcash/shared/common-ui/src/main/kotlin/com/flipcash/shared/common/ui/profile/FeaturedGroupsSection.kt b/apps/flipcash/shared/common-ui/src/androidMain/kotlin/com/flipcash/shared/common/ui/profile/FeaturedGroupsSection.kt similarity index 100% rename from apps/flipcash/shared/common-ui/src/main/kotlin/com/flipcash/shared/common/ui/profile/FeaturedGroupsSection.kt rename to apps/flipcash/shared/common-ui/src/androidMain/kotlin/com/flipcash/shared/common/ui/profile/FeaturedGroupsSection.kt diff --git a/apps/flipcash/shared/common-ui/src/main/kotlin/com/flipcash/shared/common/ui/profile/GroupChattingGrid.kt b/apps/flipcash/shared/common-ui/src/androidMain/kotlin/com/flipcash/shared/common/ui/profile/GroupChattingGrid.kt similarity index 100% rename from apps/flipcash/shared/common-ui/src/main/kotlin/com/flipcash/shared/common/ui/profile/GroupChattingGrid.kt rename to apps/flipcash/shared/common-ui/src/androidMain/kotlin/com/flipcash/shared/common/ui/profile/GroupChattingGrid.kt diff --git a/apps/flipcash/shared/common-ui/src/main/kotlin/com/flipcash/shared/common/ui/profile/JoinedLabel.kt b/apps/flipcash/shared/common-ui/src/androidMain/kotlin/com/flipcash/shared/common/ui/profile/JoinedLabel.kt similarity index 100% rename from apps/flipcash/shared/common-ui/src/main/kotlin/com/flipcash/shared/common/ui/profile/JoinedLabel.kt rename to apps/flipcash/shared/common-ui/src/androidMain/kotlin/com/flipcash/shared/common/ui/profile/JoinedLabel.kt diff --git a/apps/flipcash/shared/common-ui/src/main/kotlin/com/flipcash/shared/common/ui/profile/ProfileActionButton.kt b/apps/flipcash/shared/common-ui/src/androidMain/kotlin/com/flipcash/shared/common/ui/profile/ProfileActionButton.kt similarity index 100% rename from apps/flipcash/shared/common-ui/src/main/kotlin/com/flipcash/shared/common/ui/profile/ProfileActionButton.kt rename to apps/flipcash/shared/common-ui/src/androidMain/kotlin/com/flipcash/shared/common/ui/profile/ProfileActionButton.kt diff --git a/apps/flipcash/shared/common-ui/src/main/kotlin/com/flipcash/shared/common/ui/profile/ProfileCover.kt b/apps/flipcash/shared/common-ui/src/androidMain/kotlin/com/flipcash/shared/common/ui/profile/ProfileCover.kt similarity index 100% rename from apps/flipcash/shared/common-ui/src/main/kotlin/com/flipcash/shared/common/ui/profile/ProfileCover.kt rename to apps/flipcash/shared/common-ui/src/androidMain/kotlin/com/flipcash/shared/common/ui/profile/ProfileCover.kt diff --git a/apps/flipcash/shared/common-ui/src/main/kotlin/com/flipcash/shared/common/ui/profile/ProfileEditFields.kt b/apps/flipcash/shared/common-ui/src/androidMain/kotlin/com/flipcash/shared/common/ui/profile/ProfileEditFields.kt similarity index 100% rename from apps/flipcash/shared/common-ui/src/main/kotlin/com/flipcash/shared/common/ui/profile/ProfileEditFields.kt rename to apps/flipcash/shared/common-ui/src/androidMain/kotlin/com/flipcash/shared/common/ui/profile/ProfileEditFields.kt diff --git a/apps/flipcash/shared/common-ui/src/main/kotlin/com/flipcash/shared/common/ui/profile/ProfileHeader.kt b/apps/flipcash/shared/common-ui/src/androidMain/kotlin/com/flipcash/shared/common/ui/profile/ProfileHeader.kt similarity index 100% rename from apps/flipcash/shared/common-ui/src/main/kotlin/com/flipcash/shared/common/ui/profile/ProfileHeader.kt rename to apps/flipcash/shared/common-ui/src/androidMain/kotlin/com/flipcash/shared/common/ui/profile/ProfileHeader.kt diff --git a/apps/flipcash/shared/common-ui/src/main/kotlin/com/flipcash/shared/common/ui/profile/ProfilePinnedActionBar.kt b/apps/flipcash/shared/common-ui/src/androidMain/kotlin/com/flipcash/shared/common/ui/profile/ProfilePinnedActionBar.kt similarity index 100% rename from apps/flipcash/shared/common-ui/src/main/kotlin/com/flipcash/shared/common/ui/profile/ProfilePinnedActionBar.kt rename to apps/flipcash/shared/common-ui/src/androidMain/kotlin/com/flipcash/shared/common/ui/profile/ProfilePinnedActionBar.kt diff --git a/apps/flipcash/shared/common-ui/src/main/kotlin/com/flipcash/shared/common/ui/profile/ProfileStatsCard.kt b/apps/flipcash/shared/common-ui/src/androidMain/kotlin/com/flipcash/shared/common/ui/profile/ProfileStatsCard.kt similarity index 100% rename from apps/flipcash/shared/common-ui/src/main/kotlin/com/flipcash/shared/common/ui/profile/ProfileStatsCard.kt rename to apps/flipcash/shared/common-ui/src/androidMain/kotlin/com/flipcash/shared/common/ui/profile/ProfileStatsCard.kt diff --git a/apps/flipcash/shared/common-ui/src/main/kotlin/com/flipcash/shared/common/ui/profile/ProfileStatusChip.kt b/apps/flipcash/shared/common-ui/src/androidMain/kotlin/com/flipcash/shared/common/ui/profile/ProfileStatusChip.kt similarity index 100% rename from apps/flipcash/shared/common-ui/src/main/kotlin/com/flipcash/shared/common/ui/profile/ProfileStatusChip.kt rename to apps/flipcash/shared/common-ui/src/androidMain/kotlin/com/flipcash/shared/common/ui/profile/ProfileStatusChip.kt diff --git a/apps/flipcash/shared/common-ui/src/main/kotlin/com/flipcash/shared/common/ui/profile/ProfileTopScrollEdge.kt b/apps/flipcash/shared/common-ui/src/androidMain/kotlin/com/flipcash/shared/common/ui/profile/ProfileTopScrollEdge.kt similarity index 100% rename from apps/flipcash/shared/common-ui/src/main/kotlin/com/flipcash/shared/common/ui/profile/ProfileTopScrollEdge.kt rename to apps/flipcash/shared/common-ui/src/androidMain/kotlin/com/flipcash/shared/common/ui/profile/ProfileTopScrollEdge.kt diff --git a/apps/flipcash/shared/common-ui/src/main/res/values/strings.xml b/apps/flipcash/shared/common-ui/src/androidMain/res/values/strings.xml similarity index 100% rename from apps/flipcash/shared/common-ui/src/main/res/values/strings.xml rename to apps/flipcash/shared/common-ui/src/androidMain/res/values/strings.xml diff --git a/apps/flipcash/shared/common-ui/src/main/kotlin/com/flipcash/shared/common/ui/BlurHash.kt b/apps/flipcash/shared/common-ui/src/commonMain/kotlin/com/flipcash/shared/common/ui/BlurHash.kt similarity index 83% rename from apps/flipcash/shared/common-ui/src/main/kotlin/com/flipcash/shared/common/ui/BlurHash.kt rename to apps/flipcash/shared/common-ui/src/commonMain/kotlin/com/flipcash/shared/common/ui/BlurHash.kt index 30d9cdd11f..91c1c0f23e 100644 --- a/apps/flipcash/shared/common-ui/src/main/kotlin/com/flipcash/shared/common/ui/BlurHash.kt +++ b/apps/flipcash/shared/common-ui/src/commonMain/kotlin/com/flipcash/shared/common/ui/BlurHash.kt @@ -1,9 +1,8 @@ package com.flipcash.shared.common.ui -import android.graphics.Bitmap import androidx.compose.runtime.Composable import androidx.compose.runtime.remember -import androidx.compose.ui.graphics.asImageBitmap +import androidx.compose.ui.graphics.ImageBitmap import androidx.compose.ui.graphics.painter.BitmapPainter import androidx.compose.ui.graphics.painter.Painter import kotlin.math.PI @@ -24,10 +23,17 @@ import kotlin.math.withSign object BlurHash { /** - * Decodes [blurHash] into an [width] × [height] [Bitmap], or null if the string is malformed. - * [punch] adjusts contrast (1f = as encoded). + * Decodes [blurHash] into an [width] × [height] [ImageBitmap], or null if the string is + * malformed. [punch] adjusts contrast (1f = as encoded). */ - fun decode(blurHash: String?, width: Int, height: Int, punch: Float = 1f): Bitmap? { + fun decodeImage(blurHash: String?, width: Int, height: Int, punch: Float = 1f): ImageBitmap? = + decodePixels(blurHash, width, height, punch)?.let { argbToImageBitmap(it, width, height) } + + /** + * Decodes [blurHash] into [width] × [height] opaque ARGB pixels, row by row, or null if the + * string is malformed. The platform bitmap wrappers build on this. + */ + internal fun decodePixels(blurHash: String?, width: Int, height: Int, punch: Float = 1f): IntArray? { if (blurHash == null || blurHash.length < 6 || width <= 0 || height <= 0) return null val sizeFlag = decode83(blurHash, 0, 1) ?: return null @@ -44,7 +50,7 @@ object BlurHash { decodeAc(decode83(blurHash, from, from + 2) ?: return null, maxAc * punch) } } - return composeBitmap(width, height, numCompX, numCompY, colors) + return composePixels(width, height, numCompX, numCompY, colors) } /** @@ -103,13 +109,13 @@ object BlurHash { return (srgb * 255f + 0.5f).toInt() } - private fun composeBitmap( + private fun composePixels( width: Int, height: Int, numCompX: Int, numCompY: Int, colors: Array, - ): Bitmap { + ): IntArray { // Precompute the cosine basis for each axis so the inner pixel loop is just multiplies. val cosX = FloatArray(width * numCompX) for (x in 0 until width) { @@ -144,7 +150,7 @@ object BlurHash { (0xFF shl 24) or (linearToSrgb(r) shl 16) or (linearToSrgb(g) shl 8) or linearToSrgb(b) } } - return Bitmap.createBitmap(pixels, width, height, Bitmap.Config.ARGB_8888) + return pixels } private const val CHARS = @@ -161,6 +167,9 @@ fun rememberBlurHashPainter( width: Int = 24, height: Int = 24, ): Painter? = remember(blurHash, width, height) { - val bitmap = BlurHash.decode(blurHash, width, height) ?: return@remember null - BitmapPainter(bitmap.asImageBitmap()) + val bitmap = BlurHash.decodeImage(blurHash, width, height) ?: return@remember null + BitmapPainter(bitmap) } + +/** Wraps opaque ARGB [pixels] (row by row) in a platform [ImageBitmap]. */ +internal expect fun argbToImageBitmap(pixels: IntArray, width: Int, height: Int): ImageBitmap diff --git a/apps/flipcash/shared/common-ui/src/main/kotlin/com/flipcash/shared/common/ui/ContactAvatar.kt b/apps/flipcash/shared/common-ui/src/commonMain/kotlin/com/flipcash/shared/common/ui/ContactAvatar.kt similarity index 94% rename from apps/flipcash/shared/common-ui/src/main/kotlin/com/flipcash/shared/common/ui/ContactAvatar.kt rename to apps/flipcash/shared/common-ui/src/commonMain/kotlin/com/flipcash/shared/common/ui/ContactAvatar.kt index 9af8fde466..ea8d1da7c1 100644 --- a/apps/flipcash/shared/common-ui/src/main/kotlin/com/flipcash/shared/common/ui/ContactAvatar.kt +++ b/apps/flipcash/shared/common-ui/src/commonMain/kotlin/com/flipcash/shared/common/ui/ContactAvatar.kt @@ -1,6 +1,5 @@ package com.flipcash.shared.common.ui -import android.graphics.Bitmap import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.border @@ -22,20 +21,16 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.ColorFilter -import androidx.compose.ui.graphics.asImageBitmap +import androidx.compose.ui.graphics.ImageBitmap import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.layout.ContentScale -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.min -import androidx.core.net.toUri -import coil3.asImage import coil3.compose.AsyncImage +import coil3.compose.LocalPlatformContext import coil3.request.ImageRequest import coil3.request.crossfade -import coil3.request.error -import coil3.request.placeholder import com.flipcash.app.core.contacts.DeviceContact import com.flipcash.app.core.media.rememberMediaUrl import com.flipcash.services.models.HandlePrefix @@ -84,11 +79,11 @@ fun ContactAvatar( if (photoUri != null) { var isError by rememberSaveable(photoUri) { mutableStateOf(false) } if (!isError) { - val context = LocalContext.current + val context = LocalPlatformContext.current val request = remember(photoUri) { ImageRequest.Builder(context) .crossfade(true) - .data(photoUri.toUri()) + .data(photoUri) .build() } AsyncImage( @@ -178,11 +173,10 @@ internal fun ProfileAvatar( // while the rendition downloads, what stays on screen while a stale URL is re-minted, and // what's left if the load never succeeds — anything is a better likeness of the person than // the grey Person glyph. - // Kept as the decoded Bitmap rather than either wrapper: the two consumers want different - // ones (Compose's ImageBitmap here, Coil's Image in the request), and decoding is the - // expensive half. + // Kept as the decoded ImageBitmap; the Coil request wraps the same pixels (asCoilImage), and + // decoding is the expensive half. val blurBitmap = remember(image) { - BlurHash.decode(image?.blurhash(), width = 24, height = 24) + BlurHash.decodeImage(image?.blurhash(), width = 24, height = 24) } if (blurred) { // Blocked users are shown intentionally obscured — render the media item's self-contained @@ -206,14 +200,14 @@ internal fun ProfileAvatar( if (image != null && photoUri != null) { val isError = media.hasFailed if (!isError) { - val context = LocalContext.current + val context = LocalPlatformContext.current // Two progressively better placeholders bridge the load so we never flash a blank // gradient while the correctly-sized rendition downloads: // 1. the BlurHash — an instant, self-contained blurred preview, and // 2. the next-smaller rendition — if another surface already cached it (e.g. the // list loaded the 160 this 320 avatar sits above), Coil shows it immediately // (see placeholderMemoryCacheKey) and upgrades in place. - val blurHash = remember(blurBitmap) { blurBitmap?.asImage() } + val blurHash = remember(blurBitmap) { blurBitmap?.asCoilImage() } // Cache identity is the durable blob id, NOT the download URL: the server re-mints // and expires `download_url` on every fetch, so a URL-keyed cache misses on the next // fetch even though the bytes are immutable — every load would re-download and flash @@ -227,7 +221,7 @@ internal fun ProfileAvatar( val request = remember(photoUri, cacheKey, previewKey, blurHash) { ImageRequest.Builder(context) .crossfade(true) - .data(photoUri.toUri()) + .data(photoUri) // Key both caches on the stable blob id (not the ephemeral URL, and not // size) so every avatar load of this rendition shares one entry that // survives URL rotation and app restarts — which is also what lets a @@ -274,10 +268,10 @@ internal fun ProfileAvatar( */ @Composable private fun BoxWithConstraintsScope.BlurHashOr( - blurBitmap: Bitmap?, + blurBitmap: ImageBitmap?, fallback: @Composable BoxWithConstraintsScope.() -> Unit, ) { - val bitmap = remember(blurBitmap) { blurBitmap?.asImageBitmap() } + val bitmap = blurBitmap if (bitmap != null) { Image( bitmap = bitmap, @@ -347,4 +341,6 @@ private fun BoxWithConstraintsScope.InitialsText(displayName: String) { color = CodeTheme.colors.textSecondary, textAlign = TextAlign.Center, ) -} \ No newline at end of file +} +/** Wraps a decoded [ImageBitmap] as a Coil [coil3.Image] for request placeholders. */ +internal expect fun ImageBitmap.asCoilImage(): coil3.Image diff --git a/apps/flipcash/shared/common-ui/src/jvmMain/kotlin/com/flipcash/shared/common/ui/ImageBitmaps.jvm.kt b/apps/flipcash/shared/common-ui/src/jvmMain/kotlin/com/flipcash/shared/common/ui/ImageBitmaps.jvm.kt new file mode 100644 index 0000000000..8702c70ce9 --- /dev/null +++ b/apps/flipcash/shared/common-ui/src/jvmMain/kotlin/com/flipcash/shared/common/ui/ImageBitmaps.jvm.kt @@ -0,0 +1,26 @@ +package com.flipcash.shared.common.ui + +import androidx.compose.ui.graphics.ImageBitmap +import androidx.compose.ui.graphics.asComposeImageBitmap +import androidx.compose.ui.graphics.asSkiaBitmap +import coil3.asImage +import org.jetbrains.skia.Bitmap +import org.jetbrains.skia.ColorAlphaType +import org.jetbrains.skia.ImageInfo + +internal actual fun argbToImageBitmap(pixels: IntArray, width: Int, height: Int): ImageBitmap { + // Skia's N32 is BGRA little-endian, which is the in-memory order of an ARGB Int. + val bytes = ByteArray(pixels.size * 4) + pixels.forEachIndexed { i, argb -> + bytes[i * 4] = (argb and 0xFF).toByte() + bytes[i * 4 + 1] = (argb shr 8 and 0xFF).toByte() + bytes[i * 4 + 2] = (argb shr 16 and 0xFF).toByte() + bytes[i * 4 + 3] = (argb ushr 24).toByte() + } + val bitmap = Bitmap() + bitmap.allocPixels(ImageInfo.makeN32(width, height, ColorAlphaType.OPAQUE)) + bitmap.installPixels(bytes) + return bitmap.asComposeImageBitmap() +} + +internal actual fun ImageBitmap.asCoilImage(): coil3.Image = asSkiaBitmap().asImage() From 3d02a3e751f95ec09c12fbbb9c24f1e2efe06446 Mon Sep 17 00:00:00 2001 From: Brandon McAnsh Date: Fri, 23 Oct 2026 18:57:40 -0400 Subject: [PATCH 24/50] build(transaction-history): move transaction-history to android+jvm KMP Lift the activity feed coordinator and updater, both mappers and the recent-activity composables to commonMain. String ids go through a TxStrings expect object (R.string on Android, the Compose resource registry on desktop); the 24-hour clock check is an expect seam. NetworkUpdater moves to app:core's commonMain. --- .../core/resources/CoreResources.android.kt | 2 + .../app/core/resources/CoreResources.kt | 2 + .../app/core/updater/NetworkUpdater.kt | 0 .../app/core/resources/CoreResources.jvm.kt | 4 + .../transaction-history/build.gradle.kts | 96 ++++++++++++++---- .../MessageDirectionTest.kt | 0 .../transactionhistory/MintInvolvementTest.kt | 0 .../TransactionDetailsMapperTest.kt | 0 .../TransactionDetailsSamples.kt | 0 .../TransactionDetailsScreenshotTest.kt | 0 .../TransactionItemMapperTest.kt | 0 .../resources/tokens/dollars.webp | Bin .../resources/tokens/jeffy.png | Bin .../ActivityHistoryScreen.kt | 0 .../ActivityHistoryViewModel.kt | 0 .../Is24HourClock.android.kt | 8 ++ .../TransactionDetailsContent.kt | 0 .../resources/TxResources.android.kt | 34 +++++++ .../res/values/strings.xml | 0 .../ActivityFeedCoordinator.kt | 0 .../transactionhistory/ActivityFeedRow.kt | 13 ++- .../transactionhistory/ActivityFeedUpdater.kt | 0 .../transactionhistory/Is24HourClock.kt | 7 ++ .../transactionhistory/MintInvolvement.kt | 0 .../RecentActivitySection.kt | 11 +- .../transactionhistory/ResolvedTransaction.kt | 0 .../TransactionAvatarImage.kt | 0 .../transactionhistory/TransactionDetails.kt | 39 +++---- .../transactionhistory/TransactionListItem.kt | 0 .../TransactionSubtitles.kt | 9 +- .../internal/TransactionDetailsMapper.kt | 0 .../internal/TransactionItemMapper.kt | 10 +- .../resources/TxResources.kt | 37 +++++++ .../transactionhistory/Is24HourClock.jvm.kt | 13 +++ .../resources/TxResources.jvm.kt | 62 +++++++++++ 35 files changed, 286 insertions(+), 61 deletions(-) rename apps/flipcash/core/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/updater/NetworkUpdater.kt (100%) rename apps/flipcash/shared/transaction-history/src/{test => androidHostTest}/kotlin/com/flipcash/shared/transactionhistory/MessageDirectionTest.kt (100%) rename apps/flipcash/shared/transaction-history/src/{test => androidHostTest}/kotlin/com/flipcash/shared/transactionhistory/MintInvolvementTest.kt (100%) rename apps/flipcash/shared/transaction-history/src/{test => androidHostTest}/kotlin/com/flipcash/shared/transactionhistory/TransactionDetailsMapperTest.kt (100%) rename apps/flipcash/shared/transaction-history/src/{test => androidHostTest}/kotlin/com/flipcash/shared/transactionhistory/TransactionDetailsSamples.kt (100%) rename apps/flipcash/shared/transaction-history/src/{test => androidHostTest}/kotlin/com/flipcash/shared/transactionhistory/TransactionDetailsScreenshotTest.kt (100%) rename apps/flipcash/shared/transaction-history/src/{test => androidHostTest}/kotlin/com/flipcash/shared/transactionhistory/TransactionItemMapperTest.kt (100%) rename apps/flipcash/shared/transaction-history/src/{test => androidHostTest}/resources/tokens/dollars.webp (100%) rename apps/flipcash/shared/transaction-history/src/{test => androidHostTest}/resources/tokens/jeffy.png (100%) rename apps/flipcash/shared/transaction-history/src/{main => androidMain}/kotlin/com/flipcash/shared/transactionhistory/ActivityHistoryScreen.kt (100%) rename apps/flipcash/shared/transaction-history/src/{main => androidMain}/kotlin/com/flipcash/shared/transactionhistory/ActivityHistoryViewModel.kt (100%) create mode 100644 apps/flipcash/shared/transaction-history/src/androidMain/kotlin/com/flipcash/shared/transactionhistory/Is24HourClock.android.kt rename apps/flipcash/shared/transaction-history/src/{main => androidMain}/kotlin/com/flipcash/shared/transactionhistory/TransactionDetailsContent.kt (100%) create mode 100644 apps/flipcash/shared/transaction-history/src/androidMain/kotlin/com/flipcash/shared/transactionhistory/resources/TxResources.android.kt rename apps/flipcash/shared/transaction-history/src/{main => androidMain}/res/values/strings.xml (100%) rename apps/flipcash/shared/transaction-history/src/{main => commonMain}/kotlin/com/flipcash/shared/transactionhistory/ActivityFeedCoordinator.kt (100%) rename apps/flipcash/shared/transaction-history/src/{main => commonMain}/kotlin/com/flipcash/shared/transactionhistory/ActivityFeedRow.kt (91%) rename apps/flipcash/shared/transaction-history/src/{main => commonMain}/kotlin/com/flipcash/shared/transactionhistory/ActivityFeedUpdater.kt (100%) create mode 100644 apps/flipcash/shared/transaction-history/src/commonMain/kotlin/com/flipcash/shared/transactionhistory/Is24HourClock.kt rename apps/flipcash/shared/transaction-history/src/{main => commonMain}/kotlin/com/flipcash/shared/transactionhistory/MintInvolvement.kt (100%) rename apps/flipcash/shared/transaction-history/src/{main => commonMain}/kotlin/com/flipcash/shared/transactionhistory/RecentActivitySection.kt (89%) rename apps/flipcash/shared/transaction-history/src/{main => commonMain}/kotlin/com/flipcash/shared/transactionhistory/ResolvedTransaction.kt (100%) rename apps/flipcash/shared/transaction-history/src/{main => commonMain}/kotlin/com/flipcash/shared/transactionhistory/TransactionAvatarImage.kt (100%) rename apps/flipcash/shared/transaction-history/src/{main => commonMain}/kotlin/com/flipcash/shared/transactionhistory/TransactionDetails.kt (84%) rename apps/flipcash/shared/transaction-history/src/{main => commonMain}/kotlin/com/flipcash/shared/transactionhistory/TransactionListItem.kt (100%) rename apps/flipcash/shared/transaction-history/src/{main => commonMain}/kotlin/com/flipcash/shared/transactionhistory/TransactionSubtitles.kt (86%) rename apps/flipcash/shared/transaction-history/src/{main => commonMain}/kotlin/com/flipcash/shared/transactionhistory/internal/TransactionDetailsMapper.kt (100%) rename apps/flipcash/shared/transaction-history/src/{main => commonMain}/kotlin/com/flipcash/shared/transactionhistory/internal/TransactionItemMapper.kt (95%) create mode 100644 apps/flipcash/shared/transaction-history/src/commonMain/kotlin/com/flipcash/shared/transactionhistory/resources/TxResources.kt create mode 100644 apps/flipcash/shared/transaction-history/src/jvmMain/kotlin/com/flipcash/shared/transactionhistory/Is24HourClock.jvm.kt create mode 100644 apps/flipcash/shared/transaction-history/src/jvmMain/kotlin/com/flipcash/shared/transactionhistory/resources/TxResources.jvm.kt diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/resources/CoreResources.android.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/resources/CoreResources.android.kt index 945ba5768c..a4ee6b636a 100644 --- a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/resources/CoreResources.android.kt +++ b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/resources/CoreResources.android.kt @@ -12,6 +12,8 @@ actual object CoreStrings { actual val label_fromDepreciation: Int = R.string.label_fromDepreciation actual val label_fromCurrencyAppreciation: Int = R.string.label_fromCurrencyAppreciation actual val label_fromCurrencyDepreciation: Int = R.string.label_fromCurrencyDepreciation + actual val title_recentActivity: Int = R.string.title_recentActivity + actual val label_chatReceipt_yesterday: Int = R.string.label_chatReceipt_yesterday } @Suppress("PropertyName") diff --git a/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/resources/CoreResources.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/resources/CoreResources.kt index 61f1fda6ba..7d67f48ab1 100644 --- a/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/resources/CoreResources.kt +++ b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/resources/CoreResources.kt @@ -15,6 +15,8 @@ expect object CoreStrings { val label_fromDepreciation: Int val label_fromCurrencyAppreciation: Int val label_fromCurrencyDepreciation: Int + val title_recentActivity: Int + val label_chatReceipt_yesterday: Int } @Suppress("PropertyName") diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/updater/NetworkUpdater.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/updater/NetworkUpdater.kt similarity index 100% rename from apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/updater/NetworkUpdater.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/updater/NetworkUpdater.kt diff --git a/apps/flipcash/core/src/jvmMain/kotlin/com/flipcash/app/core/resources/CoreResources.jvm.kt b/apps/flipcash/core/src/jvmMain/kotlin/com/flipcash/app/core/resources/CoreResources.jvm.kt index 0861caa072..9b386346e5 100644 --- a/apps/flipcash/core/src/jvmMain/kotlin/com/flipcash/app/core/resources/CoreResources.jvm.kt +++ b/apps/flipcash/core/src/jvmMain/kotlin/com/flipcash/app/core/resources/CoreResources.jvm.kt @@ -11,6 +11,8 @@ import com.flipcash.core.resources.subtitle_addMoney import com.flipcash.core.resources.subtitle_scanTipCard import com.flipcash.core.resources.title_addMoney import com.flipcash.core.resources.title_scanTipCard +import com.flipcash.core.resources.title_recentActivity +import com.flipcash.core.resources.label_chatReceipt_yesterday import com.getcode.util.resources.ComposeResourceIds @Suppress("PropertyName") @@ -23,6 +25,8 @@ actual object CoreStrings { actual val label_fromDepreciation: Int = ComposeResourceIds.register(Res.string.label_fromDepreciation) actual val label_fromCurrencyAppreciation: Int = ComposeResourceIds.register(Res.string.label_fromCurrencyAppreciation) actual val label_fromCurrencyDepreciation: Int = ComposeResourceIds.register(Res.string.label_fromCurrencyDepreciation) + actual val title_recentActivity: Int = ComposeResourceIds.register(Res.string.title_recentActivity) + actual val label_chatReceipt_yesterday: Int = ComposeResourceIds.register(Res.string.label_chatReceipt_yesterday) } @Suppress("PropertyName") diff --git a/apps/flipcash/shared/transaction-history/build.gradle.kts b/apps/flipcash/shared/transaction-history/build.gradle.kts index ee44a7fbf1..2f0ad39f79 100644 --- a/apps/flipcash/shared/transaction-history/build.gradle.kts +++ b/apps/flipcash/shared/transaction-history/build.gradle.kts @@ -1,30 +1,84 @@ -plugins { - alias(libs.plugins.flipcash.android.feature) -} +import com.getcode.buildlogic.resources.androidResAsComposeResources -android { - namespace = "com.flipcash.shared.transactionhistory" +plugins { + alias(libs.plugins.flipcash.kmp.app.library) + alias(libs.plugins.compose.compiler) + alias(libs.plugins.jetbrains.compose) + alias(libs.plugins.kotlin.ksp) } // Home of the transaction-history data engine (ActivityFeedCoordinator / ActivityFeedUpdater), // consolidated out of the deprecated :shared:activityfeed. Mirrors that module's dependencies. // See docs/superpowers/plans/2026-08-11-activityfeed-phaseout.md. -dependencies { - implementation(libs.bundles.room) - implementation(libs.androidx.paging.runtime) - implementation(libs.compose.paging) +kotlin { + android { + namespace = "com.flipcash.shared.transactionhistory" + androidResources { + enable = true + } + } + + sourceSets { + commonMain.dependencies { + implementation(project(":apps:flipcash:core")) + implementation(project(":apps:flipcash:core-ui")) + implementation(project(":apps:flipcash:shared:persistence:sources")) + implementation(project(":apps:flipcash:shared:common-ui")) + implementation(project(":services:flipcash")) + implementation(project(":services:opencode")) + implementation(project(":libs:datetime")) + implementation(project(":libs:encryption:keys")) + implementation(project(":libs:encryption:utils")) + implementation(project(":libs:logging")) + implementation(project(":ui:core")) + implementation(project(":ui:resources")) + implementation(project(":ui:theme")) - compileOnly(project(":apps:flipcash:shared:persistence:db")) - implementation(project(":apps:flipcash:shared:persistence:sources")) - implementation(project(":apps:flipcash:shared:common-ui")) - implementation(project(":services:flipcash")) - implementation(project(":libs:datetime")) + implementation(libs.jetbrains.compose.runtime) + implementation(libs.jetbrains.compose.foundation) + implementation(libs.jetbrains.compose.ui) + implementation(libs.jetbrains.compose.material) + implementation(libs.jetbrains.compose.material3) + implementation(libs.jetbrains.compose.components.resources) + implementation(libs.androidx.paging.common) + implementation(libs.javax.inject) + compileOnly(project(":apps:flipcash:shared:persistence:db")) + } + androidMain.dependencies { + // What flipcash.android.feature supplied before the move to KMP. + implementation(libs.bundles.hilt) + implementation(project.dependencies.platform(libs.compose.bom)) + implementation(libs.bundles.compose) + implementation(libs.bundles.haze) + implementation(project(":libs:coroutines")) + implementation(project(":ui:navigation")) + implementation(project(":ui:components")) - testImplementation(libs.bundles.unit.testing) - testImplementation(libs.robolectric) - testImplementation(project(":ui:resources:test-fixtures")) - // Screenshot renders only: FlipcashPreview for the theme, ExchangeStub for the currency flag - // LocalExchange would otherwise resolve to ExchangeNull. - testImplementation(project(":apps:flipcash:shared:theme")) - testImplementation(project(":services:opencode-compose")) + implementation(libs.bundles.room) + implementation(libs.androidx.paging.runtime) + implementation(libs.compose.paging) + } + getByName("androidHostTest").dependencies { + implementation(libs.bundles.unit.testing) + implementation(libs.robolectric) + implementation(project(":ui:resources:test-fixtures")) + // Screenshot renders only: FlipcashPreview for the theme, ExchangeStub for the currency flag + // LocalExchange would otherwise resolve to ExchangeNull. + implementation(project(":apps:flipcash:shared:theme")) + implementation(project(":services:opencode-compose")) + } + } +} + +compose.resources { + packageOfResClass = "com.flipcash.shared.transactionhistory.generated.resources" + customDirectory( + sourceSetName = "commonMain", + directoryProvider = androidResAsComposeResources(), + ) +} + +dependencies { + add("kspAndroid", libs.hilt.android.compiler) + add("kspAndroid", libs.hilt.compiler) } diff --git a/apps/flipcash/shared/transaction-history/src/test/kotlin/com/flipcash/shared/transactionhistory/MessageDirectionTest.kt b/apps/flipcash/shared/transaction-history/src/androidHostTest/kotlin/com/flipcash/shared/transactionhistory/MessageDirectionTest.kt similarity index 100% rename from apps/flipcash/shared/transaction-history/src/test/kotlin/com/flipcash/shared/transactionhistory/MessageDirectionTest.kt rename to apps/flipcash/shared/transaction-history/src/androidHostTest/kotlin/com/flipcash/shared/transactionhistory/MessageDirectionTest.kt diff --git a/apps/flipcash/shared/transaction-history/src/test/kotlin/com/flipcash/shared/transactionhistory/MintInvolvementTest.kt b/apps/flipcash/shared/transaction-history/src/androidHostTest/kotlin/com/flipcash/shared/transactionhistory/MintInvolvementTest.kt similarity index 100% rename from apps/flipcash/shared/transaction-history/src/test/kotlin/com/flipcash/shared/transactionhistory/MintInvolvementTest.kt rename to apps/flipcash/shared/transaction-history/src/androidHostTest/kotlin/com/flipcash/shared/transactionhistory/MintInvolvementTest.kt diff --git a/apps/flipcash/shared/transaction-history/src/test/kotlin/com/flipcash/shared/transactionhistory/TransactionDetailsMapperTest.kt b/apps/flipcash/shared/transaction-history/src/androidHostTest/kotlin/com/flipcash/shared/transactionhistory/TransactionDetailsMapperTest.kt similarity index 100% rename from apps/flipcash/shared/transaction-history/src/test/kotlin/com/flipcash/shared/transactionhistory/TransactionDetailsMapperTest.kt rename to apps/flipcash/shared/transaction-history/src/androidHostTest/kotlin/com/flipcash/shared/transactionhistory/TransactionDetailsMapperTest.kt diff --git a/apps/flipcash/shared/transaction-history/src/test/kotlin/com/flipcash/shared/transactionhistory/TransactionDetailsSamples.kt b/apps/flipcash/shared/transaction-history/src/androidHostTest/kotlin/com/flipcash/shared/transactionhistory/TransactionDetailsSamples.kt similarity index 100% rename from apps/flipcash/shared/transaction-history/src/test/kotlin/com/flipcash/shared/transactionhistory/TransactionDetailsSamples.kt rename to apps/flipcash/shared/transaction-history/src/androidHostTest/kotlin/com/flipcash/shared/transactionhistory/TransactionDetailsSamples.kt diff --git a/apps/flipcash/shared/transaction-history/src/test/kotlin/com/flipcash/shared/transactionhistory/TransactionDetailsScreenshotTest.kt b/apps/flipcash/shared/transaction-history/src/androidHostTest/kotlin/com/flipcash/shared/transactionhistory/TransactionDetailsScreenshotTest.kt similarity index 100% rename from apps/flipcash/shared/transaction-history/src/test/kotlin/com/flipcash/shared/transactionhistory/TransactionDetailsScreenshotTest.kt rename to apps/flipcash/shared/transaction-history/src/androidHostTest/kotlin/com/flipcash/shared/transactionhistory/TransactionDetailsScreenshotTest.kt diff --git a/apps/flipcash/shared/transaction-history/src/test/kotlin/com/flipcash/shared/transactionhistory/TransactionItemMapperTest.kt b/apps/flipcash/shared/transaction-history/src/androidHostTest/kotlin/com/flipcash/shared/transactionhistory/TransactionItemMapperTest.kt similarity index 100% rename from apps/flipcash/shared/transaction-history/src/test/kotlin/com/flipcash/shared/transactionhistory/TransactionItemMapperTest.kt rename to apps/flipcash/shared/transaction-history/src/androidHostTest/kotlin/com/flipcash/shared/transactionhistory/TransactionItemMapperTest.kt diff --git a/apps/flipcash/shared/transaction-history/src/test/resources/tokens/dollars.webp b/apps/flipcash/shared/transaction-history/src/androidHostTest/resources/tokens/dollars.webp similarity index 100% rename from apps/flipcash/shared/transaction-history/src/test/resources/tokens/dollars.webp rename to apps/flipcash/shared/transaction-history/src/androidHostTest/resources/tokens/dollars.webp diff --git a/apps/flipcash/shared/transaction-history/src/test/resources/tokens/jeffy.png b/apps/flipcash/shared/transaction-history/src/androidHostTest/resources/tokens/jeffy.png similarity index 100% rename from apps/flipcash/shared/transaction-history/src/test/resources/tokens/jeffy.png rename to apps/flipcash/shared/transaction-history/src/androidHostTest/resources/tokens/jeffy.png diff --git a/apps/flipcash/shared/transaction-history/src/main/kotlin/com/flipcash/shared/transactionhistory/ActivityHistoryScreen.kt b/apps/flipcash/shared/transaction-history/src/androidMain/kotlin/com/flipcash/shared/transactionhistory/ActivityHistoryScreen.kt similarity index 100% rename from apps/flipcash/shared/transaction-history/src/main/kotlin/com/flipcash/shared/transactionhistory/ActivityHistoryScreen.kt rename to apps/flipcash/shared/transaction-history/src/androidMain/kotlin/com/flipcash/shared/transactionhistory/ActivityHistoryScreen.kt diff --git a/apps/flipcash/shared/transaction-history/src/main/kotlin/com/flipcash/shared/transactionhistory/ActivityHistoryViewModel.kt b/apps/flipcash/shared/transaction-history/src/androidMain/kotlin/com/flipcash/shared/transactionhistory/ActivityHistoryViewModel.kt similarity index 100% rename from apps/flipcash/shared/transaction-history/src/main/kotlin/com/flipcash/shared/transactionhistory/ActivityHistoryViewModel.kt rename to apps/flipcash/shared/transaction-history/src/androidMain/kotlin/com/flipcash/shared/transactionhistory/ActivityHistoryViewModel.kt diff --git a/apps/flipcash/shared/transaction-history/src/androidMain/kotlin/com/flipcash/shared/transactionhistory/Is24HourClock.android.kt b/apps/flipcash/shared/transaction-history/src/androidMain/kotlin/com/flipcash/shared/transactionhistory/Is24HourClock.android.kt new file mode 100644 index 0000000000..17d56d6ab4 --- /dev/null +++ b/apps/flipcash/shared/transaction-history/src/androidMain/kotlin/com/flipcash/shared/transactionhistory/Is24HourClock.android.kt @@ -0,0 +1,8 @@ +package com.flipcash.shared.transactionhistory + +import android.text.format.DateFormat +import androidx.compose.runtime.Composable +import androidx.compose.ui.platform.LocalContext + +@Composable +internal actual fun is24HourClock(): Boolean = DateFormat.is24HourFormat(LocalContext.current) diff --git a/apps/flipcash/shared/transaction-history/src/main/kotlin/com/flipcash/shared/transactionhistory/TransactionDetailsContent.kt b/apps/flipcash/shared/transaction-history/src/androidMain/kotlin/com/flipcash/shared/transactionhistory/TransactionDetailsContent.kt similarity index 100% rename from apps/flipcash/shared/transaction-history/src/main/kotlin/com/flipcash/shared/transactionhistory/TransactionDetailsContent.kt rename to apps/flipcash/shared/transaction-history/src/androidMain/kotlin/com/flipcash/shared/transactionhistory/TransactionDetailsContent.kt diff --git a/apps/flipcash/shared/transaction-history/src/androidMain/kotlin/com/flipcash/shared/transactionhistory/resources/TxResources.android.kt b/apps/flipcash/shared/transaction-history/src/androidMain/kotlin/com/flipcash/shared/transactionhistory/resources/TxResources.android.kt new file mode 100644 index 0000000000..3de9123fd1 --- /dev/null +++ b/apps/flipcash/shared/transaction-history/src/androidMain/kotlin/com/flipcash/shared/transactionhistory/resources/TxResources.android.kt @@ -0,0 +1,34 @@ +package com.flipcash.shared.transactionhistory.resources + +import com.flipcash.shared.transactionhistory.R + +@Suppress("PropertyName") +actual object TxStrings { + actual val label_activity_convertFee: Int = R.string.label_activity_convertFee + actual val label_txnDetails_from: Int = R.string.label_txnDetails_from + actual val label_txnDetails_inPerson: Int = R.string.label_txnDetails_inPerson + actual val label_txnDetails_paidWith: Int = R.string.label_txnDetails_paidWith + actual val label_txnDetails_soldFor: Int = R.string.label_txnDetails_soldFor + actual val label_txnDetails_status_completed: Int = R.string.label_txnDetails_status_completed + actual val label_txnDetails_status_failed: Int = R.string.label_txnDetails_status_failed + actual val label_txnDetails_status_pending: Int = R.string.label_txnDetails_status_pending + actual val label_txnDetails_status_unknown: Int = R.string.label_txnDetails_status_unknown + actual val label_txnDetails_to: Int = R.string.label_txnDetails_to + actual val title_activity_convert: Int = R.string.title_activity_convert + actual val title_activity_receivedFrom: Int = R.string.title_activity_receivedFrom + actual val title_activity_sentTo: Int = R.string.title_activity_sentTo + actual val title_activity_tipFrom: Int = R.string.title_activity_tipFrom + actual val title_txnDetails_buy: Int = R.string.title_txnDetails_buy + actual val title_txnDetails_convert: Int = R.string.title_txnDetails_convert + actual val title_txnDetails_deposit: Int = R.string.title_txnDetails_deposit + actual val title_txnDetails_poolPayment: Int = R.string.title_txnDetails_poolPayment + actual val title_txnDetails_sell: Int = R.string.title_txnDetails_sell + actual val title_txnDetails_unknown: Int = R.string.title_txnDetails_unknown + actual val title_txnDetails_withdraw: Int = R.string.title_txnDetails_withdraw + actual val title_txnDetails_youGaveCash: Int = R.string.title_txnDetails_youGaveCash + actual val title_txnDetails_youReceived: Int = R.string.title_txnDetails_youReceived + actual val title_txnDetails_youReceivedCash: Int = R.string.title_txnDetails_youReceivedCash + actual val title_txnDetails_youSent: Int = R.string.title_txnDetails_youSent + actual val title_txnDetails_youSentCashLink: Int = R.string.title_txnDetails_youSentCashLink + actual val title_txnDetails_youTipped: Int = R.string.title_txnDetails_youTipped +} diff --git a/apps/flipcash/shared/transaction-history/src/main/res/values/strings.xml b/apps/flipcash/shared/transaction-history/src/androidMain/res/values/strings.xml similarity index 100% rename from apps/flipcash/shared/transaction-history/src/main/res/values/strings.xml rename to apps/flipcash/shared/transaction-history/src/androidMain/res/values/strings.xml diff --git a/apps/flipcash/shared/transaction-history/src/main/kotlin/com/flipcash/shared/transactionhistory/ActivityFeedCoordinator.kt b/apps/flipcash/shared/transaction-history/src/commonMain/kotlin/com/flipcash/shared/transactionhistory/ActivityFeedCoordinator.kt similarity index 100% rename from apps/flipcash/shared/transaction-history/src/main/kotlin/com/flipcash/shared/transactionhistory/ActivityFeedCoordinator.kt rename to apps/flipcash/shared/transaction-history/src/commonMain/kotlin/com/flipcash/shared/transactionhistory/ActivityFeedCoordinator.kt diff --git a/apps/flipcash/shared/transaction-history/src/main/kotlin/com/flipcash/shared/transactionhistory/ActivityFeedRow.kt b/apps/flipcash/shared/transaction-history/src/commonMain/kotlin/com/flipcash/shared/transactionhistory/ActivityFeedRow.kt similarity index 91% rename from apps/flipcash/shared/transaction-history/src/main/kotlin/com/flipcash/shared/transactionhistory/ActivityFeedRow.kt rename to apps/flipcash/shared/transaction-history/src/commonMain/kotlin/com/flipcash/shared/transactionhistory/ActivityFeedRow.kt index f5c83a98e1..9cc8076280 100644 --- a/apps/flipcash/shared/transaction-history/src/main/kotlin/com/flipcash/shared/transactionhistory/ActivityFeedRow.kt +++ b/apps/flipcash/shared/transaction-history/src/commonMain/kotlin/com/flipcash/shared/transactionhistory/ActivityFeedRow.kt @@ -1,6 +1,7 @@ package com.flipcash.shared.transactionhistory -import android.text.format.DateFormat +import com.flipcash.shared.transactionhistory.resources.TxStrings +import com.flipcash.app.core.resources.CoreStrings import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -11,8 +12,7 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.stringResource +import com.getcode.util.resources.stringRes import androidx.compose.ui.text.style.TextOverflow import com.flipcash.app.core.ui.ActivityAmount import com.getcode.theme.CodeTheme @@ -82,7 +82,7 @@ fun ActivityFeedRow( maxLines = 1, ) Text( - text = stringResource(R.string.label_activity_convertFee, fee.formatted()), + text = stringRes(TxStrings.label_activity_convertFee, fee.formatted()), style = CodeTheme.typography.textSmall, color = CodeTheme.colors.textSecondary, maxLines = 1, @@ -106,8 +106,7 @@ fun ActivityFeedRow( */ @Composable internal fun formatActivityTimestamp(instant: Instant): String { - val context = LocalContext.current - val is24Hour = DateFormat.is24HourFormat(context) + val is24Hour = is24HourClock() val tz = TimeZone.currentSystemDefault() val todayDate = Clock.System.now().toLocalDateTime(tz).date val messageDate = instant.toLocalDateTime(tz).date @@ -115,7 +114,7 @@ internal fun formatActivityTimestamp(instant: Instant): String { val time = instant.formatLocalized("h:mm a", is24Hour = is24Hour, if24Hour = "H:mm") return when { dayDiff == 0L -> time - dayDiff == 1L -> stringResource(R.string.label_chatReceipt_yesterday) + dayDiff == 1L -> stringRes(CoreStrings.label_chatReceipt_yesterday) dayDiff in 2L..6L -> instant.formatLocalized("EEEE") messageDate.year == todayDate.year -> instant.formatLocalized("MMM d") else -> instant.formatLocalized("MMM d, yyyy") diff --git a/apps/flipcash/shared/transaction-history/src/main/kotlin/com/flipcash/shared/transactionhistory/ActivityFeedUpdater.kt b/apps/flipcash/shared/transaction-history/src/commonMain/kotlin/com/flipcash/shared/transactionhistory/ActivityFeedUpdater.kt similarity index 100% rename from apps/flipcash/shared/transaction-history/src/main/kotlin/com/flipcash/shared/transactionhistory/ActivityFeedUpdater.kt rename to apps/flipcash/shared/transaction-history/src/commonMain/kotlin/com/flipcash/shared/transactionhistory/ActivityFeedUpdater.kt diff --git a/apps/flipcash/shared/transaction-history/src/commonMain/kotlin/com/flipcash/shared/transactionhistory/Is24HourClock.kt b/apps/flipcash/shared/transaction-history/src/commonMain/kotlin/com/flipcash/shared/transactionhistory/Is24HourClock.kt new file mode 100644 index 0000000000..c2e2ff9cba --- /dev/null +++ b/apps/flipcash/shared/transaction-history/src/commonMain/kotlin/com/flipcash/shared/transactionhistory/Is24HourClock.kt @@ -0,0 +1,7 @@ +package com.flipcash.shared.transactionhistory + +import androidx.compose.runtime.Composable + +/** Whether the user's clock setting is 24-hour. */ +@Composable +internal expect fun is24HourClock(): Boolean diff --git a/apps/flipcash/shared/transaction-history/src/main/kotlin/com/flipcash/shared/transactionhistory/MintInvolvement.kt b/apps/flipcash/shared/transaction-history/src/commonMain/kotlin/com/flipcash/shared/transactionhistory/MintInvolvement.kt similarity index 100% rename from apps/flipcash/shared/transaction-history/src/main/kotlin/com/flipcash/shared/transactionhistory/MintInvolvement.kt rename to apps/flipcash/shared/transaction-history/src/commonMain/kotlin/com/flipcash/shared/transactionhistory/MintInvolvement.kt diff --git a/apps/flipcash/shared/transaction-history/src/main/kotlin/com/flipcash/shared/transactionhistory/RecentActivitySection.kt b/apps/flipcash/shared/transaction-history/src/commonMain/kotlin/com/flipcash/shared/transactionhistory/RecentActivitySection.kt similarity index 89% rename from apps/flipcash/shared/transaction-history/src/main/kotlin/com/flipcash/shared/transactionhistory/RecentActivitySection.kt rename to apps/flipcash/shared/transaction-history/src/commonMain/kotlin/com/flipcash/shared/transactionhistory/RecentActivitySection.kt index 05f3147efb..bc0c95e73a 100644 --- a/apps/flipcash/shared/transaction-history/src/main/kotlin/com/flipcash/shared/transactionhistory/RecentActivitySection.kt +++ b/apps/flipcash/shared/transaction-history/src/commonMain/kotlin/com/flipcash/shared/transactionhistory/RecentActivitySection.kt @@ -1,5 +1,7 @@ package com.flipcash.shared.transactionhistory +import com.flipcash.app.core.resources.CoreStrings +import com.flipcash.app.core.resources.CoreDrawables import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row @@ -14,10 +16,9 @@ import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource +import com.getcode.util.resources.painterForResId +import com.getcode.util.resources.stringRes import com.getcode.theme.CodeTheme -import com.getcode.util.resources.R /** * The "Recent" activity section — a tappable header (label + trailing chevron) followed by the list of @@ -63,13 +64,13 @@ private fun LazyItemScope.RecentActivityHeader(modifier: Modifier) { verticalAlignment = Alignment.CenterVertically, ) { Text( - text = stringResource(com.flipcash.core.R.string.title_recentActivity), + text = stringRes(CoreStrings.title_recentActivity), style = CodeTheme.typography.screenTitle, color = CodeTheme.colors.textMain, ) Icon( modifier = Modifier.size(CodeTheme.dimens.staticGrid.x3), - painter = painterResource(R.drawable.ic_chevron_right), + painter = painterForResId(CoreDrawables.ic_chevron_right), contentDescription = null, tint = CodeTheme.colors.textSecondary, ) diff --git a/apps/flipcash/shared/transaction-history/src/main/kotlin/com/flipcash/shared/transactionhistory/ResolvedTransaction.kt b/apps/flipcash/shared/transaction-history/src/commonMain/kotlin/com/flipcash/shared/transactionhistory/ResolvedTransaction.kt similarity index 100% rename from apps/flipcash/shared/transaction-history/src/main/kotlin/com/flipcash/shared/transactionhistory/ResolvedTransaction.kt rename to apps/flipcash/shared/transaction-history/src/commonMain/kotlin/com/flipcash/shared/transactionhistory/ResolvedTransaction.kt diff --git a/apps/flipcash/shared/transaction-history/src/main/kotlin/com/flipcash/shared/transactionhistory/TransactionAvatarImage.kt b/apps/flipcash/shared/transaction-history/src/commonMain/kotlin/com/flipcash/shared/transactionhistory/TransactionAvatarImage.kt similarity index 100% rename from apps/flipcash/shared/transaction-history/src/main/kotlin/com/flipcash/shared/transactionhistory/TransactionAvatarImage.kt rename to apps/flipcash/shared/transaction-history/src/commonMain/kotlin/com/flipcash/shared/transactionhistory/TransactionAvatarImage.kt diff --git a/apps/flipcash/shared/transaction-history/src/main/kotlin/com/flipcash/shared/transactionhistory/TransactionDetails.kt b/apps/flipcash/shared/transaction-history/src/commonMain/kotlin/com/flipcash/shared/transactionhistory/TransactionDetails.kt similarity index 84% rename from apps/flipcash/shared/transaction-history/src/main/kotlin/com/flipcash/shared/transactionhistory/TransactionDetails.kt rename to apps/flipcash/shared/transaction-history/src/commonMain/kotlin/com/flipcash/shared/transactionhistory/TransactionDetails.kt index 13d60933ca..2b14ba1ac8 100644 --- a/apps/flipcash/shared/transaction-history/src/main/kotlin/com/flipcash/shared/transactionhistory/TransactionDetails.kt +++ b/apps/flipcash/shared/transaction-history/src/commonMain/kotlin/com/flipcash/shared/transactionhistory/TransactionDetails.kt @@ -1,5 +1,6 @@ package com.flipcash.shared.transactionhistory +import com.flipcash.shared.transactionhistory.resources.TxStrings import androidx.annotation.StringRes import com.getcode.opencode.model.financial.Fiat import com.getcode.opencode.model.financial.Token @@ -22,19 +23,19 @@ import kotlin.time.Instant * from taking a bill in person — both arrive as an unattributed `ReceivedCrypto`. */ enum class TransactionKind(@StringRes val headingRes: Int) { - Tipped(R.string.title_txnDetails_youTipped), - Received(R.string.title_txnDetails_youReceived), - Sent(R.string.title_txnDetails_youSent), - GaveCash(R.string.title_txnDetails_youGaveCash), - ReceivedCash(R.string.title_txnDetails_youReceivedCash), - SentCashLink(R.string.title_txnDetails_youSentCashLink), - Buy(R.string.title_txnDetails_buy), - Sell(R.string.title_txnDetails_sell), - Withdraw(R.string.title_txnDetails_withdraw), - Deposit(R.string.title_txnDetails_deposit), - Convert(R.string.title_txnDetails_convert), - PoolPayment(R.string.title_txnDetails_poolPayment), - Unknown(R.string.title_txnDetails_unknown), + Tipped(TxStrings.title_txnDetails_youTipped), + Received(TxStrings.title_txnDetails_youReceived), + Sent(TxStrings.title_txnDetails_youSent), + GaveCash(TxStrings.title_txnDetails_youGaveCash), + ReceivedCash(TxStrings.title_txnDetails_youReceivedCash), + SentCashLink(TxStrings.title_txnDetails_youSentCashLink), + Buy(TxStrings.title_txnDetails_buy), + Sell(TxStrings.title_txnDetails_sell), + Withdraw(TxStrings.title_txnDetails_withdraw), + Deposit(TxStrings.title_txnDetails_deposit), + Convert(TxStrings.title_txnDetails_convert), + PoolPayment(TxStrings.title_txnDetails_poolPayment), + Unknown(TxStrings.title_txnDetails_unknown), } /** @@ -49,8 +50,8 @@ data class TransactionAccount( val direction: Direction, ) { enum class Direction(@StringRes val labelRes: Int) { - To(R.string.label_txnDetails_to), - From(R.string.label_txnDetails_from), + To(TxStrings.label_txnDetails_to), + From(TxStrings.label_txnDetails_from), } /** Nobody reads the middle of an address; the ends are what someone actually compares. */ @@ -65,10 +66,10 @@ data class TransactionAccount( /** The entry's settlement state, as the Status row phrases it. */ enum class TransactionStatus(@StringRes val labelRes: Int) { - Pending(R.string.label_txnDetails_status_pending), - Completed(R.string.label_txnDetails_status_completed), - Failed(R.string.label_txnDetails_status_failed), - Unknown(R.string.label_txnDetails_status_unknown), + Pending(TxStrings.label_txnDetails_status_pending), + Completed(TxStrings.label_txnDetails_status_completed), + Failed(TxStrings.label_txnDetails_status_failed), + Unknown(TxStrings.label_txnDetails_status_unknown), } /** diff --git a/apps/flipcash/shared/transaction-history/src/main/kotlin/com/flipcash/shared/transactionhistory/TransactionListItem.kt b/apps/flipcash/shared/transaction-history/src/commonMain/kotlin/com/flipcash/shared/transactionhistory/TransactionListItem.kt similarity index 100% rename from apps/flipcash/shared/transaction-history/src/main/kotlin/com/flipcash/shared/transactionhistory/TransactionListItem.kt rename to apps/flipcash/shared/transaction-history/src/commonMain/kotlin/com/flipcash/shared/transactionhistory/TransactionListItem.kt diff --git a/apps/flipcash/shared/transaction-history/src/main/kotlin/com/flipcash/shared/transactionhistory/TransactionSubtitles.kt b/apps/flipcash/shared/transaction-history/src/commonMain/kotlin/com/flipcash/shared/transactionhistory/TransactionSubtitles.kt similarity index 86% rename from apps/flipcash/shared/transaction-history/src/main/kotlin/com/flipcash/shared/transactionhistory/TransactionSubtitles.kt rename to apps/flipcash/shared/transaction-history/src/commonMain/kotlin/com/flipcash/shared/transactionhistory/TransactionSubtitles.kt index 31649136c1..0d30391d3d 100644 --- a/apps/flipcash/shared/transaction-history/src/main/kotlin/com/flipcash/shared/transactionhistory/TransactionSubtitles.kt +++ b/apps/flipcash/shared/transaction-history/src/commonMain/kotlin/com/flipcash/shared/transactionhistory/TransactionSubtitles.kt @@ -1,5 +1,6 @@ package com.flipcash.shared.transactionhistory +import com.flipcash.shared.transactionhistory.resources.TxStrings import com.getcode.util.resources.ResourceHelper /** @@ -27,22 +28,22 @@ object TransactionSubtitles { * exchanges identities, so "who" is genuinely unanswerable; how it moved is the useful fact. */ fun inPerson(resources: ResourceHelper): String = - resources.getString(R.string.label_txnDetails_inPerson) + resources.getString(TxStrings.label_txnDetails_inPerson) /** [TransactionKind.Buy] — the mint that was spent, which the amount alone never says. */ fun paidWith(resources: ResourceHelper, tokenName: String): String = - resources.getString(R.string.label_txnDetails_paidWith, tokenName) + resources.getString(TxStrings.label_txnDetails_paidWith, tokenName) /** [TransactionKind.Sell] — the mint that came back. */ fun soldFor(resources: ResourceHelper, tokenName: String): String = - resources.getString(R.string.label_txnDetails_soldFor, tokenName) + resources.getString(TxStrings.label_txnDetails_soldFor, tokenName) /** * [TransactionKind.Convert] — both mints, in the same "from → to" shape the activity row's * convert title already uses, so the row and the screen it opens read alike. */ fun converted(resources: ResourceHelper, from: String, to: String): String = - resources.getString(R.string.title_activity_convert, from, to) + resources.getString(TxStrings.title_activity_convert, from, to) /** [TransactionKind.PoolPayment] — the pool that was paid. */ fun pool(name: String): String? = name.takeIf { it.isNotBlank() } diff --git a/apps/flipcash/shared/transaction-history/src/main/kotlin/com/flipcash/shared/transactionhistory/internal/TransactionDetailsMapper.kt b/apps/flipcash/shared/transaction-history/src/commonMain/kotlin/com/flipcash/shared/transactionhistory/internal/TransactionDetailsMapper.kt similarity index 100% rename from apps/flipcash/shared/transaction-history/src/main/kotlin/com/flipcash/shared/transactionhistory/internal/TransactionDetailsMapper.kt rename to apps/flipcash/shared/transaction-history/src/commonMain/kotlin/com/flipcash/shared/transactionhistory/internal/TransactionDetailsMapper.kt diff --git a/apps/flipcash/shared/transaction-history/src/main/kotlin/com/flipcash/shared/transactionhistory/internal/TransactionItemMapper.kt b/apps/flipcash/shared/transaction-history/src/commonMain/kotlin/com/flipcash/shared/transactionhistory/internal/TransactionItemMapper.kt similarity index 95% rename from apps/flipcash/shared/transaction-history/src/main/kotlin/com/flipcash/shared/transactionhistory/internal/TransactionItemMapper.kt rename to apps/flipcash/shared/transaction-history/src/commonMain/kotlin/com/flipcash/shared/transactionhistory/internal/TransactionItemMapper.kt index 8009e0d328..7004d06418 100644 --- a/apps/flipcash/shared/transaction-history/src/main/kotlin/com/flipcash/shared/transactionhistory/internal/TransactionItemMapper.kt +++ b/apps/flipcash/shared/transaction-history/src/commonMain/kotlin/com/flipcash/shared/transactionhistory/internal/TransactionItemMapper.kt @@ -1,10 +1,10 @@ package com.flipcash.shared.transactionhistory.internal +import com.flipcash.shared.transactionhistory.resources.TxStrings import com.flipcash.app.core.feed.ActivityFeedMessageWithToken import com.flipcash.app.core.feed.MessageMetadata import com.flipcash.app.core.feed.MessageSubstitution import com.flipcash.services.models.UserProfile -import com.flipcash.shared.transactionhistory.R import com.flipcash.shared.transactionhistory.TransactionAvatar import com.flipcash.shared.transactionhistory.TransactionListItem import com.flipcash.shared.transactionhistory.convertOf @@ -82,7 +82,7 @@ private fun convertTitle( convertOf(source.message.metadata) ?: return null val from = source.token?.name?.takeIf { it.isNotBlank() } ?: return null val to = source.toToken?.name?.takeIf { it.isNotBlank() } ?: return null - return resources.getString(R.string.title_activity_convert, from, to) + return resources.getString(TxStrings.title_activity_convert, from, to) } /** @@ -130,12 +130,12 @@ private fun resolveTitle( val isTip = text.isTipVerb() return when (meta) { is MessageMetadata.ReceivedCrypto -> - if (isTip) resources.getString(R.string.title_activity_tipFrom, counterpartyName) - else resources.getString(R.string.title_activity_receivedFrom, counterpartyName) + if (isTip) resources.getString(TxStrings.title_activity_tipFrom, counterpartyName) + else resources.getString(TxStrings.title_activity_receivedFrom, counterpartyName) is MessageMetadata.DirectlySentCrypto -> // "Tipped" already reads as a transitive verb; "Sent" needs the preposition. if (isTip) "$text $counterpartyName" - else resources.getString(R.string.title_activity_sentTo, counterpartyName) + else resources.getString(TxStrings.title_activity_sentTo, counterpartyName) else -> "$text $counterpartyName" } } diff --git a/apps/flipcash/shared/transaction-history/src/commonMain/kotlin/com/flipcash/shared/transactionhistory/resources/TxResources.kt b/apps/flipcash/shared/transaction-history/src/commonMain/kotlin/com/flipcash/shared/transactionhistory/resources/TxResources.kt new file mode 100644 index 0000000000..d707ec3968 --- /dev/null +++ b/apps/flipcash/shared/transaction-history/src/commonMain/kotlin/com/flipcash/shared/transactionhistory/resources/TxResources.kt @@ -0,0 +1,37 @@ +package com.flipcash.shared.transactionhistory.resources + +/** + * `Int` IDs for the transaction-history strings that common code hands to + * [com.getcode.util.resources.ResourceHelper] and [com.getcode.util.resources.stringRes]. Android + * returns the `R` IDs; desktop registers the generated Compose resources. + */ +@Suppress("PropertyName") +expect object TxStrings { + val label_activity_convertFee: Int + val label_txnDetails_from: Int + val label_txnDetails_inPerson: Int + val label_txnDetails_paidWith: Int + val label_txnDetails_soldFor: Int + val label_txnDetails_status_completed: Int + val label_txnDetails_status_failed: Int + val label_txnDetails_status_pending: Int + val label_txnDetails_status_unknown: Int + val label_txnDetails_to: Int + val title_activity_convert: Int + val title_activity_receivedFrom: Int + val title_activity_sentTo: Int + val title_activity_tipFrom: Int + val title_txnDetails_buy: Int + val title_txnDetails_convert: Int + val title_txnDetails_deposit: Int + val title_txnDetails_poolPayment: Int + val title_txnDetails_sell: Int + val title_txnDetails_unknown: Int + val title_txnDetails_withdraw: Int + val title_txnDetails_youGaveCash: Int + val title_txnDetails_youReceived: Int + val title_txnDetails_youReceivedCash: Int + val title_txnDetails_youSent: Int + val title_txnDetails_youSentCashLink: Int + val title_txnDetails_youTipped: Int +} diff --git a/apps/flipcash/shared/transaction-history/src/jvmMain/kotlin/com/flipcash/shared/transactionhistory/Is24HourClock.jvm.kt b/apps/flipcash/shared/transaction-history/src/jvmMain/kotlin/com/flipcash/shared/transactionhistory/Is24HourClock.jvm.kt new file mode 100644 index 0000000000..e2df1d8ec2 --- /dev/null +++ b/apps/flipcash/shared/transaction-history/src/jvmMain/kotlin/com/flipcash/shared/transactionhistory/Is24HourClock.jvm.kt @@ -0,0 +1,13 @@ +package com.flipcash.shared.transactionhistory + +import androidx.compose.runtime.Composable +import java.text.DateFormat +import java.text.SimpleDateFormat +import java.util.Locale + +/** Desktop has no clock setting to read, so this follows the locale's short time pattern. */ +@Composable +internal actual fun is24HourClock(): Boolean { + val format = DateFormat.getTimeInstance(DateFormat.SHORT, Locale.getDefault()) + return (format as? SimpleDateFormat)?.toPattern()?.contains('H') ?: false +} diff --git a/apps/flipcash/shared/transaction-history/src/jvmMain/kotlin/com/flipcash/shared/transactionhistory/resources/TxResources.jvm.kt b/apps/flipcash/shared/transaction-history/src/jvmMain/kotlin/com/flipcash/shared/transactionhistory/resources/TxResources.jvm.kt new file mode 100644 index 0000000000..c04328f65f --- /dev/null +++ b/apps/flipcash/shared/transaction-history/src/jvmMain/kotlin/com/flipcash/shared/transactionhistory/resources/TxResources.jvm.kt @@ -0,0 +1,62 @@ +package com.flipcash.shared.transactionhistory.resources + +import com.flipcash.shared.transactionhistory.generated.resources.Res +import com.flipcash.shared.transactionhistory.generated.resources.label_activity_convertFee +import com.flipcash.shared.transactionhistory.generated.resources.label_txnDetails_from +import com.flipcash.shared.transactionhistory.generated.resources.label_txnDetails_inPerson +import com.flipcash.shared.transactionhistory.generated.resources.label_txnDetails_paidWith +import com.flipcash.shared.transactionhistory.generated.resources.label_txnDetails_soldFor +import com.flipcash.shared.transactionhistory.generated.resources.label_txnDetails_status_completed +import com.flipcash.shared.transactionhistory.generated.resources.label_txnDetails_status_failed +import com.flipcash.shared.transactionhistory.generated.resources.label_txnDetails_status_pending +import com.flipcash.shared.transactionhistory.generated.resources.label_txnDetails_status_unknown +import com.flipcash.shared.transactionhistory.generated.resources.label_txnDetails_to +import com.flipcash.shared.transactionhistory.generated.resources.title_activity_convert +import com.flipcash.shared.transactionhistory.generated.resources.title_activity_receivedFrom +import com.flipcash.shared.transactionhistory.generated.resources.title_activity_sentTo +import com.flipcash.shared.transactionhistory.generated.resources.title_activity_tipFrom +import com.flipcash.shared.transactionhistory.generated.resources.title_txnDetails_buy +import com.flipcash.shared.transactionhistory.generated.resources.title_txnDetails_convert +import com.flipcash.shared.transactionhistory.generated.resources.title_txnDetails_deposit +import com.flipcash.shared.transactionhistory.generated.resources.title_txnDetails_poolPayment +import com.flipcash.shared.transactionhistory.generated.resources.title_txnDetails_sell +import com.flipcash.shared.transactionhistory.generated.resources.title_txnDetails_unknown +import com.flipcash.shared.transactionhistory.generated.resources.title_txnDetails_withdraw +import com.flipcash.shared.transactionhistory.generated.resources.title_txnDetails_youGaveCash +import com.flipcash.shared.transactionhistory.generated.resources.title_txnDetails_youReceived +import com.flipcash.shared.transactionhistory.generated.resources.title_txnDetails_youReceivedCash +import com.flipcash.shared.transactionhistory.generated.resources.title_txnDetails_youSent +import com.flipcash.shared.transactionhistory.generated.resources.title_txnDetails_youSentCashLink +import com.flipcash.shared.transactionhistory.generated.resources.title_txnDetails_youTipped +import com.getcode.util.resources.ComposeResourceIds + +@Suppress("PropertyName") +actual object TxStrings { + actual val label_activity_convertFee: Int = ComposeResourceIds.register(Res.string.label_activity_convertFee) + actual val label_txnDetails_from: Int = ComposeResourceIds.register(Res.string.label_txnDetails_from) + actual val label_txnDetails_inPerson: Int = ComposeResourceIds.register(Res.string.label_txnDetails_inPerson) + actual val label_txnDetails_paidWith: Int = ComposeResourceIds.register(Res.string.label_txnDetails_paidWith) + actual val label_txnDetails_soldFor: Int = ComposeResourceIds.register(Res.string.label_txnDetails_soldFor) + actual val label_txnDetails_status_completed: Int = ComposeResourceIds.register(Res.string.label_txnDetails_status_completed) + actual val label_txnDetails_status_failed: Int = ComposeResourceIds.register(Res.string.label_txnDetails_status_failed) + actual val label_txnDetails_status_pending: Int = ComposeResourceIds.register(Res.string.label_txnDetails_status_pending) + actual val label_txnDetails_status_unknown: Int = ComposeResourceIds.register(Res.string.label_txnDetails_status_unknown) + actual val label_txnDetails_to: Int = ComposeResourceIds.register(Res.string.label_txnDetails_to) + actual val title_activity_convert: Int = ComposeResourceIds.register(Res.string.title_activity_convert) + actual val title_activity_receivedFrom: Int = ComposeResourceIds.register(Res.string.title_activity_receivedFrom) + actual val title_activity_sentTo: Int = ComposeResourceIds.register(Res.string.title_activity_sentTo) + actual val title_activity_tipFrom: Int = ComposeResourceIds.register(Res.string.title_activity_tipFrom) + actual val title_txnDetails_buy: Int = ComposeResourceIds.register(Res.string.title_txnDetails_buy) + actual val title_txnDetails_convert: Int = ComposeResourceIds.register(Res.string.title_txnDetails_convert) + actual val title_txnDetails_deposit: Int = ComposeResourceIds.register(Res.string.title_txnDetails_deposit) + actual val title_txnDetails_poolPayment: Int = ComposeResourceIds.register(Res.string.title_txnDetails_poolPayment) + actual val title_txnDetails_sell: Int = ComposeResourceIds.register(Res.string.title_txnDetails_sell) + actual val title_txnDetails_unknown: Int = ComposeResourceIds.register(Res.string.title_txnDetails_unknown) + actual val title_txnDetails_withdraw: Int = ComposeResourceIds.register(Res.string.title_txnDetails_withdraw) + actual val title_txnDetails_youGaveCash: Int = ComposeResourceIds.register(Res.string.title_txnDetails_youGaveCash) + actual val title_txnDetails_youReceived: Int = ComposeResourceIds.register(Res.string.title_txnDetails_youReceived) + actual val title_txnDetails_youReceivedCash: Int = ComposeResourceIds.register(Res.string.title_txnDetails_youReceivedCash) + actual val title_txnDetails_youSent: Int = ComposeResourceIds.register(Res.string.title_txnDetails_youSent) + actual val title_txnDetails_youSentCashLink: Int = ComposeResourceIds.register(Res.string.title_txnDetails_youSentCashLink) + actual val title_txnDetails_youTipped: Int = ComposeResourceIds.register(Res.string.title_txnDetails_youTipped) +} From 0db5af16c3dfb0feb5c0e178c4a26e3d441d62f5 Mon Sep 17 00:00:00 2001 From: Brandon McAnsh Date: Fri, 23 Oct 2026 18:59:46 -0400 Subject: [PATCH 25/50] build(funding): lift PurchaseMethod types to common PurchaseMethod, PurchaseMethodController and PurchaseMethodState move to commonMain so the balance view model can take the controller on desktop. The controller implementation and its UI stay in androidMain. The module moves to flipcash.kmp.app.library, since its app-module dependencies have no Apple targets. --- apps/flipcash/shared/funding/build.gradle.kts | 9 +++++++-- .../kotlin/com/flipcash/app/funding/PurchaseMethod.kt | 0 .../com/flipcash/app/funding/PurchaseMethodController.kt | 0 .../com/flipcash/app/funding/PurchaseMethodState.kt | 0 4 files changed, 7 insertions(+), 2 deletions(-) rename apps/flipcash/shared/funding/src/{androidMain => commonMain}/kotlin/com/flipcash/app/funding/PurchaseMethod.kt (100%) rename apps/flipcash/shared/funding/src/{androidMain => commonMain}/kotlin/com/flipcash/app/funding/PurchaseMethodController.kt (100%) rename apps/flipcash/shared/funding/src/{androidMain => commonMain}/kotlin/com/flipcash/app/funding/PurchaseMethodState.kt (100%) diff --git a/apps/flipcash/shared/funding/build.gradle.kts b/apps/flipcash/shared/funding/build.gradle.kts index 03fc03ffca..871af57bf3 100644 --- a/apps/flipcash/shared/funding/build.gradle.kts +++ b/apps/flipcash/shared/funding/build.gradle.kts @@ -1,5 +1,5 @@ plugins { - alias(libs.plugins.flipcash.kmp.library) + alias(libs.plugins.flipcash.kmp.app.library) alias(libs.plugins.compose.compiler) alias(libs.plugins.kotlin.ksp) } @@ -7,10 +7,15 @@ plugins { kotlin { android { namespace = "${Gradle.flipcashNamespace}.shared.funding" - withHostTest {} androidResources { enable = true } } sourceSets { + commonMain.dependencies { + implementation(project(":apps:flipcash:core")) + implementation(project(":services:flipcash")) + implementation(project(":services:opencode")) + implementation(project(":libs:encryption:keys")) + } androidMain.dependencies { implementation(project.dependencies.platform(libs.compose.bom)) implementation(libs.bundles.compose) diff --git a/apps/flipcash/shared/funding/src/androidMain/kotlin/com/flipcash/app/funding/PurchaseMethod.kt b/apps/flipcash/shared/funding/src/commonMain/kotlin/com/flipcash/app/funding/PurchaseMethod.kt similarity index 100% rename from apps/flipcash/shared/funding/src/androidMain/kotlin/com/flipcash/app/funding/PurchaseMethod.kt rename to apps/flipcash/shared/funding/src/commonMain/kotlin/com/flipcash/app/funding/PurchaseMethod.kt diff --git a/apps/flipcash/shared/funding/src/androidMain/kotlin/com/flipcash/app/funding/PurchaseMethodController.kt b/apps/flipcash/shared/funding/src/commonMain/kotlin/com/flipcash/app/funding/PurchaseMethodController.kt similarity index 100% rename from apps/flipcash/shared/funding/src/androidMain/kotlin/com/flipcash/app/funding/PurchaseMethodController.kt rename to apps/flipcash/shared/funding/src/commonMain/kotlin/com/flipcash/app/funding/PurchaseMethodController.kt diff --git a/apps/flipcash/shared/funding/src/androidMain/kotlin/com/flipcash/app/funding/PurchaseMethodState.kt b/apps/flipcash/shared/funding/src/commonMain/kotlin/com/flipcash/app/funding/PurchaseMethodState.kt similarity index 100% rename from apps/flipcash/shared/funding/src/androidMain/kotlin/com/flipcash/app/funding/PurchaseMethodState.kt rename to apps/flipcash/shared/funding/src/commonMain/kotlin/com/flipcash/app/funding/PurchaseMethodState.kt From 19e03d490e2a6537c6078e98bc94a68a707a0bb8 Mon Sep 17 00:00:00 2001 From: Brandon McAnsh Date: Fri, 23 Oct 2026 19:05:08 -0400 Subject: [PATCH 26/50] build(tokens): move shared:tokens to android+jvm KMP and lift the wallet coordinators TokenCoordinator, WalletRevealCoordinator, TokenSelectionResolver and SelectTokenViewModel move to commonMain; the rest of the module stays in androidMain. Two app:core seams replace the Android types TokenCoordinator used: - PreferencesFiles hands out the DataStore file; Android binds it to Context.preferencesDataStoreFile through Hilt. - AppProcessLifecycle is ProcessLifecycleOwner on Android and a lifecycle held in RESUMED on desktop, since lifecycle-process has no desktop artifact. SelectTokenViewModel becomes an open class without Hilt annotations. HiltSelectTokenViewModel in androidMain carries @HiltViewModel, and the ten hiltViewModel() call sites across eight features now request it. --- apps/flipcash/core/build.gradle.kts | 2 + .../lifecycle/AppProcessLifecycle.android.kt | 18 ++++ .../core/storage/ContextPreferencesFiles.kt | 25 +++++ .../app/core/lifecycle/AppProcessLifecycle.kt | 18 ++++ .../app/core/storage/PreferencesFiles.kt | 9 ++ .../core/lifecycle/AppProcessLifecycle.jvm.kt | 22 +++++ .../core/storage/DirectoryPreferencesFiles.kt | 8 ++ .../com/flipcash/app/balance/WalletScreen.kt | 3 +- .../screens/FundingSourceSelectionScreen.kt | 3 +- .../flipcash/app/deposit/DepositFlowScreen.kt | 3 +- .../boost/ReactionBoostCurrencySheet.kt | 3 +- .../screens/SelectGroupCurrencySheet.kt | 3 +- .../com/flipcash/app/tokens/SwapFlowScreen.kt | 7 +- .../flipcash/app/tokens/TokenSelectScreen.kt | 3 +- .../app/withdrawal/WithdrawalFlowScreen.kt | 3 +- apps/flipcash/shared/tokens/build.gradle.kts | 92 +++++++++++++------ .../flipcash/app/tokens/BalancePollerTest.kt | 0 .../app/tokens/FeeAffordableEntryTest.kt | 0 .../TokenCoordinatorMintOverloadTest.kt | 0 .../app/tokens/TokenSelectionResolverTest.kt | 0 .../app/tokens/TokenStateRepricingTest.kt | 0 .../TransactionNotificationPromptTest.kt | 0 .../app/tokens/UsdcDepositSweepTest.kt | 0 .../app/tokens/WalletRevealCoordinatorTest.kt | 0 .../BondingCurveProjectionTest.kt | 0 .../app/tokens/data/AggregationTypeTest.kt | 0 .../app/tokens/ui/DollarsConversionFeeTest.kt | 0 .../ui/MarketCapExplainerViewModelTest.kt | 0 .../ui/SelectTokenViewModelStateTest.kt | 0 .../ui/SwapViewModelBalancePrefetchTest.kt | 0 .../app/tokens/ui/SwapViewModelErrorTest.kt | 0 .../app/tokens/ui/SwapViewModelStateTest.kt | 0 .../ui/TokenInfoViewModelChartLoadTest.kt | 0 .../ui/TokenInfoViewModelConvertTest.kt | 0 .../tokens/ui/TokenInfoViewModelStateTest.kt | 0 .../com/flipcash/app/tokens/BalancePoller.kt | 0 .../flipcash/app/tokens/FeeAffordableEntry.kt | 0 .../flipcash/app/tokens/InlineCompletion.kt | 0 .../com/flipcash/app/tokens/TokenUpdater.kt | 0 .../tokens/TransactionNotificationPrompt.kt | 0 .../flipcash/app/tokens/UsdcDepositSweep.kt | 0 .../bondingcurve/BondingCurveProjection.kt | 0 .../app/tokens/data/AggregationType.kt | 0 .../app/tokens/data/MarketCapPoint.kt | 0 .../flipcash/app/tokens/data/MarketTrend.kt | 0 .../com/flipcash/app/tokens/data/Period.kt | 0 .../app/tokens/inject/PurchaseMethodModule.kt | 0 .../flipcash/app/tokens/inject/TokenModule.kt | 0 .../app/tokens/ui/HiltSelectTokenViewModel.kt | 15 +++ .../tokens/ui/MarketCapExplainerViewModel.kt | 0 .../flipcash/app/tokens/ui/SwapViewModel.kt | 0 .../app/tokens/ui/TokenInfoViewModel.kt | 0 .../com/flipcash/app/tokens/ui/TokenList.kt | 0 .../flipcash/app/tokens/TokenCoordinator.kt | 18 ++-- .../app/tokens/TokenSelectionResolver.kt | 0 .../app/tokens/WalletRevealCoordinator.kt | 0 .../app/tokens/ui/SelectTokenViewModel.kt | 8 +- 57 files changed, 210 insertions(+), 53 deletions(-) create mode 100644 apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/lifecycle/AppProcessLifecycle.android.kt create mode 100644 apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/storage/ContextPreferencesFiles.kt create mode 100644 apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/lifecycle/AppProcessLifecycle.kt create mode 100644 apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/storage/PreferencesFiles.kt create mode 100644 apps/flipcash/core/src/jvmMain/kotlin/com/flipcash/app/core/lifecycle/AppProcessLifecycle.jvm.kt create mode 100644 apps/flipcash/core/src/jvmMain/kotlin/com/flipcash/app/core/storage/DirectoryPreferencesFiles.kt rename apps/flipcash/shared/tokens/src/{test => androidHostTest}/kotlin/com/flipcash/app/tokens/BalancePollerTest.kt (100%) rename apps/flipcash/shared/tokens/src/{test => androidHostTest}/kotlin/com/flipcash/app/tokens/FeeAffordableEntryTest.kt (100%) rename apps/flipcash/shared/tokens/src/{test => androidHostTest}/kotlin/com/flipcash/app/tokens/TokenCoordinatorMintOverloadTest.kt (100%) rename apps/flipcash/shared/tokens/src/{test => androidHostTest}/kotlin/com/flipcash/app/tokens/TokenSelectionResolverTest.kt (100%) rename apps/flipcash/shared/tokens/src/{test => androidHostTest}/kotlin/com/flipcash/app/tokens/TokenStateRepricingTest.kt (100%) rename apps/flipcash/shared/tokens/src/{test => androidHostTest}/kotlin/com/flipcash/app/tokens/TransactionNotificationPromptTest.kt (100%) rename apps/flipcash/shared/tokens/src/{test => androidHostTest}/kotlin/com/flipcash/app/tokens/UsdcDepositSweepTest.kt (100%) rename apps/flipcash/shared/tokens/src/{test => androidHostTest}/kotlin/com/flipcash/app/tokens/WalletRevealCoordinatorTest.kt (100%) rename apps/flipcash/shared/tokens/src/{test => androidHostTest}/kotlin/com/flipcash/app/tokens/bondingcurve/BondingCurveProjectionTest.kt (100%) rename apps/flipcash/shared/tokens/src/{test => androidHostTest}/kotlin/com/flipcash/app/tokens/data/AggregationTypeTest.kt (100%) rename apps/flipcash/shared/tokens/src/{test => androidHostTest}/kotlin/com/flipcash/app/tokens/ui/DollarsConversionFeeTest.kt (100%) rename apps/flipcash/shared/tokens/src/{test => androidHostTest}/kotlin/com/flipcash/app/tokens/ui/MarketCapExplainerViewModelTest.kt (100%) rename apps/flipcash/shared/tokens/src/{test => androidHostTest}/kotlin/com/flipcash/app/tokens/ui/SelectTokenViewModelStateTest.kt (100%) rename apps/flipcash/shared/tokens/src/{test => androidHostTest}/kotlin/com/flipcash/app/tokens/ui/SwapViewModelBalancePrefetchTest.kt (100%) rename apps/flipcash/shared/tokens/src/{test => androidHostTest}/kotlin/com/flipcash/app/tokens/ui/SwapViewModelErrorTest.kt (100%) rename apps/flipcash/shared/tokens/src/{test => androidHostTest}/kotlin/com/flipcash/app/tokens/ui/SwapViewModelStateTest.kt (100%) rename apps/flipcash/shared/tokens/src/{test => androidHostTest}/kotlin/com/flipcash/app/tokens/ui/TokenInfoViewModelChartLoadTest.kt (100%) rename apps/flipcash/shared/tokens/src/{test => androidHostTest}/kotlin/com/flipcash/app/tokens/ui/TokenInfoViewModelConvertTest.kt (100%) rename apps/flipcash/shared/tokens/src/{test => androidHostTest}/kotlin/com/flipcash/app/tokens/ui/TokenInfoViewModelStateTest.kt (100%) rename apps/flipcash/shared/tokens/src/{main => androidMain}/kotlin/com/flipcash/app/tokens/BalancePoller.kt (100%) rename apps/flipcash/shared/tokens/src/{main => androidMain}/kotlin/com/flipcash/app/tokens/FeeAffordableEntry.kt (100%) rename apps/flipcash/shared/tokens/src/{main => androidMain}/kotlin/com/flipcash/app/tokens/InlineCompletion.kt (100%) rename apps/flipcash/shared/tokens/src/{main => androidMain}/kotlin/com/flipcash/app/tokens/TokenUpdater.kt (100%) rename apps/flipcash/shared/tokens/src/{main => androidMain}/kotlin/com/flipcash/app/tokens/TransactionNotificationPrompt.kt (100%) rename apps/flipcash/shared/tokens/src/{main => androidMain}/kotlin/com/flipcash/app/tokens/UsdcDepositSweep.kt (100%) rename apps/flipcash/shared/tokens/src/{main => androidMain}/kotlin/com/flipcash/app/tokens/bondingcurve/BondingCurveProjection.kt (100%) rename apps/flipcash/shared/tokens/src/{main => androidMain}/kotlin/com/flipcash/app/tokens/data/AggregationType.kt (100%) rename apps/flipcash/shared/tokens/src/{main => androidMain}/kotlin/com/flipcash/app/tokens/data/MarketCapPoint.kt (100%) rename apps/flipcash/shared/tokens/src/{main => androidMain}/kotlin/com/flipcash/app/tokens/data/MarketTrend.kt (100%) rename apps/flipcash/shared/tokens/src/{main => androidMain}/kotlin/com/flipcash/app/tokens/data/Period.kt (100%) rename apps/flipcash/shared/tokens/src/{main => androidMain}/kotlin/com/flipcash/app/tokens/inject/PurchaseMethodModule.kt (100%) rename apps/flipcash/shared/tokens/src/{main => androidMain}/kotlin/com/flipcash/app/tokens/inject/TokenModule.kt (100%) create mode 100644 apps/flipcash/shared/tokens/src/androidMain/kotlin/com/flipcash/app/tokens/ui/HiltSelectTokenViewModel.kt rename apps/flipcash/shared/tokens/src/{main => androidMain}/kotlin/com/flipcash/app/tokens/ui/MarketCapExplainerViewModel.kt (100%) rename apps/flipcash/shared/tokens/src/{main => androidMain}/kotlin/com/flipcash/app/tokens/ui/SwapViewModel.kt (100%) rename apps/flipcash/shared/tokens/src/{main => androidMain}/kotlin/com/flipcash/app/tokens/ui/TokenInfoViewModel.kt (100%) rename apps/flipcash/shared/tokens/src/{main => androidMain}/kotlin/com/flipcash/app/tokens/ui/TokenList.kt (100%) rename apps/flipcash/shared/tokens/src/{main => commonMain}/kotlin/com/flipcash/app/tokens/TokenCoordinator.kt (98%) rename apps/flipcash/shared/tokens/src/{main => commonMain}/kotlin/com/flipcash/app/tokens/TokenSelectionResolver.kt (100%) rename apps/flipcash/shared/tokens/src/{main => commonMain}/kotlin/com/flipcash/app/tokens/WalletRevealCoordinator.kt (100%) rename apps/flipcash/shared/tokens/src/{main => commonMain}/kotlin/com/flipcash/app/tokens/ui/SelectTokenViewModel.kt (97%) diff --git a/apps/flipcash/core/build.gradle.kts b/apps/flipcash/core/build.gradle.kts index d28cbdf678..d7da03a813 100644 --- a/apps/flipcash/core/build.gradle.kts +++ b/apps/flipcash/core/build.gradle.kts @@ -19,6 +19,7 @@ kotlin { commonMain.dependencies { implementation(project(":libs:parcelable")) implementation(libs.javax.inject) + api(libs.androidx.lifecycle.runtime.common) api(project(":ui:navigation")) api(project(":ui:core")) api(libs.navigation3.runtime) @@ -54,6 +55,7 @@ kotlin { implementation(libs.firebase.messaging) implementation(libs.androidx.localbroadcastmanager) implementation(libs.androidx.datastore) + implementation(libs.androidx.lifecycle.process) implementation(libs.compose.material3) api(libs.coil3) api(libs.coil3.network) diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/lifecycle/AppProcessLifecycle.android.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/lifecycle/AppProcessLifecycle.android.kt new file mode 100644 index 0000000000..adecd9b283 --- /dev/null +++ b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/lifecycle/AppProcessLifecycle.android.kt @@ -0,0 +1,18 @@ +package com.flipcash.app.core.lifecycle + +import android.os.Handler +import android.os.Looper +import androidx.lifecycle.LifecycleObserver +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.ProcessLifecycleOwner + +actual object AppProcessLifecycle { + actual val owner: LifecycleOwner + get() = ProcessLifecycleOwner.get() + + actual fun addObserver(observer: LifecycleObserver) { + Handler(Looper.getMainLooper()).post { + owner.lifecycle.addObserver(observer) + } + } +} diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/storage/ContextPreferencesFiles.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/storage/ContextPreferencesFiles.kt new file mode 100644 index 0000000000..26e32fdb13 --- /dev/null +++ b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/storage/ContextPreferencesFiles.kt @@ -0,0 +1,25 @@ +package com.flipcash.app.core.storage + +import android.content.Context +import androidx.datastore.preferences.preferencesDataStoreFile +import dagger.Binds +import dagger.Module +import dagger.hilt.InstallIn +import dagger.hilt.android.qualifiers.ApplicationContext +import dagger.hilt.components.SingletonComponent +import java.io.File +import javax.inject.Inject + +/** [PreferencesFiles] backed by [preferencesDataStoreFile], the location DataStore has always used. */ +internal class ContextPreferencesFiles @Inject constructor( + @param:ApplicationContext private val context: Context, +) : PreferencesFiles { + override fun file(name: String): File = context.preferencesDataStoreFile(name) +} + +@Module +@InstallIn(SingletonComponent::class) +internal abstract class PreferencesFilesModule { + @Binds + abstract fun bindPreferencesFiles(impl: ContextPreferencesFiles): PreferencesFiles +} diff --git a/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/lifecycle/AppProcessLifecycle.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/lifecycle/AppProcessLifecycle.kt new file mode 100644 index 0000000000..1b6872a281 --- /dev/null +++ b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/lifecycle/AppProcessLifecycle.kt @@ -0,0 +1,18 @@ +package com.flipcash.app.core.lifecycle + +import androidx.lifecycle.LifecycleObserver +import androidx.lifecycle.LifecycleOwner + +/** + * The process-wide lifecycle. On Android it is [androidx.lifecycle.ProcessLifecycleOwner]; on + * desktop, where `lifecycle-process` has no artifact, it is RESUMED for as long as the app runs. + */ +expect object AppProcessLifecycle { + val owner: LifecycleOwner + + /** + * Adds [observer] to [owner]'s lifecycle. Safe to call from any thread: on Android the add is + * posted to the main thread, which `addObserver` requires. + */ + fun addObserver(observer: LifecycleObserver) +} diff --git a/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/storage/PreferencesFiles.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/storage/PreferencesFiles.kt new file mode 100644 index 0000000000..760a6d0849 --- /dev/null +++ b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/storage/PreferencesFiles.kt @@ -0,0 +1,9 @@ +package com.flipcash.app.core.storage + +import java.io.File + +/** Where DataStore preference files live: the app's files dir on Android, an app data dir on desktop. */ +fun interface PreferencesFiles { + /** The file backing the preferences store called [name]. */ + fun file(name: String): File +} diff --git a/apps/flipcash/core/src/jvmMain/kotlin/com/flipcash/app/core/lifecycle/AppProcessLifecycle.jvm.kt b/apps/flipcash/core/src/jvmMain/kotlin/com/flipcash/app/core/lifecycle/AppProcessLifecycle.jvm.kt new file mode 100644 index 0000000000..1170ace0e9 --- /dev/null +++ b/apps/flipcash/core/src/jvmMain/kotlin/com/flipcash/app/core/lifecycle/AppProcessLifecycle.jvm.kt @@ -0,0 +1,22 @@ +package com.flipcash.app.core.lifecycle + +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleObserver +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.LifecycleRegistry + +actual object AppProcessLifecycle { + actual val owner: LifecycleOwner = object : LifecycleOwner { + override val lifecycle: Lifecycle get() = registry + } + + // A desktop window has no background state the app needs to react to yet, so the process + // stays RESUMED. Window minimise/close can drive this registry once something needs it. + private val registry = LifecycleRegistry.createUnsafe(owner).apply { + currentState = Lifecycle.State.RESUMED + } + + actual fun addObserver(observer: LifecycleObserver) { + synchronized(registry) { registry.addObserver(observer) } + } +} diff --git a/apps/flipcash/core/src/jvmMain/kotlin/com/flipcash/app/core/storage/DirectoryPreferencesFiles.kt b/apps/flipcash/core/src/jvmMain/kotlin/com/flipcash/app/core/storage/DirectoryPreferencesFiles.kt new file mode 100644 index 0000000000..5a698a06d4 --- /dev/null +++ b/apps/flipcash/core/src/jvmMain/kotlin/com/flipcash/app/core/storage/DirectoryPreferencesFiles.kt @@ -0,0 +1,8 @@ +package com.flipcash.app.core.storage + +import java.io.File + +/** [PreferencesFiles] rooted at [directory], using DataStore's `.preferences_pb` naming. */ +class DirectoryPreferencesFiles(private val directory: File) : PreferencesFiles { + override fun file(name: String): File = File(directory, "datastore/$name.preferences_pb") +} diff --git a/apps/flipcash/features/balance/src/main/kotlin/com/flipcash/app/balance/WalletScreen.kt b/apps/flipcash/features/balance/src/main/kotlin/com/flipcash/app/balance/WalletScreen.kt index 5bfd043f03..09874e18c5 100644 --- a/apps/flipcash/features/balance/src/main/kotlin/com/flipcash/app/balance/WalletScreen.kt +++ b/apps/flipcash/features/balance/src/main/kotlin/com/flipcash/app/balance/WalletScreen.kt @@ -13,6 +13,7 @@ import com.flipcash.app.core.AppRoute import com.flipcash.app.core.extensions.openAsSheet import com.flipcash.app.core.tokens.TokenPurpose import com.flipcash.app.tokens.ui.SelectTokenViewModel +import com.flipcash.app.tokens.ui.HiltSelectTokenViewModel import com.getcode.navigation.core.LocalCodeNavigator import kotlinx.coroutines.flow.filterIsInstance import kotlinx.coroutines.flow.launchIn @@ -27,7 +28,7 @@ fun WalletScreen() { horizontalAlignment = Alignment.CenterHorizontally, ) { val viewModel = hiltViewModel() - val tokenViewModel = hiltViewModel() + val tokenViewModel = hiltViewModel() WalletScreen(viewModel, tokenViewModel) LaunchedEffect(tokenViewModel) { diff --git a/apps/flipcash/features/currency-creator/src/main/kotlin/com/flipcash/app/currencycreator/internal/screens/FundingSourceSelectionScreen.kt b/apps/flipcash/features/currency-creator/src/main/kotlin/com/flipcash/app/currencycreator/internal/screens/FundingSourceSelectionScreen.kt index 0299395bad..01063ee26e 100644 --- a/apps/flipcash/features/currency-creator/src/main/kotlin/com/flipcash/app/currencycreator/internal/screens/FundingSourceSelectionScreen.kt +++ b/apps/flipcash/features/currency-creator/src/main/kotlin/com/flipcash/app/currencycreator/internal/screens/FundingSourceSelectionScreen.kt @@ -12,6 +12,7 @@ import com.flipcash.app.core.tokens.TokenPurpose import com.flipcash.app.currencycreator.internal.CurrencyCreatorViewModel import com.flipcash.app.tokens.TokenSelectScreen import com.flipcash.app.tokens.ui.SelectTokenViewModel +import com.flipcash.app.tokens.ui.HiltSelectTokenViewModel import com.getcode.navigation.flow.flowSharedViewModel import com.getcode.navigation.flow.rememberFlowNavigator import kotlinx.coroutines.flow.filter @@ -22,7 +23,7 @@ import kotlinx.coroutines.flow.onEach @Composable internal fun FundingSourceSelectionScreen() { - val selectionViewModel = hiltViewModel() + val selectionViewModel = hiltViewModel() val viewModel = flowSharedViewModel() val state by viewModel.stateFlow.collectAsStateWithLifecycle() val flowNavigator = rememberFlowNavigator() diff --git a/apps/flipcash/features/deposit/src/main/kotlin/com/flipcash/app/deposit/DepositFlowScreen.kt b/apps/flipcash/features/deposit/src/main/kotlin/com/flipcash/app/deposit/DepositFlowScreen.kt index dd12134da0..1261aa7524 100644 --- a/apps/flipcash/features/deposit/src/main/kotlin/com/flipcash/app/deposit/DepositFlowScreen.kt +++ b/apps/flipcash/features/deposit/src/main/kotlin/com/flipcash/app/deposit/DepositFlowScreen.kt @@ -24,6 +24,7 @@ import com.flipcash.app.deposit.internal.DepositViewModel import com.flipcash.app.deposit.internal.UsdcDepositInformationScreen import com.flipcash.app.theme.FlipcashThemeWrapper import com.flipcash.app.tokens.ui.SelectTokenViewModel +import com.flipcash.app.tokens.ui.HiltSelectTokenViewModel import com.flipcash.app.tokens.ui.TokenList import com.flipcash.core.R import com.getcode.navigation.annotatedEntry @@ -99,7 +100,7 @@ private fun depositEntryProvider( @Composable private fun DepositSelectTokenScreen() { val flowNavigator = rememberFlowNavigator() - val viewModel = hiltViewModel() + val viewModel = hiltViewModel() val state by viewModel.stateFlow.collectAsStateWithLifecycle() Column( diff --git a/apps/flipcash/features/messenger/src/main/kotlin/com/flipcash/app/messenger/internal/screens/boost/ReactionBoostCurrencySheet.kt b/apps/flipcash/features/messenger/src/main/kotlin/com/flipcash/app/messenger/internal/screens/boost/ReactionBoostCurrencySheet.kt index f6e9e49145..11799e90c3 100644 --- a/apps/flipcash/features/messenger/src/main/kotlin/com/flipcash/app/messenger/internal/screens/boost/ReactionBoostCurrencySheet.kt +++ b/apps/flipcash/features/messenger/src/main/kotlin/com/flipcash/app/messenger/internal/screens/boost/ReactionBoostCurrencySheet.kt @@ -20,6 +20,7 @@ import com.flipcash.app.core.ui.TokenBalanceStyle import com.flipcash.app.core.ui.TokenSelectionStyle import com.flipcash.app.core.ui.rememberTokenBalanceRowStyling import com.flipcash.app.tokens.ui.SelectTokenViewModel +import com.flipcash.app.tokens.ui.HiltSelectTokenViewModel import com.flipcash.app.tokens.ui.TokenList import com.flipcash.app.tokens.ui.TokenListPresentation import com.getcode.navigation.scenes.LocalBottomSheetDismissDispatcher @@ -38,7 +39,7 @@ import kotlinx.coroutines.flow.onEach internal fun ReactionBoostCurrencySheet() { // Exit through the sheet so it animates down rather than having its scene deleted mid-frame. val dismissSheet = LocalBottomSheetDismissDispatcher.current - val viewModel = hiltViewModel() + val viewModel = hiltViewModel() val state by viewModel.stateFlow.collectAsStateWithLifecycle() Column( diff --git a/apps/flipcash/features/tipping/src/main/kotlin/com/flipcash/app/tipping/internal/screens/SelectGroupCurrencySheet.kt b/apps/flipcash/features/tipping/src/main/kotlin/com/flipcash/app/tipping/internal/screens/SelectGroupCurrencySheet.kt index b20c7759ef..984f82b40d 100644 --- a/apps/flipcash/features/tipping/src/main/kotlin/com/flipcash/app/tipping/internal/screens/SelectGroupCurrencySheet.kt +++ b/apps/flipcash/features/tipping/src/main/kotlin/com/flipcash/app/tipping/internal/screens/SelectGroupCurrencySheet.kt @@ -22,6 +22,7 @@ import com.flipcash.app.tipping.internal.CreateGroupViewModel import com.flipcash.app.tipping.internal.communityCurrencies import com.flipcash.app.tipping.internal.withoutUsdf import com.flipcash.app.tokens.ui.SelectTokenViewModel +import com.flipcash.app.tokens.ui.HiltSelectTokenViewModel import com.flipcash.app.tokens.ui.TokenList import com.flipcash.app.tokens.ui.TokenListPresentation import com.flipcash.features.tipping.R @@ -48,7 +49,7 @@ internal fun SelectGroupCurrencySheet(viewModel: CreateGroupViewModel) { val dismissSheet = LocalBottomSheetDismissDispatcher.current val state by viewModel.stateFlow.collectAsStateWithLifecycle() - val tokenViewModel = hiltViewModel() + val tokenViewModel = hiltViewModel() val tokenState by tokenViewModel.stateFlow.collectAsStateWithLifecycle() val rowStyling = rememberTokenBalanceRowStyling( diff --git a/apps/flipcash/features/tokens/src/main/kotlin/com/flipcash/app/tokens/SwapFlowScreen.kt b/apps/flipcash/features/tokens/src/main/kotlin/com/flipcash/app/tokens/SwapFlowScreen.kt index 27122bb49b..c68a805280 100644 --- a/apps/flipcash/features/tokens/src/main/kotlin/com/flipcash/app/tokens/SwapFlowScreen.kt +++ b/apps/flipcash/features/tokens/src/main/kotlin/com/flipcash/app/tokens/SwapFlowScreen.kt @@ -24,6 +24,7 @@ import com.flipcash.app.core.tokens.SwapResult import com.flipcash.app.core.tokens.SwapStep import com.flipcash.app.core.tokens.TokenPurpose import com.flipcash.app.tokens.ui.SelectTokenViewModel +import com.flipcash.app.tokens.ui.HiltSelectTokenViewModel import com.flipcash.app.tokens.ui.TokenListPresentation import com.flipcash.app.tokens.ui.SwapViewModel import com.getcode.opencode.model.financial.Fiat @@ -145,7 +146,7 @@ private fun swapEntryProvider( */ @Composable private fun ConvertDestinationSelectScreen() { - val selectionViewModel = hiltViewModel() + val selectionViewModel = hiltViewModel() val viewModel = flowSharedViewModel() val flowNavigator = rememberFlowNavigator() val purpose = viewModel.stateFlow.collectAsStateWithLifecycle().value.purpose @@ -202,7 +203,7 @@ private fun ConvertDestinationSelectScreen() { */ @Composable private fun BuyFundingSelectScreen() { - val selectionViewModel = hiltViewModel() + val selectionViewModel = hiltViewModel() val viewModel = flowSharedViewModel() val flowNavigator = rememberFlowNavigator() val state = viewModel.stateFlow.collectAsStateWithLifecycle().value @@ -249,7 +250,7 @@ private fun BuyFundingSelectScreen() { @Composable private fun SwapPurchaseTokenSelectScreen(targetMint: Mint, amount: Fiat) { - val selectionViewModel = hiltViewModel() + val selectionViewModel = hiltViewModel() val viewModel = flowSharedViewModel() val flowNavigator = rememberFlowNavigator() diff --git a/apps/flipcash/features/tokens/src/main/kotlin/com/flipcash/app/tokens/TokenSelectScreen.kt b/apps/flipcash/features/tokens/src/main/kotlin/com/flipcash/app/tokens/TokenSelectScreen.kt index e6d40a21a3..ffcf401e4c 100644 --- a/apps/flipcash/features/tokens/src/main/kotlin/com/flipcash/app/tokens/TokenSelectScreen.kt +++ b/apps/flipcash/features/tokens/src/main/kotlin/com/flipcash/app/tokens/TokenSelectScreen.kt @@ -14,6 +14,7 @@ import com.flipcash.app.core.AppRoute.Transfers.Withdrawal import com.flipcash.app.core.tokens.TokenPurpose import com.flipcash.app.tokens.internal.SelectTokenScreen import com.flipcash.app.tokens.ui.SelectTokenViewModel +import com.flipcash.app.tokens.ui.HiltSelectTokenViewModel import com.flipcash.app.tokens.ui.TokenListPresentation import com.flipcash.features.tokens.R import com.getcode.navigation.core.LocalCodeNavigator @@ -33,7 +34,7 @@ fun TokenSelectScreen( loadingMint: Mint? = null, ) { val navigator = LocalCodeNavigator.current - val viewModel = hiltViewModel() + val viewModel = hiltViewModel() Column( modifier = if (presentation.wrapHeight) Modifier.fillMaxWidth() diff --git a/apps/flipcash/features/withdrawal/src/main/kotlin/com/flipcash/app/withdrawal/WithdrawalFlowScreen.kt b/apps/flipcash/features/withdrawal/src/main/kotlin/com/flipcash/app/withdrawal/WithdrawalFlowScreen.kt index 9cbfdf396e..e5154820c9 100644 --- a/apps/flipcash/features/withdrawal/src/main/kotlin/com/flipcash/app/withdrawal/WithdrawalFlowScreen.kt +++ b/apps/flipcash/features/withdrawal/src/main/kotlin/com/flipcash/app/withdrawal/WithdrawalFlowScreen.kt @@ -22,6 +22,7 @@ import com.flipcash.app.core.withdrawal.WithdrawalResult import com.flipcash.app.core.withdrawal.WithdrawalStep import com.flipcash.app.theme.FlipcashThemeWrapper import com.flipcash.app.tokens.ui.SelectTokenViewModel +import com.flipcash.app.tokens.ui.HiltSelectTokenViewModel import com.flipcash.app.tokens.ui.TokenList import com.flipcash.app.withdrawal.internal.screens.UsdcWithdrawalInformationScreen import com.flipcash.app.withdrawal.internal.screens.WithdrawalConfirmationScreen @@ -105,7 +106,7 @@ private fun withdrawalEntryProvider(): (NavKey) -> NavEntry = entryProvi @Composable private fun WithdrawalSelectTokenScreen() { val flowNavigator = rememberFlowNavigator() - val viewModel = hiltViewModel() + val viewModel = hiltViewModel() val state by viewModel.stateFlow.collectAsStateWithLifecycle() Column( diff --git a/apps/flipcash/shared/tokens/build.gradle.kts b/apps/flipcash/shared/tokens/build.gradle.kts index 18842e020e..75776da4b7 100644 --- a/apps/flipcash/shared/tokens/build.gradle.kts +++ b/apps/flipcash/shared/tokens/build.gradle.kts @@ -1,38 +1,74 @@ plugins { - alias(libs.plugins.flipcash.android.feature) + alias(libs.plugins.flipcash.kmp.app.library) + alias(libs.plugins.compose.compiler) + alias(libs.plugins.kotlin.ksp) } -android { - namespace = "${Gradle.flipcashNamespace}.shared.tokens" -} +kotlin { + android { + namespace = "${Gradle.flipcashNamespace}.shared.tokens" + // No resources of its own; SwapViewModel and TokenInfoViewModel read dependency strings through R. + androidResources { + enable = true + } + } -dependencies { - testImplementation(kotlin("test")) - testImplementation(libs.bundles.unit.testing) - testImplementation(project(":ui:resources:test-fixtures")) - testImplementation(project(":libs:currency-math:test-fixtures")) - testImplementation(libs.mockito.kotlin) + sourceSets { + commonMain.dependencies { + api(project(":apps:flipcash:shared:tokens:core")) - api(project(":apps:flipcash:shared:tokens:core")) + implementation(project(":apps:flipcash:core")) + implementation(project(":apps:flipcash:shared:persistence:sources")) + implementation(project(":services:opencode")) + implementation(project(":libs:coroutines")) + implementation(project(":libs:encryption:keys")) + implementation(project(":libs:logging")) + implementation(project(":ui:navigation")) - implementation(libs.androidx.datastore) + implementation(libs.jetbrains.compose.runtime) + implementation(libs.androidx.datastore.preferences.core) + implementation(libs.javax.inject) + } + androidMain.dependencies { + // What flipcash.android.feature supplied before the move to KMP. + implementation(libs.bundles.hilt) + implementation(project.dependencies.platform(libs.compose.bom)) + implementation(libs.bundles.compose) + implementation(project(":ui:core")) + implementation(project(":ui:components")) + implementation(project(":ui:resources")) + implementation(project(":ui:theme")) + implementation(project(":apps:flipcash:core-ui")) + implementation(project(":services:flipcash")) - implementation(libs.androidx.lifecycle.process) + implementation(libs.androidx.datastore) + implementation(libs.androidx.lifecycle.process) + implementation(libs.bundles.haze) - implementation(libs.bundles.haze) + implementation(project(":apps:flipcash:shared:amount-entry")) + implementation(project(":apps:flipcash:shared:funding")) + implementation(project(":apps:flipcash:shared:transaction-history")) + implementation(project(":apps:flipcash:shared:analytics")) + implementation(project(":apps:flipcash:shared:featureflags")) + implementation(project(":apps:flipcash:shared:onramp:coinbase")) + implementation(project(":apps:flipcash:shared:onramp:deeplinks")) + implementation(project(":apps:flipcash:shared:shareable")) + implementation(project(":apps:flipcash:shared:userflags")) + implementation(project(":libs:datetime")) + implementation(project(":libs:messaging")) + } + getByName("androidHostTest").dependencies { + implementation(kotlin("test")) + implementation(libs.bundles.unit.testing) + implementation(project(":ui:resources:test-fixtures")) + implementation(project(":libs:currency-math:test-fixtures")) + implementation(libs.mockito.kotlin) + implementation(project(":apps:flipcash:shared:analytics:test-fixtures")) + } + } +} - implementation(project(":apps:flipcash:shared:amount-entry")) - implementation(project(":apps:flipcash:shared:funding")) - implementation(project(":apps:flipcash:shared:transaction-history")) - implementation(project(":apps:flipcash:shared:analytics")) - testImplementation(project(":apps:flipcash:shared:analytics:test-fixtures")) - implementation(project(":apps:flipcash:shared:featureflags")) - implementation(project(":apps:flipcash:shared:onramp:coinbase")) - implementation(project(":apps:flipcash:shared:onramp:deeplinks")) - implementation(project(":apps:flipcash:shared:funding")) - implementation(project(":apps:flipcash:shared:persistence:sources")) - implementation(project(":apps:flipcash:shared:shareable")) - implementation(project(":apps:flipcash:shared:userflags")) - implementation(project(":libs:datetime")) - implementation(project(":libs:messaging")) +dependencies { + add("kspAndroid", libs.hilt.android.compiler) + add("kspAndroid", libs.hilt.compiler) } diff --git a/apps/flipcash/shared/tokens/src/test/kotlin/com/flipcash/app/tokens/BalancePollerTest.kt b/apps/flipcash/shared/tokens/src/androidHostTest/kotlin/com/flipcash/app/tokens/BalancePollerTest.kt similarity index 100% rename from apps/flipcash/shared/tokens/src/test/kotlin/com/flipcash/app/tokens/BalancePollerTest.kt rename to apps/flipcash/shared/tokens/src/androidHostTest/kotlin/com/flipcash/app/tokens/BalancePollerTest.kt diff --git a/apps/flipcash/shared/tokens/src/test/kotlin/com/flipcash/app/tokens/FeeAffordableEntryTest.kt b/apps/flipcash/shared/tokens/src/androidHostTest/kotlin/com/flipcash/app/tokens/FeeAffordableEntryTest.kt similarity index 100% rename from apps/flipcash/shared/tokens/src/test/kotlin/com/flipcash/app/tokens/FeeAffordableEntryTest.kt rename to apps/flipcash/shared/tokens/src/androidHostTest/kotlin/com/flipcash/app/tokens/FeeAffordableEntryTest.kt diff --git a/apps/flipcash/shared/tokens/src/test/kotlin/com/flipcash/app/tokens/TokenCoordinatorMintOverloadTest.kt b/apps/flipcash/shared/tokens/src/androidHostTest/kotlin/com/flipcash/app/tokens/TokenCoordinatorMintOverloadTest.kt similarity index 100% rename from apps/flipcash/shared/tokens/src/test/kotlin/com/flipcash/app/tokens/TokenCoordinatorMintOverloadTest.kt rename to apps/flipcash/shared/tokens/src/androidHostTest/kotlin/com/flipcash/app/tokens/TokenCoordinatorMintOverloadTest.kt diff --git a/apps/flipcash/shared/tokens/src/test/kotlin/com/flipcash/app/tokens/TokenSelectionResolverTest.kt b/apps/flipcash/shared/tokens/src/androidHostTest/kotlin/com/flipcash/app/tokens/TokenSelectionResolverTest.kt similarity index 100% rename from apps/flipcash/shared/tokens/src/test/kotlin/com/flipcash/app/tokens/TokenSelectionResolverTest.kt rename to apps/flipcash/shared/tokens/src/androidHostTest/kotlin/com/flipcash/app/tokens/TokenSelectionResolverTest.kt diff --git a/apps/flipcash/shared/tokens/src/test/kotlin/com/flipcash/app/tokens/TokenStateRepricingTest.kt b/apps/flipcash/shared/tokens/src/androidHostTest/kotlin/com/flipcash/app/tokens/TokenStateRepricingTest.kt similarity index 100% rename from apps/flipcash/shared/tokens/src/test/kotlin/com/flipcash/app/tokens/TokenStateRepricingTest.kt rename to apps/flipcash/shared/tokens/src/androidHostTest/kotlin/com/flipcash/app/tokens/TokenStateRepricingTest.kt diff --git a/apps/flipcash/shared/tokens/src/test/kotlin/com/flipcash/app/tokens/TransactionNotificationPromptTest.kt b/apps/flipcash/shared/tokens/src/androidHostTest/kotlin/com/flipcash/app/tokens/TransactionNotificationPromptTest.kt similarity index 100% rename from apps/flipcash/shared/tokens/src/test/kotlin/com/flipcash/app/tokens/TransactionNotificationPromptTest.kt rename to apps/flipcash/shared/tokens/src/androidHostTest/kotlin/com/flipcash/app/tokens/TransactionNotificationPromptTest.kt diff --git a/apps/flipcash/shared/tokens/src/test/kotlin/com/flipcash/app/tokens/UsdcDepositSweepTest.kt b/apps/flipcash/shared/tokens/src/androidHostTest/kotlin/com/flipcash/app/tokens/UsdcDepositSweepTest.kt similarity index 100% rename from apps/flipcash/shared/tokens/src/test/kotlin/com/flipcash/app/tokens/UsdcDepositSweepTest.kt rename to apps/flipcash/shared/tokens/src/androidHostTest/kotlin/com/flipcash/app/tokens/UsdcDepositSweepTest.kt diff --git a/apps/flipcash/shared/tokens/src/test/kotlin/com/flipcash/app/tokens/WalletRevealCoordinatorTest.kt b/apps/flipcash/shared/tokens/src/androidHostTest/kotlin/com/flipcash/app/tokens/WalletRevealCoordinatorTest.kt similarity index 100% rename from apps/flipcash/shared/tokens/src/test/kotlin/com/flipcash/app/tokens/WalletRevealCoordinatorTest.kt rename to apps/flipcash/shared/tokens/src/androidHostTest/kotlin/com/flipcash/app/tokens/WalletRevealCoordinatorTest.kt diff --git a/apps/flipcash/shared/tokens/src/test/kotlin/com/flipcash/app/tokens/bondingcurve/BondingCurveProjectionTest.kt b/apps/flipcash/shared/tokens/src/androidHostTest/kotlin/com/flipcash/app/tokens/bondingcurve/BondingCurveProjectionTest.kt similarity index 100% rename from apps/flipcash/shared/tokens/src/test/kotlin/com/flipcash/app/tokens/bondingcurve/BondingCurveProjectionTest.kt rename to apps/flipcash/shared/tokens/src/androidHostTest/kotlin/com/flipcash/app/tokens/bondingcurve/BondingCurveProjectionTest.kt diff --git a/apps/flipcash/shared/tokens/src/test/kotlin/com/flipcash/app/tokens/data/AggregationTypeTest.kt b/apps/flipcash/shared/tokens/src/androidHostTest/kotlin/com/flipcash/app/tokens/data/AggregationTypeTest.kt similarity index 100% rename from apps/flipcash/shared/tokens/src/test/kotlin/com/flipcash/app/tokens/data/AggregationTypeTest.kt rename to apps/flipcash/shared/tokens/src/androidHostTest/kotlin/com/flipcash/app/tokens/data/AggregationTypeTest.kt diff --git a/apps/flipcash/shared/tokens/src/test/kotlin/com/flipcash/app/tokens/ui/DollarsConversionFeeTest.kt b/apps/flipcash/shared/tokens/src/androidHostTest/kotlin/com/flipcash/app/tokens/ui/DollarsConversionFeeTest.kt similarity index 100% rename from apps/flipcash/shared/tokens/src/test/kotlin/com/flipcash/app/tokens/ui/DollarsConversionFeeTest.kt rename to apps/flipcash/shared/tokens/src/androidHostTest/kotlin/com/flipcash/app/tokens/ui/DollarsConversionFeeTest.kt diff --git a/apps/flipcash/shared/tokens/src/test/kotlin/com/flipcash/app/tokens/ui/MarketCapExplainerViewModelTest.kt b/apps/flipcash/shared/tokens/src/androidHostTest/kotlin/com/flipcash/app/tokens/ui/MarketCapExplainerViewModelTest.kt similarity index 100% rename from apps/flipcash/shared/tokens/src/test/kotlin/com/flipcash/app/tokens/ui/MarketCapExplainerViewModelTest.kt rename to apps/flipcash/shared/tokens/src/androidHostTest/kotlin/com/flipcash/app/tokens/ui/MarketCapExplainerViewModelTest.kt diff --git a/apps/flipcash/shared/tokens/src/test/kotlin/com/flipcash/app/tokens/ui/SelectTokenViewModelStateTest.kt b/apps/flipcash/shared/tokens/src/androidHostTest/kotlin/com/flipcash/app/tokens/ui/SelectTokenViewModelStateTest.kt similarity index 100% rename from apps/flipcash/shared/tokens/src/test/kotlin/com/flipcash/app/tokens/ui/SelectTokenViewModelStateTest.kt rename to apps/flipcash/shared/tokens/src/androidHostTest/kotlin/com/flipcash/app/tokens/ui/SelectTokenViewModelStateTest.kt diff --git a/apps/flipcash/shared/tokens/src/test/kotlin/com/flipcash/app/tokens/ui/SwapViewModelBalancePrefetchTest.kt b/apps/flipcash/shared/tokens/src/androidHostTest/kotlin/com/flipcash/app/tokens/ui/SwapViewModelBalancePrefetchTest.kt similarity index 100% rename from apps/flipcash/shared/tokens/src/test/kotlin/com/flipcash/app/tokens/ui/SwapViewModelBalancePrefetchTest.kt rename to apps/flipcash/shared/tokens/src/androidHostTest/kotlin/com/flipcash/app/tokens/ui/SwapViewModelBalancePrefetchTest.kt diff --git a/apps/flipcash/shared/tokens/src/test/kotlin/com/flipcash/app/tokens/ui/SwapViewModelErrorTest.kt b/apps/flipcash/shared/tokens/src/androidHostTest/kotlin/com/flipcash/app/tokens/ui/SwapViewModelErrorTest.kt similarity index 100% rename from apps/flipcash/shared/tokens/src/test/kotlin/com/flipcash/app/tokens/ui/SwapViewModelErrorTest.kt rename to apps/flipcash/shared/tokens/src/androidHostTest/kotlin/com/flipcash/app/tokens/ui/SwapViewModelErrorTest.kt diff --git a/apps/flipcash/shared/tokens/src/test/kotlin/com/flipcash/app/tokens/ui/SwapViewModelStateTest.kt b/apps/flipcash/shared/tokens/src/androidHostTest/kotlin/com/flipcash/app/tokens/ui/SwapViewModelStateTest.kt similarity index 100% rename from apps/flipcash/shared/tokens/src/test/kotlin/com/flipcash/app/tokens/ui/SwapViewModelStateTest.kt rename to apps/flipcash/shared/tokens/src/androidHostTest/kotlin/com/flipcash/app/tokens/ui/SwapViewModelStateTest.kt diff --git a/apps/flipcash/shared/tokens/src/test/kotlin/com/flipcash/app/tokens/ui/TokenInfoViewModelChartLoadTest.kt b/apps/flipcash/shared/tokens/src/androidHostTest/kotlin/com/flipcash/app/tokens/ui/TokenInfoViewModelChartLoadTest.kt similarity index 100% rename from apps/flipcash/shared/tokens/src/test/kotlin/com/flipcash/app/tokens/ui/TokenInfoViewModelChartLoadTest.kt rename to apps/flipcash/shared/tokens/src/androidHostTest/kotlin/com/flipcash/app/tokens/ui/TokenInfoViewModelChartLoadTest.kt diff --git a/apps/flipcash/shared/tokens/src/test/kotlin/com/flipcash/app/tokens/ui/TokenInfoViewModelConvertTest.kt b/apps/flipcash/shared/tokens/src/androidHostTest/kotlin/com/flipcash/app/tokens/ui/TokenInfoViewModelConvertTest.kt similarity index 100% rename from apps/flipcash/shared/tokens/src/test/kotlin/com/flipcash/app/tokens/ui/TokenInfoViewModelConvertTest.kt rename to apps/flipcash/shared/tokens/src/androidHostTest/kotlin/com/flipcash/app/tokens/ui/TokenInfoViewModelConvertTest.kt diff --git a/apps/flipcash/shared/tokens/src/test/kotlin/com/flipcash/app/tokens/ui/TokenInfoViewModelStateTest.kt b/apps/flipcash/shared/tokens/src/androidHostTest/kotlin/com/flipcash/app/tokens/ui/TokenInfoViewModelStateTest.kt similarity index 100% rename from apps/flipcash/shared/tokens/src/test/kotlin/com/flipcash/app/tokens/ui/TokenInfoViewModelStateTest.kt rename to apps/flipcash/shared/tokens/src/androidHostTest/kotlin/com/flipcash/app/tokens/ui/TokenInfoViewModelStateTest.kt diff --git a/apps/flipcash/shared/tokens/src/main/kotlin/com/flipcash/app/tokens/BalancePoller.kt b/apps/flipcash/shared/tokens/src/androidMain/kotlin/com/flipcash/app/tokens/BalancePoller.kt similarity index 100% rename from apps/flipcash/shared/tokens/src/main/kotlin/com/flipcash/app/tokens/BalancePoller.kt rename to apps/flipcash/shared/tokens/src/androidMain/kotlin/com/flipcash/app/tokens/BalancePoller.kt diff --git a/apps/flipcash/shared/tokens/src/main/kotlin/com/flipcash/app/tokens/FeeAffordableEntry.kt b/apps/flipcash/shared/tokens/src/androidMain/kotlin/com/flipcash/app/tokens/FeeAffordableEntry.kt similarity index 100% rename from apps/flipcash/shared/tokens/src/main/kotlin/com/flipcash/app/tokens/FeeAffordableEntry.kt rename to apps/flipcash/shared/tokens/src/androidMain/kotlin/com/flipcash/app/tokens/FeeAffordableEntry.kt diff --git a/apps/flipcash/shared/tokens/src/main/kotlin/com/flipcash/app/tokens/InlineCompletion.kt b/apps/flipcash/shared/tokens/src/androidMain/kotlin/com/flipcash/app/tokens/InlineCompletion.kt similarity index 100% rename from apps/flipcash/shared/tokens/src/main/kotlin/com/flipcash/app/tokens/InlineCompletion.kt rename to apps/flipcash/shared/tokens/src/androidMain/kotlin/com/flipcash/app/tokens/InlineCompletion.kt diff --git a/apps/flipcash/shared/tokens/src/main/kotlin/com/flipcash/app/tokens/TokenUpdater.kt b/apps/flipcash/shared/tokens/src/androidMain/kotlin/com/flipcash/app/tokens/TokenUpdater.kt similarity index 100% rename from apps/flipcash/shared/tokens/src/main/kotlin/com/flipcash/app/tokens/TokenUpdater.kt rename to apps/flipcash/shared/tokens/src/androidMain/kotlin/com/flipcash/app/tokens/TokenUpdater.kt diff --git a/apps/flipcash/shared/tokens/src/main/kotlin/com/flipcash/app/tokens/TransactionNotificationPrompt.kt b/apps/flipcash/shared/tokens/src/androidMain/kotlin/com/flipcash/app/tokens/TransactionNotificationPrompt.kt similarity index 100% rename from apps/flipcash/shared/tokens/src/main/kotlin/com/flipcash/app/tokens/TransactionNotificationPrompt.kt rename to apps/flipcash/shared/tokens/src/androidMain/kotlin/com/flipcash/app/tokens/TransactionNotificationPrompt.kt diff --git a/apps/flipcash/shared/tokens/src/main/kotlin/com/flipcash/app/tokens/UsdcDepositSweep.kt b/apps/flipcash/shared/tokens/src/androidMain/kotlin/com/flipcash/app/tokens/UsdcDepositSweep.kt similarity index 100% rename from apps/flipcash/shared/tokens/src/main/kotlin/com/flipcash/app/tokens/UsdcDepositSweep.kt rename to apps/flipcash/shared/tokens/src/androidMain/kotlin/com/flipcash/app/tokens/UsdcDepositSweep.kt diff --git a/apps/flipcash/shared/tokens/src/main/kotlin/com/flipcash/app/tokens/bondingcurve/BondingCurveProjection.kt b/apps/flipcash/shared/tokens/src/androidMain/kotlin/com/flipcash/app/tokens/bondingcurve/BondingCurveProjection.kt similarity index 100% rename from apps/flipcash/shared/tokens/src/main/kotlin/com/flipcash/app/tokens/bondingcurve/BondingCurveProjection.kt rename to apps/flipcash/shared/tokens/src/androidMain/kotlin/com/flipcash/app/tokens/bondingcurve/BondingCurveProjection.kt diff --git a/apps/flipcash/shared/tokens/src/main/kotlin/com/flipcash/app/tokens/data/AggregationType.kt b/apps/flipcash/shared/tokens/src/androidMain/kotlin/com/flipcash/app/tokens/data/AggregationType.kt similarity index 100% rename from apps/flipcash/shared/tokens/src/main/kotlin/com/flipcash/app/tokens/data/AggregationType.kt rename to apps/flipcash/shared/tokens/src/androidMain/kotlin/com/flipcash/app/tokens/data/AggregationType.kt diff --git a/apps/flipcash/shared/tokens/src/main/kotlin/com/flipcash/app/tokens/data/MarketCapPoint.kt b/apps/flipcash/shared/tokens/src/androidMain/kotlin/com/flipcash/app/tokens/data/MarketCapPoint.kt similarity index 100% rename from apps/flipcash/shared/tokens/src/main/kotlin/com/flipcash/app/tokens/data/MarketCapPoint.kt rename to apps/flipcash/shared/tokens/src/androidMain/kotlin/com/flipcash/app/tokens/data/MarketCapPoint.kt diff --git a/apps/flipcash/shared/tokens/src/main/kotlin/com/flipcash/app/tokens/data/MarketTrend.kt b/apps/flipcash/shared/tokens/src/androidMain/kotlin/com/flipcash/app/tokens/data/MarketTrend.kt similarity index 100% rename from apps/flipcash/shared/tokens/src/main/kotlin/com/flipcash/app/tokens/data/MarketTrend.kt rename to apps/flipcash/shared/tokens/src/androidMain/kotlin/com/flipcash/app/tokens/data/MarketTrend.kt diff --git a/apps/flipcash/shared/tokens/src/main/kotlin/com/flipcash/app/tokens/data/Period.kt b/apps/flipcash/shared/tokens/src/androidMain/kotlin/com/flipcash/app/tokens/data/Period.kt similarity index 100% rename from apps/flipcash/shared/tokens/src/main/kotlin/com/flipcash/app/tokens/data/Period.kt rename to apps/flipcash/shared/tokens/src/androidMain/kotlin/com/flipcash/app/tokens/data/Period.kt diff --git a/apps/flipcash/shared/tokens/src/main/kotlin/com/flipcash/app/tokens/inject/PurchaseMethodModule.kt b/apps/flipcash/shared/tokens/src/androidMain/kotlin/com/flipcash/app/tokens/inject/PurchaseMethodModule.kt similarity index 100% rename from apps/flipcash/shared/tokens/src/main/kotlin/com/flipcash/app/tokens/inject/PurchaseMethodModule.kt rename to apps/flipcash/shared/tokens/src/androidMain/kotlin/com/flipcash/app/tokens/inject/PurchaseMethodModule.kt diff --git a/apps/flipcash/shared/tokens/src/main/kotlin/com/flipcash/app/tokens/inject/TokenModule.kt b/apps/flipcash/shared/tokens/src/androidMain/kotlin/com/flipcash/app/tokens/inject/TokenModule.kt similarity index 100% rename from apps/flipcash/shared/tokens/src/main/kotlin/com/flipcash/app/tokens/inject/TokenModule.kt rename to apps/flipcash/shared/tokens/src/androidMain/kotlin/com/flipcash/app/tokens/inject/TokenModule.kt diff --git a/apps/flipcash/shared/tokens/src/androidMain/kotlin/com/flipcash/app/tokens/ui/HiltSelectTokenViewModel.kt b/apps/flipcash/shared/tokens/src/androidMain/kotlin/com/flipcash/app/tokens/ui/HiltSelectTokenViewModel.kt new file mode 100644 index 0000000000..741f622ea1 --- /dev/null +++ b/apps/flipcash/shared/tokens/src/androidMain/kotlin/com/flipcash/app/tokens/ui/HiltSelectTokenViewModel.kt @@ -0,0 +1,15 @@ +package com.flipcash.app.tokens.ui + +import com.flipcash.app.tokens.TokenCoordinator +import com.flipcash.libs.coroutines.DispatcherProvider +import com.getcode.opencode.exchange.Exchange +import dagger.hilt.android.lifecycle.HiltViewModel +import javax.inject.Inject + +/** Hilt entry point for [SelectTokenViewModel]; obtain with `hiltViewModel()`. */ +@HiltViewModel +class HiltSelectTokenViewModel @Inject constructor( + tokenCoordinator: TokenCoordinator, + exchange: Exchange, + dispatchers: DispatcherProvider, +) : SelectTokenViewModel(tokenCoordinator, exchange, dispatchers) diff --git a/apps/flipcash/shared/tokens/src/main/kotlin/com/flipcash/app/tokens/ui/MarketCapExplainerViewModel.kt b/apps/flipcash/shared/tokens/src/androidMain/kotlin/com/flipcash/app/tokens/ui/MarketCapExplainerViewModel.kt similarity index 100% rename from apps/flipcash/shared/tokens/src/main/kotlin/com/flipcash/app/tokens/ui/MarketCapExplainerViewModel.kt rename to apps/flipcash/shared/tokens/src/androidMain/kotlin/com/flipcash/app/tokens/ui/MarketCapExplainerViewModel.kt diff --git a/apps/flipcash/shared/tokens/src/main/kotlin/com/flipcash/app/tokens/ui/SwapViewModel.kt b/apps/flipcash/shared/tokens/src/androidMain/kotlin/com/flipcash/app/tokens/ui/SwapViewModel.kt similarity index 100% rename from apps/flipcash/shared/tokens/src/main/kotlin/com/flipcash/app/tokens/ui/SwapViewModel.kt rename to apps/flipcash/shared/tokens/src/androidMain/kotlin/com/flipcash/app/tokens/ui/SwapViewModel.kt diff --git a/apps/flipcash/shared/tokens/src/main/kotlin/com/flipcash/app/tokens/ui/TokenInfoViewModel.kt b/apps/flipcash/shared/tokens/src/androidMain/kotlin/com/flipcash/app/tokens/ui/TokenInfoViewModel.kt similarity index 100% rename from apps/flipcash/shared/tokens/src/main/kotlin/com/flipcash/app/tokens/ui/TokenInfoViewModel.kt rename to apps/flipcash/shared/tokens/src/androidMain/kotlin/com/flipcash/app/tokens/ui/TokenInfoViewModel.kt diff --git a/apps/flipcash/shared/tokens/src/main/kotlin/com/flipcash/app/tokens/ui/TokenList.kt b/apps/flipcash/shared/tokens/src/androidMain/kotlin/com/flipcash/app/tokens/ui/TokenList.kt similarity index 100% rename from apps/flipcash/shared/tokens/src/main/kotlin/com/flipcash/app/tokens/ui/TokenList.kt rename to apps/flipcash/shared/tokens/src/androidMain/kotlin/com/flipcash/app/tokens/ui/TokenList.kt diff --git a/apps/flipcash/shared/tokens/src/main/kotlin/com/flipcash/app/tokens/TokenCoordinator.kt b/apps/flipcash/shared/tokens/src/commonMain/kotlin/com/flipcash/app/tokens/TokenCoordinator.kt similarity index 98% rename from apps/flipcash/shared/tokens/src/main/kotlin/com/flipcash/app/tokens/TokenCoordinator.kt rename to apps/flipcash/shared/tokens/src/commonMain/kotlin/com/flipcash/app/tokens/TokenCoordinator.kt index 943f2c72ea..1ef303004e 100644 --- a/apps/flipcash/shared/tokens/src/main/kotlin/com/flipcash/app/tokens/TokenCoordinator.kt +++ b/apps/flipcash/shared/tokens/src/commonMain/kotlin/com/flipcash/app/tokens/TokenCoordinator.kt @@ -1,18 +1,15 @@ package com.flipcash.app.tokens -import android.content.Context import androidx.datastore.core.handlers.ReplaceFileCorruptionHandler import androidx.datastore.preferences.core.PreferenceDataStoreFactory import androidx.datastore.preferences.core.edit import androidx.datastore.preferences.core.emptyPreferences import androidx.datastore.preferences.core.booleanPreferencesKey import androidx.datastore.preferences.core.stringPreferencesKey -import androidx.datastore.preferences.preferencesDataStoreFile import androidx.lifecycle.DefaultLifecycleObserver import androidx.lifecycle.LifecycleOwner -import android.os.Handler -import android.os.Looper -import androidx.lifecycle.ProcessLifecycleOwner +import com.flipcash.app.core.lifecycle.AppProcessLifecycle +import com.flipcash.app.core.storage.PreferencesFiles import com.flipcash.app.persistence.sources.TokenDataSource import com.flipcash.libs.coroutines.DispatcherProvider import com.flipcash.app.tokens.core.ReservesBalanceProvider @@ -44,7 +41,6 @@ import com.getcode.utils.TraceType import com.getcode.utils.network.NetworkConnectivityListener import com.getcode.utils.network.retryable import com.getcode.utils.trace -import dagger.hilt.android.qualifiers.ApplicationContext import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job import kotlinx.coroutines.SupervisorJob @@ -114,7 +110,7 @@ enum class TokenSyncState { */ @Singleton class TokenCoordinator @Inject constructor( - @param:ApplicationContext private val context: Context, + private val preferencesFiles: PreferencesFiles, private val tokenController: TokenController, private val accountController: AccountController, private val networkObserver: NetworkConnectivityListener, @@ -145,7 +141,7 @@ class TokenCoordinator @Inject constructor( private val selectedToken = PreferenceDataStoreFactory.create( corruptionHandler = ReplaceFileCorruptionHandler { emptyPreferences() }, scope = scope, - produceFile = { context.preferencesDataStoreFile("selected-token") } + produceFile = { preferencesFiles.file("selected-token") } ) private val cluster = MutableStateFlow(null) @@ -293,11 +289,9 @@ class TokenCoordinator @Inject constructor( // region Lifecycle init { - // Posted, not called directly: addObserver is main-thread-only, and this singleton is built + // Posted to the main thread on Android: addObserver is main-thread-only, and this singleton is built // off the main thread so its construction stays off the startup path. - Handler(Looper.getMainLooper()).post { - ProcessLifecycleOwner.get().lifecycle.addObserver(this) - } + AppProcessLifecycle.addObserver(this) cluster.filterNotNull() .flatMapLatest { networkObserver.state.map { it.connected } } diff --git a/apps/flipcash/shared/tokens/src/main/kotlin/com/flipcash/app/tokens/TokenSelectionResolver.kt b/apps/flipcash/shared/tokens/src/commonMain/kotlin/com/flipcash/app/tokens/TokenSelectionResolver.kt similarity index 100% rename from apps/flipcash/shared/tokens/src/main/kotlin/com/flipcash/app/tokens/TokenSelectionResolver.kt rename to apps/flipcash/shared/tokens/src/commonMain/kotlin/com/flipcash/app/tokens/TokenSelectionResolver.kt diff --git a/apps/flipcash/shared/tokens/src/main/kotlin/com/flipcash/app/tokens/WalletRevealCoordinator.kt b/apps/flipcash/shared/tokens/src/commonMain/kotlin/com/flipcash/app/tokens/WalletRevealCoordinator.kt similarity index 100% rename from apps/flipcash/shared/tokens/src/main/kotlin/com/flipcash/app/tokens/WalletRevealCoordinator.kt rename to apps/flipcash/shared/tokens/src/commonMain/kotlin/com/flipcash/app/tokens/WalletRevealCoordinator.kt diff --git a/apps/flipcash/shared/tokens/src/main/kotlin/com/flipcash/app/tokens/ui/SelectTokenViewModel.kt b/apps/flipcash/shared/tokens/src/commonMain/kotlin/com/flipcash/app/tokens/ui/SelectTokenViewModel.kt similarity index 97% rename from apps/flipcash/shared/tokens/src/main/kotlin/com/flipcash/app/tokens/ui/SelectTokenViewModel.kt rename to apps/flipcash/shared/tokens/src/commonMain/kotlin/com/flipcash/app/tokens/ui/SelectTokenViewModel.kt index d930f95748..40ab565b64 100644 --- a/apps/flipcash/shared/tokens/src/main/kotlin/com/flipcash/app/tokens/ui/SelectTokenViewModel.kt +++ b/apps/flipcash/shared/tokens/src/commonMain/kotlin/com/flipcash/app/tokens/ui/SelectTokenViewModel.kt @@ -16,7 +16,6 @@ import com.getcode.solana.keys.Mint import com.getcode.solana.keys.base58 import com.flipcash.libs.coroutines.DispatcherProvider import com.getcode.view.BaseViewModel -import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.filter @@ -27,8 +26,11 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach import javax.inject.Inject -@HiltViewModel -class SelectTokenViewModel @Inject constructor( +/** + * Shared across Android and desktop. Android obtains it through [HiltSelectTokenViewModel], since + * `@HiltViewModel` is Android-only; desktop constructs it from its Metro graph. + */ +open class SelectTokenViewModel @Inject constructor( tokenCoordinator: TokenCoordinator, exchange: Exchange, dispatchers: DispatcherProvider, From 3cbffbd57dfc6ed695d82d29ea32bc4185dba51f Mon Sep 17 00:00:00 2001 From: Brandon McAnsh Date: Fri, 23 Oct 2026 19:10:32 -0400 Subject: [PATCH 27/50] build(balance): move features:balance to android+jvm KMP WalletViewModel becomes an open class in commonMain with an @Inject constructor; the @HiltViewModel subclass HiltWalletViewModel stays in androidMain, and the Android entry point asks Hilt for it. The wallet content and header composables move to commonMain and read their strings and drawables through CoreStrings/CoreDrawables. The view model only called ChatCoordinator.hasEverTipped(), so it now takes a one-method TipHistorySource from app:core. ChatCoordinator extends it and ChatModule binds it, so Android injects the same object and balance no longer depends on shared:chat (10k lines). ReportDrawnWhen becomes an expect seam (no-op on jvm). card-expand moves to android+jvm with everything in commonMain. --- apps/flipcash/card-expand/build.gradle.kts | 23 +++--- .../flipcash/app/cardexpand/CardExpansion.kt | 0 .../core/resources/CoreResources.android.kt | 9 +++ .../app/core/chat/TipHistorySource.kt | 14 ++++ .../app/core/resources/CoreResources.kt | 9 +++ .../app/core/resources/CoreResources.jvm.kt | 18 +++++ .../features/balance/build.gradle.kts | 80 ++++++++++++++----- .../internal/BalanceViewModelStateTest.kt | 0 .../balance/internal/BalanceViewModelTest.kt | 6 +- .../internal/WalletLoadingStateTest.kt | 0 .../internal/WalletMilestoneGatingTest.kt | 6 +- .../com/flipcash/app/balance/WalletScreen.kt | 3 +- .../balance/internal/HiltWalletViewModel.kt | 37 +++++++++ .../balance/internal/ReportDrawn.android.kt | 7 ++ .../app/balance/internal/ReportDrawn.kt | 7 ++ .../balance/internal/WalletScreenContent.kt | 30 +++---- .../app/balance/internal/WalletViewModel.kt | 14 ++-- .../internal/components/BalanceHeader.kt | 0 .../app/balance/internal/ReportDrawn.jvm.kt | 7 ++ .../flipcash/shared/chat/ChatCoordinator.kt | 5 +- .../flipcash/shared/chat/inject/ChatModule.kt | 6 ++ 21 files changed, 220 insertions(+), 61 deletions(-) rename apps/flipcash/card-expand/src/{main => commonMain}/kotlin/com/flipcash/app/cardexpand/CardExpansion.kt (100%) create mode 100644 apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/chat/TipHistorySource.kt rename apps/flipcash/features/balance/src/{test => androidHostTest}/kotlin/com/flipcash/app/balance/internal/BalanceViewModelStateTest.kt (100%) rename apps/flipcash/features/balance/src/{test => androidHostTest}/kotlin/com/flipcash/app/balance/internal/BalanceViewModelTest.kt (96%) rename apps/flipcash/features/balance/src/{test => androidHostTest}/kotlin/com/flipcash/app/balance/internal/WalletLoadingStateTest.kt (100%) rename apps/flipcash/features/balance/src/{test => androidHostTest}/kotlin/com/flipcash/app/balance/internal/WalletMilestoneGatingTest.kt (97%) rename apps/flipcash/features/balance/src/{main => androidMain}/kotlin/com/flipcash/app/balance/WalletScreen.kt (94%) create mode 100644 apps/flipcash/features/balance/src/androidMain/kotlin/com/flipcash/app/balance/internal/HiltWalletViewModel.kt create mode 100644 apps/flipcash/features/balance/src/androidMain/kotlin/com/flipcash/app/balance/internal/ReportDrawn.android.kt create mode 100644 apps/flipcash/features/balance/src/commonMain/kotlin/com/flipcash/app/balance/internal/ReportDrawn.kt rename apps/flipcash/features/balance/src/{main => commonMain}/kotlin/com/flipcash/app/balance/internal/WalletScreenContent.kt (94%) rename apps/flipcash/features/balance/src/{main => commonMain}/kotlin/com/flipcash/app/balance/internal/WalletViewModel.kt (97%) rename apps/flipcash/features/balance/src/{main => commonMain}/kotlin/com/flipcash/app/balance/internal/components/BalanceHeader.kt (100%) create mode 100644 apps/flipcash/features/balance/src/jvmMain/kotlin/com/flipcash/app/balance/internal/ReportDrawn.jvm.kt diff --git a/apps/flipcash/card-expand/build.gradle.kts b/apps/flipcash/card-expand/build.gradle.kts index 3def3a94a6..2eee137515 100644 --- a/apps/flipcash/card-expand/build.gradle.kts +++ b/apps/flipcash/card-expand/build.gradle.kts @@ -1,14 +1,19 @@ plugins { - alias(libs.plugins.flipcash.android.library.compose) + alias(libs.plugins.flipcash.kmp.app.library) + alias(libs.plugins.compose.compiler) } -android { - namespace = "${Gradle.flipcashNamespace}.cardexpand" -} - -dependencies { - implementation(libs.compose.foundation) +kotlin { + android { + namespace = "${Gradle.flipcashNamespace}.cardexpand" + } - testImplementation(kotlin("test")) - testImplementation(libs.bundles.unit.testing) + sourceSets { + commonMain.dependencies { + implementation(libs.jetbrains.compose.runtime) + implementation(libs.jetbrains.compose.foundation) + implementation(libs.jetbrains.compose.ui) + implementation(libs.jetbrains.compose.animation) + } + } } diff --git a/apps/flipcash/card-expand/src/main/kotlin/com/flipcash/app/cardexpand/CardExpansion.kt b/apps/flipcash/card-expand/src/commonMain/kotlin/com/flipcash/app/cardexpand/CardExpansion.kt similarity index 100% rename from apps/flipcash/card-expand/src/main/kotlin/com/flipcash/app/cardexpand/CardExpansion.kt rename to apps/flipcash/card-expand/src/commonMain/kotlin/com/flipcash/app/cardexpand/CardExpansion.kt diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/resources/CoreResources.android.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/resources/CoreResources.android.kt index a4ee6b636a..fd2dd31111 100644 --- a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/resources/CoreResources.android.kt +++ b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/resources/CoreResources.android.kt @@ -14,6 +14,11 @@ actual object CoreStrings { actual val label_fromCurrencyDepreciation: Int = R.string.label_fromCurrencyDepreciation actual val title_recentActivity: Int = R.string.title_recentActivity actual val label_chatReceipt_yesterday: Int = R.string.label_chatReceipt_yesterday + actual val title_tipOnboarding: Int = R.string.title_tipOnboarding + actual val action_createYourOwnCurrency: Int = R.string.action_createYourOwnCurrency + actual val action_currencyLeaderboard: Int = R.string.action_currencyLeaderboard + actual val action_addDollars: Int = R.string.action_addDollars + actual val action_withdrawDollars: Int = R.string.action_withdrawDollars } @Suppress("PropertyName") @@ -21,4 +26,8 @@ actual object CoreDrawables { actual val ic_nav_tipcard: Int = R.drawable.ic_nav_tipcard actual val ic_checked_green: Int = R.drawable.ic_checked_green actual val ic_chevron_right: Int = R.drawable.ic_chevron_right + actual val ic_coins_add: Int = R.drawable.ic_coins_add + actual val ic_globe: Int = R.drawable.ic_globe + actual val ic_menu_deposit: Int = R.drawable.ic_menu_deposit + actual val ic_menu_withdraw: Int = R.drawable.ic_menu_withdraw } diff --git a/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/chat/TipHistorySource.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/chat/TipHistorySource.kt new file mode 100644 index 0000000000..c6a0c8774b --- /dev/null +++ b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/chat/TipHistorySource.kt @@ -0,0 +1,14 @@ +package com.flipcash.app.core.chat + +import kotlinx.coroutines.flow.Flow + +/** + * Whether the signed-in account has ever sent a tip, read off the local chat cache. + * + * Emits `null` until that cache is known to be complete, since an absent TIPPED message proves + * nothing before then. Split out of the chat coordinator so callers that need only this answer + * (onboarding on the wallet tab) don't depend on the whole chat module. + */ +interface TipHistorySource { + fun hasEverTipped(): Flow +} diff --git a/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/resources/CoreResources.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/resources/CoreResources.kt index 7d67f48ab1..28e1615421 100644 --- a/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/resources/CoreResources.kt +++ b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/resources/CoreResources.kt @@ -17,6 +17,11 @@ expect object CoreStrings { val label_fromCurrencyDepreciation: Int val title_recentActivity: Int val label_chatReceipt_yesterday: Int + val title_tipOnboarding: Int + val action_createYourOwnCurrency: Int + val action_currencyLeaderboard: Int + val action_addDollars: Int + val action_withdrawDollars: Int } @Suppress("PropertyName") @@ -24,4 +29,8 @@ expect object CoreDrawables { val ic_nav_tipcard: Int val ic_checked_green: Int val ic_chevron_right: Int + val ic_coins_add: Int + val ic_globe: Int + val ic_menu_deposit: Int + val ic_menu_withdraw: Int } diff --git a/apps/flipcash/core/src/jvmMain/kotlin/com/flipcash/app/core/resources/CoreResources.jvm.kt b/apps/flipcash/core/src/jvmMain/kotlin/com/flipcash/app/core/resources/CoreResources.jvm.kt index 9b386346e5..92b968fcf4 100644 --- a/apps/flipcash/core/src/jvmMain/kotlin/com/flipcash/app/core/resources/CoreResources.jvm.kt +++ b/apps/flipcash/core/src/jvmMain/kotlin/com/flipcash/app/core/resources/CoreResources.jvm.kt @@ -13,6 +13,15 @@ import com.flipcash.core.resources.title_addMoney import com.flipcash.core.resources.title_scanTipCard import com.flipcash.core.resources.title_recentActivity import com.flipcash.core.resources.label_chatReceipt_yesterday +import com.flipcash.core.resources.title_tipOnboarding +import com.flipcash.core.resources.action_createYourOwnCurrency +import com.flipcash.core.resources.action_currencyLeaderboard +import com.flipcash.core.resources.action_addDollars +import com.flipcash.core.resources.action_withdrawDollars +import com.flipcash.core.resources.ic_coins_add +import com.flipcash.core.resources.ic_globe +import com.flipcash.core.resources.ic_menu_deposit +import com.flipcash.core.resources.ic_menu_withdraw import com.getcode.util.resources.ComposeResourceIds @Suppress("PropertyName") @@ -27,6 +36,11 @@ actual object CoreStrings { actual val label_fromCurrencyDepreciation: Int = ComposeResourceIds.register(Res.string.label_fromCurrencyDepreciation) actual val title_recentActivity: Int = ComposeResourceIds.register(Res.string.title_recentActivity) actual val label_chatReceipt_yesterday: Int = ComposeResourceIds.register(Res.string.label_chatReceipt_yesterday) + actual val title_tipOnboarding: Int = ComposeResourceIds.register(Res.string.title_tipOnboarding) + actual val action_createYourOwnCurrency: Int = ComposeResourceIds.register(Res.string.action_createYourOwnCurrency) + actual val action_currencyLeaderboard: Int = ComposeResourceIds.register(Res.string.action_currencyLeaderboard) + actual val action_addDollars: Int = ComposeResourceIds.register(Res.string.action_addDollars) + actual val action_withdrawDollars: Int = ComposeResourceIds.register(Res.string.action_withdrawDollars) } @Suppress("PropertyName") @@ -34,4 +48,8 @@ actual object CoreDrawables { actual val ic_nav_tipcard: Int = ComposeResourceIds.register(Res.drawable.ic_nav_tipcard) actual val ic_checked_green: Int = ComposeResourceIds.register(Res.drawable.ic_checked_green) actual val ic_chevron_right: Int = checkNotNull(ComposeResourceIds.drawableId("ic_chevron_right")) + actual val ic_coins_add: Int = ComposeResourceIds.register(Res.drawable.ic_coins_add) + actual val ic_globe: Int = ComposeResourceIds.register(Res.drawable.ic_globe) + actual val ic_menu_deposit: Int = ComposeResourceIds.register(Res.drawable.ic_menu_deposit) + actual val ic_menu_withdraw: Int = ComposeResourceIds.register(Res.drawable.ic_menu_withdraw) } diff --git a/apps/flipcash/features/balance/build.gradle.kts b/apps/flipcash/features/balance/build.gradle.kts index 3c7e428cd6..a0f4382158 100644 --- a/apps/flipcash/features/balance/build.gradle.kts +++ b/apps/flipcash/features/balance/build.gradle.kts @@ -1,29 +1,65 @@ plugins { - alias(libs.plugins.flipcash.android.feature) + alias(libs.plugins.flipcash.kmp.app.library) + alias(libs.plugins.compose.compiler) + alias(libs.plugins.kotlin.ksp) } -android { - namespace = "${Gradle.flipcashNamespace}.features.balance" -} - -dependencies { - testImplementation(kotlin("test")) - testImplementation(libs.bundles.unit.testing) - testImplementation(libs.bundles.compose.ui.testing) +kotlin { + android { + namespace = "${Gradle.flipcashNamespace}.features.balance" + } - implementation(libs.compose.paging) + sourceSets { + commonMain.dependencies { + implementation(project(":apps:flipcash:core")) + implementation(project(":apps:flipcash:core-ui")) + implementation(project(":apps:flipcash:card-expand")) + implementation(project(":apps:flipcash:shared:analytics")) + implementation(project(":apps:flipcash:shared:funding")) + implementation(project(":apps:flipcash:shared:tokens")) + implementation(project(":apps:flipcash:shared:transaction-history")) + implementation(project(":apps:flipcash:shared:userflags")) + implementation(project(":services:flipcash")) + implementation(project(":services:opencode")) + implementation(project(":services:opencode-compose")) + implementation(project(":libs:analytics-events")) + implementation(project(":libs:coroutines")) + implementation(project(":libs:encryption:keys")) + implementation(project(":ui:components")) + implementation(project(":ui:core")) + implementation(project(":ui:navigation")) + implementation(project(":ui:resources")) + implementation(project(":ui:theme")) - implementation(project(":apps:flipcash:shared:transaction-history")) - implementation(project(":apps:flipcash:shared:analytics")) - testImplementation(project(":apps:flipcash:shared:analytics:test-fixtures")) - implementation(project(":apps:flipcash:shared:chat")) - implementation(project(":apps:flipcash:shared:featureflags")) - implementation(project(":apps:flipcash:shared:funding")) - implementation(project(":apps:flipcash:shared:tokens")) - implementation(project(":apps:flipcash:shared:userflags")) - implementation(project(":apps:flipcash:card-expand")) - implementation(project(":libs:datetime")) - implementation(project(":libs:messaging")) - implementation(project(":libs:permissions:bindings")) + implementation(libs.jetbrains.compose.runtime) + implementation(libs.jetbrains.compose.foundation) + implementation(libs.jetbrains.compose.ui) + implementation(libs.jetbrains.compose.material) + implementation(libs.jetbrains.compose.material3) + implementation(libs.androidx.paging.common) + implementation(libs.javax.inject) + } + androidMain.dependencies { + // What flipcash.android.feature supplied before the move to KMP. + implementation(libs.bundles.hilt) + implementation(project.dependencies.platform(libs.compose.bom)) + implementation(libs.bundles.compose) + implementation(libs.compose.paging) + implementation(project(":apps:flipcash:shared:featureflags")) + implementation(project(":libs:datetime")) + implementation(project(":libs:messaging")) + implementation(project(":libs:permissions:bindings")) + } + getByName("androidHostTest").dependencies { + implementation(kotlin("test")) + implementation(libs.bundles.unit.testing) + implementation(project(":apps:flipcash:shared:analytics:test-fixtures")) + implementation(project(":libs:test-utils")) + } + } +} +dependencies { + add("kspAndroid", libs.hilt.android.compiler) + add("kspAndroid", libs.hilt.compiler) } diff --git a/apps/flipcash/features/balance/src/test/kotlin/com/flipcash/app/balance/internal/BalanceViewModelStateTest.kt b/apps/flipcash/features/balance/src/androidHostTest/kotlin/com/flipcash/app/balance/internal/BalanceViewModelStateTest.kt similarity index 100% rename from apps/flipcash/features/balance/src/test/kotlin/com/flipcash/app/balance/internal/BalanceViewModelStateTest.kt rename to apps/flipcash/features/balance/src/androidHostTest/kotlin/com/flipcash/app/balance/internal/BalanceViewModelStateTest.kt diff --git a/apps/flipcash/features/balance/src/test/kotlin/com/flipcash/app/balance/internal/BalanceViewModelTest.kt b/apps/flipcash/features/balance/src/androidHostTest/kotlin/com/flipcash/app/balance/internal/BalanceViewModelTest.kt similarity index 96% rename from apps/flipcash/features/balance/src/test/kotlin/com/flipcash/app/balance/internal/BalanceViewModelTest.kt rename to apps/flipcash/features/balance/src/androidHostTest/kotlin/com/flipcash/app/balance/internal/BalanceViewModelTest.kt index a5c31598b6..b5e2ef06a9 100644 --- a/apps/flipcash/features/balance/src/test/kotlin/com/flipcash/app/balance/internal/BalanceViewModelTest.kt +++ b/apps/flipcash/features/balance/src/androidHostTest/kotlin/com/flipcash/app/balance/internal/BalanceViewModelTest.kt @@ -12,7 +12,7 @@ import com.flipcash.app.funding.PurchaseMethodController import com.flipcash.app.tokens.TokenCoordinator import com.flipcash.app.tokens.WalletRevealCoordinator import com.flipcash.app.userflags.UserFlagsCoordinator -import com.flipcash.shared.chat.ChatCoordinator +import com.flipcash.app.core.chat.TipHistorySource import com.flipcash.services.internal.model.thirdparty.OnRampProvider import com.flipcash.services.user.UserManager import io.mockk.coEvery @@ -47,7 +47,7 @@ class BalanceViewModelTest { private val userManager: UserManager = mockk(relaxed = true) private val userFlags: UserFlagsCoordinator = mockk(relaxed = true) private val purchaseMethodController: PurchaseMethodController = mockk(relaxed = true) - private val chatCoordinator: ChatCoordinator = mockk(relaxed = true) + private val tipHistory: TipHistorySource = mockk(relaxed = true) private val feedCoordinator: ActivityFeedCoordinator = mockk(relaxed = true) private val tokenCoordinator: TokenCoordinator = mockk(relaxed = true) { every { hasAnyBalance } returns flowOf(false) @@ -67,7 +67,7 @@ class BalanceViewModelTest { dispatchers = dispatchers, purchaseMethodController = purchaseMethodController, analytics = analytics, - chatCoordinator = chatCoordinator, + tipHistory = tipHistory, feedCoordinator = feedCoordinator, tokenCoordinator = tokenCoordinator, walletReveal = walletReveal, diff --git a/apps/flipcash/features/balance/src/test/kotlin/com/flipcash/app/balance/internal/WalletLoadingStateTest.kt b/apps/flipcash/features/balance/src/androidHostTest/kotlin/com/flipcash/app/balance/internal/WalletLoadingStateTest.kt similarity index 100% rename from apps/flipcash/features/balance/src/test/kotlin/com/flipcash/app/balance/internal/WalletLoadingStateTest.kt rename to apps/flipcash/features/balance/src/androidHostTest/kotlin/com/flipcash/app/balance/internal/WalletLoadingStateTest.kt diff --git a/apps/flipcash/features/balance/src/test/kotlin/com/flipcash/app/balance/internal/WalletMilestoneGatingTest.kt b/apps/flipcash/features/balance/src/androidHostTest/kotlin/com/flipcash/app/balance/internal/WalletMilestoneGatingTest.kt similarity index 97% rename from apps/flipcash/features/balance/src/test/kotlin/com/flipcash/app/balance/internal/WalletMilestoneGatingTest.kt rename to apps/flipcash/features/balance/src/androidHostTest/kotlin/com/flipcash/app/balance/internal/WalletMilestoneGatingTest.kt index 384eb86e40..7818de9d95 100644 --- a/apps/flipcash/features/balance/src/test/kotlin/com/flipcash/app/balance/internal/WalletMilestoneGatingTest.kt +++ b/apps/flipcash/features/balance/src/androidHostTest/kotlin/com/flipcash/app/balance/internal/WalletMilestoneGatingTest.kt @@ -10,7 +10,7 @@ import com.flipcash.app.tokens.TokenCoordinator import com.flipcash.app.tokens.WalletRevealCoordinator import com.flipcash.app.userflags.UserFlagsCoordinator import com.flipcash.services.user.UserManager -import com.flipcash.shared.chat.ChatCoordinator +import com.flipcash.app.core.chat.TipHistorySource import com.flipcash.shared.transactionhistory.ActivityFeedCoordinator import io.mockk.every import io.mockk.mockk @@ -46,7 +46,7 @@ class WalletMilestoneGatingTest { private val hasEverTipped = MutableStateFlow(null) - private val chatCoordinator: ChatCoordinator = mockk(relaxed = true) { + private val tipHistory: TipHistorySource = mockk(relaxed = true) { every { hasEverTipped() } returns hasEverTipped } private val feedCoordinator: ActivityFeedCoordinator = mockk(relaxed = true) { @@ -68,7 +68,7 @@ class WalletMilestoneGatingTest { dispatchers = dispatchers, purchaseMethodController = mockk(relaxed = true), analytics = FlipcashAnalytics.None, - chatCoordinator = chatCoordinator, + tipHistory = tipHistory, feedCoordinator = feedCoordinator, tokenCoordinator = tokenCoordinator, walletReveal = walletReveal, diff --git a/apps/flipcash/features/balance/src/main/kotlin/com/flipcash/app/balance/WalletScreen.kt b/apps/flipcash/features/balance/src/androidMain/kotlin/com/flipcash/app/balance/WalletScreen.kt similarity index 94% rename from apps/flipcash/features/balance/src/main/kotlin/com/flipcash/app/balance/WalletScreen.kt rename to apps/flipcash/features/balance/src/androidMain/kotlin/com/flipcash/app/balance/WalletScreen.kt index 09874e18c5..87dd2b5be0 100644 --- a/apps/flipcash/features/balance/src/main/kotlin/com/flipcash/app/balance/WalletScreen.kt +++ b/apps/flipcash/features/balance/src/androidMain/kotlin/com/flipcash/app/balance/WalletScreen.kt @@ -7,6 +7,7 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel +import com.flipcash.app.balance.internal.HiltWalletViewModel import com.flipcash.app.balance.internal.WalletViewModel import com.flipcash.app.balance.internal.WalletScreen import com.flipcash.app.core.AppRoute @@ -27,7 +28,7 @@ fun WalletScreen() { modifier = Modifier.fillMaxSize(), horizontalAlignment = Alignment.CenterHorizontally, ) { - val viewModel = hiltViewModel() + val viewModel = hiltViewModel() val tokenViewModel = hiltViewModel() WalletScreen(viewModel, tokenViewModel) diff --git a/apps/flipcash/features/balance/src/androidMain/kotlin/com/flipcash/app/balance/internal/HiltWalletViewModel.kt b/apps/flipcash/features/balance/src/androidMain/kotlin/com/flipcash/app/balance/internal/HiltWalletViewModel.kt new file mode 100644 index 0000000000..eed4d2439b --- /dev/null +++ b/apps/flipcash/features/balance/src/androidMain/kotlin/com/flipcash/app/balance/internal/HiltWalletViewModel.kt @@ -0,0 +1,37 @@ +package com.flipcash.app.balance.internal + +import com.flipcash.app.analytics.FlipcashAnalytics +import com.flipcash.app.core.chat.TipHistorySource +import com.flipcash.app.funding.PurchaseMethodController +import com.flipcash.app.tokens.TokenCoordinator +import com.flipcash.app.tokens.WalletRevealCoordinator +import com.flipcash.app.userflags.UserFlagsCoordinator +import com.flipcash.libs.coroutines.DispatcherProvider +import com.flipcash.services.user.UserManager +import com.flipcash.shared.transactionhistory.ActivityFeedCoordinator +import dagger.hilt.android.lifecycle.HiltViewModel +import javax.inject.Inject + +/** Hilt entry point for the shared [WalletViewModel]. */ +@HiltViewModel +internal class HiltWalletViewModel @Inject constructor( + userManager: UserManager, + userFlags: UserFlagsCoordinator, + dispatchers: DispatcherProvider, + purchaseMethodController: PurchaseMethodController, + analytics: FlipcashAnalytics, + tipHistory: TipHistorySource, + feedCoordinator: ActivityFeedCoordinator, + tokenCoordinator: TokenCoordinator, + walletReveal: WalletRevealCoordinator, +) : WalletViewModel( + userManager = userManager, + userFlags = userFlags, + dispatchers = dispatchers, + purchaseMethodController = purchaseMethodController, + analytics = analytics, + tipHistory = tipHistory, + feedCoordinator = feedCoordinator, + tokenCoordinator = tokenCoordinator, + walletReveal = walletReveal, +) diff --git a/apps/flipcash/features/balance/src/androidMain/kotlin/com/flipcash/app/balance/internal/ReportDrawn.android.kt b/apps/flipcash/features/balance/src/androidMain/kotlin/com/flipcash/app/balance/internal/ReportDrawn.android.kt new file mode 100644 index 0000000000..bb7a0171f8 --- /dev/null +++ b/apps/flipcash/features/balance/src/androidMain/kotlin/com/flipcash/app/balance/internal/ReportDrawn.android.kt @@ -0,0 +1,7 @@ +package com.flipcash.app.balance.internal + +import androidx.activity.compose.ReportDrawnWhen +import androidx.compose.runtime.Composable + +@Composable +internal actual fun ReportDrawnWhenSeam(predicate: () -> Boolean) = ReportDrawnWhen(predicate) diff --git a/apps/flipcash/features/balance/src/commonMain/kotlin/com/flipcash/app/balance/internal/ReportDrawn.kt b/apps/flipcash/features/balance/src/commonMain/kotlin/com/flipcash/app/balance/internal/ReportDrawn.kt new file mode 100644 index 0000000000..a166ae2457 --- /dev/null +++ b/apps/flipcash/features/balance/src/commonMain/kotlin/com/flipcash/app/balance/internal/ReportDrawn.kt @@ -0,0 +1,7 @@ +package com.flipcash.app.balance.internal + +import androidx.compose.runtime.Composable + +/** Reports the screen as fully drawn once [predicate] is true. Android forwards to `ReportDrawnWhen`. */ +@Composable +internal expect fun ReportDrawnWhenSeam(predicate: () -> Boolean) diff --git a/apps/flipcash/features/balance/src/main/kotlin/com/flipcash/app/balance/internal/WalletScreenContent.kt b/apps/flipcash/features/balance/src/commonMain/kotlin/com/flipcash/app/balance/internal/WalletScreenContent.kt similarity index 94% rename from apps/flipcash/features/balance/src/main/kotlin/com/flipcash/app/balance/internal/WalletScreenContent.kt rename to apps/flipcash/features/balance/src/commonMain/kotlin/com/flipcash/app/balance/internal/WalletScreenContent.kt index 27235aaa38..5e5335bfed 100644 --- a/apps/flipcash/features/balance/src/main/kotlin/com/flipcash/app/balance/internal/WalletScreenContent.kt +++ b/apps/flipcash/features/balance/src/commonMain/kotlin/com/flipcash/app/balance/internal/WalletScreenContent.kt @@ -1,6 +1,5 @@ package com.flipcash.app.balance.internal -import androidx.activity.compose.ReportDrawnWhen import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box @@ -32,8 +31,6 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.platform.testTag -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.flipcash.app.cardexpand.CardExpansionController @@ -55,7 +52,10 @@ import com.flipcash.app.core.navigation.LocalTabBarPadding import com.flipcash.app.core.ui.TileButton import com.flipcash.app.core.ui.TileButtonStyle import com.flipcash.app.tokens.ui.SelectTokenViewModel -import com.flipcash.features.balance.R +import com.flipcash.app.core.resources.CoreDrawables +import com.flipcash.app.core.resources.CoreStrings +import com.getcode.util.resources.painterForResId +import com.getcode.util.resources.stringRes import com.flipcash.shared.transactionhistory.recentActivitySection import com.getcode.theme.CodeTheme import com.getcode.ui.theme.CodeCircularProgressIndicator @@ -86,7 +86,7 @@ internal fun WalletScreenContent( // below means "landed" is not the same frame as "composed" -- registering a reporter here holds // the activity's report open until the content below the gate has actually been drawn. Keyed to // the same condition as that gate: what the launch is finished for is the balance and the deck. - ReportDrawnWhen { !tokenState.isAwaitingTokens } + ReportDrawnWhenSeam { !tokenState.isAwaitingTokens } // The tab waits on the token set and nothing else. Tokens are what the balance and the card deck // are made of, so there is no drawing the tab without them; the activity preview and the tutorial @@ -164,7 +164,7 @@ internal fun WalletScreenContent( state = listState, // Only ever in the tree past the loading gate above, so it is the anchor for "the wallet // drew its content" -- what the startup benchmark waits on before it stops the trace. Same - // condition as ReportDrawnWhen above, so the trace stays open exactly as long as the report. + // condition as ReportDrawnWhenSeam above, so the trace stays open exactly as long as the report. modifier = Modifier .fillMaxSize() .testTag("wallet_content"), @@ -213,7 +213,7 @@ internal fun WalletScreenContent( NewUserTutorial( modifier = Modifier.fillMaxWidth() .padding(bottom = CodeTheme.dimens.grid.x5), - title = stringResource(R.string.title_tipOnboarding), + title = stringRes(CoreStrings.title_tipOnboarding), items = items, ) { item -> when (item) { @@ -322,8 +322,8 @@ internal fun WalletScreenContent( .weight(1f) .aspectRatio(1.45f), style = TileButtonStyle.Spread, - text = stringResource(R.string.action_createYourOwnCurrency), - icon = painterResource(R.drawable.ic_coins_add), + text = stringRes(CoreStrings.action_createYourOwnCurrency), + icon = painterForResId(CoreDrawables.ic_coins_add), ) { dispatchEvent(WalletViewModel.Event.OpenScreen(AppRoute.Token.CurrencyCreator)) } @@ -333,8 +333,8 @@ internal fun WalletScreenContent( .weight(1f) .aspectRatio(1.45f), style = TileButtonStyle.Spread, - text = stringResource(R.string.action_currencyLeaderboard), - icon = painterResource(R.drawable.ic_globe), + text = stringRes(CoreStrings.action_currencyLeaderboard), + icon = painterForResId(CoreDrawables.ic_globe), ) { dispatchEvent(WalletViewModel.Event.OpenScreen(AppRoute.Token.Discovery)) } @@ -351,8 +351,8 @@ internal fun WalletScreenContent( .weight(1f) .aspectRatio(1.45f), style = TileButtonStyle.Spread, - text = stringResource(R.string.action_addDollars), - icon = painterResource(R.drawable.ic_menu_deposit), + text = stringRes(CoreStrings.action_addDollars), + icon = painterForResId(CoreDrawables.ic_menu_deposit), ) { dispatchEvent(WalletViewModel.Event.PresentDepositOptions) } @@ -362,8 +362,8 @@ internal fun WalletScreenContent( .weight(1f) .aspectRatio(1.45f), style = TileButtonStyle.Spread, - text = stringResource(R.string.action_withdrawDollars), - icon = painterResource(R.drawable.ic_menu_withdraw), + text = stringRes(CoreStrings.action_withdrawDollars), + icon = painterForResId(CoreDrawables.ic_menu_withdraw), ) { // No preselected mint: the flow opens on the currency picker, which lists // every balance (Dollars included). diff --git a/apps/flipcash/features/balance/src/main/kotlin/com/flipcash/app/balance/internal/WalletViewModel.kt b/apps/flipcash/features/balance/src/commonMain/kotlin/com/flipcash/app/balance/internal/WalletViewModel.kt similarity index 97% rename from apps/flipcash/features/balance/src/main/kotlin/com/flipcash/app/balance/internal/WalletViewModel.kt rename to apps/flipcash/features/balance/src/commonMain/kotlin/com/flipcash/app/balance/internal/WalletViewModel.kt index b4c2826d1a..7a186f9ca0 100644 --- a/apps/flipcash/features/balance/src/main/kotlin/com/flipcash/app/balance/internal/WalletViewModel.kt +++ b/apps/flipcash/features/balance/src/commonMain/kotlin/com/flipcash/app/balance/internal/WalletViewModel.kt @@ -6,6 +6,7 @@ import com.flipcash.analytics.events.AddMoneyEvents import com.flipcash.app.analytics.FlipcashAnalytics import com.flipcash.app.core.ui.onboarding.TutorialItem import com.flipcash.app.core.AppRoute +import com.flipcash.app.core.chat.TipHistorySource import com.flipcash.shared.transactionhistory.ActivityFeedCoordinator import com.flipcash.shared.transactionhistory.FeedSyncState import com.flipcash.shared.transactionhistory.TransactionListItem @@ -14,13 +15,11 @@ import com.flipcash.app.tokens.TokenCoordinator import com.flipcash.app.tokens.WalletReveal import com.flipcash.app.tokens.WalletRevealCoordinator import com.flipcash.app.userflags.UserFlagsCoordinator -import com.flipcash.shared.chat.ChatCoordinator import com.flipcash.services.internal.model.thirdparty.OnRampProvider import com.flipcash.services.user.AuthState import com.flipcash.services.user.UserManager import com.flipcash.libs.coroutines.DispatcherProvider import com.getcode.view.BaseViewModel -import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.filterIsInstance @@ -30,14 +29,17 @@ import kotlinx.coroutines.flow.mapNotNull import kotlinx.coroutines.flow.onEach import javax.inject.Inject -@HiltViewModel -internal class WalletViewModel @Inject constructor( +/** + * Shared wallet-tab view model. Android injects it through [HiltWalletViewModel]; desktop builds it + * from its own graph. + */ +open class WalletViewModel @Inject constructor( userManager: UserManager, userFlags: UserFlagsCoordinator, dispatchers: DispatcherProvider, purchaseMethodController: PurchaseMethodController, analytics: FlipcashAnalytics, - chatCoordinator: ChatCoordinator, + tipHistory: TipHistorySource, feedCoordinator: ActivityFeedCoordinator, tokenCoordinator: TokenCoordinator, walletReveal: WalletRevealCoordinator, @@ -191,7 +193,7 @@ internal class WalletViewModel @Inject constructor( // row to prove it, and would otherwise be told to add money it already has. combine( feedCoordinator.hasEverReceivedMoney(), - chatCoordinator.hasEverTipped(), + tipHistory.hasEverTipped(), tokenCoordinator.hasAnyBalance, ) { hasReceivedMoney, hasTipped, holdsBalance -> // A null tip milestone means the chat cache has not been reconciled yet, and an diff --git a/apps/flipcash/features/balance/src/main/kotlin/com/flipcash/app/balance/internal/components/BalanceHeader.kt b/apps/flipcash/features/balance/src/commonMain/kotlin/com/flipcash/app/balance/internal/components/BalanceHeader.kt similarity index 100% rename from apps/flipcash/features/balance/src/main/kotlin/com/flipcash/app/balance/internal/components/BalanceHeader.kt rename to apps/flipcash/features/balance/src/commonMain/kotlin/com/flipcash/app/balance/internal/components/BalanceHeader.kt diff --git a/apps/flipcash/features/balance/src/jvmMain/kotlin/com/flipcash/app/balance/internal/ReportDrawn.jvm.kt b/apps/flipcash/features/balance/src/jvmMain/kotlin/com/flipcash/app/balance/internal/ReportDrawn.jvm.kt new file mode 100644 index 0000000000..d9254091b8 --- /dev/null +++ b/apps/flipcash/features/balance/src/jvmMain/kotlin/com/flipcash/app/balance/internal/ReportDrawn.jvm.kt @@ -0,0 +1,7 @@ +package com.flipcash.app.balance.internal + +import androidx.compose.runtime.Composable + +// Desktop has no fully-drawn reporter. +@Composable +internal actual fun ReportDrawnWhenSeam(predicate: () -> Boolean) = Unit diff --git a/apps/flipcash/shared/chat/src/main/kotlin/com/flipcash/shared/chat/ChatCoordinator.kt b/apps/flipcash/shared/chat/src/main/kotlin/com/flipcash/shared/chat/ChatCoordinator.kt index da8b75f88c..82b9b12bfe 100644 --- a/apps/flipcash/shared/chat/src/main/kotlin/com/flipcash/shared/chat/ChatCoordinator.kt +++ b/apps/flipcash/shared/chat/src/main/kotlin/com/flipcash/shared/chat/ChatCoordinator.kt @@ -4,6 +4,7 @@ package com.flipcash.shared.chat import androidx.paging.ExperimentalPagingApi import androidx.paging.PagingData +import com.flipcash.app.core.chat.TipHistorySource import com.flipcash.app.core.contacts.DeviceContact import com.flipcash.services.models.UserProfile import com.flipcash.services.models.chat.ChatId @@ -262,7 +263,7 @@ interface DmChatResolver { * * Implemented by [com.flipcash.shared.chat.internal.delegates.MessagingDelegate]. */ -interface MessagingOperations { +interface MessagingOperations : TipHistorySource { /** * Returns the other member of a DM (fetching from the server and persisting * if not cached locally), or `null` if it can't be resolved. Chat-type @@ -311,7 +312,7 @@ interface MessagingOperations { * [ChatHydrationState.Unavailable], so an unreachable server ends the wait instead of extending * it forever. */ - fun hasEverTipped(): Flow + override fun hasEverTipped(): Flow /** Observes messages in [chatId] via Paging 3, with remote-mediated page loads. */ fun observeMessagesPaged(chatId: ChatId): Flow> diff --git a/apps/flipcash/shared/chat/src/main/kotlin/com/flipcash/shared/chat/inject/ChatModule.kt b/apps/flipcash/shared/chat/src/main/kotlin/com/flipcash/shared/chat/inject/ChatModule.kt index fc277f5f8a..a5a53c5104 100644 --- a/apps/flipcash/shared/chat/src/main/kotlin/com/flipcash/shared/chat/inject/ChatModule.kt +++ b/apps/flipcash/shared/chat/src/main/kotlin/com/flipcash/shared/chat/inject/ChatModule.kt @@ -3,6 +3,7 @@ package com.flipcash.shared.chat.inject import com.flipcash.shared.chat.link.LinkPreviewImages import com.flipcash.shared.chat.link.UploadedLinkPreviewImages import com.flipcash.shared.chat.ChatArchiveStore +import com.flipcash.app.core.chat.TipHistorySource import com.flipcash.shared.chat.ChatCoordinator import com.flipcash.shared.chat.ChatDraftStore import com.flipcash.shared.chat.HostLobbies @@ -40,6 +41,11 @@ abstract class ChatModule { impl: RealChatCoordinator ): ChatCoordinator + @Binds + abstract fun bindTipHistorySource( + impl: ChatCoordinator + ): TipHistorySource + @Binds @Singleton abstract fun bindChatDraftStore( From 63a2175113ffe2237d8cc620f90cf781c8f96135 Mon Sep 17 00:00:00 2001 From: Brandon McAnsh Date: Fri, 23 Oct 2026 19:38:20 -0400 Subject: [PATCH 28/50] feat(desktop): Metro graph and wallet window Desktop builds WalletViewModel from a Metro graph that reuses the Dagger modules Android's Hilt graph installs. OpenCodeModule and FlipcashModule split into shared providers (commonMain), the Android channel/protocol config (androidMain) and an okhttp channel module in apps/desktop. Internal @Provides functions carry @JvmName so Dagger's factory names stay unmangled for Metro's runtime interop. DesktopModule binds the ten seams Android provides from Hilt modules; funding, analytics and connectivity are stubs. shared:theme moves to common so the window paints the Flipcash colour scheme. --- apps/desktop/build.gradle.kts | 39 ++++ .../com/flipcash/desktop/DesktopGraph.kt | 39 +++- .../com/flipcash/desktop/DesktopModule.kt | 111 +++++++++++ .../flipcash/desktop/DesktopWalletContent.kt | 45 +++++ .../main/kotlin/com/flipcash/desktop/Main.kt | 14 +- .../com/flipcash/desktop/SnapshotMain.kt | 32 ++++ .../inject/FlipcashDesktopChannelModule.kt | 66 +++++++ .../inject/OpenCodeDesktopChannelModule.kt | 55 ++++++ apps/flipcash/core-ui/build.gradle.kts | 2 + apps/flipcash/core/build.gradle.kts | 2 + .../features/balance/build.gradle.kts | 2 + .../balance/internal/WalletScreenContent.kt | 2 +- .../shared/analytics/build.gradle.kts | 2 + apps/flipcash/shared/funding/build.gradle.kts | 2 + .../persistence/sources/build.gradle.kts | 2 + apps/flipcash/shared/theme/build.gradle.kts | 26 ++- .../com/flipcash/app/theme/FlipcashPreview.kt | 0 .../com/flipcash/app/theme/FlipcashTheme.kt | 0 .../theme/internal/FlipcashDesignSystem.kt | 0 apps/flipcash/shared/tokens/build.gradle.kts | 2 + .../transaction-history/build.gradle.kts | 2 + .../shared/userflags/build.gradle.kts | 2 + gradle/libs.versions.toml | 2 + services/flipcash/build.gradle.kts | 2 + .../services/inject/FlipcashChannelModule.kt | 178 ++++++++++++++++++ .../services/inject/ChatCryptoModule.kt | 6 +- .../services/inject/FlipcashModule.kt | 112 +++-------- services/opencode/build.gradle.kts | 2 + .../com/getcode/opencode/RepositoryFactory.kt | 15 +- .../opencode/inject/OpenCodeChannelModule.kt | 93 +++++++++ .../getcode/opencode/inject/OpenCodeModule.kt | 91 +-------- .../opencode/inject/SessionListenersModule.kt | 0 .../opencode/inject/TransactorModule.kt | 0 .../annotations/OpenCodeManagedChannel.kt | 4 +- .../opencode/internal/annotations/Protocol.kt | 2 +- ui/navigation/build.gradle.kts | 2 + 36 files changed, 751 insertions(+), 205 deletions(-) create mode 100644 apps/desktop/src/main/kotlin/com/flipcash/desktop/DesktopModule.kt create mode 100644 apps/desktop/src/main/kotlin/com/flipcash/desktop/DesktopWalletContent.kt create mode 100644 apps/desktop/src/main/kotlin/com/flipcash/desktop/SnapshotMain.kt create mode 100644 apps/desktop/src/main/kotlin/com/flipcash/desktop/inject/FlipcashDesktopChannelModule.kt create mode 100644 apps/desktop/src/main/kotlin/com/flipcash/desktop/inject/OpenCodeDesktopChannelModule.kt rename apps/flipcash/shared/theme/src/{main => androidMain}/kotlin/com/flipcash/app/theme/FlipcashPreview.kt (100%) rename apps/flipcash/shared/theme/src/{main => commonMain}/kotlin/com/flipcash/app/theme/FlipcashTheme.kt (100%) rename apps/flipcash/shared/theme/src/{main => commonMain}/kotlin/com/flipcash/app/theme/internal/FlipcashDesignSystem.kt (100%) create mode 100644 services/flipcash/src/androidMain/kotlin/com/flipcash/services/inject/FlipcashChannelModule.kt rename services/flipcash/src/{androidMain => commonMain}/kotlin/com/flipcash/services/inject/FlipcashModule.kt (75%) create mode 100644 services/opencode/src/androidMain/kotlin/com/getcode/opencode/inject/OpenCodeChannelModule.kt rename services/opencode/src/{androidMain => commonMain}/kotlin/com/getcode/opencode/inject/OpenCodeModule.kt (62%) rename services/opencode/src/{androidMain => commonMain}/kotlin/com/getcode/opencode/inject/SessionListenersModule.kt (100%) rename services/opencode/src/{androidMain => commonMain}/kotlin/com/getcode/opencode/inject/TransactorModule.kt (100%) diff --git a/apps/desktop/build.gradle.kts b/apps/desktop/build.gradle.kts index 2fc3dfc4c3..f0dd564dc9 100644 --- a/apps/desktop/build.gradle.kts +++ b/apps/desktop/build.gradle.kts @@ -11,9 +11,40 @@ kotlin { jvmToolchain(21) } +metro { + interop { + includeJavax() + includeDagger() + enableDaggerRuntimeInterop.set(true) + } +} + dependencies { implementation(compose.desktop.currentOs) implementation(libs.jetbrains.compose.material3) + implementation(project(":services:opencode")) + implementation(project(":apps:flipcash:features:balance")) + implementation(project(":apps:flipcash:core")) + implementation(project(":apps:flipcash:shared:transaction-history")) + implementation(project(":apps:flipcash:shared:tokens")) + implementation(project(":apps:flipcash:shared:funding")) + implementation(project(":apps:flipcash:shared:userflags")) + implementation(project(":apps:flipcash:shared:analytics")) + implementation(project(":apps:flipcash:shared:persistence:sources")) + implementation(project(":apps:flipcash:shared:persistence:db")) + implementation(project(":services:flipcash")) + implementation(project(":libs:coroutines")) + implementation(project(":libs:logging")) + implementation(project(":ui:resources")) + implementation(project(":ui:theme")) + implementation(project(":apps:flipcash:shared:theme")) + implementation(project(":services:opencode-compose")) + implementation(project(":libs:locale:public")) + implementation(project(":libs:network:connectivity:public")) + implementation(project(":libs:encryption:chat-cipher")) + implementation(libs.kotlinx.coroutines.swing) + implementation(libs.dagger) + implementation(libs.grpc.okhttp) } compose.desktop { @@ -26,3 +57,11 @@ compose.desktop { } } } + +tasks.register("snapshot") { + group = "application" + description = "Renders the wallet screen off-screen to a PNG (-Pout=)." + classpath = sourceSets["main"].runtimeClasspath + mainClass.set("com.flipcash.desktop.SnapshotMainKt") + args(providers.gradleProperty("out").getOrElse(layout.buildDirectory.file("wallet.png").get().asFile.path)) +} diff --git a/apps/desktop/src/main/kotlin/com/flipcash/desktop/DesktopGraph.kt b/apps/desktop/src/main/kotlin/com/flipcash/desktop/DesktopGraph.kt index 78b62aade5..91c09bb3ba 100644 --- a/apps/desktop/src/main/kotlin/com/flipcash/desktop/DesktopGraph.kt +++ b/apps/desktop/src/main/kotlin/com/flipcash/desktop/DesktopGraph.kt @@ -1,13 +1,40 @@ package com.flipcash.desktop +import com.flipcash.app.analytics.FlipcashAnalytics +import com.flipcash.app.balance.internal.WalletViewModel +import com.flipcash.app.tokens.ui.SelectTokenViewModel +import com.getcode.opencode.exchange.Exchange +import com.getcode.util.resources.ResourceHelper +import com.getcode.utils.network.NetworkConnectivityListener +import com.flipcash.desktop.inject.FlipcashDesktopChannelModule +import com.flipcash.services.inject.FlipcashModule +import com.flipcash.desktop.inject.OpenCodeDesktopChannelModule +import com.getcode.opencode.inject.OpenCodeModule +import com.getcode.opencode.inject.SessionListenerModule +import com.getcode.opencode.inject.TransactorModule import dev.zacsweers.metro.AppScope import dev.zacsweers.metro.DependencyGraph -import dev.zacsweers.metro.Provides +import javax.inject.Singleton -@DependencyGraph(AppScope::class) +@Singleton +@DependencyGraph( + scope = AppScope::class, + bindingContainers = [ + OpenCodeModule::class, + OpenCodeDesktopChannelModule::class, + SessionListenerModule::class, + TransactorModule::class, + FlipcashModule::class, + com.flipcash.services.inject.ChatCryptoModule::class, + FlipcashDesktopChannelModule::class, + DesktopModule::class, + ], +) interface DesktopGraph { - val appName: String - - @Provides - fun provideAppName(): String = "Flipcash" + val walletViewModel: WalletViewModel + val selectTokenViewModel: SelectTokenViewModel + val exchange: Exchange + val resources: ResourceHelper + val networkObserver: NetworkConnectivityListener + val analytics: FlipcashAnalytics } diff --git a/apps/desktop/src/main/kotlin/com/flipcash/desktop/DesktopModule.kt b/apps/desktop/src/main/kotlin/com/flipcash/desktop/DesktopModule.kt new file mode 100644 index 0000000000..ee09e944c0 --- /dev/null +++ b/apps/desktop/src/main/kotlin/com/flipcash/desktop/DesktopModule.kt @@ -0,0 +1,111 @@ +package com.flipcash.desktop + +import com.flipcash.app.analytics.FlipcashAnalytics +import com.flipcash.app.core.AppRoute +import com.flipcash.app.core.chat.TipHistorySource +import com.flipcash.app.core.storage.DirectoryPreferencesFiles +import com.flipcash.app.core.storage.PreferencesFiles +import com.flipcash.app.funding.PurchaseMethod +import com.flipcash.app.funding.PurchaseMethodController +import com.flipcash.app.funding.PurchaseMethodMetadata +import com.flipcash.app.funding.PurchaseMethodSelection +import com.flipcash.app.funding.PurchaseMethodState +import com.flipcash.app.persistence.sources.ChatMessageDataSource +import com.flipcash.app.tokens.TokenCoordinator +import com.flipcash.app.userflags.UserFlagsFiles +import com.flipcash.libs.coroutines.DispatcherProvider +import com.getcode.chatcipher.ChatCipher +import com.getcode.chatcipher.DefaultChatCipher +import com.getcode.opencode.providers.TokenMetadataProvider +import com.getcode.util.locale.LocaleHelper +import com.getcode.util.resources.ComposeResourceHelper +import com.getcode.util.resources.ResourceHelper +import com.getcode.utils.network.NetworkConnectivityListener +import com.getcode.utils.network.NetworkObserverStub +import dagger.Module +import dagger.Provides +import java.io.File +import java.util.Currency +import java.util.Locale +import javax.inject.Singleton +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.emptyFlow +import kotlinx.coroutines.flow.map + +/** + * Desktop implementations of the seams Android binds in its Hilt modules. Funding, analytics and + * connectivity are stubs for this slice; the rest are real. + */ +@Module +object DesktopModule { + private val appDir: File by lazy { + File(System.getProperty("user.home"), ".flipcash").apply { mkdirs() } + } + + @Provides + @Singleton + fun dispatchers(): DispatcherProvider = object : DispatcherProvider { + override val Default: CoroutineDispatcher = Dispatchers.Default + override val Main: CoroutineDispatcher = Dispatchers.Main + override val IO: CoroutineDispatcher = Dispatchers.IO + } + + // ChatCryptoModule provides this from its companion object, which Metro's Dagger interop + // does not read from a precompiled module. + @Provides + fun chatCipher(): ChatCipher = DefaultChatCipher + + @Provides + fun analytics(): FlipcashAnalytics = FlipcashAnalytics.None + + @Provides + @Singleton + fun locale(): LocaleHelper = object : LocaleHelper { + override fun getLanguageTag(): String = Locale.getDefault().toLanguageTag() + override fun getDefaultCurrencyName(): String = + runCatching { Currency.getInstance(Locale.getDefault()).currencyCode }.getOrDefault("USD") + override suspend fun getDefaultCountry(): String? = + Locale.getDefault().country.takeIf { it.length == 2 } + } + + @Provides + @Singleton + fun network(): NetworkConnectivityListener = NetworkObserverStub() + + @Provides + @Singleton + fun preferencesFiles(): PreferencesFiles = DirectoryPreferencesFiles(appDir) + + @Provides + @Singleton + fun userFlagsFiles(): UserFlagsFiles = object : UserFlagsFiles { + override val noBackupDir: File = File(appDir, "no_backup").apply { mkdirs() } + override fun dataStoreFile(name: String): File = File(appDir, "datastore/$name.preferences_pb") + } + + @Provides + @Singleton + fun resources(): ResourceHelper = ComposeResourceHelper() + + @Provides + fun tipHistory(messages: ChatMessageDataSource): TipHistorySource = object : TipHistorySource { + override fun hasEverTipped(): Flow = messages.hasEverTipped().map { it } + } + + @Provides + fun tokenMetadata(coordinator: TokenCoordinator): TokenMetadataProvider = coordinator + + @Provides + @Singleton + fun purchaseMethods(): PurchaseMethodController = object : PurchaseMethodController { + override val state: StateFlow = MutableStateFlow(PurchaseMethodState()) + override val selections: Flow = emptyFlow() + override fun present(metadata: PurchaseMethodMetadata) = Unit + override fun select(method: PurchaseMethod, metadata: PurchaseMethodMetadata) = Unit + override suspend fun presentDepositOptions(popToRoot: Boolean): AppRoute? = null + } +} diff --git a/apps/desktop/src/main/kotlin/com/flipcash/desktop/DesktopWalletContent.kt b/apps/desktop/src/main/kotlin/com/flipcash/desktop/DesktopWalletContent.kt new file mode 100644 index 0000000000..b344cab896 --- /dev/null +++ b/apps/desktop/src/main/kotlin/com/flipcash/desktop/DesktopWalletContent.kt @@ -0,0 +1,45 @@ +package com.flipcash.desktop + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import com.flipcash.app.analytics.LocalAnalytics +import com.flipcash.app.balance.internal.WalletScreen +import com.flipcash.app.core.tokens.TokenPurpose +import com.flipcash.app.theme.FlipcashTheme +import com.flipcash.app.tokens.ui.SelectTokenViewModel +import com.getcode.opencode.compose.LocalExchange +import com.getcode.theme.CodeTheme +import com.getcode.util.resources.LocalResources +import com.getcode.utils.network.LocalNetworkObserver + +/** + * The wallet screen with the locals and window background that Android's app root provides + * (`App.kt` paints [CodeTheme.colors.background] behind every screen). The graph doesn't scope view + * models, so each read of [DesktopGraph.walletViewModel] builds a new one; they're held here. + */ +@Composable +fun DesktopWalletContent(graph: DesktopGraph) { + val walletViewModel = remember { graph.walletViewModel } + val tokenViewModel = remember { graph.selectTokenViewModel } + LaunchedEffect(tokenViewModel) { + tokenViewModel.dispatchEvent(SelectTokenViewModel.Event.OnPurposeChanged(TokenPurpose.Balance)) + } + FlipcashTheme { + CompositionLocalProvider( + LocalExchange provides graph.exchange, + LocalResources provides graph.resources, + LocalNetworkObserver provides graph.networkObserver, + LocalAnalytics provides graph.analytics, + ) { + Box(Modifier.fillMaxSize().background(CodeTheme.colors.background)) { + WalletScreen(walletViewModel, tokenViewModel) + } + } + } +} diff --git a/apps/desktop/src/main/kotlin/com/flipcash/desktop/Main.kt b/apps/desktop/src/main/kotlin/com/flipcash/desktop/Main.kt index 8f9fbed3a2..a56821ba1e 100644 --- a/apps/desktop/src/main/kotlin/com/flipcash/desktop/Main.kt +++ b/apps/desktop/src/main/kotlin/com/flipcash/desktop/Main.kt @@ -1,20 +1,22 @@ package com.flipcash.desktop -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text import androidx.compose.runtime.LaunchedEffect +import androidx.compose.ui.unit.dp import androidx.compose.ui.window.Window import androidx.compose.ui.window.application +import androidx.compose.ui.window.rememberWindowState import dev.zacsweers.metro.createGraph import java.lang.management.ManagementFactory fun main() { val graph = createGraph() application { - Window(onCloseRequest = ::exitApplication, title = "Flipcash") { - MaterialTheme { - Text(graph.appName) - } + Window( + onCloseRequest = ::exitApplication, + title = "Flipcash", + state = rememberWindowState(width = 420.dp, height = 860.dp), + ) { + DesktopWalletContent(graph) LaunchedEffect(Unit) { val sinceJvmStart = System.currentTimeMillis() - ManagementFactory.getRuntimeMXBean().startTime diff --git a/apps/desktop/src/main/kotlin/com/flipcash/desktop/SnapshotMain.kt b/apps/desktop/src/main/kotlin/com/flipcash/desktop/SnapshotMain.kt new file mode 100644 index 0000000000..c3fd176163 --- /dev/null +++ b/apps/desktop/src/main/kotlin/com/flipcash/desktop/SnapshotMain.kt @@ -0,0 +1,32 @@ +package com.flipcash.desktop + +import androidx.compose.ui.ImageComposeScene +import androidx.compose.ui.unit.Density +import androidx.compose.ui.use +import dev.zacsweers.metro.createGraph +import java.io.File +import kotlin.system.exitProcess +import org.jetbrains.skia.EncodedImageFormat + +/** + * Renders the wallet screen off-screen through the same graph as [main] and writes a PNG. + * Usage: `./gradlew :apps:desktop:snapshot -Pout=`. + */ +fun main(args: Array) { + val out = File(args.firstOrNull() ?: "wallet.png") + val graph = createGraph() + ImageComposeScene(width = 840, height = 1720, density = Density(2f)) { + DesktopWalletContent(graph) + }.use { scene -> + var nanos = 0L + repeat(80) { + scene.render(nanos) + Thread.sleep(100) + nanos += 100_000_000L + } + val png = scene.render(nanos).encodeToData(EncodedImageFormat.PNG)!!.bytes + out.writeBytes(png) + } + println("snapshot written to ${out.absolutePath}") + exitProcess(0) +} diff --git a/apps/desktop/src/main/kotlin/com/flipcash/desktop/inject/FlipcashDesktopChannelModule.kt b/apps/desktop/src/main/kotlin/com/flipcash/desktop/inject/FlipcashDesktopChannelModule.kt new file mode 100644 index 0000000000..c9617ee0ad --- /dev/null +++ b/apps/desktop/src/main/kotlin/com/flipcash/desktop/inject/FlipcashDesktopChannelModule.kt @@ -0,0 +1,66 @@ +package com.flipcash.desktop.inject + +import com.flipcash.services.ForegroundGate +import com.flipcash.services.internal.annotations.FlipcashManagedChannel +import com.flipcash.services.internal.annotations.FlipcashManagedStreamingChannel +import com.flipcash.services.internal.annotations.FlipcashProtocol +import com.flipcash.services.user.AnalyticsIdentifier +import com.getcode.opencode.ProtocolConfig +import com.getcode.opencode.utils.logging.LoggingClientInterceptor +import dagger.Module +import dagger.Provides +import io.grpc.ManagedChannel +import io.grpc.okhttp.OkHttpChannelBuilder +import java.util.concurrent.TimeUnit +import javax.inject.Singleton + +/** + * Desktop counterpart of the Android `FlipcashChannelModule`: plain okhttp channels with the + * Android settings, no analytics identity (desktop has no Mixpanel), and a gate that is always open + * because a desktop process has no background state. + */ +@Module +object FlipcashDesktopChannelModule { + @Provides + fun provideAnalyticsIdentifier(): AnalyticsIdentifier = AnalyticsIdentifier { } + + @Provides + fun providesForegroundGate(): ForegroundGate = ForegroundGate { } + + @Singleton + @FlipcashProtocol + @Provides + fun providesFlipcashProtocolConfig(): ProtocolConfig = object : ProtocolConfig { + override val baseUrl: String + get() = "fc-v2.api.flipcash-infra.net" + override val userAgent: String + get() = "Flipcash/Desktop/${System.getProperty("os.name")}" + } + + @Singleton + @Provides + @FlipcashManagedChannel + fun provideManagedChannel( + @FlipcashProtocol + config: ProtocolConfig, + ): ManagedChannel = OkHttpChannelBuilder.forAddress(config.baseUrl, config.port) + .userAgent(config.userAgent) + .keepAliveWithoutCalls(false) + .idleTimeout(5, TimeUnit.MINUTES) + .intercept(LoggingClientInterceptor()) + .build() + + @Singleton + @Provides + @FlipcashManagedStreamingChannel + fun provideManagedStreamingChannel( + @FlipcashProtocol + config: ProtocolConfig, + ): ManagedChannel = OkHttpChannelBuilder.forAddress(config.baseUrl, config.port) + .userAgent(config.userAgent) + .keepAliveTime(config.keepAlive.inWholeMilliseconds, TimeUnit.MILLISECONDS) + .keepAliveTimeout(config.keepAliveTimeout.inWholeMilliseconds, TimeUnit.MILLISECONDS) + .keepAliveWithoutCalls(true) + .intercept(LoggingClientInterceptor()) + .build() +} diff --git a/apps/desktop/src/main/kotlin/com/flipcash/desktop/inject/OpenCodeDesktopChannelModule.kt b/apps/desktop/src/main/kotlin/com/flipcash/desktop/inject/OpenCodeDesktopChannelModule.kt new file mode 100644 index 0000000000..caaae7a636 --- /dev/null +++ b/apps/desktop/src/main/kotlin/com/flipcash/desktop/inject/OpenCodeDesktopChannelModule.kt @@ -0,0 +1,55 @@ +package com.flipcash.desktop.inject + +import com.getcode.opencode.ProtocolConfig +import com.getcode.opencode.internal.annotations.OpenCodeManagedChannel +import com.getcode.opencode.internal.annotations.OpenCodeManagedStreamingChannel +import com.getcode.opencode.internal.annotations.OpenCodeProtocol +import com.getcode.opencode.utils.logging.LoggingClientInterceptor +import dagger.Module +import dagger.Provides +import io.grpc.ManagedChannel +import io.grpc.okhttp.OkHttpChannelBuilder +import java.util.concurrent.TimeUnit +import javax.inject.Singleton + +/** + * Desktop counterpart of the Android `OpenCodeChannelModule`: the same channel settings, built on + * plain okhttp instead of `AndroidChannelBuilder` (which only adds Android network-change hooks). + */ +@Module +object OpenCodeDesktopChannelModule { + @Singleton + @OpenCodeProtocol + @Provides + fun providesOpenCodeProtocolConfig(): ProtocolConfig = object : ProtocolConfig { + override val baseUrl: String + get() = "ocp-v2.api.flipcash-infra.net" + override val userAgent: String + get() = "OpenCodeProtocol/Desktop/${System.getProperty("os.name")}" + } + + @Singleton + @Provides + @OpenCodeManagedChannel + fun provideManagedChannel( + @OpenCodeProtocol + config: ProtocolConfig, + ): ManagedChannel = OkHttpChannelBuilder.forAddress(config.baseUrl, config.port) + .userAgent(config.userAgent) + .keepAliveWithoutCalls(false) + .idleTimeout(5, TimeUnit.MINUTES) + .intercept(LoggingClientInterceptor()) + .build() + + @Singleton + @Provides + @OpenCodeManagedStreamingChannel + fun provideManagedStreamingChannel( + @OpenCodeProtocol + config: ProtocolConfig, + ): ManagedChannel = OkHttpChannelBuilder.forAddress(config.baseUrl, config.port) + .userAgent(config.userAgent) + .keepAliveWithoutCalls(true) + .intercept(LoggingClientInterceptor()) + .build() +} diff --git a/apps/flipcash/core-ui/build.gradle.kts b/apps/flipcash/core-ui/build.gradle.kts index f457abba5f..5c27c4add1 100644 --- a/apps/flipcash/core-ui/build.gradle.kts +++ b/apps/flipcash/core-ui/build.gradle.kts @@ -55,4 +55,6 @@ kotlin { dependencies { add("kspAndroid", libs.hilt.android.compiler) add("kspAndroid", libs.hilt.compiler) + add("kspJvm", libs.dagger.compiler) + add("jvmMainImplementation", libs.dagger) } diff --git a/apps/flipcash/core/build.gradle.kts b/apps/flipcash/core/build.gradle.kts index d7da03a813..2fab73b963 100644 --- a/apps/flipcash/core/build.gradle.kts +++ b/apps/flipcash/core/build.gradle.kts @@ -92,4 +92,6 @@ compose.resources { dependencies { add("kspAndroid", libs.hilt.android.compiler) add("kspAndroid", libs.hilt.compiler) + add("kspJvm", libs.dagger.compiler) + add("jvmMainImplementation", libs.dagger) } diff --git a/apps/flipcash/features/balance/build.gradle.kts b/apps/flipcash/features/balance/build.gradle.kts index a0f4382158..5ee4523ab2 100644 --- a/apps/flipcash/features/balance/build.gradle.kts +++ b/apps/flipcash/features/balance/build.gradle.kts @@ -62,4 +62,6 @@ kotlin { dependencies { add("kspAndroid", libs.hilt.android.compiler) add("kspAndroid", libs.hilt.compiler) + add("kspJvm", libs.dagger.compiler) + add("jvmMainImplementation", libs.dagger) } diff --git a/apps/flipcash/features/balance/src/commonMain/kotlin/com/flipcash/app/balance/internal/WalletScreenContent.kt b/apps/flipcash/features/balance/src/commonMain/kotlin/com/flipcash/app/balance/internal/WalletScreenContent.kt index 5e5335bfed..0980c6a663 100644 --- a/apps/flipcash/features/balance/src/commonMain/kotlin/com/flipcash/app/balance/internal/WalletScreenContent.kt +++ b/apps/flipcash/features/balance/src/commonMain/kotlin/com/flipcash/app/balance/internal/WalletScreenContent.kt @@ -63,7 +63,7 @@ import com.getcode.ui.theme.CodeCircularProgressIndicator private const val TokenStackKey = "tokenStack" @Composable -internal fun WalletScreen( +fun WalletScreen( viewModel: WalletViewModel, tokenViewModel: SelectTokenViewModel, ) { diff --git a/apps/flipcash/shared/analytics/build.gradle.kts b/apps/flipcash/shared/analytics/build.gradle.kts index af3b9fdf86..a93d95a77b 100644 --- a/apps/flipcash/shared/analytics/build.gradle.kts +++ b/apps/flipcash/shared/analytics/build.gradle.kts @@ -37,4 +37,6 @@ kotlin { dependencies { add("kspAndroid", libs.hilt.android.compiler) add("kspAndroid", libs.hilt.compiler) + add("kspJvm", libs.dagger.compiler) + add("jvmMainImplementation", libs.dagger) } diff --git a/apps/flipcash/shared/funding/build.gradle.kts b/apps/flipcash/shared/funding/build.gradle.kts index 871af57bf3..23ec4527ef 100644 --- a/apps/flipcash/shared/funding/build.gradle.kts +++ b/apps/flipcash/shared/funding/build.gradle.kts @@ -46,4 +46,6 @@ kotlin { dependencies { add("kspAndroid", libs.hilt.android.compiler) add("kspAndroid", libs.hilt.compiler) + add("kspJvm", libs.dagger.compiler) + add("jvmMainImplementation", libs.dagger) } diff --git a/apps/flipcash/shared/persistence/sources/build.gradle.kts b/apps/flipcash/shared/persistence/sources/build.gradle.kts index ccb56905b3..19d9c46e97 100644 --- a/apps/flipcash/shared/persistence/sources/build.gradle.kts +++ b/apps/flipcash/shared/persistence/sources/build.gradle.kts @@ -41,4 +41,6 @@ kotlin { dependencies { add("kspAndroid", libs.hilt.android.compiler) add("kspAndroid", libs.hilt.compiler) + add("kspJvm", libs.dagger.compiler) + add("jvmMainImplementation", libs.dagger) } diff --git a/apps/flipcash/shared/theme/build.gradle.kts b/apps/flipcash/shared/theme/build.gradle.kts index f70ab124e6..cd19d34932 100644 --- a/apps/flipcash/shared/theme/build.gradle.kts +++ b/apps/flipcash/shared/theme/build.gradle.kts @@ -1,13 +1,23 @@ plugins { - alias(libs.plugins.flipcash.android.library.compose) + alias(libs.plugins.flipcash.kmp.app.library) + alias(libs.plugins.compose.compiler) } -android { - namespace = "${Gradle.flipcashNamespace}.shared.theme" -} +kotlin { + android { + namespace = "${Gradle.flipcashNamespace}.shared.theme" + } -dependencies { - implementation(project(":ui:theme")) - api(libs.androidx.ui.tooling.preview) - debugApi(libs.androidx.ui.tooling) + sourceSets { + commonMain.dependencies { + implementation(project(":ui:theme")) + implementation(libs.jetbrains.compose.runtime) + implementation(libs.jetbrains.compose.foundation) + implementation(libs.jetbrains.compose.ui) + implementation(libs.jetbrains.compose.animation) + } + androidMain.dependencies { + api(libs.androidx.ui.tooling.preview) + } + } } diff --git a/apps/flipcash/shared/theme/src/main/kotlin/com/flipcash/app/theme/FlipcashPreview.kt b/apps/flipcash/shared/theme/src/androidMain/kotlin/com/flipcash/app/theme/FlipcashPreview.kt similarity index 100% rename from apps/flipcash/shared/theme/src/main/kotlin/com/flipcash/app/theme/FlipcashPreview.kt rename to apps/flipcash/shared/theme/src/androidMain/kotlin/com/flipcash/app/theme/FlipcashPreview.kt diff --git a/apps/flipcash/shared/theme/src/main/kotlin/com/flipcash/app/theme/FlipcashTheme.kt b/apps/flipcash/shared/theme/src/commonMain/kotlin/com/flipcash/app/theme/FlipcashTheme.kt similarity index 100% rename from apps/flipcash/shared/theme/src/main/kotlin/com/flipcash/app/theme/FlipcashTheme.kt rename to apps/flipcash/shared/theme/src/commonMain/kotlin/com/flipcash/app/theme/FlipcashTheme.kt diff --git a/apps/flipcash/shared/theme/src/main/kotlin/com/flipcash/app/theme/internal/FlipcashDesignSystem.kt b/apps/flipcash/shared/theme/src/commonMain/kotlin/com/flipcash/app/theme/internal/FlipcashDesignSystem.kt similarity index 100% rename from apps/flipcash/shared/theme/src/main/kotlin/com/flipcash/app/theme/internal/FlipcashDesignSystem.kt rename to apps/flipcash/shared/theme/src/commonMain/kotlin/com/flipcash/app/theme/internal/FlipcashDesignSystem.kt diff --git a/apps/flipcash/shared/tokens/build.gradle.kts b/apps/flipcash/shared/tokens/build.gradle.kts index 75776da4b7..34e4d3caf8 100644 --- a/apps/flipcash/shared/tokens/build.gradle.kts +++ b/apps/flipcash/shared/tokens/build.gradle.kts @@ -71,4 +71,6 @@ kotlin { dependencies { add("kspAndroid", libs.hilt.android.compiler) add("kspAndroid", libs.hilt.compiler) + add("kspJvm", libs.dagger.compiler) + add("jvmMainImplementation", libs.dagger) } diff --git a/apps/flipcash/shared/transaction-history/build.gradle.kts b/apps/flipcash/shared/transaction-history/build.gradle.kts index 2f0ad39f79..5e5ccc3462 100644 --- a/apps/flipcash/shared/transaction-history/build.gradle.kts +++ b/apps/flipcash/shared/transaction-history/build.gradle.kts @@ -81,4 +81,6 @@ compose.resources { dependencies { add("kspAndroid", libs.hilt.android.compiler) add("kspAndroid", libs.hilt.compiler) + add("kspJvm", libs.dagger.compiler) + add("jvmMainImplementation", libs.dagger) } diff --git a/apps/flipcash/shared/userflags/build.gradle.kts b/apps/flipcash/shared/userflags/build.gradle.kts index 365a0bfbf0..bcb6712ac2 100644 --- a/apps/flipcash/shared/userflags/build.gradle.kts +++ b/apps/flipcash/shared/userflags/build.gradle.kts @@ -42,4 +42,6 @@ kotlin { dependencies { add("kspAndroid", libs.hilt.android.compiler) add("kspAndroid", libs.hilt.compiler) + add("kspJvm", libs.dagger.compiler) + add("jvmMainImplementation", libs.dagger) } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f9356a8896..fec7c51eff 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -185,6 +185,7 @@ hilt-android = { module = "com.google.dagger:hilt-android", version.ref = "hilt" # Plain JVM jars: @Module/@Provides/@Binds and @InstallIn/SingletonComponent compile in a KMP commonMain. dagger = { module = "com.google.dagger:dagger", version.ref = "hilt" } hilt-core = { module = "com.google.dagger:hilt-core", version.ref = "hilt" } +dagger-compiler = { module = "com.google.dagger:dagger-compiler", version.ref = "hilt" } hilt-worker = { module = "androidx.hilt:hilt-work", version.ref = "hilt-jetpack" } hilt-android-compiler = { module = "com.google.dagger:hilt-android-compiler", version.ref = "hilt" } hilt-compiler = { module = "androidx.hilt:hilt-compiler", version.ref = "hilt-jetpack" } @@ -198,6 +199,7 @@ kotlin-reflect = { module = "org.jetbrains.kotlin:kotlin-reflect", version.ref = kotlin-test-junit = { module = "org.jetbrains.kotlin:kotlin-test-junit", version.ref = "kotlin" } kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" } kotlinx-coroutines-play-services = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-play-services", version.ref = "kotlinx-coroutines" } +kotlinx-coroutines-swing = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-swing", version.ref = "kotlinx-coroutines" } kotlinx-coroutines-rx3 = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-rx3", version.ref = "kotlinx-coroutines" } kotlinx-datetime = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version.ref = "kotlinx-datetime" } kotlinx-serialization-core = { module = "org.jetbrains.kotlinx:kotlinx-serialization-core", version.ref = "kotlinx-serialization" } diff --git a/services/flipcash/build.gradle.kts b/services/flipcash/build.gradle.kts index 97e107fbf0..d6746366fc 100644 --- a/services/flipcash/build.gradle.kts +++ b/services/flipcash/build.gradle.kts @@ -62,4 +62,6 @@ kotlin { dependencies { add("kspAndroid", libs.hilt.android.compiler) add("kspAndroid", libs.hilt.compiler) + add("kspJvm", libs.dagger.compiler) + add("jvmMainImplementation", libs.dagger) } diff --git a/services/flipcash/src/androidMain/kotlin/com/flipcash/services/inject/FlipcashChannelModule.kt b/services/flipcash/src/androidMain/kotlin/com/flipcash/services/inject/FlipcashChannelModule.kt new file mode 100644 index 0000000000..2f6a6bef79 --- /dev/null +++ b/services/flipcash/src/androidMain/kotlin/com/flipcash/services/inject/FlipcashChannelModule.kt @@ -0,0 +1,178 @@ +package com.flipcash.services.inject + +import android.content.Context +import com.flipcash.services.user.AnalyticsIdentifier +import com.mixpanel.android.mpmetrics.MixpanelAPI +import com.flipcash.services.internal.annotations.FlipcashManagedChannel +import com.flipcash.services.internal.annotations.FlipcashManagedStreamingChannel +import com.flipcash.services.internal.annotations.FlipcashProtocol +import com.flipcash.services.internal.domain.ActivityFeedMessageMapper +import com.flipcash.services.internal.domain.BlockedUserMapper +import com.flipcash.services.internal.domain.ContactMapper +import com.flipcash.services.internal.domain.ImageModerationResponseMapper +import com.flipcash.services.internal.domain.UserFlagsMapper +import com.flipcash.services.internal.domain.SocialAccountMapper +import com.flipcash.services.internal.domain.TextModerationResponseMapper +import com.flipcash.services.internal.domain.UserProfileMapper +import com.flipcash.services.internal.domain.ChatMetadataMapper +import com.flipcash.services.BlobUploader +import com.flipcash.services.ForegroundGate +import com.flipcash.services.ProcessForegroundGate +import com.flipcash.services.internal.network.HttpBlobUploader +import com.flipcash.services.internal.network.services.AccountService +import com.flipcash.services.internal.network.services.ActivityFeedService +import com.flipcash.services.internal.network.services.BlobStorageService +import com.flipcash.services.internal.network.services.BlocklistService +import com.flipcash.services.internal.network.services.ChatService +import com.flipcash.services.internal.network.services.EventStreamingService +import com.flipcash.services.internal.network.services.ChatMessagingService +import com.flipcash.services.internal.network.services.EmailVerificationService +import com.flipcash.services.internal.network.services.ContactListService +import com.flipcash.services.internal.network.services.ModerationService +import com.flipcash.services.internal.network.services.PollService +import com.flipcash.services.internal.repositories.InternalPollRepository +import com.flipcash.services.repository.PollRepository +import com.flipcash.services.internal.network.services.PhoneVerificationService +import com.flipcash.services.internal.network.services.ProfileService +import com.flipcash.services.internal.network.services.PurchaseService +import com.flipcash.services.internal.network.services.PushService +import com.flipcash.services.internal.network.services.CommunityService +import com.flipcash.services.internal.network.services.ResolverService +import com.flipcash.services.internal.network.services.ReportingService +import com.flipcash.services.internal.network.services.SettingsService +import com.flipcash.services.internal.network.services.ThirdPartyService +import com.flipcash.services.internal.repositories.InternalAccountRepository +import com.flipcash.services.internal.repositories.InternalActivityFeedRepository +import com.flipcash.services.internal.repositories.InternalBlobStorageRepository +import com.flipcash.services.internal.repositories.InternalBlocklistRepository +import com.flipcash.services.internal.repositories.InternalChatRepository +import com.flipcash.services.internal.repositories.InternalEventStreamingRepository +import com.flipcash.services.internal.repositories.InternalChatMessagingRepository +import com.flipcash.services.internal.repositories.InternalContactListRepository +import com.flipcash.services.internal.repositories.InternalContactVerificationRepository +import com.flipcash.services.internal.repositories.InternalModerationRepository +import com.flipcash.services.internal.repositories.InternalProfileRepository +import com.flipcash.services.internal.repositories.InternalPurchaseRepository +import com.flipcash.services.internal.repositories.InternalPushRepository +import com.flipcash.services.internal.repositories.InternalCommunityRepository +import com.flipcash.services.internal.repositories.InternalResolverRepository +import com.flipcash.services.internal.repositories.InternalReportingRepository +import com.flipcash.services.internal.repositories.InternalSettingsRepository +import com.flipcash.services.internal.repositories.InternalThirdPartyRepository +import com.flipcash.services.repository.AccountRepository +import com.flipcash.services.repository.ActivityFeedRepository +import com.flipcash.services.repository.BlocklistRepository +import com.flipcash.services.repository.ChatRepository +import com.flipcash.services.repository.EventStreamingRepository +import com.flipcash.services.repository.ChatMessagingRepository +import com.flipcash.services.repository.ContactListRepository +import com.flipcash.services.repository.ContactVerificationRepository +import com.flipcash.services.repository.ModerationRepository +import com.flipcash.services.repository.ProfileRepository +import com.flipcash.services.repository.PurchaseRepository +import com.flipcash.services.repository.PushRepository +import com.flipcash.services.repository.BlobStorageRepository +import com.flipcash.services.repository.CommunityRepository +import com.flipcash.services.repository.ResolverRepository +import com.flipcash.services.repository.ReportingRepository +import com.flipcash.services.repository.SettingsRepository +import com.flipcash.services.repository.ThirdPartyRepository +import com.getcode.opencode.ProtocolConfig +import com.getcode.opencode.utils.logging.LoggingClientInterceptor +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.android.qualifiers.ApplicationContext +import dagger.hilt.components.SingletonComponent +import com.getcode.utils.TraceType +import com.getcode.utils.trace +import io.grpc.ConnectivityState +import io.grpc.ManagedChannel +import io.grpc.android.AndroidChannelBuilder +import io.grpc.okhttp.OkHttpChannelBuilder +import java.util.concurrent.TimeUnit +import javax.inject.Singleton + +@Module +@InstallIn(SingletonComponent::class) +internal object FlipcashChannelModule { + @Provides + fun provideAnalyticsIdentifier(mixpanelAPI: MixpanelAPI): AnalyticsIdentifier = + AnalyticsIdentifier { mixpanelAPI.identify(it) } + + @Singleton + @FlipcashProtocol + @Provides + fun providesFlipcashProtocolConfig( + @ApplicationContext context: Context + ): ProtocolConfig { + return object : ProtocolConfig { + override val baseUrl: String + get() = "fc-v2.api.flipcash-infra.net" + override val userAgent: String + get() { + val version = + context.packageManager.getPackageInfo(context.packageName, 0).versionName + return "Flipcash/Android/$version" + } + } + } + + @Singleton + @Provides + @FlipcashManagedChannel + fun provideManagedChannel( + @ApplicationContext context: Context, + @FlipcashProtocol + config: ProtocolConfig, + ): ManagedChannel { + return AndroidChannelBuilder + .usingBuilder(OkHttpChannelBuilder.forAddress(config.baseUrl, config.port)) + .context(context) + .userAgent(config.userAgent) + .keepAliveWithoutCalls(false) + .idleTimeout(5, TimeUnit.MINUTES) + .intercept(LoggingClientInterceptor()) + .build() + .also { observeChannelState("flipcash", it) } + } + + @Singleton + @Provides + @FlipcashManagedStreamingChannel + fun provideManagedStreamingChannel( + @ApplicationContext context: Context, + @FlipcashProtocol + config: ProtocolConfig, + ): ManagedChannel { + return AndroidChannelBuilder + .usingBuilder(OkHttpChannelBuilder.forAddress(config.baseUrl, config.port)) + .context(context) + .userAgent(config.userAgent) + .keepAliveTime(config.keepAlive.inWholeMilliseconds, TimeUnit.MILLISECONDS) + .keepAliveTimeout(config.keepAliveTimeout.inWholeMilliseconds, TimeUnit.MILLISECONDS) + .keepAliveWithoutCalls(true) + .intercept(LoggingClientInterceptor()) + .build() + .also { observeChannelState("flipcash-stream", it) } + } + + private fun observeChannelState(name: String, channel: ManagedChannel) { + val state = channel.getState(false) + trace( + tag = "gRPC", + message = "$name => $state", + type = TraceType.StateChange, + ) + if (state != ConnectivityState.SHUTDOWN) { + channel.notifyWhenStateChanged(state) { + observeChannelState(name, channel) + } + } + } + + @Provides + internal fun providesForegroundGate( + gate: ProcessForegroundGate, + ): ForegroundGate = gate +} diff --git a/services/flipcash/src/commonMain/kotlin/com/flipcash/services/inject/ChatCryptoModule.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/inject/ChatCryptoModule.kt index 76c4cc2d78..56920da6fe 100644 --- a/services/flipcash/src/commonMain/kotlin/com/flipcash/services/inject/ChatCryptoModule.kt +++ b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/inject/ChatCryptoModule.kt @@ -14,13 +14,13 @@ import dagger.hilt.components.SingletonComponent @Module @InstallIn(SingletonComponent::class) -internal abstract class ChatCryptoModule { +abstract class ChatCryptoModule { @Binds - abstract fun bindChatKeySource(source: DefaultChatKeySource): ChatKeySource + internal abstract fun bindChatKeySource(source: DefaultChatKeySource): ChatKeySource @Binds - abstract fun bindGroupKeySource(source: GroupKeyEnvelopes): GroupKeySource + internal abstract fun bindGroupKeySource(source: GroupKeyEnvelopes): GroupKeySource companion object { @Provides diff --git a/services/flipcash/src/androidMain/kotlin/com/flipcash/services/inject/FlipcashModule.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/inject/FlipcashModule.kt similarity index 75% rename from services/flipcash/src/androidMain/kotlin/com/flipcash/services/inject/FlipcashModule.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/inject/FlipcashModule.kt index e45cd2ff18..0ebc4c56f1 100644 --- a/services/flipcash/src/androidMain/kotlin/com/flipcash/services/inject/FlipcashModule.kt +++ b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/inject/FlipcashModule.kt @@ -1,8 +1,6 @@ package com.flipcash.services.inject -import android.content.Context import com.flipcash.services.user.AnalyticsIdentifier -import com.mixpanel.android.mpmetrics.MixpanelAPI import com.flipcash.services.internal.annotations.FlipcashManagedChannel import com.flipcash.services.internal.annotations.FlipcashManagedStreamingChannel import com.flipcash.services.internal.annotations.FlipcashProtocol @@ -17,7 +15,6 @@ import com.flipcash.services.internal.domain.UserProfileMapper import com.flipcash.services.internal.domain.ChatMetadataMapper import com.flipcash.services.BlobUploader import com.flipcash.services.ForegroundGate -import com.flipcash.services.ProcessForegroundGate import com.flipcash.services.internal.network.HttpBlobUploader import com.flipcash.services.internal.network.services.AccountService import com.flipcash.services.internal.network.services.ActivityFeedService @@ -82,96 +79,17 @@ import com.getcode.opencode.utils.logging.LoggingClientInterceptor import dagger.Module import dagger.Provides import dagger.hilt.InstallIn -import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.components.SingletonComponent import com.getcode.utils.TraceType import com.getcode.utils.trace -import io.grpc.ConnectivityState import io.grpc.ManagedChannel -import io.grpc.android.AndroidChannelBuilder -import io.grpc.okhttp.OkHttpChannelBuilder -import java.util.concurrent.TimeUnit import javax.inject.Singleton @Module @InstallIn(SingletonComponent::class) -internal object FlipcashModule { - @Provides - fun provideAnalyticsIdentifier(mixpanelAPI: MixpanelAPI): AnalyticsIdentifier = - AnalyticsIdentifier { mixpanelAPI.identify(it) } - - @Singleton - @FlipcashProtocol - @Provides - fun providesFlipcashProtocolConfig( - @ApplicationContext context: Context - ): ProtocolConfig { - return object : ProtocolConfig { - override val baseUrl: String - get() = "fc-v2.api.flipcash-infra.net" - override val userAgent: String - get() { - val version = - context.packageManager.getPackageInfo(context.packageName, 0).versionName - return "Flipcash/Android/$version" - } - } - } - - @Singleton - @Provides - @FlipcashManagedChannel - fun provideManagedChannel( - @ApplicationContext context: Context, - @FlipcashProtocol - config: ProtocolConfig, - ): ManagedChannel { - return AndroidChannelBuilder - .usingBuilder(OkHttpChannelBuilder.forAddress(config.baseUrl, config.port)) - .context(context) - .userAgent(config.userAgent) - .keepAliveWithoutCalls(false) - .idleTimeout(5, TimeUnit.MINUTES) - .intercept(LoggingClientInterceptor()) - .build() - .also { observeChannelState("flipcash", it) } - } - - @Singleton - @Provides - @FlipcashManagedStreamingChannel - fun provideManagedStreamingChannel( - @ApplicationContext context: Context, - @FlipcashProtocol - config: ProtocolConfig, - ): ManagedChannel { - return AndroidChannelBuilder - .usingBuilder(OkHttpChannelBuilder.forAddress(config.baseUrl, config.port)) - .context(context) - .userAgent(config.userAgent) - .keepAliveTime(config.keepAlive.inWholeMilliseconds, TimeUnit.MILLISECONDS) - .keepAliveTimeout(config.keepAliveTimeout.inWholeMilliseconds, TimeUnit.MILLISECONDS) - .keepAliveWithoutCalls(true) - .intercept(LoggingClientInterceptor()) - .build() - .also { observeChannelState("flipcash-stream", it) } - } - - private fun observeChannelState(name: String, channel: ManagedChannel) { - val state = channel.getState(false) - trace( - tag = "gRPC", - message = "$name => $state", - type = TraceType.StateChange, - ) - if (state != ConnectivityState.SHUTDOWN) { - channel.notifyWhenStateChanged(state) { - observeChannelState(name, channel) - } - } - } - +object FlipcashModule { @Provides + @JvmName("providesChatRepository") internal fun providesChatRepository( service: ChatService, mapper: ChatMetadataMapper, @@ -179,22 +97,26 @@ internal object FlipcashModule { ): ChatRepository = InternalChatRepository(service, mapper, userProfileMapper) @Provides + @JvmName("providesEventStreamingRepository") internal fun providesEventStreamingRepository( service: EventStreamingService, ): EventStreamingRepository = InternalEventStreamingRepository(service) @Provides + @JvmName("providesChatMessagingRepository") internal fun providesChatMessagingRepository( service: ChatMessagingService, ): ChatMessagingRepository = InternalChatMessagingRepository(service) @Provides + @JvmName("providesContactListRepository") internal fun providesContactListRepository( service: ContactListService, contactMapper: ContactMapper, ): ContactListRepository = InternalContactListRepository(service, contactMapper) @Provides + @JvmName("providesCommunityRepository") internal fun providesCommunityRepository( service: CommunityService, chatMapper: ChatMetadataMapper, @@ -202,64 +124,70 @@ internal object FlipcashModule { ): CommunityRepository = InternalCommunityRepository(service, chatMapper, userProfileMapper) @Provides + @JvmName("providesResolverRepository") internal fun providesResolverRepository( service: ResolverService, ): ResolverRepository = InternalResolverRepository(service) @Provides + @JvmName("providesBlobStorageRepository") internal fun providesBlobStorageRepository( service: BlobStorageService, ): BlobStorageRepository = InternalBlobStorageRepository(service) @Provides + @JvmName("providesBlobUploader") internal fun providesBlobUploader( uploader: HttpBlobUploader, ): BlobUploader = uploader @Provides - internal fun providesForegroundGate( - gate: ProcessForegroundGate, - ): ForegroundGate = gate - - @Provides + @JvmName("providesAccountRepository") internal fun providesAccountRepository( service: AccountService, mapper: UserFlagsMapper, ): AccountRepository = InternalAccountRepository(service, mapper) @Provides + @JvmName("providesActivityFeedRepository") internal fun providesActivityFeedRepository( service: ActivityFeedService, mapper: ActivityFeedMessageMapper, ): ActivityFeedRepository = InternalActivityFeedRepository(service, mapper) @Provides + @JvmName("providesBlocklistRepository") internal fun providesBlocklistRepository( service: BlocklistService, mapper: BlockedUserMapper, ): BlocklistRepository = InternalBlocklistRepository(service, mapper) @Provides + @JvmName("providesPurchaseRepository") internal fun providesPurchaseRepository( service: PurchaseService, ): PurchaseRepository = InternalPurchaseRepository(service) @Provides + @JvmName("providesPushRepository") internal fun providesPushRepository( service: PushService, ): PushRepository = InternalPushRepository(service) @Provides + @JvmName("providesSettingsRepository") internal fun providesSettingsRepository( service: SettingsService ): SettingsRepository = InternalSettingsRepository(service) @Provides + @JvmName("providesThirdPartyRepository") internal fun providesThirdPartyRepository( service: ThirdPartyService, ): ThirdPartyRepository = InternalThirdPartyRepository(service) @Provides + @JvmName("providesContactVerificationRepository") internal fun providesContactVerificationRepository( emailService: EmailVerificationService, phoneService: PhoneVerificationService, @@ -267,6 +195,7 @@ internal object FlipcashModule { InternalContactVerificationRepository(emailService, phoneService) @Provides + @JvmName("providesProfileRepository") internal fun providesProfileRepository( service: ProfileService, userProfileMapper: UserProfileMapper, @@ -275,11 +204,13 @@ internal object FlipcashModule { InternalProfileRepository(service, userProfileMapper, socialAccountMapper) @Provides + @JvmName("providesPollRepository") internal fun providesPollRepository( service: PollService, ): PollRepository = InternalPollRepository(service) @Provides + @JvmName("providesModerationRepository") internal fun providesModerationRepository( service: ModerationService, textModerationResponseMapper: TextModerationResponseMapper, @@ -291,7 +222,8 @@ internal object FlipcashModule { ) @Provides + @JvmName("providesReportingRepository") internal fun providesReportingRepository( service: ReportingService, ): ReportingRepository = InternalReportingRepository(service) -} \ No newline at end of file +} diff --git a/services/opencode/build.gradle.kts b/services/opencode/build.gradle.kts index bccc54869c..30b8bbfb25 100644 --- a/services/opencode/build.gradle.kts +++ b/services/opencode/build.gradle.kts @@ -80,6 +80,8 @@ kotlin { dependencies { add("kspAndroid", libs.hilt.android.compiler) add("kspAndroid", libs.hilt.compiler) + add("kspJvm", libs.dagger.compiler) + add("jvmMainImplementation", libs.dagger) } // The headless balance test reads its recovery phrase from local.properties (gitignored) or the diff --git a/services/opencode/src/androidMain/kotlin/com/getcode/opencode/RepositoryFactory.kt b/services/opencode/src/androidMain/kotlin/com/getcode/opencode/RepositoryFactory.kt index 4d0fa240ea..4502e51c25 100644 --- a/services/opencode/src/androidMain/kotlin/com/getcode/opencode/RepositoryFactory.kt +++ b/services/opencode/src/androidMain/kotlin/com/getcode/opencode/RepositoryFactory.kt @@ -1,6 +1,7 @@ package com.getcode.opencode import android.content.Context +import com.getcode.opencode.inject.OpenCodeChannelModule import com.getcode.opencode.inject.OpenCodeModule import com.getcode.opencode.internal.domain.mapping.BillCustomizationMapper import com.getcode.opencode.internal.domain.mapping.HistoricalMintDataMapper @@ -43,8 +44,8 @@ object RepositoryFactory { OpenCodeModule::class.java, ) - val api = AccountApi(module.provideManagedChannel(context, config)) - val transactionApi = TransactionApi(module.provideManagedChannel(context, config)) + val api = AccountApi(OpenCodeChannelModule.provideManagedChannel(context, config)) + val transactionApi = TransactionApi(OpenCodeChannelModule.provideManagedChannel(context, config)) val service = AccountService(api) val transactionMetadataMapper = TransactionMetadataMapper() val swapFunding = SwapFunding(transactionApi) @@ -86,7 +87,7 @@ object RepositoryFactory { OpenCodeModule::class.java, ) - val api = MessagingApi(module.provideManagedChannel(context, config)) + val api = MessagingApi(OpenCodeChannelModule.provideManagedChannel(context, config)) val service = MessagingService(api) return module.providesMessagingRepository(service) } @@ -101,7 +102,7 @@ object RepositoryFactory { OpenCodeModule::class.java, ) - val api = TransactionApi(module.provideManagedChannel(context, config)) + val api = TransactionApi(OpenCodeChannelModule.provideManagedChannel(context, config)) val transactionMetadataMapper = TransactionMetadataMapper() val swapFunding = SwapFunding(api) val service = TransactionService(api, transactionMetadataMapper, swapFunding) @@ -118,7 +119,7 @@ object RepositoryFactory { OpenCodeModule::class.java, ) - val api = TransactionApi(module.provideManagedChannel(context, config)) + val api = TransactionApi(OpenCodeChannelModule.provideManagedChannel(context, config)) val swapMetadataMapper = SwapMetadataMapper() val service = SwapService(api, swapMetadataMapper) val poller = SwapPoller(service) @@ -139,8 +140,8 @@ object RepositoryFactory { ) val api = CurrencyApi( - managedChannel = module.provideManagedChannel(context, config), - streamingChannel = module.provideManagedStreamingChannel(context, config) + managedChannel = OpenCodeChannelModule.provideManagedChannel(context, config), + streamingChannel = OpenCodeChannelModule.provideManagedStreamingChannel(context, config) ) val mintMapper = MintMapper( vmMetadataMapper = VmMetadataMapper(), diff --git a/services/opencode/src/androidMain/kotlin/com/getcode/opencode/inject/OpenCodeChannelModule.kt b/services/opencode/src/androidMain/kotlin/com/getcode/opencode/inject/OpenCodeChannelModule.kt new file mode 100644 index 0000000000..2f714dc84b --- /dev/null +++ b/services/opencode/src/androidMain/kotlin/com/getcode/opencode/inject/OpenCodeChannelModule.kt @@ -0,0 +1,93 @@ +package com.getcode.opencode.inject + +import android.content.Context +import com.getcode.opencode.ProtocolConfig +import com.getcode.opencode.internal.annotations.OpenCodeManagedChannel +import com.getcode.opencode.internal.annotations.OpenCodeManagedStreamingChannel +import com.getcode.opencode.internal.annotations.OpenCodeProtocol +import com.getcode.opencode.utils.logging.LoggingClientInterceptor +import com.getcode.utils.TraceType +import com.getcode.utils.trace +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.android.qualifiers.ApplicationContext +import dagger.hilt.components.SingletonComponent +import io.grpc.ConnectivityState +import io.grpc.ManagedChannel +import io.grpc.android.AndroidChannelBuilder +import io.grpc.okhttp.OkHttpChannelBuilder +import java.util.concurrent.TimeUnit +import javax.inject.Singleton + +@InstallIn(SingletonComponent::class) +@Module +object OpenCodeChannelModule { + @Singleton + @OpenCodeProtocol + @Provides + fun providesOpenCodeProtocolConfig( + @ApplicationContext context: Context + ): ProtocolConfig { + return object: ProtocolConfig { + override val baseUrl: String + get() = "ocp-v2.api.flipcash-infra.net" + override val userAgent: String + get() { + val version = context.packageManager.getPackageInfo(context.packageName, 0).versionName + return "OpenCodeProtocol/Android/$version" + } + } + } + + @Singleton + @Provides + @OpenCodeManagedChannel + fun provideManagedChannel( + @ApplicationContext context: Context, + @OpenCodeProtocol + config: ProtocolConfig, + ): ManagedChannel { + return AndroidChannelBuilder + .usingBuilder(OkHttpChannelBuilder.forAddress(config.baseUrl, config.port)) + .context(context) + .userAgent(config.userAgent) + .keepAliveWithoutCalls(false) + .idleTimeout(5, TimeUnit.MINUTES) // drop idle connections + .intercept(LoggingClientInterceptor()) + .build() + .also { observeChannelState("opencode", it) } + } + + @Singleton + @Provides + @OpenCodeManagedStreamingChannel + fun provideManagedStreamingChannel( + @ApplicationContext context: Context, + @OpenCodeProtocol + config: ProtocolConfig, + ): ManagedChannel { + return AndroidChannelBuilder + .usingBuilder(OkHttpChannelBuilder.forAddress(config.baseUrl, config.port)) + .context(context) + .userAgent(config.userAgent) + .keepAliveWithoutCalls(true) + .intercept(LoggingClientInterceptor()) + .build() + .also { observeChannelState("opencode-stream", it) } + } + + private fun observeChannelState(name: String, channel: ManagedChannel) { + val state = channel.getState(false) + trace( + tag = "gRPC", + message = "$name => $state", + type = TraceType.StateChange, + ) + if (state != ConnectivityState.SHUTDOWN) { + channel.notifyWhenStateChanged(state) { + observeChannelState(name, channel) + } + } + } +} diff --git a/services/opencode/src/androidMain/kotlin/com/getcode/opencode/inject/OpenCodeModule.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/inject/OpenCodeModule.kt similarity index 62% rename from services/opencode/src/androidMain/kotlin/com/getcode/opencode/inject/OpenCodeModule.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/inject/OpenCodeModule.kt index b6a6b33081..8a1b74de94 100644 --- a/services/opencode/src/androidMain/kotlin/com/getcode/opencode/inject/OpenCodeModule.kt +++ b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/inject/OpenCodeModule.kt @@ -1,7 +1,5 @@ package com.getcode.opencode.inject -import android.content.Context -import com.getcode.opencode.ProtocolConfig import com.getcode.opencode.controllers.AccountController import com.getcode.opencode.controllers.CurrencyController import com.getcode.opencode.controllers.TokenController @@ -9,9 +7,6 @@ import com.getcode.opencode.controllers.TransactionController import com.getcode.opencode.controllers.TransactionOperations import com.getcode.opencode.exchange.Exchange import com.getcode.opencode.exchange.VerifiedFiatCalculator -import com.getcode.opencode.internal.annotations.OpenCodeManagedChannel -import com.getcode.opencode.internal.annotations.OpenCodeManagedStreamingChannel -import com.getcode.opencode.internal.annotations.OpenCodeProtocol import com.getcode.opencode.internal.domain.repositories.InternalAccountRepository import com.getcode.opencode.internal.domain.repositories.InternalBalanceRepository import com.getcode.opencode.internal.domain.repositories.InternalCurrencyRepository @@ -37,22 +32,13 @@ import com.getcode.opencode.repositories.EventRepository import com.getcode.opencode.repositories.MessagingRepository import com.getcode.opencode.repositories.SwapRepository import com.getcode.opencode.repositories.TransactionRepository -import com.getcode.opencode.utils.logging.LoggingClientInterceptor import com.getcode.util.locale.LocaleHelper import com.getcode.util.resources.ResourceHelper import com.hoc081098.channeleventbus.ChannelEventBus import dagger.Module import dagger.Provides import dagger.hilt.InstallIn -import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.components.SingletonComponent -import com.getcode.utils.TraceType -import com.getcode.utils.trace -import io.grpc.ConnectivityState -import io.grpc.ManagedChannel -import io.grpc.android.AndroidChannelBuilder -import io.grpc.okhttp.OkHttpChannelBuilder -import java.util.concurrent.TimeUnit import javax.inject.Singleton import kotlin.time.Duration import kotlin.time.Duration.Companion.seconds @@ -62,6 +48,7 @@ import kotlin.time.Duration.Companion.seconds object OpenCodeModule { @Provides @Singleton + @JvmName("providesExchange") internal fun providesExchange( currencyController: CurrencyController, verifiedStateManager: VerifiedProtoManager, @@ -74,76 +61,10 @@ object OpenCodeModule { locale = locale, ) - @Singleton - @OpenCodeProtocol - @Provides - fun providesOpenCodeProtocolConfig( - @ApplicationContext context: Context - ): ProtocolConfig { - return object: ProtocolConfig { - override val baseUrl: String - get() = "ocp-v2.api.flipcash-infra.net" - override val userAgent: String - get() { - val version = context.packageManager.getPackageInfo(context.packageName, 0).versionName - return "OpenCodeProtocol/Android/$version" - } - } - } - - @Singleton - @Provides - @OpenCodeManagedChannel - fun provideManagedChannel( - @ApplicationContext context: Context, - @OpenCodeProtocol - config: ProtocolConfig, - ): ManagedChannel { - return AndroidChannelBuilder - .usingBuilder(OkHttpChannelBuilder.forAddress(config.baseUrl, config.port)) - .context(context) - .userAgent(config.userAgent) - .keepAliveWithoutCalls(false) - .idleTimeout(5, TimeUnit.MINUTES) // drop idle connections - .intercept(LoggingClientInterceptor()) - .build() - .also { observeChannelState("opencode", it) } - } - - @Singleton - @Provides - @OpenCodeManagedStreamingChannel - fun provideManagedStreamingChannel( - @ApplicationContext context: Context, - @OpenCodeProtocol - config: ProtocolConfig, - ): ManagedChannel { - return AndroidChannelBuilder - .usingBuilder(OkHttpChannelBuilder.forAddress(config.baseUrl, config.port)) - .context(context) - .userAgent(config.userAgent) - .keepAliveWithoutCalls(true) - .intercept(LoggingClientInterceptor()) - .build() - .also { observeChannelState("opencode-stream", it) } - } - - private fun observeChannelState(name: String, channel: ManagedChannel) { - val state = channel.getState(false) - trace( - tag = "gRPC", - message = "$name => $state", - type = TraceType.StateChange, - ) - if (state != ConnectivityState.SHUTDOWN) { - channel.notifyWhenStateChanged(state) { - observeChannelState(name, channel) - } - } - } @Provides @Singleton + @JvmName("providesAccountRepository") internal fun providesAccountRepository( service: AccountService, transactionService: TransactionService, @@ -151,18 +72,21 @@ object OpenCodeModule { @Provides @Singleton + @JvmName("providesMessagingRepository") internal fun providesMessagingRepository( service: MessagingService ): MessagingRepository = InternalMessagingRepository(service) @Provides @Singleton + @JvmName("providesTransactionRepository") internal fun providesTransactionRepository( service: TransactionService, ): TransactionRepository = InternalTransactionRepository(service) @Provides @Singleton + @JvmName("providesSwapRepository") internal fun providesSwapRepository( service: SwapService, swapPoller: SwapPoller, @@ -170,6 +94,7 @@ object OpenCodeModule { @Provides @Singleton + @JvmName("providesEventRepository") internal fun providesEventRepository( eventBus: ChannelEventBus, accountController: AccountController, @@ -179,18 +104,21 @@ object OpenCodeModule { @Provides @Singleton + @JvmName("providesCurrencyRepository") internal fun providesCurrencyRepository( service: CurrencyService ): CurrencyRepository = InternalCurrencyRepository(service) @Provides @Singleton + @JvmName("providesBalanceRepository") internal fun providesBalanceRepository( service: BalanceService ): BalanceRepository = InternalBalanceRepository(service) @Provides @Singleton + @JvmName("providesEventBus") internal fun providesEventBus(): ChannelEventBus = ChannelEventBus() @Provides @@ -199,5 +127,6 @@ object OpenCodeModule { @Provides @Singleton + @JvmName("bindVerifiedFiatCalculator") internal fun bindVerifiedFiatCalculator(impl: RealVerifiedFiatCalculator): VerifiedFiatCalculator = impl } \ No newline at end of file diff --git a/services/opencode/src/androidMain/kotlin/com/getcode/opencode/inject/SessionListenersModule.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/inject/SessionListenersModule.kt similarity index 100% rename from services/opencode/src/androidMain/kotlin/com/getcode/opencode/inject/SessionListenersModule.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/inject/SessionListenersModule.kt diff --git a/services/opencode/src/androidMain/kotlin/com/getcode/opencode/inject/TransactorModule.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/inject/TransactorModule.kt similarity index 100% rename from services/opencode/src/androidMain/kotlin/com/getcode/opencode/inject/TransactorModule.kt rename to services/opencode/src/commonMain/kotlin/com/getcode/opencode/inject/TransactorModule.kt diff --git a/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/annotations/OpenCodeManagedChannel.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/annotations/OpenCodeManagedChannel.kt index 00a4dfd2bb..6dabebc73d 100644 --- a/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/annotations/OpenCodeManagedChannel.kt +++ b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/annotations/OpenCodeManagedChannel.kt @@ -10,7 +10,7 @@ import javax.inject.Qualifier AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.FIELD ) -internal annotation class OpenCodeManagedChannel +annotation class OpenCodeManagedChannel @Qualifier @@ -21,4 +21,4 @@ internal annotation class OpenCodeManagedChannel AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.FIELD ) -internal annotation class OpenCodeManagedStreamingChannel \ No newline at end of file +annotation class OpenCodeManagedStreamingChannel \ No newline at end of file diff --git a/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/annotations/Protocol.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/annotations/Protocol.kt index bbb968bbc9..8437d347ed 100644 --- a/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/annotations/Protocol.kt +++ b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/annotations/Protocol.kt @@ -11,4 +11,4 @@ import javax.inject.Qualifier AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.FIELD ) -internal annotation class OpenCodeProtocol \ No newline at end of file +annotation class OpenCodeProtocol \ No newline at end of file diff --git a/ui/navigation/build.gradle.kts b/ui/navigation/build.gradle.kts index b124afb989..c658b24e56 100644 --- a/ui/navigation/build.gradle.kts +++ b/ui/navigation/build.gradle.kts @@ -52,4 +52,6 @@ kotlin { dependencies { add("kspAndroid", libs.hilt.android.compiler) add("kspAndroid", libs.hilt.compiler) + add("kspJvm", libs.dagger.compiler) + add("jvmMainImplementation", libs.dagger) } From c9ef6dc5d80c3ef17de569604eecbcb7b05debdb Mon Sep 17 00:00:00 2001 From: Brandon McAnsh Date: Fri, 23 Oct 2026 19:55:15 -0400 Subject: [PATCH 29/50] feat(desktop): sign in with a dev phrase and show the live balance DevSession reads FLIPCASH_DEV_MNEMONIC, which Gradle sets for the desktop JavaExec tasks only when local.properties has flipcash.test.mnemonic. It goes in the environment rather than a -D flag so the phrase stays out of the process command line, and it is never logged. Four gaps kept the wallet on its loading state after sign-in: - Nothing constructed EventRepository, which turns Events.OnLoggedIn into SessionListener.onUserLoggedIn. Android builds it eagerly in FlipcashApp; the graph now exposes it and devSignIn touches it first. - TokenCoordinator joins the listener set in TokenModule, which is Android-only. DesktopModule now adds it. - Through Dagger's generated factories, Metro 1.4.5 drops provider-level @Singleton, so each injection site got its own ChannelEventBus and events never reached the repository. services:opencode now applies Metro with Dagger interop and generates its own factories instead of running dagger-compiler on jvm. - The bonding curve tables were never loaded, so every balance threw "DiscreteBondingCurve not initialized" inside a retry that swallowed it. devSignIn calls Curves.initialize() first, as Android's Application does. OpenCodeExchange's state fields move above init: init hands streamRates to another thread, which could read them before they were assigned. --- apps/desktop/build.gradle.kts | 9 ++++ .../com/flipcash/desktop/DesktopGraph.kt | 6 +++ .../com/flipcash/desktop/DesktopModule.kt | 11 +++- .../kotlin/com/flipcash/desktop/DevSession.kt | 50 +++++++++++++++++++ .../main/kotlin/com/flipcash/desktop/Main.kt | 2 + .../com/flipcash/desktop/SnapshotMain.kt | 2 + services/opencode/build.gradle.kts | 12 ++++- .../internal/exchange/OpenCodeExchange.kt | 12 ++--- 8 files changed, 96 insertions(+), 8 deletions(-) create mode 100644 apps/desktop/src/main/kotlin/com/flipcash/desktop/DevSession.kt diff --git a/apps/desktop/build.gradle.kts b/apps/desktop/build.gradle.kts index f0dd564dc9..fd050df399 100644 --- a/apps/desktop/build.gradle.kts +++ b/apps/desktop/build.gradle.kts @@ -47,6 +47,11 @@ dependencies { implementation(libs.grpc.okhttp) } +// Dev-only sign-in phrase (see DevSession), forwarded only when local.properties has one. It goes in +// the environment, not a -D flag, so it stays out of the process's command line. +val devMnemonic = tryReadProperty(rootProject.rootDir, "flipcash.test.mnemonic", "") + .takeIf { it.isNotBlank() } + compose.desktop { application { mainClass = "com.flipcash.desktop.MainKt" @@ -65,3 +70,7 @@ tasks.register("snapshot") { mainClass.set("com.flipcash.desktop.SnapshotMainKt") args(providers.gradleProperty("out").getOrElse(layout.buildDirectory.file("wallet.png").get().asFile.path)) } + +tasks.withType().configureEach { + devMnemonic?.let { environment("FLIPCASH_DEV_MNEMONIC", it) } +} diff --git a/apps/desktop/src/main/kotlin/com/flipcash/desktop/DesktopGraph.kt b/apps/desktop/src/main/kotlin/com/flipcash/desktop/DesktopGraph.kt index 91c09bb3ba..686beba4e4 100644 --- a/apps/desktop/src/main/kotlin/com/flipcash/desktop/DesktopGraph.kt +++ b/apps/desktop/src/main/kotlin/com/flipcash/desktop/DesktopGraph.kt @@ -37,4 +37,10 @@ interface DesktopGraph { val resources: ResourceHelper val networkObserver: NetworkConnectivityListener val analytics: FlipcashAnalytics + val userManager: com.flipcash.services.user.UserManager + val accountController: com.flipcash.services.controllers.AccountController + + // Android constructs this eagerly in FlipcashApp.onCreate; it is what turns Events.OnLoggedIn into + // SessionListener.onUserLoggedIn calls. + val eventRepository: com.getcode.opencode.repositories.EventRepository } diff --git a/apps/desktop/src/main/kotlin/com/flipcash/desktop/DesktopModule.kt b/apps/desktop/src/main/kotlin/com/flipcash/desktop/DesktopModule.kt index ee09e944c0..f984eb8a38 100644 --- a/apps/desktop/src/main/kotlin/com/flipcash/desktop/DesktopModule.kt +++ b/apps/desktop/src/main/kotlin/com/flipcash/desktop/DesktopModule.kt @@ -16,6 +16,7 @@ import com.flipcash.app.userflags.UserFlagsFiles import com.flipcash.libs.coroutines.DispatcherProvider import com.getcode.chatcipher.ChatCipher import com.getcode.chatcipher.DefaultChatCipher +import com.getcode.opencode.providers.SessionListener import com.getcode.opencode.providers.TokenMetadataProvider import com.getcode.util.locale.LocaleHelper import com.getcode.util.resources.ComposeResourceHelper @@ -24,6 +25,7 @@ import com.getcode.utils.network.NetworkConnectivityListener import com.getcode.utils.network.NetworkObserverStub import dagger.Module import dagger.Provides +import dagger.multibindings.IntoSet import java.io.File import java.util.Currency import java.util.Locale @@ -42,7 +44,8 @@ import kotlinx.coroutines.flow.map */ @Module object DesktopModule { - private val appDir: File by lazy { + /** Per-user data directory: the database, DataStore files and no-backup files. */ + internal val appDir: File by lazy { File(System.getProperty("user.home"), ".flipcash").apply { mkdirs() } } @@ -99,6 +102,12 @@ object DesktopModule { @Provides fun tokenMetadata(coordinator: TokenCoordinator): TokenMetadataProvider = coordinator + // Android adds TokenCoordinator to the listener set in TokenModule, which is Android-only. Without this + // the coordinator never sees onUserLoggedIn and the wallet stays on its loading state. + @Provides + @IntoSet + fun tokenSessionListener(coordinator: TokenCoordinator): SessionListener = coordinator + @Provides @Singleton fun purchaseMethods(): PurchaseMethodController = object : PurchaseMethodController { diff --git a/apps/desktop/src/main/kotlin/com/flipcash/desktop/DevSession.kt b/apps/desktop/src/main/kotlin/com/flipcash/desktop/DevSession.kt new file mode 100644 index 0000000000..94b45960b3 --- /dev/null +++ b/apps/desktop/src/main/kotlin/com/flipcash/desktop/DevSession.kt @@ -0,0 +1,50 @@ +package com.flipcash.desktop + +import com.flipcash.app.persistence.FlipcashDatabase +import com.flipcash.app.persistence.init +import com.flipcash.libs.currency.math.Curves +import com.flipcash.libs.currency.math.initialize +import com.flipcash.services.controllers.AccountController +import com.flipcash.services.user.AuthState +import com.flipcash.services.user.UserManager +import com.getcode.crypt.MnemonicPhrase +import java.io.File + +/** + * Development-only sign-in until the link-from-phone flow lands: reads a recovery phrase from the + * `FLIPCASH_DEV_MNEMONIC` environment variable (set by Gradle from `flipcash.test.mnemonic` in + * local.properties, only when present) and walks the same steps `AuthManager.login` does for an + * account that has finished onboarding. The phrase is never logged. + */ +internal object DevSession { + private const val VARIABLE = "FLIPCASH_DEV_MNEMONIC" + + suspend fun signIn( + userManager: UserManager, + accountController: AccountController, + dataDir: File, + ): Result { + val words = System.getenv(VARIABLE)?.trim()?.split(Regex("\\s+")) + ?.takeIf { it.size > 1 } + ?: return Result.failure(IllegalStateException("$VARIABLE not set")) + val entropy = MnemonicPhrase.newInstance(words)?.getBase64EncodedEntropy() + ?: return Result.failure(IllegalArgumentException("$VARIABLE is not a 12 or 24 word phrase")) + + userManager.establish(entropy) + return accountController.login().map { accountId -> + FlipcashDatabase.init(dataDir, entropy) + userManager.set(accountId = accountId) + userManager.set(AuthState.Ready) + } + } +} + +/** Signs in with the dev phrase when one is configured; otherwise the wallet stays signed out. */ +internal suspend fun DesktopGraph.devSignIn() { + // Android loads the curve tables in its Application; balances throw without them. + Curves.initialize() + eventRepository // must exist before login so OnLoggedIn reaches the session listeners + DevSession.signIn(userManager, accountController, DesktopModule.appDir) + .onSuccess { println("dev session: signed in") } + .onFailure { println("dev session: not signed in (${it.message})") } +} diff --git a/apps/desktop/src/main/kotlin/com/flipcash/desktop/Main.kt b/apps/desktop/src/main/kotlin/com/flipcash/desktop/Main.kt index a56821ba1e..f8c5e95ba2 100644 --- a/apps/desktop/src/main/kotlin/com/flipcash/desktop/Main.kt +++ b/apps/desktop/src/main/kotlin/com/flipcash/desktop/Main.kt @@ -6,10 +6,12 @@ import androidx.compose.ui.window.Window import androidx.compose.ui.window.application import androidx.compose.ui.window.rememberWindowState import dev.zacsweers.metro.createGraph +import kotlinx.coroutines.runBlocking import java.lang.management.ManagementFactory fun main() { val graph = createGraph() + runBlocking { graph.devSignIn() } application { Window( onCloseRequest = ::exitApplication, diff --git a/apps/desktop/src/main/kotlin/com/flipcash/desktop/SnapshotMain.kt b/apps/desktop/src/main/kotlin/com/flipcash/desktop/SnapshotMain.kt index c3fd176163..f93bd85cb0 100644 --- a/apps/desktop/src/main/kotlin/com/flipcash/desktop/SnapshotMain.kt +++ b/apps/desktop/src/main/kotlin/com/flipcash/desktop/SnapshotMain.kt @@ -4,6 +4,7 @@ import androidx.compose.ui.ImageComposeScene import androidx.compose.ui.unit.Density import androidx.compose.ui.use import dev.zacsweers.metro.createGraph +import kotlinx.coroutines.runBlocking import java.io.File import kotlin.system.exitProcess import org.jetbrains.skia.EncodedImageFormat @@ -15,6 +16,7 @@ import org.jetbrains.skia.EncodedImageFormat fun main(args: Array) { val out = File(args.firstOrNull() ?: "wallet.png") val graph = createGraph() + runBlocking { graph.devSignIn() } ImageComposeScene(width = 840, height = 1720, density = Density(2f)) { DesktopWalletContent(graph) }.use { scene -> diff --git a/services/opencode/build.gradle.kts b/services/opencode/build.gradle.kts index 30b8bbfb25..abdd630019 100644 --- a/services/opencode/build.gradle.kts +++ b/services/opencode/build.gradle.kts @@ -2,6 +2,17 @@ plugins { alias(libs.plugins.flipcash.kmp.app.library) alias(libs.plugins.kotlin.ksp) id("org.jetbrains.kotlin.plugin.parcelize") + alias(libs.plugins.metro) +} + +// Metro generates this module's provider factories for the desktop graph. Through Dagger's factories +// instead, Metro 1.4.5 drops provider-level @Singleton (it does not read @ScopeMetadata), so each +// injection site got its own ChannelEventBus. +metro { + interop { + includeJavax() + includeDagger() + } } kotlin { @@ -80,7 +91,6 @@ kotlin { dependencies { add("kspAndroid", libs.hilt.android.compiler) add("kspAndroid", libs.hilt.compiler) - add("kspJvm", libs.dagger.compiler) add("jvmMainImplementation", libs.dagger) } diff --git a/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/exchange/OpenCodeExchange.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/exchange/OpenCodeExchange.kt index 2a41088692..8ab1a82e63 100644 --- a/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/exchange/OpenCodeExchange.kt +++ b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/exchange/OpenCodeExchange.kt @@ -37,6 +37,12 @@ internal class OpenCodeExchange @Inject constructor( private val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO) + // Declared ahead of init: it hands streamRates to another thread and launches a write to + // preferredCurrency, and either can run before initializers further down have. + private val _preferredRate = MutableStateFlow(Rate.oneToOne) + private val mints = MutableStateFlow>(emptyList()) + private var preferredCurrency: CurrencyCode? = null + init { // Deferred, not registered in place: this singleton is built off the main thread so its // construction stays off the startup path, and its fields below are not yet initialized. @@ -51,15 +57,11 @@ internal class OpenCodeExchange @Inject constructor( } } - - private val _preferredRate = MutableStateFlow(Rate.oneToOne) override val preferredRate: Rate get() = _preferredRate.value override fun observePreferredRate(): Flow = _preferredRate - private val mints = MutableStateFlow>(emptyList()) - override suspend fun setPreferredCurrency(currencyCode: CurrencyCode) { preferredCurrency = currencyCode verifiedStateManager.rateFor(currencyCode)?.let { @@ -73,8 +75,6 @@ internal class OpenCodeExchange @Inject constructor( this.mints.value = mints } - private var preferredCurrency: CurrencyCode? = null - override fun rates() = verifiedStateManager.rates() override fun observeRates(): Flow> = verifiedStateManager.observeRates() From d5856835d3ee5257939a516e36e8d53f94f08dd0 Mon Sep 17 00:00:00 2001 From: Brandon McAnsh Date: Sat, 24 Oct 2026 15:17:29 -0400 Subject: [PATCH 30/50] fix(desktop): add Coil's OkHttp network fetcher so token logos load Token logos are https URLs. Coil 3 ships no network fetcher, and the desktop app had no coil-network artifact on its classpath, so every logo failed with "Unable to create a fetcher" and the card stack showed blank avatars. coil-network-okhttp registers its fetcher through ServiceLoader, so adding the dependency is the fix. installImageLoader mirrors FlipcashApp.newImageLoader (crossfade, memory cache, 50 MB disk cache), minus the chat photo keyer and fetcher. --- apps/desktop/build.gradle.kts | 2 ++ .../flipcash/desktop/DesktopImageLoader.kt | 32 +++++++++++++++++++ .../main/kotlin/com/flipcash/desktop/Main.kt | 1 + .../com/flipcash/desktop/SnapshotMain.kt | 1 + 4 files changed, 36 insertions(+) create mode 100644 apps/desktop/src/main/kotlin/com/flipcash/desktop/DesktopImageLoader.kt diff --git a/apps/desktop/build.gradle.kts b/apps/desktop/build.gradle.kts index fd050df399..848bb43d71 100644 --- a/apps/desktop/build.gradle.kts +++ b/apps/desktop/build.gradle.kts @@ -45,6 +45,8 @@ dependencies { implementation(libs.kotlinx.coroutines.swing) implementation(libs.dagger) implementation(libs.grpc.okhttp) + implementation(libs.coil3) + implementation(libs.coil3.network) } // Dev-only sign-in phrase (see DevSession), forwarded only when local.properties has one. It goes in diff --git a/apps/desktop/src/main/kotlin/com/flipcash/desktop/DesktopImageLoader.kt b/apps/desktop/src/main/kotlin/com/flipcash/desktop/DesktopImageLoader.kt new file mode 100644 index 0000000000..0c146a860d --- /dev/null +++ b/apps/desktop/src/main/kotlin/com/flipcash/desktop/DesktopImageLoader.kt @@ -0,0 +1,32 @@ +package com.flipcash.desktop + +import coil3.ImageLoader +import coil3.PlatformContext +import coil3.SingletonImageLoader +import coil3.disk.DiskCache +import coil3.network.okhttp.OkHttpNetworkFetcherFactory +import coil3.request.CachePolicy +import coil3.request.crossfade +import okio.Path.Companion.toOkioPath + +/** + * Desktop counterpart of `FlipcashApp.newImageLoader`. Coil 3 has no network fetcher unless one is + * added, so without this every token logo (an https URL) fails with "Unable to create a fetcher". + * The chat photo keyer/fetcher are left out: chat is not on desktop. + */ +internal fun installImageLoader() { + SingletonImageLoader.setSafe { context -> newImageLoader(context) } +} + +private fun newImageLoader(context: PlatformContext): ImageLoader = + ImageLoader.Builder(context) + .crossfade(true) + .memoryCachePolicy(CachePolicy.ENABLED) + .diskCache { + DiskCache.Builder() + .directory(DesktopModule.appDir.resolve("image_cache").toOkioPath()) + .maxSizeBytes(50L * 1024 * 1024) + .build() + } + .components { add(OkHttpNetworkFetcherFactory()) } + .build() diff --git a/apps/desktop/src/main/kotlin/com/flipcash/desktop/Main.kt b/apps/desktop/src/main/kotlin/com/flipcash/desktop/Main.kt index f8c5e95ba2..9fa12ad208 100644 --- a/apps/desktop/src/main/kotlin/com/flipcash/desktop/Main.kt +++ b/apps/desktop/src/main/kotlin/com/flipcash/desktop/Main.kt @@ -10,6 +10,7 @@ import kotlinx.coroutines.runBlocking import java.lang.management.ManagementFactory fun main() { + installImageLoader() val graph = createGraph() runBlocking { graph.devSignIn() } application { diff --git a/apps/desktop/src/main/kotlin/com/flipcash/desktop/SnapshotMain.kt b/apps/desktop/src/main/kotlin/com/flipcash/desktop/SnapshotMain.kt index f93bd85cb0..ad6a2caccc 100644 --- a/apps/desktop/src/main/kotlin/com/flipcash/desktop/SnapshotMain.kt +++ b/apps/desktop/src/main/kotlin/com/flipcash/desktop/SnapshotMain.kt @@ -15,6 +15,7 @@ import org.jetbrains.skia.EncodedImageFormat */ fun main(args: Array) { val out = File(args.firstOrNull() ?: "wallet.png") + installImageLoader() val graph = createGraph() runBlocking { graph.devSignIn() } ImageComposeScene(width = 840, height = 1720, density = Density(2f)) { From 7a7b785e1bf8b293ae4a9969fca4f7c77b3b0550 Mon Sep 17 00:00:00 2001 From: Brandon McAnsh Date: Sat, 24 Oct 2026 15:30:25 -0400 Subject: [PATCH 31/50] test(desktop): check desktop wiring against Android's in a shared contract Each wiring gap in A2 (the token coordinator's listener binding, the eager event repository, the curve tables, the network image loader) left the desktop wallet on a spinner or blank logos with no error. :apps:flipcash:startup-contract lists the SessionListeners desktop must bind, the ones only Android binds, and every Android startup entry point, each marked as mirrored on desktop (with a Step) or not, with a reason. - AndroidWiringTest builds the real Hilt graph under Robolectric and fails when a SessionListener or startup entry point (manifest initializer, FlipcashApp injection, SingletonImageLoader.Factory) is missing from the contract. ApiModule is replaced because MixpanelAPI.getInstance returns null under Robolectric. - DesktopWiringTest builds the real Metro graph, runs DesktopGraph.startup(), and checks the effect of each mirrored step, the listener set, and that scoped bindings resolve to one instance. The desktop startup steps move out of devSignIn into startup() so the test can run them without a sign-in phrase. Tests set opencode.processLifecycle.autoStart=false so building the exchange does not open its rate stream to the backend. --- apps/desktop/build.gradle.kts | 10 ++ .../com/flipcash/desktop/DesktopGraph.kt | 5 + .../com/flipcash/desktop/DesktopStartup.kt | 18 +++ .../kotlin/com/flipcash/desktop/DevSession.kt | 7 +- .../main/kotlin/com/flipcash/desktop/Main.kt | 6 +- .../com/flipcash/desktop/SnapshotMain.kt | 6 +- .../com/flipcash/desktop/DesktopWiringTest.kt | 115 ++++++++++++++++++ apps/flipcash/app/build.gradle.kts | 1 + .../com/flipcash/app/AndroidWiringTest.kt | 105 ++++++++++++++++ .../startup-contract/build.gradle.kts | 10 ++ .../app/startup/contract/StartupContract.kt | 87 +++++++++++++ .../internal/platform/ProcessLifecycle.jvm.kt | 7 ++ settings.gradle.kts | 1 + 13 files changed, 368 insertions(+), 10 deletions(-) create mode 100644 apps/desktop/src/main/kotlin/com/flipcash/desktop/DesktopStartup.kt create mode 100644 apps/desktop/src/test/kotlin/com/flipcash/desktop/DesktopWiringTest.kt create mode 100644 apps/flipcash/app/src/test/kotlin/com/flipcash/app/AndroidWiringTest.kt create mode 100644 apps/flipcash/startup-contract/build.gradle.kts create mode 100644 apps/flipcash/startup-contract/src/commonMain/kotlin/com/flipcash/app/startup/contract/StartupContract.kt diff --git a/apps/desktop/build.gradle.kts b/apps/desktop/build.gradle.kts index 848bb43d71..9fd564a8f6 100644 --- a/apps/desktop/build.gradle.kts +++ b/apps/desktop/build.gradle.kts @@ -47,6 +47,16 @@ dependencies { implementation(libs.grpc.okhttp) implementation(libs.coil3) implementation(libs.coil3.network) + implementation(libs.event.bus) + + testImplementation(project(":apps:flipcash:startup-contract")) + testImplementation(libs.kotlin.test.junit) + testImplementation(libs.kotlinx.coroutines.test) +} + +tasks.withType().configureEach { + // No backend in tests: keep the exchange's rate stream from starting when the graph builds it. + systemProperty("opencode.processLifecycle.autoStart", "false") } // Dev-only sign-in phrase (see DevSession), forwarded only when local.properties has one. It goes in diff --git a/apps/desktop/src/main/kotlin/com/flipcash/desktop/DesktopGraph.kt b/apps/desktop/src/main/kotlin/com/flipcash/desktop/DesktopGraph.kt index 686beba4e4..42fa4573bd 100644 --- a/apps/desktop/src/main/kotlin/com/flipcash/desktop/DesktopGraph.kt +++ b/apps/desktop/src/main/kotlin/com/flipcash/desktop/DesktopGraph.kt @@ -43,4 +43,9 @@ interface DesktopGraph { // Android constructs this eagerly in FlipcashApp.onCreate; it is what turns Events.OnLoggedIn into // SessionListener.onUserLoggedIn calls. val eventRepository: com.getcode.opencode.repositories.EventRepository + + // For DesktopWiringTest: the listener set, and singletons to check are shared across injection sites. + val sessionListeners: Set + val tokenCoordinator: com.flipcash.app.tokens.TokenCoordinator + val eventBus: com.hoc081098.channeleventbus.ChannelEventBus } diff --git a/apps/desktop/src/main/kotlin/com/flipcash/desktop/DesktopStartup.kt b/apps/desktop/src/main/kotlin/com/flipcash/desktop/DesktopStartup.kt new file mode 100644 index 0000000000..e4edde761b --- /dev/null +++ b/apps/desktop/src/main/kotlin/com/flipcash/desktop/DesktopStartup.kt @@ -0,0 +1,18 @@ +package com.flipcash.desktop + +import com.flipcash.libs.currency.math.Curves +import com.flipcash.libs.currency.math.initialize + +/** + * The startup work Android does in its androidx-startup initializers and `FlipcashApp.onCreate` + * that the balance path relies on. `StartupContract` lists each step; `DesktopWiringTest` checks + * that each took effect. + */ +internal suspend fun DesktopGraph.startup() { + // NetworkImageLoader: token logos are https URLs, and Coil 3 has no network fetcher by default. + installImageLoader() + // CurveTables: balance valuations throw without them. + Curves.initialize() + // EventRepository: must exist before login, or OnLoggedIn reaches no session listener. + eventRepository +} diff --git a/apps/desktop/src/main/kotlin/com/flipcash/desktop/DevSession.kt b/apps/desktop/src/main/kotlin/com/flipcash/desktop/DevSession.kt index 94b45960b3..5663043352 100644 --- a/apps/desktop/src/main/kotlin/com/flipcash/desktop/DevSession.kt +++ b/apps/desktop/src/main/kotlin/com/flipcash/desktop/DevSession.kt @@ -2,8 +2,6 @@ package com.flipcash.desktop import com.flipcash.app.persistence.FlipcashDatabase import com.flipcash.app.persistence.init -import com.flipcash.libs.currency.math.Curves -import com.flipcash.libs.currency.math.initialize import com.flipcash.services.controllers.AccountController import com.flipcash.services.user.AuthState import com.flipcash.services.user.UserManager @@ -39,11 +37,8 @@ internal object DevSession { } } -/** Signs in with the dev phrase when one is configured; otherwise the wallet stays signed out. */ +/** Signs in with the dev phrase when one is configured; otherwise the wallet stays signed out. Run [startup] first. */ internal suspend fun DesktopGraph.devSignIn() { - // Android loads the curve tables in its Application; balances throw without them. - Curves.initialize() - eventRepository // must exist before login so OnLoggedIn reaches the session listeners DevSession.signIn(userManager, accountController, DesktopModule.appDir) .onSuccess { println("dev session: signed in") } .onFailure { println("dev session: not signed in (${it.message})") } diff --git a/apps/desktop/src/main/kotlin/com/flipcash/desktop/Main.kt b/apps/desktop/src/main/kotlin/com/flipcash/desktop/Main.kt index 9fa12ad208..df61615149 100644 --- a/apps/desktop/src/main/kotlin/com/flipcash/desktop/Main.kt +++ b/apps/desktop/src/main/kotlin/com/flipcash/desktop/Main.kt @@ -10,9 +10,11 @@ import kotlinx.coroutines.runBlocking import java.lang.management.ManagementFactory fun main() { - installImageLoader() val graph = createGraph() - runBlocking { graph.devSignIn() } + runBlocking { + graph.startup() + graph.devSignIn() + } application { Window( onCloseRequest = ::exitApplication, diff --git a/apps/desktop/src/main/kotlin/com/flipcash/desktop/SnapshotMain.kt b/apps/desktop/src/main/kotlin/com/flipcash/desktop/SnapshotMain.kt index ad6a2caccc..fa8d2dac4b 100644 --- a/apps/desktop/src/main/kotlin/com/flipcash/desktop/SnapshotMain.kt +++ b/apps/desktop/src/main/kotlin/com/flipcash/desktop/SnapshotMain.kt @@ -15,9 +15,11 @@ import org.jetbrains.skia.EncodedImageFormat */ fun main(args: Array) { val out = File(args.firstOrNull() ?: "wallet.png") - installImageLoader() val graph = createGraph() - runBlocking { graph.devSignIn() } + runBlocking { + graph.startup() + graph.devSignIn() + } ImageComposeScene(width = 840, height = 1720, density = Density(2f)) { DesktopWalletContent(graph) }.use { scene -> diff --git a/apps/desktop/src/test/kotlin/com/flipcash/desktop/DesktopWiringTest.kt b/apps/desktop/src/test/kotlin/com/flipcash/desktop/DesktopWiringTest.kt new file mode 100644 index 0000000000..43d8ca7e3a --- /dev/null +++ b/apps/desktop/src/test/kotlin/com/flipcash/desktop/DesktopWiringTest.kt @@ -0,0 +1,115 @@ +package com.flipcash.desktop + +import coil3.PlatformContext +import coil3.SingletonImageLoader +import com.flipcash.app.startup.contract.StartupContract +import com.flipcash.app.startup.contract.StartupContract.Desktop +import com.flipcash.app.startup.contract.StartupContract.Step +import com.flipcash.libs.currency.math.Estimator +import com.getcode.opencode.events.Events +import com.hoc081098.channeleventbus.ChannelEventBusException +import com.hoc081098.channeleventbus.ValidationBeforeClosing +import dev.zacsweers.metro.createGraph +import kotlinx.coroutines.delay +import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.withTimeoutOrNull +import java.math.BigDecimal +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertSame +import kotlin.test.assertTrue +import kotlin.test.fail + +/** + * Builds the real Metro graph and checks it against [StartupContract]: the session listeners + * desktop must bind, the startup steps it must repeat, and that singletons stay single. Each check + * here stands for a gap that once left the desktop wallet on its loading spinner with no error. + */ +class DesktopWiringTest { + private val graph = createGraph() + + @Test + fun `binds every shared session listener and nothing unclassified`() { + val bound = graph.sessionListeners.map { it::class.qualifiedName }.toSet() + val missing = StartupContract.sharedSessionListeners - bound + assertTrue(missing.isEmpty(), "desktop graph does not bind these SessionListeners: $missing") + val unclassified = bound - StartupContract.sharedSessionListeners - + StartupContract.androidOnlySessionListeners.keys + assertTrue(unclassified.isEmpty(), "SessionListeners missing from StartupContract: $unclassified") + } + + @Test + fun `startup takes effect for every mirrored step`() = runBlocking { + graph.startup() + val steps = StartupContract.androidStartup.values.filterIsInstance().map { it.step } + assertEquals(Step.entries.toSet(), steps.toSet(), "a Step no Android entry point maps to") + for (step in Step.entries) { + // Exhaustive, so a new Step does not compile until it has a check here. + when (step) { + Step.EventRepository -> assertEventRepositoryListening() + Step.CurveTables -> assertTrue( + Estimator.reserveAtSupply(BigDecimal.ONE).isSuccess, + "curve tables not loaded: ${Estimator.reserveAtSupply(BigDecimal.ONE).exceptionOrNull()}", + ) + Step.NetworkImageLoader -> { + val loader = SingletonImageLoader.get(PlatformContext.INSTANCE) + // coil-network-okhttp registers its fetcher through ServiceLoader, so this + // fails when the artifact is off the classpath, which is what blanked the logos. + val factories = loader.components.fetcherFactories.map { it.first::class.qualifiedName } + assertTrue( + factories.any { it?.startsWith("coil3.network.") == true }, + "image loader has no network fetcher: $factories", + ) + // The disk cache comes only from installImageLoader, so this fails when Coil + // built its default loader instead. + assertTrue( + loader.diskCache?.directory?.name == "image_cache", + "Coil is using its default loader, not installImageLoader's", + ) + } + } + } + } + + @Test + fun `scoped bindings resolve to one instance`() { + // Metro once dropped provider-level @Singleton read through Dagger factories, which gave + // every consumer its own event bus; login events then reached nobody. Only bindings scoped + // on Android belong here: AccountController, for one, is unscoped there too. + assertSame(graph.eventBus, graph.eventBus, "ChannelEventBus") + assertSame(graph.userManager, graph.userManager, "UserManager") + assertSame(graph.exchange, graph.exchange, "Exchange") + assertSame(graph.eventRepository, graph.eventRepository, "EventRepository") + assertSame(graph.tokenCoordinator, graph.tokenCoordinator, "TokenCoordinator") + val inSet = graph.sessionListeners.single { it::class == graph.tokenCoordinator::class } + assertSame(graph.tokenCoordinator, inSet, "TokenCoordinator in the listener set is a second instance") + } + + /** + * The repository subscribes to `Events.OnLoggedIn` on the shared bus. Closing that key with + * REQUIRE_FLOW_IS_NOT_COLLECTING fails only while someone collects it; the subscription is + * launched on IO, so give it a moment. + */ + private suspend fun assertEventRepositoryListening() { + val collecting = withTimeoutOrNull(5_000) { + while (true) { + try { + graph.eventBus.closeKey( + Events.OnLoggedIn, + setOf( + ValidationBeforeClosing.REQUIRE_BUS_IS_EXISTING, + ValidationBeforeClosing.REQUIRE_FLOW_IS_NOT_COLLECTING, + ), + ) + fail("Events.OnLoggedIn has a bus but no collector") + } catch (_: ChannelEventBusException.CloseException.BusIsCollecting) { + return@withTimeoutOrNull true + } catch (_: ChannelEventBusException.CloseException.BusDoesNotExist) { + delay(50) + } + } + @Suppress("UNREACHABLE_CODE") false + } + assertEquals(true, collecting, "nothing collects Events.OnLoggedIn: the event repository was never created") + } +} diff --git a/apps/flipcash/app/build.gradle.kts b/apps/flipcash/app/build.gradle.kts index 8c621ee69d..ad8a022efd 100644 --- a/apps/flipcash/app/build.gradle.kts +++ b/apps/flipcash/app/build.gradle.kts @@ -374,4 +374,5 @@ dependencies { testImplementation(libs.kotlinx.coroutines.test) testImplementation(libs.mockk) testImplementation(libs.robolectric) + testImplementation(project(":apps:flipcash:startup-contract")) } diff --git a/apps/flipcash/app/src/test/kotlin/com/flipcash/app/AndroidWiringTest.kt b/apps/flipcash/app/src/test/kotlin/com/flipcash/app/AndroidWiringTest.kt new file mode 100644 index 0000000000..5d6f363e51 --- /dev/null +++ b/apps/flipcash/app/src/test/kotlin/com/flipcash/app/AndroidWiringTest.kt @@ -0,0 +1,105 @@ +package com.flipcash.app + +import coil3.SingletonImageLoader +import com.flipcash.app.inject.ApiModule +import com.flipcash.app.startup.contract.StartupContract +import com.getcode.opencode.providers.SessionListener +import com.mixpanel.android.mpmetrics.MixpanelAPI +import dagger.hilt.android.testing.BindValue +import dagger.hilt.android.testing.HiltAndroidRule +import dagger.hilt.android.testing.HiltAndroidTest +import dagger.hilt.android.testing.HiltTestApplication +import dagger.hilt.android.testing.UninstallModules +import io.mockk.mockk +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner +import org.robolectric.annotation.Config +import org.w3c.dom.Element +import java.io.File +import java.lang.reflect.ParameterizedType +import javax.inject.Inject +import javax.xml.parsers.DocumentBuilderFactory +import kotlin.test.assertEquals + +/** + * Checks the Android app's wiring against [StartupContract], so a session listener or startup entry + * point added here has to be classified there before the build passes, and the desktop graph's own + * test then holds desktop to it. + * + * `HiltTestApplication` replaces [FlipcashApp], so this does not run Android's startup; it checks + * the listener set the real Hilt graph builds and that every startup entry point is accounted for. + * + * [ApiModule] is replaced because `MixpanelAPI.getInstance` returns null under Robolectric; it has no + * part in session listeners or startup. + */ +@HiltAndroidTest +@UninstallModules(ApiModule::class) +@RunWith(RobolectricTestRunner::class) +@Config(manifest = Config.NONE, application = HiltTestApplication::class, sdk = [35]) +class AndroidWiringTest { + @get:Rule + val hilt = HiltAndroidRule(this) + + @BindValue + val mixpanel: MixpanelAPI = mockk(relaxed = true) + + @Inject + lateinit var sessionListeners: Set<@JvmSuppressWildcards SessionListener> + + @Before + fun setUp() = hilt.inject() + + @Test + fun `session listeners are exactly the classified set`() { + val bound = sessionListeners.map { it::class.java.name }.toSet() + val classified = StartupContract.sharedSessionListeners + StartupContract.androidOnlySessionListeners.keys + assertEquals(classified, bound, "classify each SessionListener in StartupContract") + } + + @Test + fun `every startup entry point is classified`() { + assertEquals( + StartupContract.androidStartup.keys.sorted(), + (manifestInitializers() + appInjections() + appImageLoader()).sorted(), + "classify each startup entry point in StartupContract.androidStartup", + ) + } + + /** androidx-startup initializers this module's manifest adds (not the ones it removes). */ + private fun manifestInitializers(): List { + val doc = DocumentBuilderFactory.newInstance().apply { isNamespaceAware = true } + .newDocumentBuilder().parse(File("src/main/AndroidManifest.xml")) + val metaData = doc.getElementsByTagName("meta-data") + return (0 until metaData.length).map { metaData.item(it) as Element } + .filter { it.getAttributeNS(ANDROID, "value") == "androidx.startup" } + .filter { it.getAttributeNS(TOOLS, "node") != "remove" } + .map { it.getAttributeNS(ANDROID, "name") } + } + + /** What [FlipcashApp] injects, unwrapping `Lazy` to `T`. */ + private fun appInjections(): List = + FlipcashApp::class.java.declaredFields + .filter { it.isAnnotationPresent(Inject::class.java) } + .map { field -> + val type = field.genericType + if (type is ParameterizedType && type.rawType == dagger.Lazy::class.java) { + (type.actualTypeArguments.single() as Class<*>).name + } else { + field.type.name + } + } + + private fun appImageLoader(): List = + listOfNotNull( + SingletonImageLoader.Factory::class.java.name + .takeIf { SingletonImageLoader.Factory::class.java.isAssignableFrom(FlipcashApp::class.java) }, + ) + + private companion object { + const val ANDROID = "http://schemas.android.com/apk/res/android" + const val TOOLS = "http://schemas.android.com/tools" + } +} diff --git a/apps/flipcash/startup-contract/build.gradle.kts b/apps/flipcash/startup-contract/build.gradle.kts new file mode 100644 index 0000000000..95fcdf30b4 --- /dev/null +++ b/apps/flipcash/startup-contract/build.gradle.kts @@ -0,0 +1,10 @@ +plugins { + alias(libs.plugins.flipcash.kmp.app.library) +} + +// Test-only: the startup wiring both the Android and desktop graphs are checked against. +kotlin { + android { + namespace = "${Gradle.flipcashNamespace}.startup.contract" + } +} diff --git a/apps/flipcash/startup-contract/src/commonMain/kotlin/com/flipcash/app/startup/contract/StartupContract.kt b/apps/flipcash/startup-contract/src/commonMain/kotlin/com/flipcash/app/startup/contract/StartupContract.kt new file mode 100644 index 0000000000..978d9a48c5 --- /dev/null +++ b/apps/flipcash/startup-contract/src/commonMain/kotlin/com/flipcash/app/startup/contract/StartupContract.kt @@ -0,0 +1,87 @@ +package com.flipcash.app.startup.contract + +/** + * The wiring the wallet's balance path needs before its first screen, written down once so the + * Android and desktop wiring tests check the same list. + * + * Desktop rebuilds by hand what Android gets from Hilt modules, androidx-startup initializers and + * `FlipcashApp.onCreate`. Each piece it missed in the spike (the token coordinator's listener + * binding, the eager event repository, the curve tables, the network image loader) left the wallet + * on a spinner or blank logos with no error. Here, Android's side has to classify every startup + * entry point it has, and desktop has to prove each mirrored step took effect. + */ +object StartupContract { + + /** A piece of startup work desktop has to repeat. The desktop test checks each one's effect. */ + enum class Step { + /** The event repository exists, so `Events.OnLoggedIn` reaches the session listeners. */ + EventRepository, + + /** The discrete curve tables are loaded; every balance valuation throws without them. */ + CurveTables, + + /** The image loader can fetch https URLs, which is where token logos live. */ + NetworkImageLoader, + } + + sealed interface Desktop { + data class Mirrored(val step: Step) : Desktop + data class NotOnDesktop(val reason: String) : Desktop + } + + /** `SessionListener` implementations desktop must bind as well. Fully qualified class names. */ + val sharedSessionListeners: Set = setOf( + "com.flipcash.app.tokens.TokenCoordinator", + ) + + /** `SessionListener` implementations only Android binds, with why desktop goes without. */ + val androidOnlySessionListeners: Map = mapOf( + "com.flipcash.shared.chat.internal.RealChatCoordinator" to "chat is not on desktop", + "com.flipcash.app.contacts.ContactCoordinator" to "contacts are not on desktop", + ) + + /** + * Every startup entry point the Android app declares: the androidx-startup initializers in its + * manifest, the types `FlipcashApp` injects, and `SingletonImageLoader.Factory`, which it + * implements. Keyed by fully qualified name. + */ + val androidStartup: Map = mapOf( + // androidx-startup initializers + "com.flipcash.app.internal.startup.TraceInitializer" to + Desktop.NotOnDesktop("trace export and Bugsnag breadcrumbs are Android tooling"), + "com.flipcash.app.internal.startup.ClockDriftInitializer" to + Desktop.NotOnDesktop("diagnostic only: records SNTP drift for the trace header"), + "com.flipcash.app.internal.startup.FirebaseInitializer" to + Desktop.NotOnDesktop("Firebase is Android-only"), + "com.flipcash.app.internal.startup.LibSodiumInitializer" to + Desktop.NotOnDesktop("the balance path makes no libsodium call; chat crypto does, and chat is not on desktop"), + "com.flipcash.app.internal.startup.MnemonicCacheInitializer" to + Desktop.NotOnDesktop("preloads the BIP39 word list; it loads on first use otherwise"), + "com.flipcash.app.internal.startup.DiscreteBondingCurveInitializer" to + Desktop.Mirrored(Step.CurveTables), + "com.flipcash.app.internal.startup.CameraXInitializer" to + Desktop.NotOnDesktop("no camera on desktop"), + + // FlipcashApp's injected dependencies + "com.flipcash.app.auth.AuthManager" to + Desktop.NotOnDesktop("restores the stored session; desktop signs in through DevSession until Keychain storage lands"), + "com.getcode.opencode.repositories.EventRepository" to + Desktop.Mirrored(Step.EventRepository), + "com.flipcash.app.currency.PreferredCurrencyController" to + Desktop.NotOnDesktop("the exchange falls back to the locale's currency"), + "com.flipcash.shared.chat.media.ChatPhotoFetcher\$Factory" to + Desktop.NotOnDesktop("chat is not on desktop"), + "com.flipcash.app.messenger.LinkPreviewStartup" to + Desktop.NotOnDesktop("link previews belong to chat"), + "androidx.hilt.work.HiltWorkerFactory" to + Desktop.NotOnDesktop("WorkManager is Android-only"), + "com.flipcash.app.core.android.ActivityProvider" to + Desktop.NotOnDesktop("tracks the foreground Activity"), + "com.flipcash.app.bills.share.TipCodePreviewCache" to + Desktop.NotOnDesktop("tip-code share previews are not on desktop"), + + // FlipcashApp implements this to build Coil's singleton loader + "coil3.SingletonImageLoader\$Factory" to + Desktop.Mirrored(Step.NetworkImageLoader), + ) +} diff --git a/services/opencode/src/jvmMain/kotlin/com/getcode/opencode/internal/platform/ProcessLifecycle.jvm.kt b/services/opencode/src/jvmMain/kotlin/com/getcode/opencode/internal/platform/ProcessLifecycle.jvm.kt index d00eadf201..381064e457 100644 --- a/services/opencode/src/jvmMain/kotlin/com/getcode/opencode/internal/platform/ProcessLifecycle.jvm.kt +++ b/services/opencode/src/jvmMain/kotlin/com/getcode/opencode/internal/platform/ProcessLifecycle.jvm.kt @@ -4,11 +4,18 @@ import java.util.concurrent.Executors private val dispatcher = Executors.newSingleThreadExecutor { Thread(it, "process-lifecycle").apply { isDaemon = true } } +/** + * Set to `false` to keep [onStart] from running, so tests can build the graph without the + * exchange opening its rate stream to the backend. + */ +private const val AUTO_START_PROPERTY = "opencode.processLifecycle.autoStart" + /** A desktop process is in the foreground for as long as it runs, so only [onStart] is ever called. */ internal actual fun observeProcessLifecycle( immediateOnMain: Boolean, onStart: () -> Unit, onStop: () -> Unit, ) { + if (System.getProperty(AUTO_START_PROPERTY) == "false") return dispatcher.execute(onStart) } diff --git a/settings.gradle.kts b/settings.gradle.kts index 593daac175..98137caca5 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -119,6 +119,7 @@ include( ":apps:flipcash:core", ":apps:flipcash:core-ui", ":apps:flipcash:card-expand", + ":apps:flipcash:startup-contract", ":libs:test-utils", // shared flipcash coordinators/controllers/viewmodels/services ":apps:flipcash:shared:amount-entry", From 2fa0c0417b410e19a038a26698f5398a6a038801 Mon Sep 17 00:00:00 2001 From: Brandon McAnsh Date: Sat, 24 Oct 2026 15:58:46 -0400 Subject: [PATCH 32/50] refactor(kmp): move platform-neutral sources from androidMain to commonMain Moves 90 files whose code compiles for jvm unchanged: ui:components 37, app:core 27, core-ui 9, shared:tokens 7, ui:core 5, ui:navigation 3, common-ui 1, theme 1. Six modules get the Compose (and, for app:core, libsodium) artifacts on commonMain so the moved files resolve. Each file was moved, compiled for jvm, and moved back if it failed, so no code changed. What stays in androidMain references R, Hilt, java.*, Android APIs, or a neighbour that does. --- apps/flipcash/core-ui/build.gradle.kts | 2 ++ .../kotlin/com/flipcash/app/core/ui/BrandedGradientIcon.kt | 0 .../kotlin/com/flipcash/app/core/ui/ConfirmationStyle.kt | 0 .../kotlin/com/flipcash/app/core/ui/CurrencyHolder.kt | 0 .../kotlin/com/flipcash/app/core/ui/ReceiptLineItem.kt | 0 .../kotlin/com/flipcash/app/core/ui/Skeleton.kt | 0 .../kotlin/com/flipcash/app/core/ui/flow/FlowProgress.kt | 0 .../com/flipcash/app/core/ui/flow/FlowStepBarController.kt | 0 .../kotlin/com/flipcash/app/core/ui/flow/FlowStepper.kt | 0 .../app/core/ui/transitions/CardExpandTransition.kt | 0 apps/flipcash/core/build.gradle.kts | 6 ++++++ .../kotlin/com/flipcash/app/core/Locals.kt | 0 .../kotlin/com/flipcash/app/core/android/VersionInfo.kt | 0 .../kotlin/com/flipcash/app/core/annotations/AccountType.kt | 0 .../kotlin/com/flipcash/app/core/cache/CacheEntry.kt | 0 .../kotlin/com/flipcash/app/core/cache/CachePolicy.kt | 0 .../com/flipcash/app/core/cache/CachePolicyHandler.kt | 0 .../kotlin/com/flipcash/app/core/data/Loadable.kt | 0 .../kotlin/com/flipcash/app/core/encryption/Sodium.kt | 0 .../kotlin/com/flipcash/app/core/extensions/Flow.kt | 0 .../kotlin/com/flipcash/app/core/extensions/List.kt | 0 .../kotlin/com/flipcash/app/core/extensions/Pair.kt | 0 .../kotlin/com/flipcash/app/core/extensions/Result.kt | 0 .../com/flipcash/app/core/internal/extensions/Result.kt | 0 .../flipcash/app/core/internal/updater/ProfileUpdater.kt | 0 .../kotlin/com/flipcash/app/core/links/TrustedWebsites.kt | 0 .../kotlin/com/flipcash/app/core/tipping/OwnTipCard.kt | 0 .../kotlin/com/flipcash/app/core/tipping/TipSelection.kt | 0 .../com/flipcash/app/core/toast/SystemToastController.kt | 0 .../kotlin/com/flipcash/app/core/toast/ToastController.kt | 0 .../kotlin/com/flipcash/app/core/util/AbbreviatedLink.kt | 0 .../kotlin/com/flipcash/app/core/util/Fiat.kt | 0 .../kotlin/com/flipcash/app/core/util/Linkify.kt | 0 .../kotlin/com/flipcash/app/core/util/MessagingPackages.kt | 0 .../kotlin/com/flipcash/app/core/util/Number.kt | 0 .../app/core/verification/email/EmailCodeChannel.kt | 0 .../app/core/verification/email/EmailDeeplinkOrigin.kt | 0 .../app/core/verification/email/LocalEmailCodeChannel.kt | 0 apps/flipcash/shared/common-ui/build.gradle.kts | 3 +++ .../com/flipcash/shared/common/ui/amount/AmountChip.kt | 0 apps/flipcash/shared/theme/build.gradle.kts | 3 +++ .../kotlin/com/flipcash/app/theme/FlipcashPreview.kt | 0 apps/flipcash/shared/tokens/build.gradle.kts | 6 ++++++ .../kotlin/com/flipcash/app/tokens/BalancePoller.kt | 0 .../kotlin/com/flipcash/app/tokens/FeeAffordableEntry.kt | 0 .../kotlin/com/flipcash/app/tokens/InlineCompletion.kt | 0 .../kotlin/com/flipcash/app/tokens/TokenUpdater.kt | 0 .../kotlin/com/flipcash/app/tokens/UsdcDepositSweep.kt | 0 .../kotlin/com/flipcash/app/tokens/data/MarketTrend.kt | 0 .../kotlin/com/flipcash/app/tokens/data/Period.kt | 0 .../kotlin/com/getcode/ui/Locals.kt | 0 .../kotlin/com/getcode/ui/components/BlurredContent.kt | 0 .../kotlin/com/getcode/ui/components/BottomScrollEdge.kt | 0 .../kotlin/com/getcode/ui/components/BulletRow.kt | 0 .../kotlin/com/getcode/ui/components/CapsuleProgressBar.kt | 0 .../kotlin/com/getcode/ui/components/Chip.kt | 0 .../kotlin/com/getcode/ui/components/FilterChip.kt | 0 .../kotlin/com/getcode/ui/components/Flippable.kt | 0 .../com/getcode/ui/components/FullWidthScrollableTabRow.kt | 0 .../kotlin/com/getcode/ui/components/Modal.kt | 0 .../kotlin/com/getcode/ui/components/NotificationDot.kt | 0 .../kotlin/com/getcode/ui/components/Pill.kt | 0 .../kotlin/com/getcode/ui/components/PullToReveal.kt | 0 .../kotlin/com/getcode/ui/components/SegmentedControl.kt | 0 .../kotlin/com/getcode/ui/components/TopScrollEdge.kt | 0 .../kotlin/com/getcode/ui/components/VerticalDivider.kt | 0 .../kotlin/com/getcode/ui/components/charts/ChartPoint.kt | 0 .../kotlin/com/getcode/ui/components/charts/Trends.kt | 0 .../kotlin/com/getcode/ui/components/chat/DateBubble.kt | 0 .../com/getcode/ui/components/chat/MessageNodeDefaults.kt | 0 .../com/getcode/ui/components/chat/TypingIndicator.kt | 0 .../kotlin/com/getcode/ui/components/text/SectionHeader.kt | 0 .../getcode/ui/components/text/animated/DigitContainer.kt | 0 .../kotlin/com/getcode/ui/theme/CodeBillSwipeToDismiss.kt | 0 .../kotlin/com/getcode/ui/theme/CodeCheckbox.kt | 0 .../kotlin/com/getcode/ui/theme/CodeRadioButton.kt | 0 .../kotlin/com/getcode/ui/theme/CodeScaffold.kt | 0 .../kotlin/com/getcode/ui/theme/CodeSeedView.kt | 0 .../kotlin/com/getcode/ui/theme/CodeSegmentedControl.kt | 0 .../kotlin/com/getcode/ui/theme/CodeSwitch.kt | 0 .../kotlin/com/getcode/ui/utils/AnimationUtils.kt | 0 .../kotlin/com/getcode/ui/utils/Geometry.kt | 0 .../kotlin/com/getcode/ui/utils/LazyList.kt | 0 .../kotlin/com/getcode/ui/utils/Maps.kt | 0 .../kotlin/com/getcode/ui/utils/MeasureScope.kt | 0 .../kotlin/com/getcode/ui/utils/PaddingValues.kt | 0 .../kotlin/com/getcode/ui/utils/TextStyle.kt | 0 .../kotlin/com/getcode/ui/core/ContextMenuAction.kt | 0 .../kotlin/com/getcode/ui/core/ExpandedTouchTarget.kt | 0 .../com/getcode/ui/core/StarMaskVisualTransformation.kt | 0 .../kotlin/com/getcode/ui/core/visibility/VisibilityInfo.kt | 0 .../com/getcode/ui/core/visibility/VisibilityTrackerNode.kt | 0 ui/navigation/build.gradle.kts | 4 ++++ .../kotlin/com/getcode/navigation/flow/FlowDismissStyle.kt | 0 .../kotlin/com/getcode/navigation/scrim/Scrim.kt | 0 .../kotlin/com/getcode/ui/utils/SheetExpansion.kt | 0 96 files changed, 24 insertions(+) rename apps/flipcash/core-ui/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/ui/BrandedGradientIcon.kt (100%) rename apps/flipcash/core-ui/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/ui/ConfirmationStyle.kt (100%) rename apps/flipcash/core-ui/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/ui/CurrencyHolder.kt (100%) rename apps/flipcash/core-ui/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/ui/ReceiptLineItem.kt (100%) rename apps/flipcash/core-ui/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/ui/Skeleton.kt (100%) rename apps/flipcash/core-ui/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/ui/flow/FlowProgress.kt (100%) rename apps/flipcash/core-ui/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/ui/flow/FlowStepBarController.kt (100%) rename apps/flipcash/core-ui/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/ui/flow/FlowStepper.kt (100%) rename apps/flipcash/core-ui/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/ui/transitions/CardExpandTransition.kt (100%) rename apps/flipcash/core/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/Locals.kt (100%) rename apps/flipcash/core/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/android/VersionInfo.kt (100%) rename apps/flipcash/core/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/annotations/AccountType.kt (100%) rename apps/flipcash/core/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/cache/CacheEntry.kt (100%) rename apps/flipcash/core/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/cache/CachePolicy.kt (100%) rename apps/flipcash/core/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/cache/CachePolicyHandler.kt (100%) rename apps/flipcash/core/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/data/Loadable.kt (100%) rename apps/flipcash/core/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/encryption/Sodium.kt (100%) rename apps/flipcash/core/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/extensions/Flow.kt (100%) rename apps/flipcash/core/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/extensions/List.kt (100%) rename apps/flipcash/core/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/extensions/Pair.kt (100%) rename apps/flipcash/core/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/extensions/Result.kt (100%) rename apps/flipcash/core/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/internal/extensions/Result.kt (100%) rename apps/flipcash/core/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/internal/updater/ProfileUpdater.kt (100%) rename apps/flipcash/core/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/links/TrustedWebsites.kt (100%) rename apps/flipcash/core/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/tipping/OwnTipCard.kt (100%) rename apps/flipcash/core/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/tipping/TipSelection.kt (100%) rename apps/flipcash/core/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/toast/SystemToastController.kt (100%) rename apps/flipcash/core/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/toast/ToastController.kt (100%) rename apps/flipcash/core/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/util/AbbreviatedLink.kt (100%) rename apps/flipcash/core/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/util/Fiat.kt (100%) rename apps/flipcash/core/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/util/Linkify.kt (100%) rename apps/flipcash/core/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/util/MessagingPackages.kt (100%) rename apps/flipcash/core/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/util/Number.kt (100%) rename apps/flipcash/core/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/verification/email/EmailCodeChannel.kt (100%) rename apps/flipcash/core/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/verification/email/EmailDeeplinkOrigin.kt (100%) rename apps/flipcash/core/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/verification/email/LocalEmailCodeChannel.kt (100%) rename apps/flipcash/shared/common-ui/src/{androidMain => commonMain}/kotlin/com/flipcash/shared/common/ui/amount/AmountChip.kt (100%) rename apps/flipcash/shared/theme/src/{androidMain => commonMain}/kotlin/com/flipcash/app/theme/FlipcashPreview.kt (100%) rename apps/flipcash/shared/tokens/src/{androidMain => commonMain}/kotlin/com/flipcash/app/tokens/BalancePoller.kt (100%) rename apps/flipcash/shared/tokens/src/{androidMain => commonMain}/kotlin/com/flipcash/app/tokens/FeeAffordableEntry.kt (100%) rename apps/flipcash/shared/tokens/src/{androidMain => commonMain}/kotlin/com/flipcash/app/tokens/InlineCompletion.kt (100%) rename apps/flipcash/shared/tokens/src/{androidMain => commonMain}/kotlin/com/flipcash/app/tokens/TokenUpdater.kt (100%) rename apps/flipcash/shared/tokens/src/{androidMain => commonMain}/kotlin/com/flipcash/app/tokens/UsdcDepositSweep.kt (100%) rename apps/flipcash/shared/tokens/src/{androidMain => commonMain}/kotlin/com/flipcash/app/tokens/data/MarketTrend.kt (100%) rename apps/flipcash/shared/tokens/src/{androidMain => commonMain}/kotlin/com/flipcash/app/tokens/data/Period.kt (100%) rename ui/components/src/{androidMain => commonMain}/kotlin/com/getcode/ui/Locals.kt (100%) rename ui/components/src/{androidMain => commonMain}/kotlin/com/getcode/ui/components/BlurredContent.kt (100%) rename ui/components/src/{androidMain => commonMain}/kotlin/com/getcode/ui/components/BottomScrollEdge.kt (100%) rename ui/components/src/{androidMain => commonMain}/kotlin/com/getcode/ui/components/BulletRow.kt (100%) rename ui/components/src/{androidMain => commonMain}/kotlin/com/getcode/ui/components/CapsuleProgressBar.kt (100%) rename ui/components/src/{androidMain => commonMain}/kotlin/com/getcode/ui/components/Chip.kt (100%) rename ui/components/src/{androidMain => commonMain}/kotlin/com/getcode/ui/components/FilterChip.kt (100%) rename ui/components/src/{androidMain => commonMain}/kotlin/com/getcode/ui/components/Flippable.kt (100%) rename ui/components/src/{androidMain => commonMain}/kotlin/com/getcode/ui/components/FullWidthScrollableTabRow.kt (100%) rename ui/components/src/{androidMain => commonMain}/kotlin/com/getcode/ui/components/Modal.kt (100%) rename ui/components/src/{androidMain => commonMain}/kotlin/com/getcode/ui/components/NotificationDot.kt (100%) rename ui/components/src/{androidMain => commonMain}/kotlin/com/getcode/ui/components/Pill.kt (100%) rename ui/components/src/{androidMain => commonMain}/kotlin/com/getcode/ui/components/PullToReveal.kt (100%) rename ui/components/src/{androidMain => commonMain}/kotlin/com/getcode/ui/components/SegmentedControl.kt (100%) rename ui/components/src/{androidMain => commonMain}/kotlin/com/getcode/ui/components/TopScrollEdge.kt (100%) rename ui/components/src/{androidMain => commonMain}/kotlin/com/getcode/ui/components/VerticalDivider.kt (100%) rename ui/components/src/{androidMain => commonMain}/kotlin/com/getcode/ui/components/charts/ChartPoint.kt (100%) rename ui/components/src/{androidMain => commonMain}/kotlin/com/getcode/ui/components/charts/Trends.kt (100%) rename ui/components/src/{androidMain => commonMain}/kotlin/com/getcode/ui/components/chat/DateBubble.kt (100%) rename ui/components/src/{androidMain => commonMain}/kotlin/com/getcode/ui/components/chat/MessageNodeDefaults.kt (100%) rename ui/components/src/{androidMain => commonMain}/kotlin/com/getcode/ui/components/chat/TypingIndicator.kt (100%) rename ui/components/src/{androidMain => commonMain}/kotlin/com/getcode/ui/components/text/SectionHeader.kt (100%) rename ui/components/src/{androidMain => commonMain}/kotlin/com/getcode/ui/components/text/animated/DigitContainer.kt (100%) rename ui/components/src/{androidMain => commonMain}/kotlin/com/getcode/ui/theme/CodeBillSwipeToDismiss.kt (100%) rename ui/components/src/{androidMain => commonMain}/kotlin/com/getcode/ui/theme/CodeCheckbox.kt (100%) rename ui/components/src/{androidMain => commonMain}/kotlin/com/getcode/ui/theme/CodeRadioButton.kt (100%) rename ui/components/src/{androidMain => commonMain}/kotlin/com/getcode/ui/theme/CodeScaffold.kt (100%) rename ui/components/src/{androidMain => commonMain}/kotlin/com/getcode/ui/theme/CodeSeedView.kt (100%) rename ui/components/src/{androidMain => commonMain}/kotlin/com/getcode/ui/theme/CodeSegmentedControl.kt (100%) rename ui/components/src/{androidMain => commonMain}/kotlin/com/getcode/ui/theme/CodeSwitch.kt (100%) rename ui/components/src/{androidMain => commonMain}/kotlin/com/getcode/ui/utils/AnimationUtils.kt (100%) rename ui/components/src/{androidMain => commonMain}/kotlin/com/getcode/ui/utils/Geometry.kt (100%) rename ui/components/src/{androidMain => commonMain}/kotlin/com/getcode/ui/utils/LazyList.kt (100%) rename ui/components/src/{androidMain => commonMain}/kotlin/com/getcode/ui/utils/Maps.kt (100%) rename ui/components/src/{androidMain => commonMain}/kotlin/com/getcode/ui/utils/MeasureScope.kt (100%) rename ui/components/src/{androidMain => commonMain}/kotlin/com/getcode/ui/utils/PaddingValues.kt (100%) rename ui/components/src/{androidMain => commonMain}/kotlin/com/getcode/ui/utils/TextStyle.kt (100%) rename ui/core/src/{androidMain => commonMain}/kotlin/com/getcode/ui/core/ContextMenuAction.kt (100%) rename ui/core/src/{androidMain => commonMain}/kotlin/com/getcode/ui/core/ExpandedTouchTarget.kt (100%) rename ui/core/src/{androidMain => commonMain}/kotlin/com/getcode/ui/core/StarMaskVisualTransformation.kt (100%) rename ui/core/src/{androidMain => commonMain}/kotlin/com/getcode/ui/core/visibility/VisibilityInfo.kt (100%) rename ui/core/src/{androidMain => commonMain}/kotlin/com/getcode/ui/core/visibility/VisibilityTrackerNode.kt (100%) rename ui/navigation/src/{androidMain => commonMain}/kotlin/com/getcode/navigation/flow/FlowDismissStyle.kt (100%) rename ui/navigation/src/{androidMain => commonMain}/kotlin/com/getcode/navigation/scrim/Scrim.kt (100%) rename ui/navigation/src/{androidMain => commonMain}/kotlin/com/getcode/ui/utils/SheetExpansion.kt (100%) diff --git a/apps/flipcash/core-ui/build.gradle.kts b/apps/flipcash/core-ui/build.gradle.kts index 5c27c4add1..48cdd70695 100644 --- a/apps/flipcash/core-ui/build.gradle.kts +++ b/apps/flipcash/core-ui/build.gradle.kts @@ -14,6 +14,8 @@ kotlin { sourceSets { commonMain.dependencies { + implementation(libs.jetbrains.compose.animation) + implementation(libs.jetbrains.compose.ui.tooling.preview) implementation(project(":apps:flipcash:core")) implementation(project(":services:opencode")) implementation(project(":services:opencode-compose")) diff --git a/apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/BrandedGradientIcon.kt b/apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/BrandedGradientIcon.kt similarity index 100% rename from apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/BrandedGradientIcon.kt rename to apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/BrandedGradientIcon.kt diff --git a/apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/ConfirmationStyle.kt b/apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/ConfirmationStyle.kt similarity index 100% rename from apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/ConfirmationStyle.kt rename to apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/ConfirmationStyle.kt diff --git a/apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/CurrencyHolder.kt b/apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/CurrencyHolder.kt similarity index 100% rename from apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/CurrencyHolder.kt rename to apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/CurrencyHolder.kt diff --git a/apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/ReceiptLineItem.kt b/apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/ReceiptLineItem.kt similarity index 100% rename from apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/ReceiptLineItem.kt rename to apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/ReceiptLineItem.kt diff --git a/apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/Skeleton.kt b/apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/Skeleton.kt similarity index 100% rename from apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/Skeleton.kt rename to apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/Skeleton.kt diff --git a/apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/flow/FlowProgress.kt b/apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/flow/FlowProgress.kt similarity index 100% rename from apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/flow/FlowProgress.kt rename to apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/flow/FlowProgress.kt diff --git a/apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/flow/FlowStepBarController.kt b/apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/flow/FlowStepBarController.kt similarity index 100% rename from apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/flow/FlowStepBarController.kt rename to apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/flow/FlowStepBarController.kt diff --git a/apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/flow/FlowStepper.kt b/apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/flow/FlowStepper.kt similarity index 100% rename from apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/flow/FlowStepper.kt rename to apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/flow/FlowStepper.kt diff --git a/apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/transitions/CardExpandTransition.kt b/apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/transitions/CardExpandTransition.kt similarity index 100% rename from apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/transitions/CardExpandTransition.kt rename to apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/transitions/CardExpandTransition.kt diff --git a/apps/flipcash/core/build.gradle.kts b/apps/flipcash/core/build.gradle.kts index 2fab73b963..6fac369089 100644 --- a/apps/flipcash/core/build.gradle.kts +++ b/apps/flipcash/core/build.gradle.kts @@ -17,6 +17,12 @@ kotlin { sourceSets { commonMain.dependencies { + implementation(libs.jetbrains.compose.ui) + implementation(libs.jetbrains.compose.animation) + implementation(libs.jetbrains.compose.material) + implementation(libs.jetbrains.compose.material3) + implementation(libs.jetbrains.compose.ui.tooling.preview) + implementation(libs.sodium.bindings.kmp) implementation(project(":libs:parcelable")) implementation(libs.javax.inject) api(libs.androidx.lifecycle.runtime.common) diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/Locals.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/Locals.kt similarity index 100% rename from apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/Locals.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/Locals.kt diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/android/VersionInfo.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/android/VersionInfo.kt similarity index 100% rename from apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/android/VersionInfo.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/android/VersionInfo.kt diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/annotations/AccountType.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/annotations/AccountType.kt similarity index 100% rename from apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/annotations/AccountType.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/annotations/AccountType.kt diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/cache/CacheEntry.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/cache/CacheEntry.kt similarity index 100% rename from apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/cache/CacheEntry.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/cache/CacheEntry.kt diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/cache/CachePolicy.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/cache/CachePolicy.kt similarity index 100% rename from apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/cache/CachePolicy.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/cache/CachePolicy.kt diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/cache/CachePolicyHandler.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/cache/CachePolicyHandler.kt similarity index 100% rename from apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/cache/CachePolicyHandler.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/cache/CachePolicyHandler.kt diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/data/Loadable.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/data/Loadable.kt similarity index 100% rename from apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/data/Loadable.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/data/Loadable.kt diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/encryption/Sodium.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/encryption/Sodium.kt similarity index 100% rename from apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/encryption/Sodium.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/encryption/Sodium.kt diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/extensions/Flow.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/extensions/Flow.kt similarity index 100% rename from apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/extensions/Flow.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/extensions/Flow.kt diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/extensions/List.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/extensions/List.kt similarity index 100% rename from apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/extensions/List.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/extensions/List.kt diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/extensions/Pair.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/extensions/Pair.kt similarity index 100% rename from apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/extensions/Pair.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/extensions/Pair.kt diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/extensions/Result.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/extensions/Result.kt similarity index 100% rename from apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/extensions/Result.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/extensions/Result.kt diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/internal/extensions/Result.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/internal/extensions/Result.kt similarity index 100% rename from apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/internal/extensions/Result.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/internal/extensions/Result.kt diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/internal/updater/ProfileUpdater.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/internal/updater/ProfileUpdater.kt similarity index 100% rename from apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/internal/updater/ProfileUpdater.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/internal/updater/ProfileUpdater.kt diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/links/TrustedWebsites.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/links/TrustedWebsites.kt similarity index 100% rename from apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/links/TrustedWebsites.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/links/TrustedWebsites.kt diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/tipping/OwnTipCard.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/tipping/OwnTipCard.kt similarity index 100% rename from apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/tipping/OwnTipCard.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/tipping/OwnTipCard.kt diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/tipping/TipSelection.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/tipping/TipSelection.kt similarity index 100% rename from apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/tipping/TipSelection.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/tipping/TipSelection.kt diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/toast/SystemToastController.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/toast/SystemToastController.kt similarity index 100% rename from apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/toast/SystemToastController.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/toast/SystemToastController.kt diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/toast/ToastController.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/toast/ToastController.kt similarity index 100% rename from apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/toast/ToastController.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/toast/ToastController.kt diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/util/AbbreviatedLink.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/util/AbbreviatedLink.kt similarity index 100% rename from apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/util/AbbreviatedLink.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/util/AbbreviatedLink.kt diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/util/Fiat.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/util/Fiat.kt similarity index 100% rename from apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/util/Fiat.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/util/Fiat.kt diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/util/Linkify.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/util/Linkify.kt similarity index 100% rename from apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/util/Linkify.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/util/Linkify.kt diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/util/MessagingPackages.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/util/MessagingPackages.kt similarity index 100% rename from apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/util/MessagingPackages.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/util/MessagingPackages.kt diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/util/Number.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/util/Number.kt similarity index 100% rename from apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/util/Number.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/util/Number.kt diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/verification/email/EmailCodeChannel.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/verification/email/EmailCodeChannel.kt similarity index 100% rename from apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/verification/email/EmailCodeChannel.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/verification/email/EmailCodeChannel.kt diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/verification/email/EmailDeeplinkOrigin.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/verification/email/EmailDeeplinkOrigin.kt similarity index 100% rename from apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/verification/email/EmailDeeplinkOrigin.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/verification/email/EmailDeeplinkOrigin.kt diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/verification/email/LocalEmailCodeChannel.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/verification/email/LocalEmailCodeChannel.kt similarity index 100% rename from apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/verification/email/LocalEmailCodeChannel.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/verification/email/LocalEmailCodeChannel.kt diff --git a/apps/flipcash/shared/common-ui/build.gradle.kts b/apps/flipcash/shared/common-ui/build.gradle.kts index afa584a830..309e27b1db 100644 --- a/apps/flipcash/shared/common-ui/build.gradle.kts +++ b/apps/flipcash/shared/common-ui/build.gradle.kts @@ -13,6 +13,9 @@ kotlin { sourceSets { commonMain.dependencies { + implementation(libs.jetbrains.compose.animation) + implementation(libs.jetbrains.compose.material) + implementation(libs.jetbrains.compose.ui.tooling.preview) implementation(project(":apps:flipcash:core")) implementation(project(":ui:core")) implementation(project(":ui:theme")) diff --git a/apps/flipcash/shared/common-ui/src/androidMain/kotlin/com/flipcash/shared/common/ui/amount/AmountChip.kt b/apps/flipcash/shared/common-ui/src/commonMain/kotlin/com/flipcash/shared/common/ui/amount/AmountChip.kt similarity index 100% rename from apps/flipcash/shared/common-ui/src/androidMain/kotlin/com/flipcash/shared/common/ui/amount/AmountChip.kt rename to apps/flipcash/shared/common-ui/src/commonMain/kotlin/com/flipcash/shared/common/ui/amount/AmountChip.kt diff --git a/apps/flipcash/shared/theme/build.gradle.kts b/apps/flipcash/shared/theme/build.gradle.kts index cd19d34932..a543099804 100644 --- a/apps/flipcash/shared/theme/build.gradle.kts +++ b/apps/flipcash/shared/theme/build.gradle.kts @@ -10,6 +10,9 @@ kotlin { sourceSets { commonMain.dependencies { + implementation(libs.jetbrains.compose.material) + implementation(libs.jetbrains.compose.material3) + implementation(libs.jetbrains.compose.ui.tooling.preview) implementation(project(":ui:theme")) implementation(libs.jetbrains.compose.runtime) implementation(libs.jetbrains.compose.foundation) diff --git a/apps/flipcash/shared/theme/src/androidMain/kotlin/com/flipcash/app/theme/FlipcashPreview.kt b/apps/flipcash/shared/theme/src/commonMain/kotlin/com/flipcash/app/theme/FlipcashPreview.kt similarity index 100% rename from apps/flipcash/shared/theme/src/androidMain/kotlin/com/flipcash/app/theme/FlipcashPreview.kt rename to apps/flipcash/shared/theme/src/commonMain/kotlin/com/flipcash/app/theme/FlipcashPreview.kt diff --git a/apps/flipcash/shared/tokens/build.gradle.kts b/apps/flipcash/shared/tokens/build.gradle.kts index 34e4d3caf8..e717bd4947 100644 --- a/apps/flipcash/shared/tokens/build.gradle.kts +++ b/apps/flipcash/shared/tokens/build.gradle.kts @@ -15,6 +15,12 @@ kotlin { sourceSets { commonMain.dependencies { + implementation(libs.jetbrains.compose.foundation) + implementation(libs.jetbrains.compose.ui) + implementation(libs.jetbrains.compose.animation) + implementation(libs.jetbrains.compose.material) + implementation(libs.jetbrains.compose.material3) + implementation(libs.jetbrains.compose.ui.tooling.preview) api(project(":apps:flipcash:shared:tokens:core")) implementation(project(":apps:flipcash:core")) diff --git a/apps/flipcash/shared/tokens/src/androidMain/kotlin/com/flipcash/app/tokens/BalancePoller.kt b/apps/flipcash/shared/tokens/src/commonMain/kotlin/com/flipcash/app/tokens/BalancePoller.kt similarity index 100% rename from apps/flipcash/shared/tokens/src/androidMain/kotlin/com/flipcash/app/tokens/BalancePoller.kt rename to apps/flipcash/shared/tokens/src/commonMain/kotlin/com/flipcash/app/tokens/BalancePoller.kt diff --git a/apps/flipcash/shared/tokens/src/androidMain/kotlin/com/flipcash/app/tokens/FeeAffordableEntry.kt b/apps/flipcash/shared/tokens/src/commonMain/kotlin/com/flipcash/app/tokens/FeeAffordableEntry.kt similarity index 100% rename from apps/flipcash/shared/tokens/src/androidMain/kotlin/com/flipcash/app/tokens/FeeAffordableEntry.kt rename to apps/flipcash/shared/tokens/src/commonMain/kotlin/com/flipcash/app/tokens/FeeAffordableEntry.kt diff --git a/apps/flipcash/shared/tokens/src/androidMain/kotlin/com/flipcash/app/tokens/InlineCompletion.kt b/apps/flipcash/shared/tokens/src/commonMain/kotlin/com/flipcash/app/tokens/InlineCompletion.kt similarity index 100% rename from apps/flipcash/shared/tokens/src/androidMain/kotlin/com/flipcash/app/tokens/InlineCompletion.kt rename to apps/flipcash/shared/tokens/src/commonMain/kotlin/com/flipcash/app/tokens/InlineCompletion.kt diff --git a/apps/flipcash/shared/tokens/src/androidMain/kotlin/com/flipcash/app/tokens/TokenUpdater.kt b/apps/flipcash/shared/tokens/src/commonMain/kotlin/com/flipcash/app/tokens/TokenUpdater.kt similarity index 100% rename from apps/flipcash/shared/tokens/src/androidMain/kotlin/com/flipcash/app/tokens/TokenUpdater.kt rename to apps/flipcash/shared/tokens/src/commonMain/kotlin/com/flipcash/app/tokens/TokenUpdater.kt diff --git a/apps/flipcash/shared/tokens/src/androidMain/kotlin/com/flipcash/app/tokens/UsdcDepositSweep.kt b/apps/flipcash/shared/tokens/src/commonMain/kotlin/com/flipcash/app/tokens/UsdcDepositSweep.kt similarity index 100% rename from apps/flipcash/shared/tokens/src/androidMain/kotlin/com/flipcash/app/tokens/UsdcDepositSweep.kt rename to apps/flipcash/shared/tokens/src/commonMain/kotlin/com/flipcash/app/tokens/UsdcDepositSweep.kt diff --git a/apps/flipcash/shared/tokens/src/androidMain/kotlin/com/flipcash/app/tokens/data/MarketTrend.kt b/apps/flipcash/shared/tokens/src/commonMain/kotlin/com/flipcash/app/tokens/data/MarketTrend.kt similarity index 100% rename from apps/flipcash/shared/tokens/src/androidMain/kotlin/com/flipcash/app/tokens/data/MarketTrend.kt rename to apps/flipcash/shared/tokens/src/commonMain/kotlin/com/flipcash/app/tokens/data/MarketTrend.kt diff --git a/apps/flipcash/shared/tokens/src/androidMain/kotlin/com/flipcash/app/tokens/data/Period.kt b/apps/flipcash/shared/tokens/src/commonMain/kotlin/com/flipcash/app/tokens/data/Period.kt similarity index 100% rename from apps/flipcash/shared/tokens/src/androidMain/kotlin/com/flipcash/app/tokens/data/Period.kt rename to apps/flipcash/shared/tokens/src/commonMain/kotlin/com/flipcash/app/tokens/data/Period.kt diff --git a/ui/components/src/androidMain/kotlin/com/getcode/ui/Locals.kt b/ui/components/src/commonMain/kotlin/com/getcode/ui/Locals.kt similarity index 100% rename from ui/components/src/androidMain/kotlin/com/getcode/ui/Locals.kt rename to ui/components/src/commonMain/kotlin/com/getcode/ui/Locals.kt diff --git a/ui/components/src/androidMain/kotlin/com/getcode/ui/components/BlurredContent.kt b/ui/components/src/commonMain/kotlin/com/getcode/ui/components/BlurredContent.kt similarity index 100% rename from ui/components/src/androidMain/kotlin/com/getcode/ui/components/BlurredContent.kt rename to ui/components/src/commonMain/kotlin/com/getcode/ui/components/BlurredContent.kt diff --git a/ui/components/src/androidMain/kotlin/com/getcode/ui/components/BottomScrollEdge.kt b/ui/components/src/commonMain/kotlin/com/getcode/ui/components/BottomScrollEdge.kt similarity index 100% rename from ui/components/src/androidMain/kotlin/com/getcode/ui/components/BottomScrollEdge.kt rename to ui/components/src/commonMain/kotlin/com/getcode/ui/components/BottomScrollEdge.kt diff --git a/ui/components/src/androidMain/kotlin/com/getcode/ui/components/BulletRow.kt b/ui/components/src/commonMain/kotlin/com/getcode/ui/components/BulletRow.kt similarity index 100% rename from ui/components/src/androidMain/kotlin/com/getcode/ui/components/BulletRow.kt rename to ui/components/src/commonMain/kotlin/com/getcode/ui/components/BulletRow.kt diff --git a/ui/components/src/androidMain/kotlin/com/getcode/ui/components/CapsuleProgressBar.kt b/ui/components/src/commonMain/kotlin/com/getcode/ui/components/CapsuleProgressBar.kt similarity index 100% rename from ui/components/src/androidMain/kotlin/com/getcode/ui/components/CapsuleProgressBar.kt rename to ui/components/src/commonMain/kotlin/com/getcode/ui/components/CapsuleProgressBar.kt diff --git a/ui/components/src/androidMain/kotlin/com/getcode/ui/components/Chip.kt b/ui/components/src/commonMain/kotlin/com/getcode/ui/components/Chip.kt similarity index 100% rename from ui/components/src/androidMain/kotlin/com/getcode/ui/components/Chip.kt rename to ui/components/src/commonMain/kotlin/com/getcode/ui/components/Chip.kt diff --git a/ui/components/src/androidMain/kotlin/com/getcode/ui/components/FilterChip.kt b/ui/components/src/commonMain/kotlin/com/getcode/ui/components/FilterChip.kt similarity index 100% rename from ui/components/src/androidMain/kotlin/com/getcode/ui/components/FilterChip.kt rename to ui/components/src/commonMain/kotlin/com/getcode/ui/components/FilterChip.kt diff --git a/ui/components/src/androidMain/kotlin/com/getcode/ui/components/Flippable.kt b/ui/components/src/commonMain/kotlin/com/getcode/ui/components/Flippable.kt similarity index 100% rename from ui/components/src/androidMain/kotlin/com/getcode/ui/components/Flippable.kt rename to ui/components/src/commonMain/kotlin/com/getcode/ui/components/Flippable.kt diff --git a/ui/components/src/androidMain/kotlin/com/getcode/ui/components/FullWidthScrollableTabRow.kt b/ui/components/src/commonMain/kotlin/com/getcode/ui/components/FullWidthScrollableTabRow.kt similarity index 100% rename from ui/components/src/androidMain/kotlin/com/getcode/ui/components/FullWidthScrollableTabRow.kt rename to ui/components/src/commonMain/kotlin/com/getcode/ui/components/FullWidthScrollableTabRow.kt diff --git a/ui/components/src/androidMain/kotlin/com/getcode/ui/components/Modal.kt b/ui/components/src/commonMain/kotlin/com/getcode/ui/components/Modal.kt similarity index 100% rename from ui/components/src/androidMain/kotlin/com/getcode/ui/components/Modal.kt rename to ui/components/src/commonMain/kotlin/com/getcode/ui/components/Modal.kt diff --git a/ui/components/src/androidMain/kotlin/com/getcode/ui/components/NotificationDot.kt b/ui/components/src/commonMain/kotlin/com/getcode/ui/components/NotificationDot.kt similarity index 100% rename from ui/components/src/androidMain/kotlin/com/getcode/ui/components/NotificationDot.kt rename to ui/components/src/commonMain/kotlin/com/getcode/ui/components/NotificationDot.kt diff --git a/ui/components/src/androidMain/kotlin/com/getcode/ui/components/Pill.kt b/ui/components/src/commonMain/kotlin/com/getcode/ui/components/Pill.kt similarity index 100% rename from ui/components/src/androidMain/kotlin/com/getcode/ui/components/Pill.kt rename to ui/components/src/commonMain/kotlin/com/getcode/ui/components/Pill.kt diff --git a/ui/components/src/androidMain/kotlin/com/getcode/ui/components/PullToReveal.kt b/ui/components/src/commonMain/kotlin/com/getcode/ui/components/PullToReveal.kt similarity index 100% rename from ui/components/src/androidMain/kotlin/com/getcode/ui/components/PullToReveal.kt rename to ui/components/src/commonMain/kotlin/com/getcode/ui/components/PullToReveal.kt diff --git a/ui/components/src/androidMain/kotlin/com/getcode/ui/components/SegmentedControl.kt b/ui/components/src/commonMain/kotlin/com/getcode/ui/components/SegmentedControl.kt similarity index 100% rename from ui/components/src/androidMain/kotlin/com/getcode/ui/components/SegmentedControl.kt rename to ui/components/src/commonMain/kotlin/com/getcode/ui/components/SegmentedControl.kt diff --git a/ui/components/src/androidMain/kotlin/com/getcode/ui/components/TopScrollEdge.kt b/ui/components/src/commonMain/kotlin/com/getcode/ui/components/TopScrollEdge.kt similarity index 100% rename from ui/components/src/androidMain/kotlin/com/getcode/ui/components/TopScrollEdge.kt rename to ui/components/src/commonMain/kotlin/com/getcode/ui/components/TopScrollEdge.kt diff --git a/ui/components/src/androidMain/kotlin/com/getcode/ui/components/VerticalDivider.kt b/ui/components/src/commonMain/kotlin/com/getcode/ui/components/VerticalDivider.kt similarity index 100% rename from ui/components/src/androidMain/kotlin/com/getcode/ui/components/VerticalDivider.kt rename to ui/components/src/commonMain/kotlin/com/getcode/ui/components/VerticalDivider.kt diff --git a/ui/components/src/androidMain/kotlin/com/getcode/ui/components/charts/ChartPoint.kt b/ui/components/src/commonMain/kotlin/com/getcode/ui/components/charts/ChartPoint.kt similarity index 100% rename from ui/components/src/androidMain/kotlin/com/getcode/ui/components/charts/ChartPoint.kt rename to ui/components/src/commonMain/kotlin/com/getcode/ui/components/charts/ChartPoint.kt diff --git a/ui/components/src/androidMain/kotlin/com/getcode/ui/components/charts/Trends.kt b/ui/components/src/commonMain/kotlin/com/getcode/ui/components/charts/Trends.kt similarity index 100% rename from ui/components/src/androidMain/kotlin/com/getcode/ui/components/charts/Trends.kt rename to ui/components/src/commonMain/kotlin/com/getcode/ui/components/charts/Trends.kt diff --git a/ui/components/src/androidMain/kotlin/com/getcode/ui/components/chat/DateBubble.kt b/ui/components/src/commonMain/kotlin/com/getcode/ui/components/chat/DateBubble.kt similarity index 100% rename from ui/components/src/androidMain/kotlin/com/getcode/ui/components/chat/DateBubble.kt rename to ui/components/src/commonMain/kotlin/com/getcode/ui/components/chat/DateBubble.kt diff --git a/ui/components/src/androidMain/kotlin/com/getcode/ui/components/chat/MessageNodeDefaults.kt b/ui/components/src/commonMain/kotlin/com/getcode/ui/components/chat/MessageNodeDefaults.kt similarity index 100% rename from ui/components/src/androidMain/kotlin/com/getcode/ui/components/chat/MessageNodeDefaults.kt rename to ui/components/src/commonMain/kotlin/com/getcode/ui/components/chat/MessageNodeDefaults.kt diff --git a/ui/components/src/androidMain/kotlin/com/getcode/ui/components/chat/TypingIndicator.kt b/ui/components/src/commonMain/kotlin/com/getcode/ui/components/chat/TypingIndicator.kt similarity index 100% rename from ui/components/src/androidMain/kotlin/com/getcode/ui/components/chat/TypingIndicator.kt rename to ui/components/src/commonMain/kotlin/com/getcode/ui/components/chat/TypingIndicator.kt diff --git a/ui/components/src/androidMain/kotlin/com/getcode/ui/components/text/SectionHeader.kt b/ui/components/src/commonMain/kotlin/com/getcode/ui/components/text/SectionHeader.kt similarity index 100% rename from ui/components/src/androidMain/kotlin/com/getcode/ui/components/text/SectionHeader.kt rename to ui/components/src/commonMain/kotlin/com/getcode/ui/components/text/SectionHeader.kt diff --git a/ui/components/src/androidMain/kotlin/com/getcode/ui/components/text/animated/DigitContainer.kt b/ui/components/src/commonMain/kotlin/com/getcode/ui/components/text/animated/DigitContainer.kt similarity index 100% rename from ui/components/src/androidMain/kotlin/com/getcode/ui/components/text/animated/DigitContainer.kt rename to ui/components/src/commonMain/kotlin/com/getcode/ui/components/text/animated/DigitContainer.kt diff --git a/ui/components/src/androidMain/kotlin/com/getcode/ui/theme/CodeBillSwipeToDismiss.kt b/ui/components/src/commonMain/kotlin/com/getcode/ui/theme/CodeBillSwipeToDismiss.kt similarity index 100% rename from ui/components/src/androidMain/kotlin/com/getcode/ui/theme/CodeBillSwipeToDismiss.kt rename to ui/components/src/commonMain/kotlin/com/getcode/ui/theme/CodeBillSwipeToDismiss.kt diff --git a/ui/components/src/androidMain/kotlin/com/getcode/ui/theme/CodeCheckbox.kt b/ui/components/src/commonMain/kotlin/com/getcode/ui/theme/CodeCheckbox.kt similarity index 100% rename from ui/components/src/androidMain/kotlin/com/getcode/ui/theme/CodeCheckbox.kt rename to ui/components/src/commonMain/kotlin/com/getcode/ui/theme/CodeCheckbox.kt diff --git a/ui/components/src/androidMain/kotlin/com/getcode/ui/theme/CodeRadioButton.kt b/ui/components/src/commonMain/kotlin/com/getcode/ui/theme/CodeRadioButton.kt similarity index 100% rename from ui/components/src/androidMain/kotlin/com/getcode/ui/theme/CodeRadioButton.kt rename to ui/components/src/commonMain/kotlin/com/getcode/ui/theme/CodeRadioButton.kt diff --git a/ui/components/src/androidMain/kotlin/com/getcode/ui/theme/CodeScaffold.kt b/ui/components/src/commonMain/kotlin/com/getcode/ui/theme/CodeScaffold.kt similarity index 100% rename from ui/components/src/androidMain/kotlin/com/getcode/ui/theme/CodeScaffold.kt rename to ui/components/src/commonMain/kotlin/com/getcode/ui/theme/CodeScaffold.kt diff --git a/ui/components/src/androidMain/kotlin/com/getcode/ui/theme/CodeSeedView.kt b/ui/components/src/commonMain/kotlin/com/getcode/ui/theme/CodeSeedView.kt similarity index 100% rename from ui/components/src/androidMain/kotlin/com/getcode/ui/theme/CodeSeedView.kt rename to ui/components/src/commonMain/kotlin/com/getcode/ui/theme/CodeSeedView.kt diff --git a/ui/components/src/androidMain/kotlin/com/getcode/ui/theme/CodeSegmentedControl.kt b/ui/components/src/commonMain/kotlin/com/getcode/ui/theme/CodeSegmentedControl.kt similarity index 100% rename from ui/components/src/androidMain/kotlin/com/getcode/ui/theme/CodeSegmentedControl.kt rename to ui/components/src/commonMain/kotlin/com/getcode/ui/theme/CodeSegmentedControl.kt diff --git a/ui/components/src/androidMain/kotlin/com/getcode/ui/theme/CodeSwitch.kt b/ui/components/src/commonMain/kotlin/com/getcode/ui/theme/CodeSwitch.kt similarity index 100% rename from ui/components/src/androidMain/kotlin/com/getcode/ui/theme/CodeSwitch.kt rename to ui/components/src/commonMain/kotlin/com/getcode/ui/theme/CodeSwitch.kt diff --git a/ui/components/src/androidMain/kotlin/com/getcode/ui/utils/AnimationUtils.kt b/ui/components/src/commonMain/kotlin/com/getcode/ui/utils/AnimationUtils.kt similarity index 100% rename from ui/components/src/androidMain/kotlin/com/getcode/ui/utils/AnimationUtils.kt rename to ui/components/src/commonMain/kotlin/com/getcode/ui/utils/AnimationUtils.kt diff --git a/ui/components/src/androidMain/kotlin/com/getcode/ui/utils/Geometry.kt b/ui/components/src/commonMain/kotlin/com/getcode/ui/utils/Geometry.kt similarity index 100% rename from ui/components/src/androidMain/kotlin/com/getcode/ui/utils/Geometry.kt rename to ui/components/src/commonMain/kotlin/com/getcode/ui/utils/Geometry.kt diff --git a/ui/components/src/androidMain/kotlin/com/getcode/ui/utils/LazyList.kt b/ui/components/src/commonMain/kotlin/com/getcode/ui/utils/LazyList.kt similarity index 100% rename from ui/components/src/androidMain/kotlin/com/getcode/ui/utils/LazyList.kt rename to ui/components/src/commonMain/kotlin/com/getcode/ui/utils/LazyList.kt diff --git a/ui/components/src/androidMain/kotlin/com/getcode/ui/utils/Maps.kt b/ui/components/src/commonMain/kotlin/com/getcode/ui/utils/Maps.kt similarity index 100% rename from ui/components/src/androidMain/kotlin/com/getcode/ui/utils/Maps.kt rename to ui/components/src/commonMain/kotlin/com/getcode/ui/utils/Maps.kt diff --git a/ui/components/src/androidMain/kotlin/com/getcode/ui/utils/MeasureScope.kt b/ui/components/src/commonMain/kotlin/com/getcode/ui/utils/MeasureScope.kt similarity index 100% rename from ui/components/src/androidMain/kotlin/com/getcode/ui/utils/MeasureScope.kt rename to ui/components/src/commonMain/kotlin/com/getcode/ui/utils/MeasureScope.kt diff --git a/ui/components/src/androidMain/kotlin/com/getcode/ui/utils/PaddingValues.kt b/ui/components/src/commonMain/kotlin/com/getcode/ui/utils/PaddingValues.kt similarity index 100% rename from ui/components/src/androidMain/kotlin/com/getcode/ui/utils/PaddingValues.kt rename to ui/components/src/commonMain/kotlin/com/getcode/ui/utils/PaddingValues.kt diff --git a/ui/components/src/androidMain/kotlin/com/getcode/ui/utils/TextStyle.kt b/ui/components/src/commonMain/kotlin/com/getcode/ui/utils/TextStyle.kt similarity index 100% rename from ui/components/src/androidMain/kotlin/com/getcode/ui/utils/TextStyle.kt rename to ui/components/src/commonMain/kotlin/com/getcode/ui/utils/TextStyle.kt diff --git a/ui/core/src/androidMain/kotlin/com/getcode/ui/core/ContextMenuAction.kt b/ui/core/src/commonMain/kotlin/com/getcode/ui/core/ContextMenuAction.kt similarity index 100% rename from ui/core/src/androidMain/kotlin/com/getcode/ui/core/ContextMenuAction.kt rename to ui/core/src/commonMain/kotlin/com/getcode/ui/core/ContextMenuAction.kt diff --git a/ui/core/src/androidMain/kotlin/com/getcode/ui/core/ExpandedTouchTarget.kt b/ui/core/src/commonMain/kotlin/com/getcode/ui/core/ExpandedTouchTarget.kt similarity index 100% rename from ui/core/src/androidMain/kotlin/com/getcode/ui/core/ExpandedTouchTarget.kt rename to ui/core/src/commonMain/kotlin/com/getcode/ui/core/ExpandedTouchTarget.kt diff --git a/ui/core/src/androidMain/kotlin/com/getcode/ui/core/StarMaskVisualTransformation.kt b/ui/core/src/commonMain/kotlin/com/getcode/ui/core/StarMaskVisualTransformation.kt similarity index 100% rename from ui/core/src/androidMain/kotlin/com/getcode/ui/core/StarMaskVisualTransformation.kt rename to ui/core/src/commonMain/kotlin/com/getcode/ui/core/StarMaskVisualTransformation.kt diff --git a/ui/core/src/androidMain/kotlin/com/getcode/ui/core/visibility/VisibilityInfo.kt b/ui/core/src/commonMain/kotlin/com/getcode/ui/core/visibility/VisibilityInfo.kt similarity index 100% rename from ui/core/src/androidMain/kotlin/com/getcode/ui/core/visibility/VisibilityInfo.kt rename to ui/core/src/commonMain/kotlin/com/getcode/ui/core/visibility/VisibilityInfo.kt diff --git a/ui/core/src/androidMain/kotlin/com/getcode/ui/core/visibility/VisibilityTrackerNode.kt b/ui/core/src/commonMain/kotlin/com/getcode/ui/core/visibility/VisibilityTrackerNode.kt similarity index 100% rename from ui/core/src/androidMain/kotlin/com/getcode/ui/core/visibility/VisibilityTrackerNode.kt rename to ui/core/src/commonMain/kotlin/com/getcode/ui/core/visibility/VisibilityTrackerNode.kt diff --git a/ui/navigation/build.gradle.kts b/ui/navigation/build.gradle.kts index c658b24e56..27266d9bf8 100644 --- a/ui/navigation/build.gradle.kts +++ b/ui/navigation/build.gradle.kts @@ -12,6 +12,10 @@ kotlin { sourceSets { commonMain.dependencies { + implementation(libs.jetbrains.compose.animation) + implementation(libs.jetbrains.compose.material) + implementation(libs.jetbrains.compose.material3) + implementation(libs.jetbrains.compose.ui.tooling.preview) api(project(":libs:coroutines")) implementation(project(":libs:logging")) implementation(project(":libs:parcelable")) diff --git a/ui/navigation/src/androidMain/kotlin/com/getcode/navigation/flow/FlowDismissStyle.kt b/ui/navigation/src/commonMain/kotlin/com/getcode/navigation/flow/FlowDismissStyle.kt similarity index 100% rename from ui/navigation/src/androidMain/kotlin/com/getcode/navigation/flow/FlowDismissStyle.kt rename to ui/navigation/src/commonMain/kotlin/com/getcode/navigation/flow/FlowDismissStyle.kt diff --git a/ui/navigation/src/androidMain/kotlin/com/getcode/navigation/scrim/Scrim.kt b/ui/navigation/src/commonMain/kotlin/com/getcode/navigation/scrim/Scrim.kt similarity index 100% rename from ui/navigation/src/androidMain/kotlin/com/getcode/navigation/scrim/Scrim.kt rename to ui/navigation/src/commonMain/kotlin/com/getcode/navigation/scrim/Scrim.kt diff --git a/ui/navigation/src/androidMain/kotlin/com/getcode/ui/utils/SheetExpansion.kt b/ui/navigation/src/commonMain/kotlin/com/getcode/ui/utils/SheetExpansion.kt similarity index 100% rename from ui/navigation/src/androidMain/kotlin/com/getcode/ui/utils/SheetExpansion.kt rename to ui/navigation/src/commonMain/kotlin/com/getcode/ui/utils/SheetExpansion.kt From 1d77df4756c76ccb4ae09dfe8c76752b559ca1c2 Mon Sep 17 00:00:00 2001 From: Brandon McAnsh Date: Sat, 24 Oct 2026 16:12:02 -0400 Subject: [PATCH 33/50] refactor(kmp): read Compose resources in common code and lift R-only files 13 files that were held in androidMain only by `R` move to commonMain (core-ui 6, ui:components 4, common-ui 2, app:core 1). They read strings and drawables through the generated `Res` with org.jetbrains.compose.resources, on Android as well as desktop, so no Int-id seam is added. ui:components and common-ui gain the Compose resources plugin with the same res-sync block app:core uses. ui:components gets the multiplatform material icons on commonMain and core-ui gets shared:theme there. UnreadSeparator stays in androidMain: its plural items point at other strings with @string/, which Compose resources does not resolve. ComposeResourcesOnAndroidTest renders a converted string and vector under Robolectric, since a missing Compose resource throws at runtime rather than failing the build. --- apps/flipcash/core-ui/build.gradle.kts | 1 + .../flipcash/app/core/ui/ConversionGraphic.kt | 13 ++++-- .../com/flipcash/app/core/ui/DeviceFrame.kt | 10 ++-- .../app/core/ui/NotificationPreview.kt | 15 +++--- .../com/flipcash/app/core/ui/SwitchPreview.kt | 7 +-- .../app/core/ui/TokenSelectionPill.kt | 9 ++-- .../processing/ProcessingLoadingIndicator.kt | 10 ++-- .../flipcash/app/core/extensions/Boolean.kt | 8 ---- .../flipcash/app/core/extensions/Boolean.kt | 10 ++++ .../shared/common-ui/build.gradle.kts | 15 +++++- .../ui/profile/BalanceRequirementsCard.kt | 30 +++++++----- .../common/ui/profile/ProfileStatsCard.kt | 13 ++++-- ui/components/build.gradle.kts | 13 ++++++ .../ComposeResourcesOnAndroidTest.kt | 46 +++++++++++++++++++ .../getcode/ui/components/BetaIndicator.kt | 6 ++- .../com/getcode/ui/components/ListItem.kt | 6 ++- .../getcode/ui/components/SwipeActionRow.kt | 7 +-- .../ui/components/text/ExpandableText.kt | 8 ++-- 18 files changed, 166 insertions(+), 61 deletions(-) rename apps/flipcash/core-ui/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/ui/ConversionGraphic.kt (84%) rename apps/flipcash/core-ui/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/ui/DeviceFrame.kt (83%) rename apps/flipcash/core-ui/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/ui/NotificationPreview.kt (85%) rename apps/flipcash/core-ui/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/ui/SwitchPreview.kt (93%) rename apps/flipcash/core-ui/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/ui/TokenSelectionPill.kt (93%) rename apps/flipcash/core-ui/src/{androidMain => commonMain}/kotlin/com/flipcash/app/core/ui/processing/ProcessingLoadingIndicator.kt (91%) delete mode 100644 apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/extensions/Boolean.kt create mode 100644 apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/extensions/Boolean.kt rename apps/flipcash/shared/common-ui/src/{androidMain => commonMain}/kotlin/com/flipcash/shared/common/ui/profile/BalanceRequirementsCard.kt (83%) rename apps/flipcash/shared/common-ui/src/{androidMain => commonMain}/kotlin/com/flipcash/shared/common/ui/profile/ProfileStatsCard.kt (85%) create mode 100644 ui/components/src/androidHostTest/kotlin/com/getcode/ui/components/ComposeResourcesOnAndroidTest.kt rename ui/components/src/{androidMain => commonMain}/kotlin/com/getcode/ui/components/BetaIndicator.kt (84%) rename ui/components/src/{androidMain => commonMain}/kotlin/com/getcode/ui/components/ListItem.kt (96%) rename ui/components/src/{androidMain => commonMain}/kotlin/com/getcode/ui/components/SwipeActionRow.kt (98%) rename ui/components/src/{androidMain => commonMain}/kotlin/com/getcode/ui/components/text/ExpandableText.kt (93%) diff --git a/apps/flipcash/core-ui/build.gradle.kts b/apps/flipcash/core-ui/build.gradle.kts index 48cdd70695..28e7f1a441 100644 --- a/apps/flipcash/core-ui/build.gradle.kts +++ b/apps/flipcash/core-ui/build.gradle.kts @@ -23,6 +23,7 @@ kotlin { implementation(project(":ui:components")) implementation(project(":ui:resources")) implementation(project(":ui:theme")) + implementation(project(":apps:flipcash:shared:theme")) implementation(libs.jetbrains.compose.runtime) implementation(libs.jetbrains.compose.foundation) diff --git a/apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/ConversionGraphic.kt b/apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/ConversionGraphic.kt similarity index 84% rename from apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/ConversionGraphic.kt rename to apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/ConversionGraphic.kt index a4c2713e51..fd3dae6d9e 100644 --- a/apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/ConversionGraphic.kt +++ b/apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/ConversionGraphic.kt @@ -8,9 +8,12 @@ import androidx.compose.foundation.layout.size import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.res.painterResource +import org.jetbrains.compose.resources.painterResource import androidx.compose.ui.unit.dp -import com.flipcash.core.R +import com.flipcash.core.resources.Res +import com.flipcash.core.resources.ic_arrow_right +import com.flipcash.core.resources.ic_coin_dollars +import com.flipcash.core.resources.ic_usdc_on_solana /** * A coin face the [ConversionGraphic] can show on either side of the arrow. @@ -50,7 +53,7 @@ fun ConversionGraphic( // Nudged onto the coin faces' centre line, which the top alignment above leaves at // 50 dp: (100 - 28) / 2. modifier = Modifier.padding(top = 36.dp).size(28.dp), - painter = painterResource(R.drawable.ic_arrow_right), + painter = painterResource(Res.drawable.ic_arrow_right), contentDescription = null, ) Coin(to) @@ -62,13 +65,13 @@ private fun Coin(coin: ConversionCoin) { when (coin) { ConversionCoin.Dollars -> Image( modifier = Modifier.size(100.dp), - painter = painterResource(R.drawable.ic_coin_dollars), + painter = painterResource(Res.drawable.ic_coin_dollars), contentDescription = null, ) // Natural size (111x112): the 100 dp coin plus the badge overhanging its corner. ConversionCoin.UsdcOnSolana -> Image( - painter = painterResource(R.drawable.ic_usdc_on_solana), + painter = painterResource(Res.drawable.ic_usdc_on_solana), contentDescription = null, ) } diff --git a/apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/DeviceFrame.kt b/apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/DeviceFrame.kt similarity index 83% rename from apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/DeviceFrame.kt rename to apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/DeviceFrame.kt index 7dcc411002..f32900a3cc 100644 --- a/apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/DeviceFrame.kt +++ b/apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/DeviceFrame.kt @@ -8,9 +8,11 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip -import androidx.compose.ui.res.painterResource +import org.jetbrains.compose.resources.painterResource import androidx.compose.ui.unit.dp -import com.flipcash.core.R +import com.flipcash.core.resources.Res +import com.flipcash.core.resources.ic_device_frame +import com.flipcash.core.resources.ic_screen_frame @Composable fun ScreenFrame( @@ -20,7 +22,7 @@ fun ScreenFrame( ) { Box(modifier = modifier, contentAlignment = Alignment.TopCenter) { Image( - painter = painterResource(id = R.drawable.ic_screen_frame), + painter = painterResource(Res.drawable.ic_screen_frame), contentDescription = "", ) Box( @@ -43,7 +45,7 @@ fun DeviceFrame( ) { Box(modifier = modifier, contentAlignment = Alignment.TopCenter) { Image( - painter = painterResource(id = R.drawable.ic_device_frame), + painter = painterResource(Res.drawable.ic_device_frame), contentDescription = "", ) // Inner viewport clipped to frame edge diff --git a/apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/NotificationPreview.kt b/apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/NotificationPreview.kt similarity index 85% rename from apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/NotificationPreview.kt rename to apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/NotificationPreview.kt index 5deabe0aad..95b26f7160 100644 --- a/apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/NotificationPreview.kt +++ b/apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/NotificationPreview.kt @@ -19,16 +19,19 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource +import org.jetbrains.compose.resources.painterResource +import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.flipcash.app.theme.FlipcashPreview -import com.flipcash.core.R import com.getcode.theme.CodeTheme +import com.flipcash.core.resources.Res +import com.flipcash.core.resources.ic_notification_preview_icon +import com.flipcash.core.resources.notification_preview_body +import com.flipcash.core.resources.notification_preview_title @Composable fun NotificationPreview( @@ -53,7 +56,7 @@ fun NotificationPreview( .fillMaxHeight() .requiredSize(32.dp) .aspectRatio(1f), - painter = painterResource(R.drawable.ic_notification_preview_icon), + painter = painterResource(Res.drawable.ic_notification_preview_icon), contentDescription = null, ) Spacer(modifier = Modifier.width(8.dp)) @@ -96,8 +99,8 @@ fun NotificationPreview( fun Preview_Notification() { FlipcashPreview { NotificationPreview( - title = stringResource(R.string.notification_preview_title), - body = stringResource(R.string.notification_preview_body), + title = stringResource(Res.string.notification_preview_title), + body = stringResource(Res.string.notification_preview_body), ) } } \ No newline at end of file diff --git a/apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/SwitchPreview.kt b/apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/SwitchPreview.kt similarity index 93% rename from apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/SwitchPreview.kt rename to apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/SwitchPreview.kt index 5ed02e05eb..00b915a662 100644 --- a/apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/SwitchPreview.kt +++ b/apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/SwitchPreview.kt @@ -20,15 +20,16 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.graphicsLayer -import androidx.compose.ui.res.stringResource +import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.flipcash.app.theme.FlipcashPreview -import com.flipcash.core.R import com.getcode.theme.CodeTheme +import com.flipcash.core.resources.Res +import com.flipcash.core.resources.title_allowNotifications @Composable fun SwitchPreview(modifier: Modifier = Modifier, checked: Boolean = false) { @@ -45,7 +46,7 @@ fun SwitchPreview(modifier: Modifier = Modifier, checked: Boolean = false) { ) { Text( modifier = Modifier.weight(1f), - text = stringResource(R.string.title_allowNotifications), + text = stringResource(Res.string.title_allowNotifications), fontSize = 14.sp, fontFamily = FontFamily.Default, fontWeight = FontWeight.Medium diff --git a/apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/TokenSelectionPill.kt b/apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/TokenSelectionPill.kt similarity index 93% rename from apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/TokenSelectionPill.kt rename to apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/TokenSelectionPill.kt index ec82200dd9..d5199efa4f 100644 --- a/apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/TokenSelectionPill.kt +++ b/apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/TokenSelectionPill.kt @@ -18,12 +18,13 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color -import androidx.compose.ui.res.painterResource +import org.jetbrains.compose.resources.painterResource import androidx.compose.ui.text.TextStyle import androidx.compose.ui.unit.Dp import com.getcode.opencode.model.financial.Token import com.getcode.theme.CodeTheme -import com.getcode.ui.core.R +import com.getcode.util.resources.Res +import com.getcode.util.resources.ic_dropdown @Composable fun TokenSelectionPill( @@ -64,7 +65,7 @@ fun TokenSelectionPill( Image( modifier = Modifier .size(CodeTheme.dimens.grid.x4), - painter = painterResource(R.drawable.ic_dropdown), + painter = painterResource(Res.drawable.ic_dropdown), contentDescription = "" ) } @@ -105,7 +106,7 @@ fun TokenSelectionPill( Image( modifier = Modifier .width(CodeTheme.dimens.grid.x4), - painter = painterResource(R.drawable.ic_dropdown), + painter = painterResource(Res.drawable.ic_dropdown), contentDescription = "" ) } diff --git a/apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/processing/ProcessingLoadingIndicator.kt b/apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/processing/ProcessingLoadingIndicator.kt similarity index 91% rename from apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/processing/ProcessingLoadingIndicator.kt rename to apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/processing/ProcessingLoadingIndicator.kt index d91b21dfc6..ab9dfa1cca 100644 --- a/apps/flipcash/core-ui/src/androidMain/kotlin/com/flipcash/app/core/ui/processing/ProcessingLoadingIndicator.kt +++ b/apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/processing/ProcessingLoadingIndicator.kt @@ -20,8 +20,7 @@ import androidx.compose.runtime.withFrameMillis import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.StrokeCap -import androidx.compose.ui.res.painterResource -import com.flipcash.core.R +import org.jetbrains.compose.resources.painterResource import com.getcode.theme.CodeTheme import com.getcode.ui.theme.CodeCircularProgressIndicator import com.getcode.view.LoadingSuccessState @@ -29,6 +28,9 @@ import kotlinx.coroutines.isActive import kotlin.math.pow import kotlin.time.Duration import kotlin.time.Duration.Companion.seconds +import com.flipcash.core.resources.Res +import com.flipcash.core.resources.ic_circle_check_large +import com.flipcash.core.resources.ic_circle_exclamation_large @Composable fun ProcessingLoadingIndicator( @@ -96,7 +98,7 @@ fun ProcessingLoadingIndicator( when (targetState) { LoadingSuccessState.State.Error -> Image( modifier = modifier, - painter = painterResource(R.drawable.ic_circle_exclamation_large), + painter = painterResource(Res.drawable.ic_circle_exclamation_large), contentDescription = null, ) LoadingSuccessState.State.Idle -> Spacer(modifier) @@ -110,7 +112,7 @@ fun ProcessingLoadingIndicator( ) LoadingSuccessState.State.Success -> Image( modifier = modifier, - painter = painterResource(R.drawable.ic_circle_check_large), + painter = painterResource(Res.drawable.ic_circle_check_large), contentDescription = null, ) } diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/extensions/Boolean.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/extensions/Boolean.kt deleted file mode 100644 index fd1cd833fe..0000000000 --- a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/extensions/Boolean.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.flipcash.app.core.extensions - -import androidx.compose.runtime.Composable -import androidx.compose.ui.res.stringResource -import com.flipcash.core.R - -@Composable -fun Boolean.toYesOrNo() = if (this) stringResource(R.string.label_yes) else stringResource(R.string.label_no) \ No newline at end of file diff --git a/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/extensions/Boolean.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/extensions/Boolean.kt new file mode 100644 index 0000000000..b2c7209ca9 --- /dev/null +++ b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/extensions/Boolean.kt @@ -0,0 +1,10 @@ +package com.flipcash.app.core.extensions + +import androidx.compose.runtime.Composable +import org.jetbrains.compose.resources.stringResource +import com.flipcash.core.resources.Res +import com.flipcash.core.resources.label_no +import com.flipcash.core.resources.label_yes + +@Composable +fun Boolean.toYesOrNo() = if (this) stringResource(Res.string.label_yes) else stringResource(Res.string.label_no) \ No newline at end of file diff --git a/apps/flipcash/shared/common-ui/build.gradle.kts b/apps/flipcash/shared/common-ui/build.gradle.kts index 309e27b1db..9d5e1a37f5 100644 --- a/apps/flipcash/shared/common-ui/build.gradle.kts +++ b/apps/flipcash/shared/common-ui/build.gradle.kts @@ -1,6 +1,9 @@ +import com.getcode.buildlogic.resources.androidResAsComposeResources + plugins { alias(libs.plugins.flipcash.kmp.app.library) alias(libs.plugins.compose.compiler) + alias(libs.plugins.jetbrains.compose) } kotlin { @@ -13,6 +16,7 @@ kotlin { sourceSets { commonMain.dependencies { + implementation(libs.jetbrains.compose.components.resources) implementation(libs.jetbrains.compose.animation) implementation(libs.jetbrains.compose.material) implementation(libs.jetbrains.compose.ui.tooling.preview) @@ -21,6 +25,7 @@ kotlin { implementation(project(":ui:theme")) implementation(project(":services:flipcash")) implementation(project(":services:opencode")) + implementation(project(":apps:flipcash:shared:theme")) implementation(libs.jetbrains.compose.runtime) implementation(libs.jetbrains.compose.foundation) @@ -33,7 +38,6 @@ kotlin { implementation(project(":ui:components")) implementation(project(":ui:resources")) implementation(project(":libs:datetime")) - implementation(project(":apps:flipcash:shared:theme")) implementation(project.dependencies.platform(libs.compose.bom)) implementation(libs.bundles.compose) implementation(libs.bundles.haze) @@ -47,3 +51,12 @@ kotlin { } } } + +compose.resources { + publicResClass = true + packageOfResClass = "${Gradle.flipcashNamespace}.shared.common.ui.resources" + customDirectory( + sourceSetName = "commonMain", + directoryProvider = androidResAsComposeResources(), + ) +} diff --git a/apps/flipcash/shared/common-ui/src/androidMain/kotlin/com/flipcash/shared/common/ui/profile/BalanceRequirementsCard.kt b/apps/flipcash/shared/common-ui/src/commonMain/kotlin/com/flipcash/shared/common/ui/profile/BalanceRequirementsCard.kt similarity index 83% rename from apps/flipcash/shared/common-ui/src/androidMain/kotlin/com/flipcash/shared/common/ui/profile/BalanceRequirementsCard.kt rename to apps/flipcash/shared/common-ui/src/commonMain/kotlin/com/flipcash/shared/common/ui/profile/BalanceRequirementsCard.kt index 7efce6668d..89e1b059fd 100644 --- a/apps/flipcash/shared/common-ui/src/androidMain/kotlin/com/flipcash/shared/common/ui/profile/BalanceRequirementsCard.kt +++ b/apps/flipcash/shared/common-ui/src/commonMain/kotlin/com/flipcash/shared/common/ui/profile/BalanceRequirementsCard.kt @@ -24,15 +24,23 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource +import org.jetbrains.compose.resources.painterResource +import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewWrapper import androidx.compose.ui.unit.dp import com.flipcash.app.theme.FlipcashThemeWrapper -import com.flipcash.shared.common.ui.R import com.getcode.theme.CodeTheme import com.getcode.theme.White05 +import com.flipcash.shared.common.ui.resources.Res as CommonUiRes +import com.flipcash.shared.common.ui.resources.label_balanceRequirementChat +import com.flipcash.shared.common.ui.resources.label_balanceRequirementCommunityCurrency +import com.flipcash.shared.common.ui.resources.label_balanceRequirementJoin +import com.flipcash.shared.common.ui.resources.label_balanceRequirementNone +import com.flipcash.shared.common.ui.resources.label_yourBalance +import com.flipcash.shared.common.ui.resources.title_balanceRequirements +import com.getcode.util.resources.Res as UiRes +import com.getcode.util.resources.ic_chevron_right private val RowHeight = 56.dp private val CompactRowHeight = 48.dp @@ -69,7 +77,7 @@ fun BalanceRequirementsCard( verticalArrangement = Arrangement.spacedBy(if (compact) 8.dp else 16.dp), ) { Text( - text = stringResource(R.string.title_balanceRequirements), + text = stringResource(CommonUiRes.string.title_balanceRequirements), style = if (compact) CodeTheme.typography.textMedium else CodeTheme.typography.textLarge, color = CodeTheme.colors.textMain, ) @@ -84,14 +92,14 @@ fun BalanceRequirementsCard( RowSeparator() } RequirementRow( - label = stringResource(R.string.label_balanceRequirementJoin), - value = join ?: stringResource(R.string.label_balanceRequirementNone), + label = stringResource(CommonUiRes.string.label_balanceRequirementJoin), + value = join ?: stringResource(CommonUiRes.string.label_balanceRequirementNone), compact = compact, ) RowSeparator() RequirementRow( - label = stringResource(R.string.label_balanceRequirementChat), - value = chat ?: stringResource(R.string.label_balanceRequirementNone), + label = stringResource(CommonUiRes.string.label_balanceRequirementChat), + value = chat ?: stringResource(CommonUiRes.string.label_balanceRequirementNone), compact = compact, ) } @@ -118,7 +126,7 @@ fun BalanceRequirementsCard( horizontalArrangement = Arrangement.SpaceBetween, ) { Text( - text = stringResource(R.string.label_yourBalance), + text = stringResource(CommonUiRes.string.label_yourBalance), style = CodeTheme.typography.textSmall, color = CodeTheme.colors.textSecondary, ) @@ -154,13 +162,13 @@ private fun CommunityCurrencyRow(onClick: () -> Unit, content: @Composable RowSc ) { Text( modifier = Modifier.weight(1f), - text = stringResource(R.string.label_balanceRequirementCommunityCurrency), + text = stringResource(CommonUiRes.string.label_balanceRequirementCommunityCurrency), style = CodeTheme.typography.textSmall, color = CodeTheme.colors.textSecondary, ) content() Icon( - painter = painterResource(R.drawable.ic_chevron_right), + painter = painterResource(UiRes.drawable.ic_chevron_right), contentDescription = null, tint = CodeTheme.colors.textSecondary, ) diff --git a/apps/flipcash/shared/common-ui/src/androidMain/kotlin/com/flipcash/shared/common/ui/profile/ProfileStatsCard.kt b/apps/flipcash/shared/common-ui/src/commonMain/kotlin/com/flipcash/shared/common/ui/profile/ProfileStatsCard.kt similarity index 85% rename from apps/flipcash/shared/common-ui/src/androidMain/kotlin/com/flipcash/shared/common/ui/profile/ProfileStatsCard.kt rename to apps/flipcash/shared/common-ui/src/commonMain/kotlin/com/flipcash/shared/common/ui/profile/ProfileStatsCard.kt index 1b3accfba7..53f2374790 100644 --- a/apps/flipcash/shared/common-ui/src/androidMain/kotlin/com/flipcash/shared/common/ui/profile/ProfileStatsCard.kt +++ b/apps/flipcash/shared/common-ui/src/commonMain/kotlin/com/flipcash/shared/common/ui/profile/ProfileStatsCard.kt @@ -15,14 +15,17 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip -import androidx.compose.ui.res.stringResource +import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewWrapper import androidx.compose.ui.unit.dp import com.flipcash.app.theme.FlipcashThemeWrapper -import com.flipcash.shared.common.ui.R import com.getcode.theme.CodeTheme import com.getcode.theme.White05 +import com.flipcash.shared.common.ui.resources.Res +import com.flipcash.shared.common.ui.resources.text_profileStatEmpty +import com.flipcash.shared.common.ui.resources.title_profileDateJoined +import com.flipcash.shared.common.ui.resources.title_profileMinimumToChat private val StatsCardHeight = 84.dp private val LeadingStatWidth = 176.dp @@ -49,7 +52,7 @@ fun ProfileStatsCard( ) { Stat( modifier = Modifier.width(LeadingStatWidth).fillMaxHeight(), - caption = stringResource(R.string.title_profileMinimumToChat), + caption = stringResource(Res.string.title_profileMinimumToChat), value = minimumToChat, ) Box( @@ -60,7 +63,7 @@ fun ProfileStatsCard( ) Stat( modifier = Modifier.weight(1f).fillMaxHeight(), - caption = stringResource(R.string.title_profileDateJoined), + caption = stringResource(Res.string.title_profileDateJoined), value = joined, ) } @@ -84,7 +87,7 @@ private fun Stat( color = CodeTheme.colors.textSecondary, ) Text( - text = value ?: stringResource(R.string.text_profileStatEmpty), + text = value ?: stringResource(Res.string.text_profileStatEmpty), style = CodeTheme.typography.textLarge, color = CodeTheme.colors.textMain, ) diff --git a/ui/components/build.gradle.kts b/ui/components/build.gradle.kts index d578f47feb..8b0494ea60 100644 --- a/ui/components/build.gradle.kts +++ b/ui/components/build.gradle.kts @@ -1,6 +1,9 @@ +import com.getcode.buildlogic.resources.androidResAsComposeResources + plugins { alias(libs.plugins.flipcash.kmp.app.library) alias(libs.plugins.compose.compiler) + alias(libs.plugins.jetbrains.compose) id("org.jetbrains.kotlin.plugin.parcelize") } @@ -19,6 +22,7 @@ kotlin { implementation(libs.jetbrains.compose.material) api(libs.jetbrains.compose.material3) implementation(libs.jetbrains.compose.components.resources) + implementation(libs.jetbrains.compose.material.icons.extended) api(libs.jetbrains.compose.ui.tooling.preview) // api: TopScrollEdge and the app bar take a HazeState, so callers need the type. api(libs.bundles.haze) @@ -59,3 +63,12 @@ kotlin { } } + +compose.resources { + publicResClass = true + packageOfResClass = "${Gradle.codeNamespace}.ui.components.resources" + customDirectory( + sourceSetName = "commonMain", + directoryProvider = androidResAsComposeResources(), + ) +} diff --git a/ui/components/src/androidHostTest/kotlin/com/getcode/ui/components/ComposeResourcesOnAndroidTest.kt b/ui/components/src/androidHostTest/kotlin/com/getcode/ui/components/ComposeResourcesOnAndroidTest.kt new file mode 100644 index 0000000000..42b58770f0 --- /dev/null +++ b/ui/components/src/androidHostTest/kotlin/com/getcode/ui/components/ComposeResourcesOnAndroidTest.kt @@ -0,0 +1,46 @@ +package com.getcode.ui.components + +import androidx.compose.foundation.Image +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.testTag +import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.junit4.createComposeRule +import androidx.compose.ui.test.onNodeWithTag +import androidx.compose.ui.test.onNodeWithText +import com.getcode.theme.DesignSystem +import com.getcode.util.resources.Res +import com.getcode.util.resources.ic_chevron_right +import org.jetbrains.compose.resources.painterResource +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner + +/** + * Common code reads strings and drawables through Compose resources, where Android used to read `R`. + * These check the Android build packages them and resolves them at runtime, not only that it compiles. + */ +@RunWith(RobolectricTestRunner::class) +class ComposeResourcesOnAndroidTest { + + @get:Rule + val composeTestRule = createComposeRule() + + @Test + fun `string from this module resolves`() { + composeTestRule.setContent { DesignSystem { BetaIndicator() } } + composeTestRule.onNodeWithText("Beta").assertIsDisplayed() + } + + @Test + fun `vector drawable from ui resources resolves`() { + composeTestRule.setContent { + Image( + painter = painterResource(Res.drawable.ic_chevron_right), + contentDescription = null, + modifier = Modifier.testTag("chevron"), + ) + } + composeTestRule.onNodeWithTag("chevron").assertIsDisplayed() + } +} diff --git a/ui/components/src/androidMain/kotlin/com/getcode/ui/components/BetaIndicator.kt b/ui/components/src/commonMain/kotlin/com/getcode/ui/components/BetaIndicator.kt similarity index 84% rename from ui/components/src/androidMain/kotlin/com/getcode/ui/components/BetaIndicator.kt rename to ui/components/src/commonMain/kotlin/com/getcode/ui/components/BetaIndicator.kt index 07f15b19fe..48492d1bdd 100644 --- a/ui/components/src/androidMain/kotlin/com/getcode/ui/components/BetaIndicator.kt +++ b/ui/components/src/commonMain/kotlin/com/getcode/ui/components/BetaIndicator.kt @@ -10,8 +10,10 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment.Companion.CenterVertically import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource +import org.jetbrains.compose.resources.stringResource import com.getcode.theme.CodeTheme +import com.getcode.ui.components.resources.Res +import com.getcode.ui.components.resources.subtitle_beta @Composable fun BetaIndicator(modifier: Modifier = Modifier) { @@ -30,7 +32,7 @@ fun BetaIndicator(modifier: Modifier = Modifier) { ) Text( - text = stringResource(R.string.subtitle_beta), + text = stringResource(Res.string.subtitle_beta), style = CodeTheme.typography.textSmall, color = CodeTheme.colors.textSecondary ) diff --git a/ui/components/src/androidMain/kotlin/com/getcode/ui/components/ListItem.kt b/ui/components/src/commonMain/kotlin/com/getcode/ui/components/ListItem.kt similarity index 96% rename from ui/components/src/androidMain/kotlin/com/getcode/ui/components/ListItem.kt rename to ui/components/src/commonMain/kotlin/com/getcode/ui/components/ListItem.kt index d109b9caa3..22ac260a22 100644 --- a/ui/components/src/androidMain/kotlin/com/getcode/ui/components/ListItem.kt +++ b/ui/components/src/commonMain/kotlin/com/getcode/ui/components/ListItem.kt @@ -21,13 +21,15 @@ import androidx.compose.ui.Alignment.Companion.CenterVertically import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.ColorFilter import androidx.compose.ui.graphics.painter.Painter -import androidx.compose.ui.res.painterResource +import org.jetbrains.compose.resources.painterResource import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.getcode.theme.CodeTheme import com.getcode.theme.White20 import com.getcode.ui.theme.CodeToggleSwitch import androidx.compose.foundation.clickable +import com.getcode.util.resources.Res +import com.getcode.util.resources.ic_chevron_right private val ListItemIconSize = 24.dp @@ -152,7 +154,7 @@ object ListItemDefaults { @Composable fun Chevron() { Icon( - painter = painterResource(id = R.drawable.ic_chevron_right), + painter = painterResource(Res.drawable.ic_chevron_right), contentDescription = null, tint = White20, ) diff --git a/ui/components/src/androidMain/kotlin/com/getcode/ui/components/SwipeActionRow.kt b/ui/components/src/commonMain/kotlin/com/getcode/ui/components/SwipeActionRow.kt similarity index 98% rename from ui/components/src/androidMain/kotlin/com/getcode/ui/components/SwipeActionRow.kt rename to ui/components/src/commonMain/kotlin/com/getcode/ui/components/SwipeActionRow.kt index 7ff1638336..4a1ac308b1 100644 --- a/ui/components/src/androidMain/kotlin/com/getcode/ui/components/SwipeActionRow.kt +++ b/ui/components/src/commonMain/kotlin/com/getcode/ui/components/SwipeActionRow.kt @@ -43,7 +43,7 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.Layout import androidx.compose.ui.layout.onSizeChanged import androidx.compose.ui.platform.LocalDensity -import androidx.compose.ui.res.painterResource +import org.jetbrains.compose.resources.painterResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.Constraints import androidx.compose.ui.unit.IntOffset @@ -51,9 +51,10 @@ import com.getcode.theme.CodeTheme import com.getcode.theme.DesignSystem import com.getcode.theme.White50 import androidx.compose.foundation.clickable -import com.getcode.util.resources.R import kotlin.math.abs import kotlinx.coroutines.launch +import com.getcode.util.resources.Res +import com.getcode.util.resources.ic_delete /** * Describes a single action revealed behind the row content on swipe. @@ -111,7 +112,7 @@ fun SwipeActionRow( resetOnDismiss = resetOnDismiss, ) { Icon( - painter = painterResource(R.drawable.ic_delete), + painter = painterResource(Res.drawable.ic_delete), contentDescription = null, tint = Color.White, modifier = Modifier.requiredSize(iconSize), diff --git a/ui/components/src/androidMain/kotlin/com/getcode/ui/components/text/ExpandableText.kt b/ui/components/src/commonMain/kotlin/com/getcode/ui/components/text/ExpandableText.kt similarity index 93% rename from ui/components/src/androidMain/kotlin/com/getcode/ui/components/text/ExpandableText.kt rename to ui/components/src/commonMain/kotlin/com/getcode/ui/components/text/ExpandableText.kt index 7ffc154c5f..846d942efb 100644 --- a/ui/components/src/androidMain/kotlin/com/getcode/ui/components/text/ExpandableText.kt +++ b/ui/components/src/commonMain/kotlin/com/getcode/ui/components/text/ExpandableText.kt @@ -24,14 +24,16 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.res.stringResource +import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import com.getcode.theme.CodeTheme -import com.getcode.ui.components.R import com.getcode.ui.core.debugBounds import com.getcode.ui.core.drawWithGradient +import com.getcode.ui.components.resources.Res +import com.getcode.ui.components.resources.action_showLess +import com.getcode.ui.components.resources.action_showMore @Composable fun ExpandableText( @@ -132,7 +134,7 @@ private fun ExpandVisibilityButton( horizontalArrangement = Arrangement.spacedBy(CodeTheme.dimens.grid.x1) ) { Text( - text = if (isExpanded) stringResource(R.string.action_showLess) else stringResource(R.string.action_showMore), + text = if (isExpanded) stringResource(Res.string.action_showLess) else stringResource(Res.string.action_showMore), style = CodeTheme.typography.textMedium, color = CodeTheme.colors.textMain, ) From 597c4125d1f8202340aaf6fee695bde3b705097e Mon Sep 17 00:00:00 2001 From: Brandon McAnsh Date: Sat, 24 Oct 2026 16:30:49 -0400 Subject: [PATCH 34/50] refactor(resources): read the Int-id lookups through Compose resources Common code read strings and icons through stringRes/painterForResId and per-module id objects (CoreStrings, CoreDrawables, TxStrings, FlagStrings), each an expect object with R on Android and Compose ids on jvm. Call sites now use Res.string.x / Res.drawable.x directly and the id objects are gone. - ResourceHelper gains getString(StringResource, args). The transaction mappers build text outside composition, so Android maps the resource key back to R and jvm calls getString. ResourceHelperStringResourceTest checks the Android path finds the real string. - shared:userflags gets Compose resources; Field.label/hint are StringResource, and the Android-only editor reads them with stringResource. - Currency flags are still looked up by name at runtime on jvm, so ComposeResourceIds stays for the name-keyed ResourceHelper. --- apps/flipcash/core-ui/build.gradle.kts | 1 + .../app/core/ui/CurrencyAppreciationLabel.kt | 16 +++-- .../app/core/ui/onboarding/NewUserTutorial.kt | 29 +++++--- .../core/resources/CoreResources.android.kt | 33 --------- .../app/core/resources/CoreResources.kt | 36 ---------- .../app/core/resources/CoreResources.jvm.kt | 55 --------------- .../balance/internal/WalletScreenContent.kt | 34 ++++++---- .../features/userflags/build.gradle.kts | 1 + .../app/userflags/internal/UserFlagsEditor.kt | 2 +- .../internal/components/EditableRow.kt | 2 +- .../internal/components/EditorSheetContent.kt | 2 +- .../userflags/internal/components/Editors.kt | 2 +- .../ResourceHelperStringResourceTest.kt | 25 +++++++ .../TransactionDetailsMapperTest.kt | 7 +- .../TransactionItemMapperTest.kt | 13 ++-- .../TransactionDetailsContent.kt | 7 +- .../resources/TxResources.android.kt | 34 ---------- .../transactionhistory/ActivityFeedRow.kt | 12 ++-- .../RecentActivitySection.kt | 14 ++-- .../transactionhistory/TransactionDetails.kt | 67 ++++++++++++------- .../TransactionSubtitles.kt | 14 ++-- .../internal/TransactionItemMapper.kt | 14 ++-- .../resources/TxResources.kt | 37 ---------- .../resources/TxResources.jvm.kt | 62 ----------------- .../shared/userflags/build.gradle.kts | 12 ++++ .../app/userflags/FlagStrings.android.kt | 26 ------- .../com/flipcash/app/userflags/Field.kt | 67 ++++++++++++------- .../com/flipcash/app/userflags/FlagStrings.kt | 28 -------- .../flipcash/app/userflags/FlagStrings.jvm.kt | 24 ------- .../util/resources/AndroidResources.kt | 8 +++ .../util/resources/StringRes.android.kt | 15 ----- .../getcode/util/resources/ResourceHelper.kt | 6 ++ .../com/getcode/util/resources/StringRes.kt | 18 ----- .../util/resources/ComposeResourceHelper.kt | 4 ++ .../getcode/util/resources/StringRes.jvm.kt | 16 ----- .../util/resources/FakeResourceHelper.kt | 11 +++ 36 files changed, 259 insertions(+), 495 deletions(-) delete mode 100644 apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/resources/CoreResources.android.kt delete mode 100644 apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/resources/CoreResources.kt delete mode 100644 apps/flipcash/core/src/jvmMain/kotlin/com/flipcash/app/core/resources/CoreResources.jvm.kt create mode 100644 apps/flipcash/shared/transaction-history/src/androidHostTest/kotlin/com/flipcash/shared/transactionhistory/ResourceHelperStringResourceTest.kt delete mode 100644 apps/flipcash/shared/transaction-history/src/androidMain/kotlin/com/flipcash/shared/transactionhistory/resources/TxResources.android.kt delete mode 100644 apps/flipcash/shared/transaction-history/src/commonMain/kotlin/com/flipcash/shared/transactionhistory/resources/TxResources.kt delete mode 100644 apps/flipcash/shared/transaction-history/src/jvmMain/kotlin/com/flipcash/shared/transactionhistory/resources/TxResources.jvm.kt delete mode 100644 apps/flipcash/shared/userflags/src/androidMain/kotlin/com/flipcash/app/userflags/FlagStrings.android.kt delete mode 100644 apps/flipcash/shared/userflags/src/commonMain/kotlin/com/flipcash/app/userflags/FlagStrings.kt delete mode 100644 apps/flipcash/shared/userflags/src/jvmMain/kotlin/com/flipcash/app/userflags/FlagStrings.jvm.kt delete mode 100644 ui/resources/src/androidMain/kotlin/com/getcode/util/resources/StringRes.android.kt delete mode 100644 ui/resources/src/commonMain/kotlin/com/getcode/util/resources/StringRes.kt delete mode 100644 ui/resources/src/jvmMain/kotlin/com/getcode/util/resources/StringRes.jvm.kt diff --git a/apps/flipcash/core-ui/build.gradle.kts b/apps/flipcash/core-ui/build.gradle.kts index 28e7f1a441..d177e08c90 100644 --- a/apps/flipcash/core-ui/build.gradle.kts +++ b/apps/flipcash/core-ui/build.gradle.kts @@ -28,6 +28,7 @@ kotlin { implementation(libs.jetbrains.compose.runtime) implementation(libs.jetbrains.compose.foundation) implementation(libs.jetbrains.compose.ui) + implementation(libs.jetbrains.compose.components.resources) implementation(libs.jetbrains.compose.material) implementation(libs.jetbrains.compose.material3) implementation(libs.jetbrains.compose.material.icons.extended) diff --git a/apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/CurrencyAppreciationLabel.kt b/apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/CurrencyAppreciationLabel.kt index bc05434934..3a420dd8d8 100644 --- a/apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/CurrencyAppreciationLabel.kt +++ b/apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/CurrencyAppreciationLabel.kt @@ -1,5 +1,11 @@ package com.flipcash.app.core.ui +import org.jetbrains.compose.resources.stringResource +import com.flipcash.core.resources.Res +import com.flipcash.core.resources.label_fromAppreciation +import com.flipcash.core.resources.label_fromCurrencyAppreciation +import com.flipcash.core.resources.label_fromCurrencyDepreciation +import com.flipcash.core.resources.label_fromDepreciation import androidx.compose.foundation.background import androidx.compose.foundation.border import androidx.compose.foundation.layout.Arrangement @@ -12,13 +18,11 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import com.flipcash.app.core.money.formattedAppreciation -import com.flipcash.app.core.resources.CoreStrings import com.getcode.opencode.model.financial.Fiat import com.getcode.theme.CodeTheme import com.getcode.theme.White20 import com.getcode.theme.extraSmall import com.getcode.ui.components.text.AnimatedNumberText -import com.getcode.util.resources.stringRes /** Controls the visual treatment of the appreciation badge. */ enum class AppreciationStyle { @@ -88,15 +92,15 @@ fun CurrencyAppreciationLabel( val label = when (style) { AppreciationStyle.Pill -> if (hasAppreciation) { - stringRes(CoreStrings.label_fromAppreciation) + stringResource(Res.string.label_fromAppreciation) } else { - stringRes(CoreStrings.label_fromDepreciation) + stringResource(Res.string.label_fromDepreciation) } AppreciationStyle.Classic -> if (hasAppreciation) { - stringRes(CoreStrings.label_fromCurrencyAppreciation) + stringResource(Res.string.label_fromCurrencyAppreciation) } else { - stringRes(CoreStrings.label_fromCurrencyDepreciation) + stringResource(Res.string.label_fromCurrencyDepreciation) } } Text( diff --git a/apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/onboarding/NewUserTutorial.kt b/apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/onboarding/NewUserTutorial.kt index cb1a56b6c8..2a78b1eda6 100644 --- a/apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/onboarding/NewUserTutorial.kt +++ b/apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/onboarding/NewUserTutorial.kt @@ -1,5 +1,16 @@ package com.flipcash.app.core.ui.onboarding +import org.jetbrains.compose.resources.stringResource +import org.jetbrains.compose.resources.painterResource +import com.flipcash.core.resources.Res +import com.flipcash.core.resources.ic_checked_green +import com.getcode.util.resources.ic_chevron_right +import com.getcode.util.resources.Res as UiRes +import com.flipcash.core.resources.ic_nav_tipcard +import com.flipcash.core.resources.subtitle_addMoney +import com.flipcash.core.resources.subtitle_scanTipCard +import com.flipcash.core.resources.title_addMoney +import com.flipcash.core.resources.title_scanTipCard import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.clickable @@ -26,12 +37,8 @@ import androidx.compose.ui.graphics.vector.rememberVectorPainter import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.compose.ui.util.fastForEach -import com.flipcash.app.core.resources.CoreDrawables -import com.flipcash.app.core.resources.CoreStrings import com.getcode.theme.CodeTheme import com.getcode.theme.extraSmall -import com.getcode.util.resources.painterForResId -import com.getcode.util.resources.stringRes /** * A row in a "what's left to do" checklist. @@ -53,20 +60,20 @@ sealed interface TutorialItem { class AddMoney(override val isCompleted: Boolean) : Wallet { override val title: String - @Composable get() = stringRes(CoreStrings.title_addMoney) + @Composable get() = stringResource(Res.string.title_addMoney) override val description: String - @Composable get() = stringRes(CoreStrings.subtitle_addMoney) + @Composable get() = stringResource(Res.string.subtitle_addMoney) override val icon: Painter @Composable get() = rememberVectorPainter(Icons.Outlined.AddCircleOutline) } class ScanTipCard(override val isCompleted: Boolean) : Wallet { override val title: String - @Composable get() = stringRes(CoreStrings.title_scanTipCard) + @Composable get() = stringResource(Res.string.title_scanTipCard) override val description: String - @Composable get() = stringRes(CoreStrings.subtitle_scanTipCard) + @Composable get() = stringResource(Res.string.subtitle_scanTipCard) override val icon: Painter - @Composable get() = painterForResId(CoreDrawables.ic_nav_tipcard) + @Composable get() = painterResource(Res.drawable.ic_nav_tipcard) } } @@ -137,7 +144,7 @@ private fun OnboardingItemRow( Image( modifier = Modifier.align(Alignment.Top).size(24.dp), painter = if (item.isCompleted) { - painterForResId(CoreDrawables.ic_checked_green) + painterResource(Res.drawable.ic_checked_green) } else { item.icon }, @@ -162,7 +169,7 @@ private fun OnboardingItemRow( } Icon( modifier = Modifier.align(Alignment.CenterVertically).size(16.dp), - painter = painterForResId(CoreDrawables.ic_chevron_right), + painter = painterResource(UiRes.drawable.ic_chevron_right), tint = CodeTheme.colors.textSecondary, contentDescription = null ) diff --git a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/resources/CoreResources.android.kt b/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/resources/CoreResources.android.kt deleted file mode 100644 index fd2dd31111..0000000000 --- a/apps/flipcash/core/src/androidMain/kotlin/com/flipcash/app/core/resources/CoreResources.android.kt +++ /dev/null @@ -1,33 +0,0 @@ -package com.flipcash.app.core.resources - -import com.flipcash.core.R - -@Suppress("PropertyName") -actual object CoreStrings { - actual val title_addMoney: Int = R.string.title_addMoney - actual val subtitle_addMoney: Int = R.string.subtitle_addMoney - actual val title_scanTipCard: Int = R.string.title_scanTipCard - actual val subtitle_scanTipCard: Int = R.string.subtitle_scanTipCard - actual val label_fromAppreciation: Int = R.string.label_fromAppreciation - actual val label_fromDepreciation: Int = R.string.label_fromDepreciation - actual val label_fromCurrencyAppreciation: Int = R.string.label_fromCurrencyAppreciation - actual val label_fromCurrencyDepreciation: Int = R.string.label_fromCurrencyDepreciation - actual val title_recentActivity: Int = R.string.title_recentActivity - actual val label_chatReceipt_yesterday: Int = R.string.label_chatReceipt_yesterday - actual val title_tipOnboarding: Int = R.string.title_tipOnboarding - actual val action_createYourOwnCurrency: Int = R.string.action_createYourOwnCurrency - actual val action_currencyLeaderboard: Int = R.string.action_currencyLeaderboard - actual val action_addDollars: Int = R.string.action_addDollars - actual val action_withdrawDollars: Int = R.string.action_withdrawDollars -} - -@Suppress("PropertyName") -actual object CoreDrawables { - actual val ic_nav_tipcard: Int = R.drawable.ic_nav_tipcard - actual val ic_checked_green: Int = R.drawable.ic_checked_green - actual val ic_chevron_right: Int = R.drawable.ic_chevron_right - actual val ic_coins_add: Int = R.drawable.ic_coins_add - actual val ic_globe: Int = R.drawable.ic_globe - actual val ic_menu_deposit: Int = R.drawable.ic_menu_deposit - actual val ic_menu_withdraw: Int = R.drawable.ic_menu_withdraw -} diff --git a/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/resources/CoreResources.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/resources/CoreResources.kt deleted file mode 100644 index 28e1615421..0000000000 --- a/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/resources/CoreResources.kt +++ /dev/null @@ -1,36 +0,0 @@ -package com.flipcash.app.core.resources - -/** - * `Int` IDs for the `app:core` resources that common UI hands to [com.getcode.util.resources.stringRes] - * and [com.getcode.util.resources.painterForResId]. Android returns the `R` IDs; desktop registers the - * generated Compose resources. - */ -@Suppress("PropertyName") -expect object CoreStrings { - val title_addMoney: Int - val subtitle_addMoney: Int - val title_scanTipCard: Int - val subtitle_scanTipCard: Int - val label_fromAppreciation: Int - val label_fromDepreciation: Int - val label_fromCurrencyAppreciation: Int - val label_fromCurrencyDepreciation: Int - val title_recentActivity: Int - val label_chatReceipt_yesterday: Int - val title_tipOnboarding: Int - val action_createYourOwnCurrency: Int - val action_currencyLeaderboard: Int - val action_addDollars: Int - val action_withdrawDollars: Int -} - -@Suppress("PropertyName") -expect object CoreDrawables { - val ic_nav_tipcard: Int - val ic_checked_green: Int - val ic_chevron_right: Int - val ic_coins_add: Int - val ic_globe: Int - val ic_menu_deposit: Int - val ic_menu_withdraw: Int -} diff --git a/apps/flipcash/core/src/jvmMain/kotlin/com/flipcash/app/core/resources/CoreResources.jvm.kt b/apps/flipcash/core/src/jvmMain/kotlin/com/flipcash/app/core/resources/CoreResources.jvm.kt deleted file mode 100644 index 92b968fcf4..0000000000 --- a/apps/flipcash/core/src/jvmMain/kotlin/com/flipcash/app/core/resources/CoreResources.jvm.kt +++ /dev/null @@ -1,55 +0,0 @@ -package com.flipcash.app.core.resources - -import com.flipcash.core.resources.Res -import com.flipcash.core.resources.ic_checked_green -import com.flipcash.core.resources.ic_nav_tipcard -import com.flipcash.core.resources.label_fromAppreciation -import com.flipcash.core.resources.label_fromCurrencyAppreciation -import com.flipcash.core.resources.label_fromCurrencyDepreciation -import com.flipcash.core.resources.label_fromDepreciation -import com.flipcash.core.resources.subtitle_addMoney -import com.flipcash.core.resources.subtitle_scanTipCard -import com.flipcash.core.resources.title_addMoney -import com.flipcash.core.resources.title_scanTipCard -import com.flipcash.core.resources.title_recentActivity -import com.flipcash.core.resources.label_chatReceipt_yesterday -import com.flipcash.core.resources.title_tipOnboarding -import com.flipcash.core.resources.action_createYourOwnCurrency -import com.flipcash.core.resources.action_currencyLeaderboard -import com.flipcash.core.resources.action_addDollars -import com.flipcash.core.resources.action_withdrawDollars -import com.flipcash.core.resources.ic_coins_add -import com.flipcash.core.resources.ic_globe -import com.flipcash.core.resources.ic_menu_deposit -import com.flipcash.core.resources.ic_menu_withdraw -import com.getcode.util.resources.ComposeResourceIds - -@Suppress("PropertyName") -actual object CoreStrings { - actual val title_addMoney: Int = ComposeResourceIds.register(Res.string.title_addMoney) - actual val subtitle_addMoney: Int = ComposeResourceIds.register(Res.string.subtitle_addMoney) - actual val title_scanTipCard: Int = ComposeResourceIds.register(Res.string.title_scanTipCard) - actual val subtitle_scanTipCard: Int = ComposeResourceIds.register(Res.string.subtitle_scanTipCard) - actual val label_fromAppreciation: Int = ComposeResourceIds.register(Res.string.label_fromAppreciation) - actual val label_fromDepreciation: Int = ComposeResourceIds.register(Res.string.label_fromDepreciation) - actual val label_fromCurrencyAppreciation: Int = ComposeResourceIds.register(Res.string.label_fromCurrencyAppreciation) - actual val label_fromCurrencyDepreciation: Int = ComposeResourceIds.register(Res.string.label_fromCurrencyDepreciation) - actual val title_recentActivity: Int = ComposeResourceIds.register(Res.string.title_recentActivity) - actual val label_chatReceipt_yesterday: Int = ComposeResourceIds.register(Res.string.label_chatReceipt_yesterday) - actual val title_tipOnboarding: Int = ComposeResourceIds.register(Res.string.title_tipOnboarding) - actual val action_createYourOwnCurrency: Int = ComposeResourceIds.register(Res.string.action_createYourOwnCurrency) - actual val action_currencyLeaderboard: Int = ComposeResourceIds.register(Res.string.action_currencyLeaderboard) - actual val action_addDollars: Int = ComposeResourceIds.register(Res.string.action_addDollars) - actual val action_withdrawDollars: Int = ComposeResourceIds.register(Res.string.action_withdrawDollars) -} - -@Suppress("PropertyName") -actual object CoreDrawables { - actual val ic_nav_tipcard: Int = ComposeResourceIds.register(Res.drawable.ic_nav_tipcard) - actual val ic_checked_green: Int = ComposeResourceIds.register(Res.drawable.ic_checked_green) - actual val ic_chevron_right: Int = checkNotNull(ComposeResourceIds.drawableId("ic_chevron_right")) - actual val ic_coins_add: Int = ComposeResourceIds.register(Res.drawable.ic_coins_add) - actual val ic_globe: Int = ComposeResourceIds.register(Res.drawable.ic_globe) - actual val ic_menu_deposit: Int = ComposeResourceIds.register(Res.drawable.ic_menu_deposit) - actual val ic_menu_withdraw: Int = ComposeResourceIds.register(Res.drawable.ic_menu_withdraw) -} diff --git a/apps/flipcash/features/balance/src/commonMain/kotlin/com/flipcash/app/balance/internal/WalletScreenContent.kt b/apps/flipcash/features/balance/src/commonMain/kotlin/com/flipcash/app/balance/internal/WalletScreenContent.kt index 0980c6a663..ffbeaf8506 100644 --- a/apps/flipcash/features/balance/src/commonMain/kotlin/com/flipcash/app/balance/internal/WalletScreenContent.kt +++ b/apps/flipcash/features/balance/src/commonMain/kotlin/com/flipcash/app/balance/internal/WalletScreenContent.kt @@ -1,5 +1,17 @@ package com.flipcash.app.balance.internal +import org.jetbrains.compose.resources.stringResource +import org.jetbrains.compose.resources.painterResource +import com.flipcash.core.resources.Res +import com.flipcash.core.resources.action_addDollars +import com.flipcash.core.resources.action_createYourOwnCurrency +import com.flipcash.core.resources.action_currencyLeaderboard +import com.flipcash.core.resources.action_withdrawDollars +import com.flipcash.core.resources.ic_coins_add +import com.flipcash.core.resources.ic_globe +import com.flipcash.core.resources.ic_menu_deposit +import com.flipcash.core.resources.ic_menu_withdraw +import com.flipcash.core.resources.title_tipOnboarding import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box @@ -52,10 +64,6 @@ import com.flipcash.app.core.navigation.LocalTabBarPadding import com.flipcash.app.core.ui.TileButton import com.flipcash.app.core.ui.TileButtonStyle import com.flipcash.app.tokens.ui.SelectTokenViewModel -import com.flipcash.app.core.resources.CoreDrawables -import com.flipcash.app.core.resources.CoreStrings -import com.getcode.util.resources.painterForResId -import com.getcode.util.resources.stringRes import com.flipcash.shared.transactionhistory.recentActivitySection import com.getcode.theme.CodeTheme import com.getcode.ui.theme.CodeCircularProgressIndicator @@ -213,7 +221,7 @@ internal fun WalletScreenContent( NewUserTutorial( modifier = Modifier.fillMaxWidth() .padding(bottom = CodeTheme.dimens.grid.x5), - title = stringRes(CoreStrings.title_tipOnboarding), + title = stringResource(Res.string.title_tipOnboarding), items = items, ) { item -> when (item) { @@ -322,8 +330,8 @@ internal fun WalletScreenContent( .weight(1f) .aspectRatio(1.45f), style = TileButtonStyle.Spread, - text = stringRes(CoreStrings.action_createYourOwnCurrency), - icon = painterForResId(CoreDrawables.ic_coins_add), + text = stringResource(Res.string.action_createYourOwnCurrency), + icon = painterResource(Res.drawable.ic_coins_add), ) { dispatchEvent(WalletViewModel.Event.OpenScreen(AppRoute.Token.CurrencyCreator)) } @@ -333,8 +341,8 @@ internal fun WalletScreenContent( .weight(1f) .aspectRatio(1.45f), style = TileButtonStyle.Spread, - text = stringRes(CoreStrings.action_currencyLeaderboard), - icon = painterForResId(CoreDrawables.ic_globe), + text = stringResource(Res.string.action_currencyLeaderboard), + icon = painterResource(Res.drawable.ic_globe), ) { dispatchEvent(WalletViewModel.Event.OpenScreen(AppRoute.Token.Discovery)) } @@ -351,8 +359,8 @@ internal fun WalletScreenContent( .weight(1f) .aspectRatio(1.45f), style = TileButtonStyle.Spread, - text = stringRes(CoreStrings.action_addDollars), - icon = painterForResId(CoreDrawables.ic_menu_deposit), + text = stringResource(Res.string.action_addDollars), + icon = painterResource(Res.drawable.ic_menu_deposit), ) { dispatchEvent(WalletViewModel.Event.PresentDepositOptions) } @@ -362,8 +370,8 @@ internal fun WalletScreenContent( .weight(1f) .aspectRatio(1.45f), style = TileButtonStyle.Spread, - text = stringRes(CoreStrings.action_withdrawDollars), - icon = painterForResId(CoreDrawables.ic_menu_withdraw), + text = stringResource(Res.string.action_withdrawDollars), + icon = painterResource(Res.drawable.ic_menu_withdraw), ) { // No preselected mint: the flow opens on the currency picker, which lists // every balance (Dollars included). diff --git a/apps/flipcash/features/userflags/build.gradle.kts b/apps/flipcash/features/userflags/build.gradle.kts index d7b15af12a..6dadce3e46 100644 --- a/apps/flipcash/features/userflags/build.gradle.kts +++ b/apps/flipcash/features/userflags/build.gradle.kts @@ -10,4 +10,5 @@ dependencies { implementation(project(":apps:flipcash:shared:userflags")) implementation(project(":apps:flipcash:shared:region-selection:core")) implementation(project(":libs:messaging")) + implementation(libs.jetbrains.compose.components.resources) } diff --git a/apps/flipcash/features/userflags/src/main/kotlin/com/flipcash/app/userflags/internal/UserFlagsEditor.kt b/apps/flipcash/features/userflags/src/main/kotlin/com/flipcash/app/userflags/internal/UserFlagsEditor.kt index 9cc77a8e41..595aec648b 100644 --- a/apps/flipcash/features/userflags/src/main/kotlin/com/flipcash/app/userflags/internal/UserFlagsEditor.kt +++ b/apps/flipcash/features/userflags/src/main/kotlin/com/flipcash/app/userflags/internal/UserFlagsEditor.kt @@ -95,7 +95,7 @@ private fun UserFlagsEditor( item(contentType = "section_header") { SectionHeader("Overridable") } items( items = state.editableEntries, - key = { it.field.label }, + key = { it.field.label.key }, contentType = { "editable_row" }, ) { entry -> EditableRow( diff --git a/apps/flipcash/features/userflags/src/main/kotlin/com/flipcash/app/userflags/internal/components/EditableRow.kt b/apps/flipcash/features/userflags/src/main/kotlin/com/flipcash/app/userflags/internal/components/EditableRow.kt index 82de8a7386..d9eeb01b1b 100644 --- a/apps/flipcash/features/userflags/src/main/kotlin/com/flipcash/app/userflags/internal/components/EditableRow.kt +++ b/apps/flipcash/features/userflags/src/main/kotlin/com/flipcash/app/userflags/internal/components/EditableRow.kt @@ -20,7 +20,7 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource +import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp import com.flipcash.app.userflags.internal.EditableEntry import com.getcode.theme.CodeTheme diff --git a/apps/flipcash/features/userflags/src/main/kotlin/com/flipcash/app/userflags/internal/components/EditorSheetContent.kt b/apps/flipcash/features/userflags/src/main/kotlin/com/flipcash/app/userflags/internal/components/EditorSheetContent.kt index b26e14916b..748204478a 100644 --- a/apps/flipcash/features/userflags/src/main/kotlin/com/flipcash/app/userflags/internal/components/EditorSheetContent.kt +++ b/apps/flipcash/features/userflags/src/main/kotlin/com/flipcash/app/userflags/internal/components/EditorSheetContent.kt @@ -13,7 +13,7 @@ import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource +import org.jetbrains.compose.resources.stringResource import com.flipcash.app.userflags.FieldEditor import com.flipcash.app.userflags.internal.EditableEntry import com.flipcash.app.userflags.internal.UserFlagsViewModel diff --git a/apps/flipcash/features/userflags/src/main/kotlin/com/flipcash/app/userflags/internal/components/Editors.kt b/apps/flipcash/features/userflags/src/main/kotlin/com/flipcash/app/userflags/internal/components/Editors.kt index 89c1c52a5e..3367a1d3fa 100644 --- a/apps/flipcash/features/userflags/src/main/kotlin/com/flipcash/app/userflags/internal/components/Editors.kt +++ b/apps/flipcash/features/userflags/src/main/kotlin/com/flipcash/app/userflags/internal/components/Editors.kt @@ -19,7 +19,7 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource +import org.jetbrains.compose.resources.stringResource import com.flipcash.app.userflags.FieldEditor import com.flipcash.app.userflags.internal.EditableEntry import com.flipcash.app.userflags.internal.UserFlagsViewModel diff --git a/apps/flipcash/shared/transaction-history/src/androidHostTest/kotlin/com/flipcash/shared/transactionhistory/ResourceHelperStringResourceTest.kt b/apps/flipcash/shared/transaction-history/src/androidHostTest/kotlin/com/flipcash/shared/transactionhistory/ResourceHelperStringResourceTest.kt new file mode 100644 index 0000000000..922511d852 --- /dev/null +++ b/apps/flipcash/shared/transaction-history/src/androidHostTest/kotlin/com/flipcash/shared/transactionhistory/ResourceHelperStringResourceTest.kt @@ -0,0 +1,25 @@ +package com.flipcash.shared.transactionhistory + +import androidx.test.core.app.ApplicationProvider +import com.flipcash.shared.transactionhistory.generated.resources.Res +import com.flipcash.shared.transactionhistory.generated.resources.title_activity_sentTo +import com.getcode.util.resources.AndroidResources +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner +import kotlin.test.assertEquals + +/** + * The transaction mappers build display text outside composition from a Compose [Res] string. On Android + * that goes back to `R` by the resource's key, so this checks the key still finds the real Android string. + */ +@RunWith(RobolectricTestRunner::class) +class ResourceHelperStringResourceTest { + + @Test + fun `compose string resource resolves through Android resources`() { + val resources = AndroidResources(ApplicationProvider.getApplicationContext()) + + assertEquals("Sent to Ann", resources.getString(Res.string.title_activity_sentTo, "Ann")) + } +} diff --git a/apps/flipcash/shared/transaction-history/src/androidHostTest/kotlin/com/flipcash/shared/transactionhistory/TransactionDetailsMapperTest.kt b/apps/flipcash/shared/transaction-history/src/androidHostTest/kotlin/com/flipcash/shared/transactionhistory/TransactionDetailsMapperTest.kt index a0f3b58704..939fd012f4 100644 --- a/apps/flipcash/shared/transaction-history/src/androidHostTest/kotlin/com/flipcash/shared/transactionhistory/TransactionDetailsMapperTest.kt +++ b/apps/flipcash/shared/transaction-history/src/androidHostTest/kotlin/com/flipcash/shared/transactionhistory/TransactionDetailsMapperTest.kt @@ -1,5 +1,8 @@ package com.flipcash.shared.transactionhistory +import com.flipcash.shared.transactionhistory.generated.resources.Res +import com.flipcash.shared.transactionhistory.generated.resources.label_txnDetails_inPerson +import com.flipcash.shared.transactionhistory.generated.resources.title_activity_convert import com.flipcash.app.core.feed.ActivityFeedMessage import com.flipcash.app.core.feed.ActivityFeedMessageWithToken import com.flipcash.app.core.feed.MessageMetadata @@ -39,8 +42,8 @@ import org.junit.Test class TransactionDetailsMapperTest { private val resources = FakeResourceHelper() - .stub(R.string.title_activity_convert, "%1\$s → %2\$s") - .stub(R.string.label_txnDetails_inPerson, "In Person") + .stub(Res.string.title_activity_convert, "%1\$s → %2\$s") + .stub(Res.string.label_txnDetails_inPerson, "In Person") private val mapper = TransactionDetailsMapper(resources) private val knownUserId: ID = listOf(0x0A, 0x0B, 0x0C) diff --git a/apps/flipcash/shared/transaction-history/src/androidHostTest/kotlin/com/flipcash/shared/transactionhistory/TransactionItemMapperTest.kt b/apps/flipcash/shared/transaction-history/src/androidHostTest/kotlin/com/flipcash/shared/transactionhistory/TransactionItemMapperTest.kt index 94ca34ae52..ed776cac70 100644 --- a/apps/flipcash/shared/transaction-history/src/androidHostTest/kotlin/com/flipcash/shared/transactionhistory/TransactionItemMapperTest.kt +++ b/apps/flipcash/shared/transaction-history/src/androidHostTest/kotlin/com/flipcash/shared/transactionhistory/TransactionItemMapperTest.kt @@ -1,5 +1,10 @@ package com.flipcash.shared.transactionhistory +import com.flipcash.shared.transactionhistory.generated.resources.Res +import com.flipcash.shared.transactionhistory.generated.resources.title_activity_convert +import com.flipcash.shared.transactionhistory.generated.resources.title_activity_receivedFrom +import com.flipcash.shared.transactionhistory.generated.resources.title_activity_sentTo +import com.flipcash.shared.transactionhistory.generated.resources.title_activity_tipFrom import com.flipcash.app.core.feed.ActivityFeedMessage import com.flipcash.app.core.feed.ActivityFeedMessageWithToken import com.flipcash.app.core.feed.MessageMetadata @@ -28,10 +33,10 @@ import org.junit.Test class TransactionItemMapperTest { private val resources = FakeResourceHelper() - .stub(R.string.title_activity_tipFrom, "Tip from %1\$s") - .stub(R.string.title_activity_sentTo, "Sent to %1\$s") - .stub(R.string.title_activity_receivedFrom, "Received from %1\$s") - .stub(R.string.title_activity_convert, "%1\$s → %2\$s") + .stub(Res.string.title_activity_tipFrom, "Tip from %1\$s") + .stub(Res.string.title_activity_sentTo, "Sent to %1\$s") + .stub(Res.string.title_activity_receivedFrom, "Received from %1\$s") + .stub(Res.string.title_activity_convert, "%1\$s → %2\$s") private val mapper = TransactionItemMapper(resources) private val knownUserId: ID = listOf(0x0A, 0x0B, 0x0C) diff --git a/apps/flipcash/shared/transaction-history/src/androidMain/kotlin/com/flipcash/shared/transactionhistory/TransactionDetailsContent.kt b/apps/flipcash/shared/transaction-history/src/androidMain/kotlin/com/flipcash/shared/transactionhistory/TransactionDetailsContent.kt index d9e079d448..d41b6ac8db 100644 --- a/apps/flipcash/shared/transaction-history/src/androidMain/kotlin/com/flipcash/shared/transactionhistory/TransactionDetailsContent.kt +++ b/apps/flipcash/shared/transaction-history/src/androidMain/kotlin/com/flipcash/shared/transactionhistory/TransactionDetailsContent.kt @@ -1,5 +1,6 @@ package com.flipcash.shared.transactionhistory +import org.jetbrains.compose.resources.stringResource as composeStringResource import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box @@ -159,7 +160,7 @@ private fun Header( // A person-to-person entry is titled by the person; everything else by what it was. Text( text = details.heading?.takeIf { it.isNotBlank() } - ?: stringResource(details.kind.headingRes), + ?: composeStringResource(details.kind.headingRes), style = CodeTheme.typography.textLarge, color = CodeTheme.colors.textMain, textAlign = TextAlign.Center, @@ -262,7 +263,7 @@ private fun DetailCard(details: TransactionDetails, modifier: Modifier = Modifie details.account?.let { account -> ReceiptLineItem( modifier = Modifier.fillMaxWidth(), - label = stringResource(account.direction.labelRes), + label = composeStringResource(account.direction.labelRes), amount = account.shortAddress, ) } @@ -283,7 +284,7 @@ private fun DetailCard(details: TransactionDetails, modifier: Modifier = Modifie ReceiptLineItem( modifier = Modifier.fillMaxWidth(), label = stringResource(R.string.label_txnDetails_status), - amount = stringResource(details.status.labelRes), + amount = composeStringResource(details.status.labelRes), ) } } diff --git a/apps/flipcash/shared/transaction-history/src/androidMain/kotlin/com/flipcash/shared/transactionhistory/resources/TxResources.android.kt b/apps/flipcash/shared/transaction-history/src/androidMain/kotlin/com/flipcash/shared/transactionhistory/resources/TxResources.android.kt deleted file mode 100644 index 3de9123fd1..0000000000 --- a/apps/flipcash/shared/transaction-history/src/androidMain/kotlin/com/flipcash/shared/transactionhistory/resources/TxResources.android.kt +++ /dev/null @@ -1,34 +0,0 @@ -package com.flipcash.shared.transactionhistory.resources - -import com.flipcash.shared.transactionhistory.R - -@Suppress("PropertyName") -actual object TxStrings { - actual val label_activity_convertFee: Int = R.string.label_activity_convertFee - actual val label_txnDetails_from: Int = R.string.label_txnDetails_from - actual val label_txnDetails_inPerson: Int = R.string.label_txnDetails_inPerson - actual val label_txnDetails_paidWith: Int = R.string.label_txnDetails_paidWith - actual val label_txnDetails_soldFor: Int = R.string.label_txnDetails_soldFor - actual val label_txnDetails_status_completed: Int = R.string.label_txnDetails_status_completed - actual val label_txnDetails_status_failed: Int = R.string.label_txnDetails_status_failed - actual val label_txnDetails_status_pending: Int = R.string.label_txnDetails_status_pending - actual val label_txnDetails_status_unknown: Int = R.string.label_txnDetails_status_unknown - actual val label_txnDetails_to: Int = R.string.label_txnDetails_to - actual val title_activity_convert: Int = R.string.title_activity_convert - actual val title_activity_receivedFrom: Int = R.string.title_activity_receivedFrom - actual val title_activity_sentTo: Int = R.string.title_activity_sentTo - actual val title_activity_tipFrom: Int = R.string.title_activity_tipFrom - actual val title_txnDetails_buy: Int = R.string.title_txnDetails_buy - actual val title_txnDetails_convert: Int = R.string.title_txnDetails_convert - actual val title_txnDetails_deposit: Int = R.string.title_txnDetails_deposit - actual val title_txnDetails_poolPayment: Int = R.string.title_txnDetails_poolPayment - actual val title_txnDetails_sell: Int = R.string.title_txnDetails_sell - actual val title_txnDetails_unknown: Int = R.string.title_txnDetails_unknown - actual val title_txnDetails_withdraw: Int = R.string.title_txnDetails_withdraw - actual val title_txnDetails_youGaveCash: Int = R.string.title_txnDetails_youGaveCash - actual val title_txnDetails_youReceived: Int = R.string.title_txnDetails_youReceived - actual val title_txnDetails_youReceivedCash: Int = R.string.title_txnDetails_youReceivedCash - actual val title_txnDetails_youSent: Int = R.string.title_txnDetails_youSent - actual val title_txnDetails_youSentCashLink: Int = R.string.title_txnDetails_youSentCashLink - actual val title_txnDetails_youTipped: Int = R.string.title_txnDetails_youTipped -} diff --git a/apps/flipcash/shared/transaction-history/src/commonMain/kotlin/com/flipcash/shared/transactionhistory/ActivityFeedRow.kt b/apps/flipcash/shared/transaction-history/src/commonMain/kotlin/com/flipcash/shared/transactionhistory/ActivityFeedRow.kt index 9cc8076280..433ee65bcc 100644 --- a/apps/flipcash/shared/transaction-history/src/commonMain/kotlin/com/flipcash/shared/transactionhistory/ActivityFeedRow.kt +++ b/apps/flipcash/shared/transaction-history/src/commonMain/kotlin/com/flipcash/shared/transactionhistory/ActivityFeedRow.kt @@ -1,7 +1,10 @@ package com.flipcash.shared.transactionhistory -import com.flipcash.shared.transactionhistory.resources.TxStrings -import com.flipcash.app.core.resources.CoreStrings +import org.jetbrains.compose.resources.stringResource +import com.flipcash.core.resources.Res as CoreRes +import com.flipcash.core.resources.label_chatReceipt_yesterday +import com.flipcash.shared.transactionhistory.generated.resources.Res as TxRes +import com.flipcash.shared.transactionhistory.generated.resources.label_activity_convertFee import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -12,7 +15,6 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import com.getcode.util.resources.stringRes import androidx.compose.ui.text.style.TextOverflow import com.flipcash.app.core.ui.ActivityAmount import com.getcode.theme.CodeTheme @@ -82,7 +84,7 @@ fun ActivityFeedRow( maxLines = 1, ) Text( - text = stringRes(TxStrings.label_activity_convertFee, fee.formatted()), + text = stringResource(TxRes.string.label_activity_convertFee, fee.formatted()), style = CodeTheme.typography.textSmall, color = CodeTheme.colors.textSecondary, maxLines = 1, @@ -114,7 +116,7 @@ internal fun formatActivityTimestamp(instant: Instant): String { val time = instant.formatLocalized("h:mm a", is24Hour = is24Hour, if24Hour = "H:mm") return when { dayDiff == 0L -> time - dayDiff == 1L -> stringRes(CoreStrings.label_chatReceipt_yesterday) + dayDiff == 1L -> stringResource(CoreRes.string.label_chatReceipt_yesterday) dayDiff in 2L..6L -> instant.formatLocalized("EEEE") messageDate.year == todayDate.year -> instant.formatLocalized("MMM d") else -> instant.formatLocalized("MMM d, yyyy") diff --git a/apps/flipcash/shared/transaction-history/src/commonMain/kotlin/com/flipcash/shared/transactionhistory/RecentActivitySection.kt b/apps/flipcash/shared/transaction-history/src/commonMain/kotlin/com/flipcash/shared/transactionhistory/RecentActivitySection.kt index bc0c95e73a..3129a06f38 100644 --- a/apps/flipcash/shared/transaction-history/src/commonMain/kotlin/com/flipcash/shared/transactionhistory/RecentActivitySection.kt +++ b/apps/flipcash/shared/transaction-history/src/commonMain/kotlin/com/flipcash/shared/transactionhistory/RecentActivitySection.kt @@ -1,7 +1,11 @@ package com.flipcash.shared.transactionhistory -import com.flipcash.app.core.resources.CoreStrings -import com.flipcash.app.core.resources.CoreDrawables +import org.jetbrains.compose.resources.stringResource +import org.jetbrains.compose.resources.painterResource +import com.flipcash.core.resources.Res +import com.getcode.util.resources.ic_chevron_right +import com.getcode.util.resources.Res as UiRes +import com.flipcash.core.resources.title_recentActivity import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row @@ -16,8 +20,6 @@ import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import com.getcode.util.resources.painterForResId -import com.getcode.util.resources.stringRes import com.getcode.theme.CodeTheme /** @@ -64,13 +66,13 @@ private fun LazyItemScope.RecentActivityHeader(modifier: Modifier) { verticalAlignment = Alignment.CenterVertically, ) { Text( - text = stringRes(CoreStrings.title_recentActivity), + text = stringResource(Res.string.title_recentActivity), style = CodeTheme.typography.screenTitle, color = CodeTheme.colors.textMain, ) Icon( modifier = Modifier.size(CodeTheme.dimens.staticGrid.x3), - painter = painterForResId(CoreDrawables.ic_chevron_right), + painter = painterResource(UiRes.drawable.ic_chevron_right), contentDescription = null, tint = CodeTheme.colors.textSecondary, ) diff --git a/apps/flipcash/shared/transaction-history/src/commonMain/kotlin/com/flipcash/shared/transactionhistory/TransactionDetails.kt b/apps/flipcash/shared/transaction-history/src/commonMain/kotlin/com/flipcash/shared/transactionhistory/TransactionDetails.kt index 2b14ba1ac8..25875474ae 100644 --- a/apps/flipcash/shared/transaction-history/src/commonMain/kotlin/com/flipcash/shared/transactionhistory/TransactionDetails.kt +++ b/apps/flipcash/shared/transaction-history/src/commonMain/kotlin/com/flipcash/shared/transactionhistory/TransactionDetails.kt @@ -1,7 +1,26 @@ package com.flipcash.shared.transactionhistory -import com.flipcash.shared.transactionhistory.resources.TxStrings -import androidx.annotation.StringRes +import com.flipcash.shared.transactionhistory.generated.resources.Res +import com.flipcash.shared.transactionhistory.generated.resources.label_txnDetails_from +import com.flipcash.shared.transactionhistory.generated.resources.label_txnDetails_status_completed +import com.flipcash.shared.transactionhistory.generated.resources.label_txnDetails_status_failed +import com.flipcash.shared.transactionhistory.generated.resources.label_txnDetails_status_pending +import com.flipcash.shared.transactionhistory.generated.resources.label_txnDetails_status_unknown +import com.flipcash.shared.transactionhistory.generated.resources.label_txnDetails_to +import com.flipcash.shared.transactionhistory.generated.resources.title_txnDetails_buy +import com.flipcash.shared.transactionhistory.generated.resources.title_txnDetails_convert +import com.flipcash.shared.transactionhistory.generated.resources.title_txnDetails_deposit +import com.flipcash.shared.transactionhistory.generated.resources.title_txnDetails_poolPayment +import com.flipcash.shared.transactionhistory.generated.resources.title_txnDetails_sell +import com.flipcash.shared.transactionhistory.generated.resources.title_txnDetails_unknown +import com.flipcash.shared.transactionhistory.generated.resources.title_txnDetails_withdraw +import com.flipcash.shared.transactionhistory.generated.resources.title_txnDetails_youGaveCash +import com.flipcash.shared.transactionhistory.generated.resources.title_txnDetails_youReceived +import com.flipcash.shared.transactionhistory.generated.resources.title_txnDetails_youReceivedCash +import com.flipcash.shared.transactionhistory.generated.resources.title_txnDetails_youSent +import com.flipcash.shared.transactionhistory.generated.resources.title_txnDetails_youSentCashLink +import com.flipcash.shared.transactionhistory.generated.resources.title_txnDetails_youTipped +import org.jetbrains.compose.resources.StringResource import com.getcode.opencode.model.financial.Fiat import com.getcode.opencode.model.financial.Token import kotlin.time.Instant @@ -22,20 +41,20 @@ import kotlin.time.Instant * received-cash-link counterpart because collecting one is indistinguishable, in the metadata, * from taking a bill in person — both arrive as an unattributed `ReceivedCrypto`. */ -enum class TransactionKind(@StringRes val headingRes: Int) { - Tipped(TxStrings.title_txnDetails_youTipped), - Received(TxStrings.title_txnDetails_youReceived), - Sent(TxStrings.title_txnDetails_youSent), - GaveCash(TxStrings.title_txnDetails_youGaveCash), - ReceivedCash(TxStrings.title_txnDetails_youReceivedCash), - SentCashLink(TxStrings.title_txnDetails_youSentCashLink), - Buy(TxStrings.title_txnDetails_buy), - Sell(TxStrings.title_txnDetails_sell), - Withdraw(TxStrings.title_txnDetails_withdraw), - Deposit(TxStrings.title_txnDetails_deposit), - Convert(TxStrings.title_txnDetails_convert), - PoolPayment(TxStrings.title_txnDetails_poolPayment), - Unknown(TxStrings.title_txnDetails_unknown), +enum class TransactionKind(val headingRes: StringResource) { + Tipped(Res.string.title_txnDetails_youTipped), + Received(Res.string.title_txnDetails_youReceived), + Sent(Res.string.title_txnDetails_youSent), + GaveCash(Res.string.title_txnDetails_youGaveCash), + ReceivedCash(Res.string.title_txnDetails_youReceivedCash), + SentCashLink(Res.string.title_txnDetails_youSentCashLink), + Buy(Res.string.title_txnDetails_buy), + Sell(Res.string.title_txnDetails_sell), + Withdraw(Res.string.title_txnDetails_withdraw), + Deposit(Res.string.title_txnDetails_deposit), + Convert(Res.string.title_txnDetails_convert), + PoolPayment(Res.string.title_txnDetails_poolPayment), + Unknown(Res.string.title_txnDetails_unknown), } /** @@ -49,9 +68,9 @@ data class TransactionAccount( val address: String, val direction: Direction, ) { - enum class Direction(@StringRes val labelRes: Int) { - To(TxStrings.label_txnDetails_to), - From(TxStrings.label_txnDetails_from), + enum class Direction(val labelRes: StringResource) { + To(Res.string.label_txnDetails_to), + From(Res.string.label_txnDetails_from), } /** Nobody reads the middle of an address; the ends are what someone actually compares. */ @@ -65,11 +84,11 @@ data class TransactionAccount( } /** The entry's settlement state, as the Status row phrases it. */ -enum class TransactionStatus(@StringRes val labelRes: Int) { - Pending(TxStrings.label_txnDetails_status_pending), - Completed(TxStrings.label_txnDetails_status_completed), - Failed(TxStrings.label_txnDetails_status_failed), - Unknown(TxStrings.label_txnDetails_status_unknown), +enum class TransactionStatus(val labelRes: StringResource) { + Pending(Res.string.label_txnDetails_status_pending), + Completed(Res.string.label_txnDetails_status_completed), + Failed(Res.string.label_txnDetails_status_failed), + Unknown(Res.string.label_txnDetails_status_unknown), } /** diff --git a/apps/flipcash/shared/transaction-history/src/commonMain/kotlin/com/flipcash/shared/transactionhistory/TransactionSubtitles.kt b/apps/flipcash/shared/transaction-history/src/commonMain/kotlin/com/flipcash/shared/transactionhistory/TransactionSubtitles.kt index 0d30391d3d..179b716cfa 100644 --- a/apps/flipcash/shared/transaction-history/src/commonMain/kotlin/com/flipcash/shared/transactionhistory/TransactionSubtitles.kt +++ b/apps/flipcash/shared/transaction-history/src/commonMain/kotlin/com/flipcash/shared/transactionhistory/TransactionSubtitles.kt @@ -1,6 +1,10 @@ package com.flipcash.shared.transactionhistory -import com.flipcash.shared.transactionhistory.resources.TxStrings +import com.flipcash.shared.transactionhistory.generated.resources.Res +import com.flipcash.shared.transactionhistory.generated.resources.label_txnDetails_inPerson +import com.flipcash.shared.transactionhistory.generated.resources.label_txnDetails_paidWith +import com.flipcash.shared.transactionhistory.generated.resources.label_txnDetails_soldFor +import com.flipcash.shared.transactionhistory.generated.resources.title_activity_convert import com.getcode.util.resources.ResourceHelper /** @@ -28,22 +32,22 @@ object TransactionSubtitles { * exchanges identities, so "who" is genuinely unanswerable; how it moved is the useful fact. */ fun inPerson(resources: ResourceHelper): String = - resources.getString(TxStrings.label_txnDetails_inPerson) + resources.getString(Res.string.label_txnDetails_inPerson) /** [TransactionKind.Buy] — the mint that was spent, which the amount alone never says. */ fun paidWith(resources: ResourceHelper, tokenName: String): String = - resources.getString(TxStrings.label_txnDetails_paidWith, tokenName) + resources.getString(Res.string.label_txnDetails_paidWith, tokenName) /** [TransactionKind.Sell] — the mint that came back. */ fun soldFor(resources: ResourceHelper, tokenName: String): String = - resources.getString(TxStrings.label_txnDetails_soldFor, tokenName) + resources.getString(Res.string.label_txnDetails_soldFor, tokenName) /** * [TransactionKind.Convert] — both mints, in the same "from → to" shape the activity row's * convert title already uses, so the row and the screen it opens read alike. */ fun converted(resources: ResourceHelper, from: String, to: String): String = - resources.getString(TxStrings.title_activity_convert, from, to) + resources.getString(Res.string.title_activity_convert, from, to) /** [TransactionKind.PoolPayment] — the pool that was paid. */ fun pool(name: String): String? = name.takeIf { it.isNotBlank() } diff --git a/apps/flipcash/shared/transaction-history/src/commonMain/kotlin/com/flipcash/shared/transactionhistory/internal/TransactionItemMapper.kt b/apps/flipcash/shared/transaction-history/src/commonMain/kotlin/com/flipcash/shared/transactionhistory/internal/TransactionItemMapper.kt index 7004d06418..d7644d2403 100644 --- a/apps/flipcash/shared/transaction-history/src/commonMain/kotlin/com/flipcash/shared/transactionhistory/internal/TransactionItemMapper.kt +++ b/apps/flipcash/shared/transaction-history/src/commonMain/kotlin/com/flipcash/shared/transactionhistory/internal/TransactionItemMapper.kt @@ -1,6 +1,10 @@ package com.flipcash.shared.transactionhistory.internal -import com.flipcash.shared.transactionhistory.resources.TxStrings +import com.flipcash.shared.transactionhistory.generated.resources.Res +import com.flipcash.shared.transactionhistory.generated.resources.title_activity_convert +import com.flipcash.shared.transactionhistory.generated.resources.title_activity_receivedFrom +import com.flipcash.shared.transactionhistory.generated.resources.title_activity_sentTo +import com.flipcash.shared.transactionhistory.generated.resources.title_activity_tipFrom import com.flipcash.app.core.feed.ActivityFeedMessageWithToken import com.flipcash.app.core.feed.MessageMetadata import com.flipcash.app.core.feed.MessageSubstitution @@ -82,7 +86,7 @@ private fun convertTitle( convertOf(source.message.metadata) ?: return null val from = source.token?.name?.takeIf { it.isNotBlank() } ?: return null val to = source.toToken?.name?.takeIf { it.isNotBlank() } ?: return null - return resources.getString(TxStrings.title_activity_convert, from, to) + return resources.getString(Res.string.title_activity_convert, from, to) } /** @@ -130,12 +134,12 @@ private fun resolveTitle( val isTip = text.isTipVerb() return when (meta) { is MessageMetadata.ReceivedCrypto -> - if (isTip) resources.getString(TxStrings.title_activity_tipFrom, counterpartyName) - else resources.getString(TxStrings.title_activity_receivedFrom, counterpartyName) + if (isTip) resources.getString(Res.string.title_activity_tipFrom, counterpartyName) + else resources.getString(Res.string.title_activity_receivedFrom, counterpartyName) is MessageMetadata.DirectlySentCrypto -> // "Tipped" already reads as a transitive verb; "Sent" needs the preposition. if (isTip) "$text $counterpartyName" - else resources.getString(TxStrings.title_activity_sentTo, counterpartyName) + else resources.getString(Res.string.title_activity_sentTo, counterpartyName) else -> "$text $counterpartyName" } } diff --git a/apps/flipcash/shared/transaction-history/src/commonMain/kotlin/com/flipcash/shared/transactionhistory/resources/TxResources.kt b/apps/flipcash/shared/transaction-history/src/commonMain/kotlin/com/flipcash/shared/transactionhistory/resources/TxResources.kt deleted file mode 100644 index d707ec3968..0000000000 --- a/apps/flipcash/shared/transaction-history/src/commonMain/kotlin/com/flipcash/shared/transactionhistory/resources/TxResources.kt +++ /dev/null @@ -1,37 +0,0 @@ -package com.flipcash.shared.transactionhistory.resources - -/** - * `Int` IDs for the transaction-history strings that common code hands to - * [com.getcode.util.resources.ResourceHelper] and [com.getcode.util.resources.stringRes]. Android - * returns the `R` IDs; desktop registers the generated Compose resources. - */ -@Suppress("PropertyName") -expect object TxStrings { - val label_activity_convertFee: Int - val label_txnDetails_from: Int - val label_txnDetails_inPerson: Int - val label_txnDetails_paidWith: Int - val label_txnDetails_soldFor: Int - val label_txnDetails_status_completed: Int - val label_txnDetails_status_failed: Int - val label_txnDetails_status_pending: Int - val label_txnDetails_status_unknown: Int - val label_txnDetails_to: Int - val title_activity_convert: Int - val title_activity_receivedFrom: Int - val title_activity_sentTo: Int - val title_activity_tipFrom: Int - val title_txnDetails_buy: Int - val title_txnDetails_convert: Int - val title_txnDetails_deposit: Int - val title_txnDetails_poolPayment: Int - val title_txnDetails_sell: Int - val title_txnDetails_unknown: Int - val title_txnDetails_withdraw: Int - val title_txnDetails_youGaveCash: Int - val title_txnDetails_youReceived: Int - val title_txnDetails_youReceivedCash: Int - val title_txnDetails_youSent: Int - val title_txnDetails_youSentCashLink: Int - val title_txnDetails_youTipped: Int -} diff --git a/apps/flipcash/shared/transaction-history/src/jvmMain/kotlin/com/flipcash/shared/transactionhistory/resources/TxResources.jvm.kt b/apps/flipcash/shared/transaction-history/src/jvmMain/kotlin/com/flipcash/shared/transactionhistory/resources/TxResources.jvm.kt deleted file mode 100644 index c04328f65f..0000000000 --- a/apps/flipcash/shared/transaction-history/src/jvmMain/kotlin/com/flipcash/shared/transactionhistory/resources/TxResources.jvm.kt +++ /dev/null @@ -1,62 +0,0 @@ -package com.flipcash.shared.transactionhistory.resources - -import com.flipcash.shared.transactionhistory.generated.resources.Res -import com.flipcash.shared.transactionhistory.generated.resources.label_activity_convertFee -import com.flipcash.shared.transactionhistory.generated.resources.label_txnDetails_from -import com.flipcash.shared.transactionhistory.generated.resources.label_txnDetails_inPerson -import com.flipcash.shared.transactionhistory.generated.resources.label_txnDetails_paidWith -import com.flipcash.shared.transactionhistory.generated.resources.label_txnDetails_soldFor -import com.flipcash.shared.transactionhistory.generated.resources.label_txnDetails_status_completed -import com.flipcash.shared.transactionhistory.generated.resources.label_txnDetails_status_failed -import com.flipcash.shared.transactionhistory.generated.resources.label_txnDetails_status_pending -import com.flipcash.shared.transactionhistory.generated.resources.label_txnDetails_status_unknown -import com.flipcash.shared.transactionhistory.generated.resources.label_txnDetails_to -import com.flipcash.shared.transactionhistory.generated.resources.title_activity_convert -import com.flipcash.shared.transactionhistory.generated.resources.title_activity_receivedFrom -import com.flipcash.shared.transactionhistory.generated.resources.title_activity_sentTo -import com.flipcash.shared.transactionhistory.generated.resources.title_activity_tipFrom -import com.flipcash.shared.transactionhistory.generated.resources.title_txnDetails_buy -import com.flipcash.shared.transactionhistory.generated.resources.title_txnDetails_convert -import com.flipcash.shared.transactionhistory.generated.resources.title_txnDetails_deposit -import com.flipcash.shared.transactionhistory.generated.resources.title_txnDetails_poolPayment -import com.flipcash.shared.transactionhistory.generated.resources.title_txnDetails_sell -import com.flipcash.shared.transactionhistory.generated.resources.title_txnDetails_unknown -import com.flipcash.shared.transactionhistory.generated.resources.title_txnDetails_withdraw -import com.flipcash.shared.transactionhistory.generated.resources.title_txnDetails_youGaveCash -import com.flipcash.shared.transactionhistory.generated.resources.title_txnDetails_youReceived -import com.flipcash.shared.transactionhistory.generated.resources.title_txnDetails_youReceivedCash -import com.flipcash.shared.transactionhistory.generated.resources.title_txnDetails_youSent -import com.flipcash.shared.transactionhistory.generated.resources.title_txnDetails_youSentCashLink -import com.flipcash.shared.transactionhistory.generated.resources.title_txnDetails_youTipped -import com.getcode.util.resources.ComposeResourceIds - -@Suppress("PropertyName") -actual object TxStrings { - actual val label_activity_convertFee: Int = ComposeResourceIds.register(Res.string.label_activity_convertFee) - actual val label_txnDetails_from: Int = ComposeResourceIds.register(Res.string.label_txnDetails_from) - actual val label_txnDetails_inPerson: Int = ComposeResourceIds.register(Res.string.label_txnDetails_inPerson) - actual val label_txnDetails_paidWith: Int = ComposeResourceIds.register(Res.string.label_txnDetails_paidWith) - actual val label_txnDetails_soldFor: Int = ComposeResourceIds.register(Res.string.label_txnDetails_soldFor) - actual val label_txnDetails_status_completed: Int = ComposeResourceIds.register(Res.string.label_txnDetails_status_completed) - actual val label_txnDetails_status_failed: Int = ComposeResourceIds.register(Res.string.label_txnDetails_status_failed) - actual val label_txnDetails_status_pending: Int = ComposeResourceIds.register(Res.string.label_txnDetails_status_pending) - actual val label_txnDetails_status_unknown: Int = ComposeResourceIds.register(Res.string.label_txnDetails_status_unknown) - actual val label_txnDetails_to: Int = ComposeResourceIds.register(Res.string.label_txnDetails_to) - actual val title_activity_convert: Int = ComposeResourceIds.register(Res.string.title_activity_convert) - actual val title_activity_receivedFrom: Int = ComposeResourceIds.register(Res.string.title_activity_receivedFrom) - actual val title_activity_sentTo: Int = ComposeResourceIds.register(Res.string.title_activity_sentTo) - actual val title_activity_tipFrom: Int = ComposeResourceIds.register(Res.string.title_activity_tipFrom) - actual val title_txnDetails_buy: Int = ComposeResourceIds.register(Res.string.title_txnDetails_buy) - actual val title_txnDetails_convert: Int = ComposeResourceIds.register(Res.string.title_txnDetails_convert) - actual val title_txnDetails_deposit: Int = ComposeResourceIds.register(Res.string.title_txnDetails_deposit) - actual val title_txnDetails_poolPayment: Int = ComposeResourceIds.register(Res.string.title_txnDetails_poolPayment) - actual val title_txnDetails_sell: Int = ComposeResourceIds.register(Res.string.title_txnDetails_sell) - actual val title_txnDetails_unknown: Int = ComposeResourceIds.register(Res.string.title_txnDetails_unknown) - actual val title_txnDetails_withdraw: Int = ComposeResourceIds.register(Res.string.title_txnDetails_withdraw) - actual val title_txnDetails_youGaveCash: Int = ComposeResourceIds.register(Res.string.title_txnDetails_youGaveCash) - actual val title_txnDetails_youReceived: Int = ComposeResourceIds.register(Res.string.title_txnDetails_youReceived) - actual val title_txnDetails_youReceivedCash: Int = ComposeResourceIds.register(Res.string.title_txnDetails_youReceivedCash) - actual val title_txnDetails_youSent: Int = ComposeResourceIds.register(Res.string.title_txnDetails_youSent) - actual val title_txnDetails_youSentCashLink: Int = ComposeResourceIds.register(Res.string.title_txnDetails_youSentCashLink) - actual val title_txnDetails_youTipped: Int = ComposeResourceIds.register(Res.string.title_txnDetails_youTipped) -} diff --git a/apps/flipcash/shared/userflags/build.gradle.kts b/apps/flipcash/shared/userflags/build.gradle.kts index bcb6712ac2..68416a6e07 100644 --- a/apps/flipcash/shared/userflags/build.gradle.kts +++ b/apps/flipcash/shared/userflags/build.gradle.kts @@ -1,6 +1,9 @@ +import com.getcode.buildlogic.resources.androidResAsComposeResources + plugins { alias(libs.plugins.flipcash.kmp.app.library) alias(libs.plugins.compose.compiler) + alias(libs.plugins.jetbrains.compose) alias(libs.plugins.kotlin.ksp) } @@ -14,6 +17,7 @@ kotlin { commonMain.dependencies { implementation(libs.jetbrains.compose.runtime) implementation(libs.jetbrains.compose.foundation) + implementation(libs.jetbrains.compose.components.resources) implementation(libs.androidx.annotation) implementation(libs.androidx.datastore.preferences.core) implementation(libs.javax.inject) @@ -39,6 +43,14 @@ kotlin { } } +compose.resources { + packageOfResClass = "com.flipcash.app.userflags.generated.resources" + customDirectory( + sourceSetName = "commonMain", + directoryProvider = androidResAsComposeResources(), + ) +} + dependencies { add("kspAndroid", libs.hilt.android.compiler) add("kspAndroid", libs.hilt.compiler) diff --git a/apps/flipcash/shared/userflags/src/androidMain/kotlin/com/flipcash/app/userflags/FlagStrings.android.kt b/apps/flipcash/shared/userflags/src/androidMain/kotlin/com/flipcash/app/userflags/FlagStrings.android.kt deleted file mode 100644 index bf9407fcfc..0000000000 --- a/apps/flipcash/shared/userflags/src/androidMain/kotlin/com/flipcash/app/userflags/FlagStrings.android.kt +++ /dev/null @@ -1,26 +0,0 @@ -package com.flipcash.app.userflags - -import com.flipcash.shared.userflags.R - -internal actual object FlagStrings { - actual val hint_flag_billExchangeDataTimeout: Int = R.string.hint_flag_billExchangeDataTimeout - actual val hint_flag_messageDeleteWindow: Int = R.string.hint_flag_messageDeleteWindow - actual val hint_flag_messageEditWindow: Int = R.string.hint_flag_messageEditWindow - actual val hint_flag_minHolderAmount: Int = R.string.hint_flag_minHolderAmount - actual val hint_flag_minimumVersion: Int = R.string.hint_flag_minimumVersion - actual val hint_flag_newCurrencyFeeAmount: Int = R.string.hint_flag_newCurrencyFeeAmount - actual val hint_flag_newCurrencyPurchaseAmount: Int = R.string.hint_flag_newCurrencyPurchaseAmount - actual val hint_flag_withdrawalFeeAmount: Int = R.string.hint_flag_withdrawalFeeAmount - actual val label_flag_billExchangeDataTimeout: Int = R.string.label_flag_billExchangeDataTimeout - actual val label_flag_messageDeleteWindow: Int = R.string.label_flag_messageDeleteWindow - actual val label_flag_messageEditWindow: Int = R.string.label_flag_messageEditWindow - actual val label_flag_minHolderAmount: Int = R.string.label_flag_minHolderAmount - actual val label_flag_minimumVersion: Int = R.string.label_flag_minimumVersion - actual val label_flag_newCurrencyFeeAmount: Int = R.string.label_flag_newCurrencyFeeAmount - actual val label_flag_newCurrencyPurchaseAmount: Int = R.string.label_flag_newCurrencyPurchaseAmount - actual val label_flag_preferredProvider: Int = R.string.label_flag_preferredProvider - actual val label_flag_preferredUsdcLiquidityPool: Int = R.string.label_flag_preferredUsdcLiquidityPool - actual val label_flag_requireCoinbaseEmailVerification: Int = R.string.label_flag_requireCoinbaseEmailVerification - actual val label_flag_supportedOnRampProviders: Int = R.string.label_flag_supportedOnRampProviders - actual val label_flag_withdrawalFeeAmount: Int = R.string.label_flag_withdrawalFeeAmount -} diff --git a/apps/flipcash/shared/userflags/src/commonMain/kotlin/com/flipcash/app/userflags/Field.kt b/apps/flipcash/shared/userflags/src/commonMain/kotlin/com/flipcash/app/userflags/Field.kt index 6f94b50caa..6579f2d0b9 100644 --- a/apps/flipcash/shared/userflags/src/commonMain/kotlin/com/flipcash/app/userflags/Field.kt +++ b/apps/flipcash/shared/userflags/src/commonMain/kotlin/com/flipcash/app/userflags/Field.kt @@ -1,6 +1,27 @@ package com.flipcash.app.userflags -import androidx.annotation.StringRes +import org.jetbrains.compose.resources.StringResource +import com.flipcash.app.userflags.generated.resources.Res +import com.flipcash.app.userflags.generated.resources.hint_flag_billExchangeDataTimeout +import com.flipcash.app.userflags.generated.resources.hint_flag_messageDeleteWindow +import com.flipcash.app.userflags.generated.resources.hint_flag_messageEditWindow +import com.flipcash.app.userflags.generated.resources.hint_flag_minHolderAmount +import com.flipcash.app.userflags.generated.resources.hint_flag_minimumVersion +import com.flipcash.app.userflags.generated.resources.hint_flag_newCurrencyFeeAmount +import com.flipcash.app.userflags.generated.resources.hint_flag_newCurrencyPurchaseAmount +import com.flipcash.app.userflags.generated.resources.hint_flag_withdrawalFeeAmount +import com.flipcash.app.userflags.generated.resources.label_flag_billExchangeDataTimeout +import com.flipcash.app.userflags.generated.resources.label_flag_messageDeleteWindow +import com.flipcash.app.userflags.generated.resources.label_flag_messageEditWindow +import com.flipcash.app.userflags.generated.resources.label_flag_minHolderAmount +import com.flipcash.app.userflags.generated.resources.label_flag_minimumVersion +import com.flipcash.app.userflags.generated.resources.label_flag_newCurrencyFeeAmount +import com.flipcash.app.userflags.generated.resources.label_flag_newCurrencyPurchaseAmount +import com.flipcash.app.userflags.generated.resources.label_flag_preferredProvider +import com.flipcash.app.userflags.generated.resources.label_flag_preferredUsdcLiquidityPool +import com.flipcash.app.userflags.generated.resources.label_flag_requireCoinbaseEmailVerification +import com.flipcash.app.userflags.generated.resources.label_flag_supportedOnRampProviders +import com.flipcash.app.userflags.generated.resources.label_flag_withdrawalFeeAmount import androidx.compose.foundation.text.input.InputTransformation import androidx.compose.foundation.text.input.OutputTransformation import androidx.compose.foundation.text.input.insert @@ -22,8 +43,8 @@ sealed class Field( val preferenceKey: Preferences.Key, val encode: (Domain) -> Stored, val decode: (Stored) -> Domain?, - @get:StringRes val label: Int, - @get:StringRes val hint: Int = label, + val label: StringResource, + val hint: StringResource = label, val format: (Domain) -> String, val editFormat: (Domain) -> String = format, val editor: FieldEditor, @@ -34,7 +55,7 @@ sealed class Field( stringPreferencesKey("override_preferred_provider"), encode = { it?.encode() ?: "None" }, decode = { decodeOnRampProvider(it) }, - label = FlagStrings.label_flag_preferredProvider, + label = Res.string.label_flag_preferredProvider, format = { provider -> provider?.displayName() ?: "None" }, editor = FieldEditor.SingleSelect( options = listOf( @@ -56,7 +77,7 @@ sealed class Field( else -> "${providers.size} selected" } }, - label = FlagStrings.label_flag_supportedOnRampProviders, + label = Res.string.label_flag_supportedOnRampProviders, editor = FieldEditor.MultiSelect( options = listOf( "Manual Deposit" to OnRampProvider.ManualDeposit, @@ -70,8 +91,8 @@ sealed class Field( intPreferencesKey("override_min_version"), encode = { it ?: 0 }, decode = { it }, - label = FlagStrings.label_flag_minimumVersion, - hint = FlagStrings.hint_flag_minimumVersion, + label = Res.string.label_flag_minimumVersion, + hint = Res.string.hint_flag_minimumVersion, format = { it.toString() }, editor = FieldEditor.TextInput( keyboard = KeyboardType.Number, @@ -86,8 +107,8 @@ sealed class Field( longPreferencesKey("override_bill_timeout"), encode = { it?.inWholeMilliseconds ?: -1L }, decode = { if (it < 0) null else it.milliseconds }, - label = FlagStrings.label_flag_billExchangeDataTimeout, - hint = FlagStrings.hint_flag_billExchangeDataTimeout, + label = Res.string.label_flag_billExchangeDataTimeout, + hint = Res.string.hint_flag_billExchangeDataTimeout, format = { it?.let { "${it.inWholeSeconds}s" } ?: "None" }, editFormat = { it?.inWholeSeconds?.toString() ?: "" }, editor = FieldEditor.TextInput( @@ -108,8 +129,8 @@ sealed class Field( longPreferencesKey("override_message_edit_window"), encode = { it?.inWholeMilliseconds ?: -1L }, decode = { if (it < 0) null else it.milliseconds }, - label = FlagStrings.label_flag_messageEditWindow, - hint = FlagStrings.hint_flag_messageEditWindow, + label = Res.string.label_flag_messageEditWindow, + hint = Res.string.hint_flag_messageEditWindow, format = { it?.let { "${it.inWholeSeconds}s" } ?: "None" }, editFormat = { it?.inWholeSeconds?.toString() ?: "" }, editor = FieldEditor.TextInput( @@ -125,8 +146,8 @@ sealed class Field( longPreferencesKey("override_message_delete_window"), encode = { it?.inWholeMilliseconds ?: -1L }, decode = { if (it < 0) null else it.milliseconds }, - label = FlagStrings.label_flag_messageDeleteWindow, - hint = FlagStrings.hint_flag_messageDeleteWindow, + label = Res.string.label_flag_messageDeleteWindow, + hint = Res.string.hint_flag_messageDeleteWindow, format = { it?.let { "${it.inWholeSeconds}s" } ?: "None" }, editFormat = { it?.inWholeSeconds?.toString() ?: "" }, editor = FieldEditor.TextInput( @@ -142,8 +163,8 @@ sealed class Field( longPreferencesKey("override_new_currency_amount"), encode = { it.quarks }, decode = { Fiat(quarks = it) }, - label = FlagStrings.label_flag_newCurrencyPurchaseAmount, - hint = FlagStrings.hint_flag_newCurrencyPurchaseAmount, + label = Res.string.label_flag_newCurrencyPurchaseAmount, + hint = Res.string.hint_flag_newCurrencyPurchaseAmount, format = { it.formatted(rule = Fiat.FormattingRule.Truncated) }, editFormat = { it.formatted(showPrefix = false, rule = Fiat.FormattingRule.Truncated) }, editor = FieldEditor.TextInput( @@ -161,8 +182,8 @@ sealed class Field( longPreferencesKey("override_new_fee_amount"), encode = { it.quarks }, decode = { Fiat(quarks = it) }, - label = FlagStrings.label_flag_newCurrencyFeeAmount, - hint = FlagStrings.hint_flag_newCurrencyFeeAmount, + label = Res.string.label_flag_newCurrencyFeeAmount, + hint = Res.string.hint_flag_newCurrencyFeeAmount, format = { it.formatted(rule = Fiat.FormattingRule.Truncated) }, editFormat = { it.formatted(showPrefix = false, rule = Fiat.FormattingRule.Truncated) }, editor = FieldEditor.TextInput( @@ -180,8 +201,8 @@ sealed class Field( longPreferencesKey("override_withdrawal_fee_amount"), encode = { it.quarks }, decode = { Fiat(quarks = it) }, - label = FlagStrings.label_flag_withdrawalFeeAmount, - hint = FlagStrings.hint_flag_withdrawalFeeAmount, + label = Res.string.label_flag_withdrawalFeeAmount, + hint = Res.string.hint_flag_withdrawalFeeAmount, format = { it.formatted(rule = Fiat.FormattingRule.Truncated) }, editFormat = { it.formatted(showPrefix = false, rule = Fiat.FormattingRule.Truncated) }, editor = FieldEditor.TextInput( @@ -199,7 +220,7 @@ sealed class Field( stringPreferencesKey("override_preferred_liquidity_pool"), encode = { it.name }, decode = { runCatching { UsdcLiquidtyPool.valueOf(it) }.getOrNull() }, - label = FlagStrings.label_flag_preferredUsdcLiquidityPool, + label = Res.string.label_flag_preferredUsdcLiquidityPool, format = { provider -> provider.displayName() }, editor = FieldEditor.SingleSelect( options = listOf( @@ -213,7 +234,7 @@ sealed class Field( booleanPreferencesKey("override_require_coinbase_email_verification"), encode = { it }, decode = { it }, - label = FlagStrings.label_flag_requireCoinbaseEmailVerification, + label = Res.string.label_flag_requireCoinbaseEmailVerification, format = { if (it) "Yes" else "No" }, editor = FieldEditor.SingleSelect( options = listOf("Yes" to true, "No" to false) @@ -224,8 +245,8 @@ sealed class Field( longPreferencesKey("override_min_holder_amount"), encode = { it.quarks }, decode = { Fiat(quarks = it) }, - label = FlagStrings.label_flag_minHolderAmount, - hint = FlagStrings.hint_flag_minHolderAmount, + label = Res.string.label_flag_minHolderAmount, + hint = Res.string.hint_flag_minHolderAmount, format = { it.formatted(rule = Fiat.FormattingRule.Truncated) }, editFormat = { it.formatted(showPrefix = false, rule = Fiat.FormattingRule.Truncated) }, editor = FieldEditor.TextInput( diff --git a/apps/flipcash/shared/userflags/src/commonMain/kotlin/com/flipcash/app/userflags/FlagStrings.kt b/apps/flipcash/shared/userflags/src/commonMain/kotlin/com/flipcash/app/userflags/FlagStrings.kt deleted file mode 100644 index f7923bed81..0000000000 --- a/apps/flipcash/shared/userflags/src/commonMain/kotlin/com/flipcash/app/userflags/FlagStrings.kt +++ /dev/null @@ -1,28 +0,0 @@ -package com.flipcash.app.userflags - -/** - * String resource ids for the debug flag editor's labels and hints. Android reads them from - * this module's `R`; desktop has no flag editor, so its ids are 0. - */ -internal expect object FlagStrings { - val hint_flag_billExchangeDataTimeout: Int - val hint_flag_messageDeleteWindow: Int - val hint_flag_messageEditWindow: Int - val hint_flag_minHolderAmount: Int - val hint_flag_minimumVersion: Int - val hint_flag_newCurrencyFeeAmount: Int - val hint_flag_newCurrencyPurchaseAmount: Int - val hint_flag_withdrawalFeeAmount: Int - val label_flag_billExchangeDataTimeout: Int - val label_flag_messageDeleteWindow: Int - val label_flag_messageEditWindow: Int - val label_flag_minHolderAmount: Int - val label_flag_minimumVersion: Int - val label_flag_newCurrencyFeeAmount: Int - val label_flag_newCurrencyPurchaseAmount: Int - val label_flag_preferredProvider: Int - val label_flag_preferredUsdcLiquidityPool: Int - val label_flag_requireCoinbaseEmailVerification: Int - val label_flag_supportedOnRampProviders: Int - val label_flag_withdrawalFeeAmount: Int -} diff --git a/apps/flipcash/shared/userflags/src/jvmMain/kotlin/com/flipcash/app/userflags/FlagStrings.jvm.kt b/apps/flipcash/shared/userflags/src/jvmMain/kotlin/com/flipcash/app/userflags/FlagStrings.jvm.kt deleted file mode 100644 index 5e9c5fbd6d..0000000000 --- a/apps/flipcash/shared/userflags/src/jvmMain/kotlin/com/flipcash/app/userflags/FlagStrings.jvm.kt +++ /dev/null @@ -1,24 +0,0 @@ -package com.flipcash.app.userflags - -internal actual object FlagStrings { - actual val hint_flag_billExchangeDataTimeout: Int = 0 - actual val hint_flag_messageDeleteWindow: Int = 0 - actual val hint_flag_messageEditWindow: Int = 0 - actual val hint_flag_minHolderAmount: Int = 0 - actual val hint_flag_minimumVersion: Int = 0 - actual val hint_flag_newCurrencyFeeAmount: Int = 0 - actual val hint_flag_newCurrencyPurchaseAmount: Int = 0 - actual val hint_flag_withdrawalFeeAmount: Int = 0 - actual val label_flag_billExchangeDataTimeout: Int = 0 - actual val label_flag_messageDeleteWindow: Int = 0 - actual val label_flag_messageEditWindow: Int = 0 - actual val label_flag_minHolderAmount: Int = 0 - actual val label_flag_minimumVersion: Int = 0 - actual val label_flag_newCurrencyFeeAmount: Int = 0 - actual val label_flag_newCurrencyPurchaseAmount: Int = 0 - actual val label_flag_preferredProvider: Int = 0 - actual val label_flag_preferredUsdcLiquidityPool: Int = 0 - actual val label_flag_requireCoinbaseEmailVerification: Int = 0 - actual val label_flag_supportedOnRampProviders: Int = 0 - actual val label_flag_withdrawalFeeAmount: Int = 0 -} diff --git a/ui/resources/src/androidMain/kotlin/com/getcode/util/resources/AndroidResources.kt b/ui/resources/src/androidMain/kotlin/com/getcode/util/resources/AndroidResources.kt index db84bf05b6..c1b7463d3b 100644 --- a/ui/resources/src/androidMain/kotlin/com/getcode/util/resources/AndroidResources.kt +++ b/ui/resources/src/androidMain/kotlin/com/getcode/util/resources/AndroidResources.kt @@ -10,6 +10,7 @@ import androidx.annotation.RawRes import androidx.annotation.StringRes import androidx.appcompat.content.res.AppCompatResources import androidx.core.content.res.ResourcesCompat +import org.jetbrains.compose.resources.StringResource import timber.log.Timber import java.io.File @@ -25,6 +26,13 @@ class AndroidResources( return context.getString(resourceId, *formatArgs) } + // Compose resources keep the Android resource name as their key, and every module's resources are + // merged into the app package, so the key resolves to the same R entry Android always read. + override fun getString(resource: StringResource, vararg formatArgs: Any): String { + val id = getIdentifier(resource.key, ResourceType.String) ?: return "" + return context.getString(id, *formatArgs) + } + override fun getRawResource(@RawRes resourceId: Int): String { return try { context.resources.openRawResource(resourceId).bufferedReader().use { it.readText() } diff --git a/ui/resources/src/androidMain/kotlin/com/getcode/util/resources/StringRes.android.kt b/ui/resources/src/androidMain/kotlin/com/getcode/util/resources/StringRes.android.kt deleted file mode 100644 index 5819f8d2f9..0000000000 --- a/ui/resources/src/androidMain/kotlin/com/getcode/util/resources/StringRes.android.kt +++ /dev/null @@ -1,15 +0,0 @@ -package com.getcode.util.resources - -import androidx.compose.runtime.Composable -import androidx.compose.ui.res.pluralStringResource -import androidx.compose.ui.res.stringResource - -@Composable -actual fun stringRes(id: Int): String = stringResource(id) - -@Composable -actual fun stringRes(id: Int, vararg formatArgs: Any): String = stringResource(id, *formatArgs) - -@Composable -actual fun pluralStringRes(id: Int, count: Int, vararg formatArgs: Any): String = - pluralStringResource(id, count, *formatArgs) diff --git a/ui/resources/src/commonMain/kotlin/com/getcode/util/resources/ResourceHelper.kt b/ui/resources/src/commonMain/kotlin/com/getcode/util/resources/ResourceHelper.kt index fb339aa961..72f1cc0070 100644 --- a/ui/resources/src/commonMain/kotlin/com/getcode/util/resources/ResourceHelper.kt +++ b/ui/resources/src/commonMain/kotlin/com/getcode/util/resources/ResourceHelper.kt @@ -5,6 +5,7 @@ import androidx.annotation.PluralsRes import androidx.annotation.RawRes import androidx.annotation.StringRes import androidx.compose.runtime.staticCompositionLocalOf +import org.jetbrains.compose.resources.StringResource /** * Looks up app resources by their Android resource ID. @@ -17,6 +18,9 @@ interface ResourceHelper { fun getString(@StringRes resourceId: Int, vararg formatArgs: Any): String + /** Reads a Compose string resource outside composition, for mappers that build display text. */ + fun getString(resource: StringResource, vararg formatArgs: Any): String + fun getRawResource(@RawRes resourceId: Int): String fun getQuantityString( @@ -49,6 +53,8 @@ private object NoOpResources : ResourceHelper { override fun getString(resourceId: Int, vararg formatArgs: Any): String = "" + override fun getString(resource: StringResource, vararg formatArgs: Any): String = "" + override fun getRawResource(resourceId: Int): String = "" override fun getQuantityString( diff --git a/ui/resources/src/commonMain/kotlin/com/getcode/util/resources/StringRes.kt b/ui/resources/src/commonMain/kotlin/com/getcode/util/resources/StringRes.kt deleted file mode 100644 index 5bb17bec3e..0000000000 --- a/ui/resources/src/commonMain/kotlin/com/getcode/util/resources/StringRes.kt +++ /dev/null @@ -1,18 +0,0 @@ -package com.getcode.util.resources - -import androidx.annotation.PluralsRes -import androidx.annotation.StringRes -import androidx.compose.runtime.Composable - -/** - * Reads the string behind a resource ID in composition. On Android these are `R.string` values; - * on desktop they come from [ResourceHelper.getIdentifier] or a module's string table. - */ -@Composable -expect fun stringRes(@StringRes id: Int): String - -@Composable -expect fun stringRes(@StringRes id: Int, vararg formatArgs: Any): String - -@Composable -expect fun pluralStringRes(@PluralsRes id: Int, count: Int, vararg formatArgs: Any): String diff --git a/ui/resources/src/jvmMain/kotlin/com/getcode/util/resources/ComposeResourceHelper.kt b/ui/resources/src/jvmMain/kotlin/com/getcode/util/resources/ComposeResourceHelper.kt index c55ed631b5..17df59207e 100644 --- a/ui/resources/src/jvmMain/kotlin/com/getcode/util/resources/ComposeResourceHelper.kt +++ b/ui/resources/src/jvmMain/kotlin/com/getcode/util/resources/ComposeResourceHelper.kt @@ -2,6 +2,7 @@ package com.getcode.util.resources import kotlinx.coroutines.runBlocking import org.jetbrains.compose.resources.getPluralString +import org.jetbrains.compose.resources.StringResource import org.jetbrains.compose.resources.getString /** @@ -15,6 +16,9 @@ class ComposeResourceHelper : ResourceHelper { override fun getString(resourceId: Int, vararg formatArgs: Any): String = runBlocking { getString(ComposeResourceIds.string(resourceId), *formatArgs) } + override fun getString(resource: StringResource, vararg formatArgs: Any): String = + runBlocking { getString(resource, *formatArgs) } + override fun getRawResource(resourceId: Int): String = "" override fun getQuantityString(id: Int, quantity: Int, vararg formatArgs: Any, default: String): String = diff --git a/ui/resources/src/jvmMain/kotlin/com/getcode/util/resources/StringRes.jvm.kt b/ui/resources/src/jvmMain/kotlin/com/getcode/util/resources/StringRes.jvm.kt deleted file mode 100644 index 6e9a8f1313..0000000000 --- a/ui/resources/src/jvmMain/kotlin/com/getcode/util/resources/StringRes.jvm.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.getcode.util.resources - -import androidx.compose.runtime.Composable -import org.jetbrains.compose.resources.pluralStringResource -import org.jetbrains.compose.resources.stringResource - -@Composable -actual fun stringRes(id: Int): String = stringResource(ComposeResourceIds.string(id)) - -@Composable -actual fun stringRes(id: Int, vararg formatArgs: Any): String = - stringResource(ComposeResourceIds.string(id), *formatArgs) - -@Composable -actual fun pluralStringRes(id: Int, count: Int, vararg formatArgs: Any): String = - pluralStringResource(ComposeResourceIds.plural(id), count, *formatArgs) diff --git a/ui/resources/test-fixtures/src/main/kotlin/com/getcode/util/resources/FakeResourceHelper.kt b/ui/resources/test-fixtures/src/main/kotlin/com/getcode/util/resources/FakeResourceHelper.kt index e9881b8b62..84d9e73cc2 100644 --- a/ui/resources/test-fixtures/src/main/kotlin/com/getcode/util/resources/FakeResourceHelper.kt +++ b/ui/resources/test-fixtures/src/main/kotlin/com/getcode/util/resources/FakeResourceHelper.kt @@ -3,6 +3,7 @@ package com.getcode.util.resources import android.graphics.Typeface import android.graphics.drawable.Drawable import android.util.DisplayMetrics +import org.jetbrains.compose.resources.StringResource import java.io.File import java.net.URL import java.net.URLClassLoader @@ -17,6 +18,7 @@ class FakeResourceHelper(vararg rClasses: Class<*>) : AndroidResourceHelper { } private val overrides = mutableMapOf() + private val keyOverrides = mutableMapOf() fun stub(resourceId: Int, value: String): FakeResourceHelper = apply { overrides[resourceId] = value @@ -30,6 +32,15 @@ class FakeResourceHelper(vararg rClasses: Class<*>) : AndroidResourceHelper { return runCatching { template.format(*formatArgs) }.getOrDefault(template) } + fun stub(resource: StringResource, value: String): FakeResourceHelper = apply { + keyOverrides[resource.key] = value + } + + override fun getString(resource: StringResource, vararg formatArgs: Any): String { + val template = keyOverrides[resource.key] ?: return resource.key + return runCatching { template.format(*formatArgs) }.getOrDefault(template) + } + override fun getRawResource(resourceId: Int): String = "" override fun getQuantityString(id: Int, quantity: Int, vararg formatArgs: Any, default: String): String = default override fun getDimension(dimenId: Int, default: Float): Float = default From 406f8df09ccc57a62b7853da443c9452f85a47ff Mon Sep 17 00:00:00 2001 From: Brandon McAnsh Date: Sat, 24 Oct 2026 16:43:56 -0400 Subject: [PATCH 35/50] feat(device-link): add the seed vault and LAN link protocol New KMP module :apps:flipcash:shared:device-link. Everything is in commonMain except the OS keyring vault. - SeedVault: interface for the stored account seed. KeyringSeedVault (jvmMain) backs it with Keychain, Credential Manager or Secret Service through java-keyring; those are native APIs with no common surface. Android keeps AuthManager for now. - LinkInvite: the QR payload: host, port, the desktop's one-time X25519 key, and a 16-byte one-time secret. - LinkCrypto: libsodium kx (phone is client, desktop server). The transcript binds both public keys and the secret; the six-digit code is a keyed hash of the transcript under the phone-to-desktop key, and the seed is sealed with XChaCha20-Poly1305 with the transcript as AD. - DesktopLinkHost / PhoneLinker: one connection over ktor-network sockets. The phone sends the sealed seed only from Pending.confirm(), after the user says the codes match. ktor-network is a second networking stack next to OkHttp/gRPC; it keeps the sockets in common code instead of an expect/actual per platform. Tests are jvmTest, not commonTest: the Android libsodium binding loads its .so from an APK, so the protocol can't run as a host test. LinkProtocolTest runs both sides over a loopback socket (7 cases, including a swapped phone key, a wrong secret, tampered ciphertext and cancel). KeyringSeedVaultTest is opt-in (-Pflipcash.keyringTest) and writes a random value under a test-only service name, then deletes it. --- .../shared/device-link/build.gradle.kts | 41 +++++ .../app/devicelink/DesktopLinkHost.kt | 88 +++++++++++ .../flipcash/app/devicelink/LinkChannel.kt | 43 ++++++ .../com/flipcash/app/devicelink/LinkCrypto.kt | 115 ++++++++++++++ .../com/flipcash/app/devicelink/LinkInvite.kt | 41 +++++ .../flipcash/app/devicelink/PhoneLinker.kt | 63 ++++++++ .../com/flipcash/app/devicelink/SeedVault.kt | 11 ++ .../app/devicelink/KeyringSeedVault.kt | 38 +++++ .../app/devicelink/KeyringSeedVaultTest.kt | 29 ++++ .../app/devicelink/LinkProtocolTest.kt | 143 ++++++++++++++++++ gradle/libs.versions.toml | 6 + settings.gradle.kts | 1 + 12 files changed, 619 insertions(+) create mode 100644 apps/flipcash/shared/device-link/build.gradle.kts create mode 100644 apps/flipcash/shared/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/DesktopLinkHost.kt create mode 100644 apps/flipcash/shared/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/LinkChannel.kt create mode 100644 apps/flipcash/shared/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/LinkCrypto.kt create mode 100644 apps/flipcash/shared/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/LinkInvite.kt create mode 100644 apps/flipcash/shared/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/PhoneLinker.kt create mode 100644 apps/flipcash/shared/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/SeedVault.kt create mode 100644 apps/flipcash/shared/device-link/src/jvmMain/kotlin/com/flipcash/app/devicelink/KeyringSeedVault.kt create mode 100644 apps/flipcash/shared/device-link/src/jvmTest/kotlin/com/flipcash/app/devicelink/KeyringSeedVaultTest.kt create mode 100644 apps/flipcash/shared/device-link/src/jvmTest/kotlin/com/flipcash/app/devicelink/LinkProtocolTest.kt diff --git a/apps/flipcash/shared/device-link/build.gradle.kts b/apps/flipcash/shared/device-link/build.gradle.kts new file mode 100644 index 0000000000..d8dc6fe88c --- /dev/null +++ b/apps/flipcash/shared/device-link/build.gradle.kts @@ -0,0 +1,41 @@ +plugins { + alias(libs.plugins.flipcash.kmp.app.library) + alias(libs.plugins.compose.compiler) + alias(libs.plugins.jetbrains.compose) +} + +// Link a desktop to a phone over the LAN. The protocol, crypto, state and screens are common; the +// platform pieces are the seed store (jvmMain: OS keyring) and the camera, which the Android app +// passes into the phone screen. +kotlin { + android { + namespace = "${Gradle.flipcashNamespace}.shared.devicelink" + } + + sourceSets { + commonMain.dependencies { + implementation(libs.kotlinx.coroutines.core) + implementation(libs.sodium.bindings.kmp) + implementation(libs.ktor.network) + implementation(libs.qrose) + implementation(libs.jetbrains.compose.runtime) + implementation(libs.jetbrains.compose.foundation) + implementation(libs.jetbrains.compose.ui) + implementation(libs.jetbrains.compose.material) + implementation(project(":ui:theme")) + } + jvmMain.dependencies { + implementation(libs.java.keyring) + } + // jvmTest, not commonTest: libsodium's Android binding loads its .so from an APK, so the + // protocol can't run in an Android host test (the same reason chat-cipher has no host test). + jvmTest.dependencies { + implementation(kotlin("test")) + implementation(libs.kotlinx.coroutines.test) + } + } +} + +tasks.withType().configureEach { + if (providers.gradleProperty("flipcash.keyringTest").isPresent) systemProperty("flipcash.keyringTest", "true") +} diff --git a/apps/flipcash/shared/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/DesktopLinkHost.kt b/apps/flipcash/shared/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/DesktopLinkHost.kt new file mode 100644 index 0000000000..b416752b56 --- /dev/null +++ b/apps/flipcash/shared/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/DesktopLinkHost.kt @@ -0,0 +1,88 @@ +package com.flipcash.app.devicelink + +import io.ktor.network.selector.SelectorManager +import io.ktor.network.sockets.InetSocketAddress +import io.ktor.network.sockets.aSocket +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.withTimeoutOrNull +import kotlin.io.encoding.Base64 +import kotlin.time.Duration +import kotlin.time.Duration.Companion.minutes + +/** + * The desktop side of a link: listens on [host], shows the invite, takes one connection, and + * emits the seed once the phone sends it sealed under the session key. Each collection is one + * attempt with fresh keys; the listener closes after the first connection. + */ +class DesktopLinkHost( + private val host: String, + private val bindHost: String = "0.0.0.0", + private val timeout: Duration = 5.minutes, +) { + sealed interface State { + data class Waiting(val invite: String) : State + data class Confirm(val code: String) : State + /** [entropyB64] is the seed; the caller stores it and signs in. */ + class Linked(val entropyB64: String) : State + data class Failed(val reason: String) : State + } + + fun link(): Flow = flow { + val desktop = LinkCrypto.ephemeral() + val secret = LinkCrypto.secret() + val selector = SelectorManager(Dispatchers.Default) + var session: LinkCrypto.Session? = null + try { + val server = aSocket(selector).tcp().bind(InetSocketAddress(bindHost, 0)) + val port = (server.localAddress as InetSocketAddress).port + emit(State.Waiting(LinkInvite(host, port, desktop.publicKey, secret).encode())) + + val socket = withTimeoutOrNull(timeout) { server.accept() } + server.close() + if (socket == null) return@flow emit(State.Failed("Timed out waiting for the phone")) + val channel = LinkChannel(socket) + try { + val hello = channel.receive() + if (hello == null || hello.first != Frame.HELLO || hello.second.size != 1 + LinkCrypto.KEY_BYTES || + hello.second[0] != Frame.PROTOCOL_VERSION + ) { + return@flow emit(State.Failed("The phone sent an unexpected message")) + } + val phoneKey = hello.second.copyOfRange(1, hello.second.size) + val s = LinkCrypto.desktopSession(desktop, phoneKey, secret).also { session = it } + emit(State.Confirm(LinkCrypto.shortCode(s))) + + val reply = withTimeoutOrNull(timeout) { channel.receive() } + when { + reply == null -> emit(State.Failed("The phone disconnected")) + reply.first == Frame.CANCEL -> emit(State.Failed("Cancelled on the phone")) + reply.first != Frame.SEED -> emit(State.Failed("The phone sent an unexpected message")) + else -> { + val entropy = LinkCrypto.open(s.phoneToDesktop, reply.second, s.transcript) + if (entropy == null || entropy.size !in ENTROPY_SIZES) { + emit(State.Failed("Couldn't verify the phone's message")) + } else { + channel.send(Frame.ACK, LinkCrypto.seal(s.desktopToPhone, ACK_BODY, s.transcript)) + val b64 = Base64.encode(entropy) + entropy.fill(0) + emit(State.Linked(b64)) + } + } + } + } finally { + channel.close() + } + } finally { + desktop.wipe() + session?.wipe() + selector.close() + } + } + + internal companion object { + val ENTROPY_SIZES = setOf(16, 32) + val ACK_BODY = "linked".encodeToByteArray() + } +} diff --git a/apps/flipcash/shared/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/LinkChannel.kt b/apps/flipcash/shared/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/LinkChannel.kt new file mode 100644 index 0000000000..974d9b8c3a --- /dev/null +++ b/apps/flipcash/shared/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/LinkChannel.kt @@ -0,0 +1,43 @@ +package com.flipcash.app.devicelink + +import io.ktor.network.sockets.Socket +import io.ktor.network.sockets.openReadChannel +import io.ktor.network.sockets.openWriteChannel +import io.ktor.utils.io.readByteArray +import io.ktor.utils.io.readInt +import io.ktor.utils.io.writeByteArray +import io.ktor.utils.io.writeInt + +/** Length-prefixed frames over a TCP socket. The first byte of each frame is its [Frame] type. */ +internal class LinkChannel(private val socket: Socket) { + private val input = socket.openReadChannel() + private val output = socket.openWriteChannel(autoFlush = false) + + suspend fun send(type: Byte, body: ByteArray = ByteArray(0)) { + output.writeInt(body.size + 1) + output.writeByteArray(byteArrayOf(type) + body) + output.flush() + } + + /** The next frame, or null when the peer closed the connection or sent something malformed. */ + suspend fun receive(): Pair? = runCatching { + val size = input.readInt() + if (size !in 1..MAX_FRAME) return null + val frame = input.readByteArray(size) + frame[0] to frame.copyOfRange(1, frame.size) + }.getOrNull() + + fun close() = socket.close() + + private companion object { + const val MAX_FRAME = 4096 + } +} + +internal object Frame { + const val HELLO: Byte = 1 + const val SEED: Byte = 2 + const val ACK: Byte = 3 + const val CANCEL: Byte = 4 + const val PROTOCOL_VERSION: Byte = 1 +} diff --git a/apps/flipcash/shared/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/LinkCrypto.kt b/apps/flipcash/shared/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/LinkCrypto.kt new file mode 100644 index 0000000000..6663337bce --- /dev/null +++ b/apps/flipcash/shared/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/LinkCrypto.kt @@ -0,0 +1,115 @@ +@file:OptIn(ExperimentalUnsignedTypes::class) + +package com.flipcash.app.devicelink + +import com.ionspin.kotlin.crypto.LibsodiumInitializer +import com.ionspin.kotlin.crypto.aead.AuthenticatedEncryptionWithAssociatedData +import com.ionspin.kotlin.crypto.generichash.GenericHash +import com.ionspin.kotlin.crypto.keyexchange.KeyExchange +import com.ionspin.kotlin.crypto.util.LibsodiumRandom + +/** + * Keys and codes for one link. The phone is libsodium's kx client and the desktop its server. + * + * The transcript binds both public keys and the QR secret. The short code is a keyed hash of the + * transcript under the phone-to-desktop session key, so it can only match when both sides hold the + * same key: an attacker who swaps the phone's public key on its way to the desktop ends up with a + * different key and can't predict the phone's code, so grinding keys for a collision doesn't help. + */ +internal object LinkCrypto { + const val KEY_BYTES = 32 + const val SECRET_BYTES = 16 + private const val NONCE_BYTES = 24 + private val LABEL = "flipcash-link-v1".encodeToByteArray() + + class Ephemeral(val publicKey: ByteArray, val secretKey: ByteArray) { + fun wipe() = secretKey.fill(0) + } + + class Session( + val phoneToDesktop: ByteArray, + val desktopToPhone: ByteArray, + val transcript: ByteArray, + ) { + fun wipe() { + phoneToDesktop.fill(0) + desktopToPhone.fill(0) + } + } + + fun ephemeral(): Ephemeral { + ensureSodium() + val pair = KeyExchange.keypair() + return Ephemeral(pair.publicKey.toByteArray(), pair.secretKey.toByteArray()) + } + + fun secret(): ByteArray { + ensureSodium() + return LibsodiumRandom.buf(SECRET_BYTES).toByteArray() + } + + fun phoneSession(phone: Ephemeral, desktopKey: ByteArray, secret: ByteArray): Session { + ensureSodium() + val keys = KeyExchange.clientSessionKeys( + phone.publicKey.toUByteArray(), phone.secretKey.toUByteArray(), desktopKey.toUByteArray(), + ) + return Session( + phoneToDesktop = keys.sendKey.toByteArray(), + desktopToPhone = keys.receiveKey.toByteArray(), + transcript = transcript(desktopKey, phone.publicKey, secret), + ) + } + + fun desktopSession(desktop: Ephemeral, phoneKey: ByteArray, secret: ByteArray): Session { + ensureSodium() + val keys = KeyExchange.serverSessionKeys( + desktop.publicKey.toUByteArray(), desktop.secretKey.toUByteArray(), phoneKey.toUByteArray(), + ) + return Session( + phoneToDesktop = keys.receiveKey.toByteArray(), + desktopToPhone = keys.sendKey.toByteArray(), + transcript = transcript(desktop.publicKey, phoneKey, secret), + ) + } + + /** Six digits both screens show; the user confirms they match on the phone before the seed is sent. */ + fun shortCode(session: Session): String { + ensureSodium() + val h = GenericHash.genericHash( + session.transcript.toUByteArray(), 32, session.phoneToDesktop.toUByteArray(), + ) + val n = ((h[0].toLong() shl 24) or (h[1].toLong() shl 16) or (h[2].toLong() shl 8) or h[3].toLong()) + return (n % 1_000_000).toString().padStart(6, '0') + } + + fun seal(key: ByteArray, plaintext: ByteArray, transcript: ByteArray): ByteArray { + ensureSodium() + val nonce = LibsodiumRandom.buf(NONCE_BYTES) + val ct = AuthenticatedEncryptionWithAssociatedData.xChaCha20Poly1305IetfEncrypt( + plaintext.toUByteArray(), transcript.toUByteArray(), nonce, key.toUByteArray(), + ) + return nonce.toByteArray() + ct.toByteArray() + } + + /** Null when the ciphertext was tampered with or sealed under another key or transcript. */ + fun open(key: ByteArray, sealed: ByteArray, transcript: ByteArray): ByteArray? { + if (sealed.size <= NONCE_BYTES) return null + ensureSodium() + return runCatching { + AuthenticatedEncryptionWithAssociatedData.xChaCha20Poly1305IetfDecrypt( + sealed.copyOfRange(NONCE_BYTES, sealed.size).toUByteArray(), + transcript.toUByteArray(), + sealed.copyOfRange(0, NONCE_BYTES).toUByteArray(), + key.toUByteArray(), + ).toByteArray() + }.getOrNull() + } + + private fun transcript(desktopKey: ByteArray, phoneKey: ByteArray, secret: ByteArray) = + LABEL + desktopKey + phoneKey + secret + + private fun ensureSodium() { + // Synchronous on JVM/Android/Native, as in chat-cipher. + if (!LibsodiumInitializer.isInitialized()) LibsodiumInitializer.initializeWithCallback { } + } +} diff --git a/apps/flipcash/shared/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/LinkInvite.kt b/apps/flipcash/shared/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/LinkInvite.kt new file mode 100644 index 0000000000..d924be8dae --- /dev/null +++ b/apps/flipcash/shared/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/LinkInvite.kt @@ -0,0 +1,41 @@ +package com.flipcash.app.devicelink + +import kotlin.io.encoding.Base64 + +/** + * What the desktop's QR code carries: where to connect, the desktop's one-time public key, and a + * one-time secret. Only a device that scanned the code knows the secret, and it is bound into every + * key and code derived after, so a device on the LAN that finds the port without the QR can't link. + */ +class LinkInvite( + val host: String, + val port: Int, + val publicKey: ByteArray, + val secret: ByteArray, +) { + fun encode(): String = + "$SCHEME:$VERSION?h=$host&p=$port&k=${b64.encode(publicKey)}&s=${b64.encode(secret)}" + + companion object { + private const val SCHEME = "flipcash-link" + private const val VERSION = 1 + private val b64 = Base64.UrlSafe.withPadding(Base64.PaddingOption.ABSENT) + + fun parse(text: String): LinkInvite? { + val prefix = "$SCHEME:$VERSION?" + if (!text.startsWith(prefix)) return null + val params = text.removePrefix(prefix).split('&').mapNotNull { + val i = it.indexOf('=') + if (i <= 0) null else it.substring(0, i) to it.substring(i + 1) + }.toMap() + return runCatching { + LinkInvite( + host = params.getValue("h").takeIf { it.isNotBlank() }!!, + port = params.getValue("p").toInt().takeIf { it in 1..65535 }!!, + publicKey = b64.decode(params.getValue("k")).takeIf { it.size == LinkCrypto.KEY_BYTES }!!, + secret = b64.decode(params.getValue("s")).takeIf { it.size == LinkCrypto.SECRET_BYTES }!!, + ) + }.getOrNull() + } + } +} diff --git a/apps/flipcash/shared/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/PhoneLinker.kt b/apps/flipcash/shared/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/PhoneLinker.kt new file mode 100644 index 0000000000..2f385fa06b --- /dev/null +++ b/apps/flipcash/shared/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/PhoneLinker.kt @@ -0,0 +1,63 @@ +package com.flipcash.app.devicelink + +import io.ktor.network.selector.SelectorManager +import io.ktor.network.sockets.InetSocketAddress +import io.ktor.network.sockets.aSocket +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withTimeoutOrNull +import kotlin.io.encoding.Base64 +import kotlin.time.Duration.Companion.seconds + +/** + * The phone side of a link. [connect] dials the invite's address and returns the code to compare; + * the seed only leaves the phone through [Pending.confirm], after the user says the codes match. + */ +object PhoneLinker { + suspend fun connect(invite: LinkInvite): Result { + val selector = SelectorManager(Dispatchers.Default) + val phone = LinkCrypto.ephemeral() + return runCatching { + val socket = withTimeoutOrNull(10.seconds) { + aSocket(selector).tcp().connect(InetSocketAddress(invite.host, invite.port)) + } ?: error("Couldn't reach the desktop at ${invite.host}") + val channel = LinkChannel(socket) + channel.send(Frame.HELLO, byteArrayOf(Frame.PROTOCOL_VERSION) + phone.publicKey) + val session = LinkCrypto.phoneSession(phone, invite.publicKey, invite.secret) + Pending(channel, session, selector) + }.onFailure { selector.close() } + .also { phone.wipe() } + } + + class Pending internal constructor( + private val channel: LinkChannel, + private val session: LinkCrypto.Session, + private val selector: SelectorManager, + ) { + val code: String = LinkCrypto.shortCode(session) + + /** Sends the seed and waits for the desktop to confirm it opened it. */ + suspend fun confirm(entropyB64: String): Result = runCatching { + val entropy = Base64.decode(entropyB64) + try { + channel.send(Frame.SEED, LinkCrypto.seal(session.phoneToDesktop, entropy, session.transcript)) + } finally { + entropy.fill(0) + } + val ack = withTimeoutOrNull(10.seconds) { channel.receive() } + val body = ack?.takeIf { it.first == Frame.ACK } + ?.let { LinkCrypto.open(session.desktopToPhone, it.second, session.transcript) } + check(body?.contentEquals(DesktopLinkHost.ACK_BODY) == true) { "The desktop didn't confirm the link" } + }.also { close() } + + suspend fun cancel() { + runCatching { channel.send(Frame.CANCEL) } + close() + } + + private fun close() { + session.wipe() + channel.close() + selector.close() + } + } +} diff --git a/apps/flipcash/shared/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/SeedVault.kt b/apps/flipcash/shared/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/SeedVault.kt new file mode 100644 index 0000000000..2f57d182a8 --- /dev/null +++ b/apps/flipcash/shared/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/SeedVault.kt @@ -0,0 +1,11 @@ +package com.flipcash.app.devicelink + +/** + * Where a signed-in device keeps its account seed (base64 entropy, as `UserManager.establish` takes + * it). Desktop backs it with the OS keyring; Android still keeps the seed in `AuthManager`. + */ +interface SeedVault { + suspend fun read(): String? + suspend fun write(entropyB64: String) + suspend fun clear() +} diff --git a/apps/flipcash/shared/device-link/src/jvmMain/kotlin/com/flipcash/app/devicelink/KeyringSeedVault.kt b/apps/flipcash/shared/device-link/src/jvmMain/kotlin/com/flipcash/app/devicelink/KeyringSeedVault.kt new file mode 100644 index 0000000000..849c7f0e9e --- /dev/null +++ b/apps/flipcash/shared/device-link/src/jvmMain/kotlin/com/flipcash/app/devicelink/KeyringSeedVault.kt @@ -0,0 +1,38 @@ +package com.flipcash.app.devicelink + +import com.github.javakeyring.Keyring +import com.github.javakeyring.PasswordAccessException +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext + +/** + * [SeedVault] in the OS keyring: Keychain on macOS, Credential Manager on Windows, Secret Service on + * Linux, through one library. jvmMain because each of those is a native API with no common surface. + */ +class KeyringSeedVault( + private val service: String = "com.flipcash.desktop", + private val account: String = "seed", +) : SeedVault { + override suspend fun read(): String? = withContext(Dispatchers.IO) { + Keyring.create().use { keyring -> + try { + keyring.getPassword(service, account) + } catch (_: PasswordAccessException) { + null + } + } + } + + override suspend fun write(entropyB64: String) = withContext(Dispatchers.IO) { + Keyring.create().use { it.setPassword(service, account, entropyB64) } + } + + override suspend fun clear() = withContext(Dispatchers.IO) { + Keyring.create().use { keyring -> + try { + keyring.deletePassword(service, account) + } catch (_: PasswordAccessException) { + } + } + } +} diff --git a/apps/flipcash/shared/device-link/src/jvmTest/kotlin/com/flipcash/app/devicelink/KeyringSeedVaultTest.kt b/apps/flipcash/shared/device-link/src/jvmTest/kotlin/com/flipcash/app/devicelink/KeyringSeedVaultTest.kt new file mode 100644 index 0000000000..7b6078ab96 --- /dev/null +++ b/apps/flipcash/shared/device-link/src/jvmTest/kotlin/com/flipcash/app/devicelink/KeyringSeedVaultTest.kt @@ -0,0 +1,29 @@ +package com.flipcash.app.devicelink + +import kotlinx.coroutines.runBlocking +import kotlin.io.encoding.Base64 +import kotlin.random.Random +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertNull + +/** + * Writes a random throwaway value to the real OS keyring under a test-only service name and deletes + * it. Opt-in (`-Pflipcash.keyringTest`), because CI machines may have no unlocked keyring and a + * locked one can block on a prompt. + */ +class KeyringSeedVaultTest { + @Test + fun `round-trips through the OS keyring`() = runBlocking { + if (System.getProperty("flipcash.keyringTest") != "true") return@runBlocking + val vault = KeyringSeedVault(service = "com.flipcash.desktop.test", account = "throwaway") + val value = Base64.encode(Random.nextBytes(16)) + try { + vault.write(value) + assertEquals(value, vault.read()) + } finally { + vault.clear() + } + assertNull(vault.read()) + } +} diff --git a/apps/flipcash/shared/device-link/src/jvmTest/kotlin/com/flipcash/app/devicelink/LinkProtocolTest.kt b/apps/flipcash/shared/device-link/src/jvmTest/kotlin/com/flipcash/app/devicelink/LinkProtocolTest.kt new file mode 100644 index 0000000000..78ef00f92b --- /dev/null +++ b/apps/flipcash/shared/device-link/src/jvmTest/kotlin/com/flipcash/app/devicelink/LinkProtocolTest.kt @@ -0,0 +1,143 @@ +package com.flipcash.app.devicelink + +import io.ktor.network.selector.SelectorManager +import io.ktor.network.sockets.InetSocketAddress +import io.ktor.network.sockets.aSocket +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.async +import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.flow.collect +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.withTimeout +import kotlin.io.encoding.Base64 +import kotlin.random.Random +import kotlin.test.Test +import kotlin.test.assertContentEquals +import kotlin.test.assertEquals +import kotlin.test.assertIs +import kotlin.test.assertNotEquals +import kotlin.test.assertNull +import kotlin.test.assertTrue + +/** Both sides of a link over a real loopback socket. The seed is random bytes, never a real account's. */ +class LinkProtocolTest { + private val seed = Base64.encode(Random.nextBytes(16)) + + /** Runs the desktop side, hands its invite to [phone], and returns every state the desktop emitted. */ + private fun runLink(phone: suspend (LinkInvite) -> Unit): List = runBlocking { + withTimeout(20_000) { + val states = mutableListOf() + val invites = Channel(1) + val desktop = launch(Dispatchers.Default) { + DesktopLinkHost(host = "127.0.0.1", bindHost = "127.0.0.1").link() + .onEach { states += it; if (it is DesktopLinkHost.State.Waiting) invites.send(it.invite) } + .collect() + } + phone(LinkInvite.parse(invites.receive())!!) + desktop.join() + states + } + } + + @Test + fun `codes match and the seed arrives`() { + var phoneCode: String? = null + val states = runLink { invite -> + val pending = PhoneLinker.connect(invite).getOrThrow() + phoneCode = pending.code + pending.confirm(seed).getOrThrow() + } + val confirm = states.filterIsInstance().single() + assertEquals(phoneCode, confirm.code) + assertTrue(confirm.code.matches(Regex("\\d{6}"))) + assertEquals(seed, assertIs(states.last()).entropyB64) + } + + @Test + fun `cancelling on the phone sends nothing`() { + val states = runLink { invite -> PhoneLinker.connect(invite).getOrThrow().cancel() } + assertEquals(DesktopLinkHost.State.Failed("Cancelled on the phone"), states.last()) + } + + @Test + fun `a swapped phone key changes the desktop's code`() { + // A man in the middle replaces the phone's key on the way to the desktop with one of its own. + var phoneCode: String? = null + val states = runLink { invite -> + val phone = LinkCrypto.ephemeral() + phoneCode = LinkCrypto.shortCode(LinkCrypto.phoneSession(phone, invite.publicKey, invite.secret)) + val attacker = LinkCrypto.ephemeral() + val selector = SelectorManager(Dispatchers.Default) + val channel = LinkChannel(aSocket(selector).tcp().connect(InetSocketAddress(invite.host, invite.port))) + channel.send(Frame.HELLO, byteArrayOf(Frame.PROTOCOL_VERSION) + attacker.publicKey) + // The phone, having seen a matching-looking prompt, would seal under its own session. + val session = LinkCrypto.phoneSession(phone, invite.publicKey, invite.secret) + channel.send(Frame.SEED, LinkCrypto.seal(session.phoneToDesktop, Base64.decode(seed), session.transcript)) + channel.receive() + channel.close() + selector.close() + } + assertNotEquals(phoneCode, states.filterIsInstance().single().code) + assertEquals(DesktopLinkHost.State.Failed("Couldn't verify the phone's message"), states.last()) + } + + @Test + fun `tampered seed is rejected`() { + val states = runLink { invite -> + val phone = LinkCrypto.ephemeral() + val session = LinkCrypto.phoneSession(phone, invite.publicKey, invite.secret) + val selector = SelectorManager(Dispatchers.Default) + val channel = LinkChannel(aSocket(selector).tcp().connect(InetSocketAddress(invite.host, invite.port))) + channel.send(Frame.HELLO, byteArrayOf(Frame.PROTOCOL_VERSION) + phone.publicKey) + val sealed = LinkCrypto.seal(session.phoneToDesktop, Base64.decode(seed), session.transcript) + sealed[sealed.size - 1] = (sealed.last().toInt() xor 1).toByte() + channel.send(Frame.SEED, sealed) + channel.receive() + channel.close() + selector.close() + } + assertEquals(DesktopLinkHost.State.Failed("Couldn't verify the phone's message"), states.last()) + } + + @Test + fun `a device without the QR secret can't link`() { + val states = runLink { invite -> + val pending = PhoneLinker.connect( + LinkInvite(invite.host, invite.port, invite.publicKey, LinkCrypto.secret()), + ).getOrThrow() + assertTrue(pending.confirm(seed).isFailure) + } + assertIs(states.last()) + } + + @Test + fun `invite round-trips and rejects junk`() { + val invite = LinkInvite("192.168.1.20", 50123, ByteArray(32) { it.toByte() }, ByteArray(16) { 7 }) + val parsed = LinkInvite.parse(invite.encode())!! + assertEquals(invite.host, parsed.host) + assertEquals(invite.port, parsed.port) + assertContentEquals(invite.publicKey, parsed.publicKey) + assertContentEquals(invite.secret, parsed.secret) + assertNull(LinkInvite.parse("https://example.com")) + assertNull(LinkInvite.parse(invite.encode().replace("p=50123", "p=0"))) + } + + @Test + fun `vault round-trips through the fake`() = runBlocking { + val vault = InMemorySeedVault() + assertNull(vault.read()) + vault.write(seed) + assertEquals(seed, vault.read()) + vault.clear() + assertNull(vault.read()) + } +} + +internal class InMemorySeedVault : SeedVault { + private var value: String? = null + override suspend fun read() = value + override suspend fun write(entropyB64: String) { value = entropyB64 } + override suspend fun clear() { value = null } +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index fec7c51eff..70cb1c5766 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -85,6 +85,9 @@ flipcash2-client-protocol = "0.20.0" # because it loads its metadata from the AAR's assets rather than from a static instance. lib-phone-number-port = "9.0.40" zxing = "3.5.4" +ktor = "3.4.1" +java-keyring = "1.0.4" +qrose = "1.3.1" androidx-benchmark-macro = "1.5.0" androidx-profileinstaller = "1.4.1" @@ -282,6 +285,9 @@ lib-phone-number-port = { module = "io.michaelrocks:libphonenumber-android", ver # QR / Scanning zxing = { module = "com.google.zxing:core", version.ref = "zxing" } +ktor-network = { module = "io.ktor:ktor-network", version.ref = "ktor" } +java-keyring = { module = "com.github.javakeyring:java-keyring", version.ref = "java-keyring" } +qrose = { module = "io.github.alexzhirkevich:qrose", version.ref = "qrose" } # Logging / Error Tracking timber = { module = "com.jakewharton.timber:timber", version.ref = "timber" } diff --git a/settings.gradle.kts b/settings.gradle.kts index 98137caca5..567d7bca20 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -120,6 +120,7 @@ include( ":apps:flipcash:core-ui", ":apps:flipcash:card-expand", ":apps:flipcash:startup-contract", + ":apps:flipcash:shared:device-link", ":libs:test-utils", // shared flipcash coordinators/controllers/viewmodels/services ":apps:flipcash:shared:amount-entry", From b3866b27a98b07a8b742c5dfdcbc3256e230b803 Mon Sep 17 00:00:00 2001 From: Brandon McAnsh Date: Sat, 24 Oct 2026 16:48:25 -0400 Subject: [PATCH 36/50] feat(desktop): sign in from the linked seed or show the link screen At launch the desktop signs in with the dev phrase if one is set, else with the seed a phone linked into the Keychain. With neither, it shows DesktopLinkScreen; when the phone sends the seed, the desktop writes it to the vault and signs in. The dev phrase is never written to the vault. The screens (DesktopLinkScreen, PhoneLinkScreen) and the phone's state holder (PhoneLinkController) are in device-link's commonMain. The phone screen takes the camera as a composable slot. PhoneLinkController reads the seed only after the user confirms the codes match; a new loopback test checks that. Two pieces stay in the desktop app (JVM-only): - DesktopSession: FlipcashDatabase.init takes a java.io.File. - lanAddress(): picks the address the phone dials from java.net.NetworkInterface. Only the desktop needs it. `snapshot -Pscreen=link` renders the link screen without signing in. --- apps/desktop/build.gradle.kts | 10 ++- .../kotlin/com/flipcash/desktop/DesktopApp.kt | 68 +++++++++++++++ .../com/flipcash/desktop/DesktopGraph.kt | 1 + .../com/flipcash/desktop/DesktopModule.kt | 6 ++ .../com/flipcash/desktop/DesktopSession.kt | 64 ++++++++++++++ .../kotlin/com/flipcash/desktop/DevSession.kt | 45 ---------- .../main/kotlin/com/flipcash/desktop/Main.kt | 6 +- .../com/flipcash/desktop/SnapshotMain.kt | 8 +- .../app/devicelink/PhoneLinkController.kt | 67 +++++++++++++++ .../app/devicelink/ui/DesktopLinkScreen.kt | 83 +++++++++++++++++++ .../app/devicelink/ui/PhoneLinkScreen.kt | 81 ++++++++++++++++++ .../app/devicelink/LinkProtocolTest.kt | 21 +++++ 12 files changed, 406 insertions(+), 54 deletions(-) create mode 100644 apps/desktop/src/main/kotlin/com/flipcash/desktop/DesktopApp.kt create mode 100644 apps/desktop/src/main/kotlin/com/flipcash/desktop/DesktopSession.kt delete mode 100644 apps/desktop/src/main/kotlin/com/flipcash/desktop/DevSession.kt create mode 100644 apps/flipcash/shared/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/PhoneLinkController.kt create mode 100644 apps/flipcash/shared/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/ui/DesktopLinkScreen.kt create mode 100644 apps/flipcash/shared/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/ui/PhoneLinkScreen.kt diff --git a/apps/desktop/build.gradle.kts b/apps/desktop/build.gradle.kts index 9fd564a8f6..280c819fd3 100644 --- a/apps/desktop/build.gradle.kts +++ b/apps/desktop/build.gradle.kts @@ -42,6 +42,7 @@ dependencies { implementation(project(":libs:locale:public")) implementation(project(":libs:network:connectivity:public")) implementation(project(":libs:encryption:chat-cipher")) + implementation(project(":apps:flipcash:shared:device-link")) implementation(libs.kotlinx.coroutines.swing) implementation(libs.dagger) implementation(libs.grpc.okhttp) @@ -59,7 +60,7 @@ tasks.withType().configureEach { systemProperty("opencode.processLifecycle.autoStart", "false") } -// Dev-only sign-in phrase (see DevSession), forwarded only when local.properties has one. It goes in +// Dev-only sign-in phrase (see DesktopSession), forwarded only when local.properties has one. It goes in // the environment, not a -D flag, so it stays out of the process's command line. val devMnemonic = tryReadProperty(rootProject.rootDir, "flipcash.test.mnemonic", "") .takeIf { it.isNotBlank() } @@ -77,10 +78,13 @@ compose.desktop { tasks.register("snapshot") { group = "application" - description = "Renders the wallet screen off-screen to a PNG (-Pout=)." + description = "Renders the wallet (or, with -Pscreen=link, the link screen) off-screen to a PNG (-Pout=)." classpath = sourceSets["main"].runtimeClasspath mainClass.set("com.flipcash.desktop.SnapshotMainKt") - args(providers.gradleProperty("out").getOrElse(layout.buildDirectory.file("wallet.png").get().asFile.path)) + args( + providers.gradleProperty("out").getOrElse(layout.buildDirectory.file("wallet.png").get().asFile.path), + providers.gradleProperty("screen").getOrElse("wallet"), + ) } tasks.withType().configureEach { diff --git a/apps/desktop/src/main/kotlin/com/flipcash/desktop/DesktopApp.kt b/apps/desktop/src/main/kotlin/com/flipcash/desktop/DesktopApp.kt new file mode 100644 index 0000000000..41200a7782 --- /dev/null +++ b/apps/desktop/src/main/kotlin/com/flipcash/desktop/DesktopApp.kt @@ -0,0 +1,68 @@ +package com.flipcash.desktop + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableIntStateOf +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import com.flipcash.app.devicelink.DesktopLinkHost +import com.flipcash.app.devicelink.ui.DesktopLinkScreen +import com.flipcash.app.theme.FlipcashTheme +import com.getcode.theme.CodeTheme +import java.net.Inet4Address +import java.net.NetworkInterface + +/** The wallet when signed in; otherwise the link screen, which stores the phone's seed and signs in. */ +@Composable +fun DesktopApp(graph: DesktopGraph, signedIn: Boolean) { + var linked by remember { mutableStateOf(signedIn) } + if (linked) { + DesktopWalletContent(graph) + } else { + DesktopLinkContent(graph, onSignedIn = { linked = true }) + } +} + +@Composable +fun DesktopLinkContent(graph: DesktopGraph, onSignedIn: () -> Unit) { + var attempt by remember { mutableIntStateOf(0) } + var state by remember { mutableStateOf(null) } + LaunchedEffect(attempt) { + val host = lanAddress() + if (host == null) { + state = DesktopLinkHost.State.Failed("This computer isn't on a local network") + return@LaunchedEffect + } + DesktopLinkHost(host).link().collect { next -> + state = next + if (next is DesktopLinkHost.State.Linked) { + graph.seedVault.write(next.entropyB64) + graph.signIn(next.entropyB64) + .onSuccess { onSignedIn() } + .onFailure { state = DesktopLinkHost.State.Failed("Linked, but sign-in failed: ${it.message}") } + } + } + } + FlipcashTheme { + Box(Modifier.fillMaxSize().background(CodeTheme.colors.background)) { + DesktopLinkScreen(state, onRetry = { attempt++ }) + } + } +} + +/** + * The address the phone dials: the first site-local IPv4 address on an interface that is up. The + * one piece of linking that stays in the desktop app, since the phone never needs its own address. + */ +internal fun lanAddress(): String? = NetworkInterface.getNetworkInterfaces().asSequence() + .filter { it.isUp && !it.isLoopback && !it.isVirtual } + .flatMap { it.inetAddresses.asSequence() } + .filterIsInstance() + .firstOrNull { it.isSiteLocalAddress } + ?.hostAddress diff --git a/apps/desktop/src/main/kotlin/com/flipcash/desktop/DesktopGraph.kt b/apps/desktop/src/main/kotlin/com/flipcash/desktop/DesktopGraph.kt index 42fa4573bd..43b60dd831 100644 --- a/apps/desktop/src/main/kotlin/com/flipcash/desktop/DesktopGraph.kt +++ b/apps/desktop/src/main/kotlin/com/flipcash/desktop/DesktopGraph.kt @@ -39,6 +39,7 @@ interface DesktopGraph { val analytics: FlipcashAnalytics val userManager: com.flipcash.services.user.UserManager val accountController: com.flipcash.services.controllers.AccountController + val seedVault: com.flipcash.app.devicelink.SeedVault // Android constructs this eagerly in FlipcashApp.onCreate; it is what turns Events.OnLoggedIn into // SessionListener.onUserLoggedIn calls. diff --git a/apps/desktop/src/main/kotlin/com/flipcash/desktop/DesktopModule.kt b/apps/desktop/src/main/kotlin/com/flipcash/desktop/DesktopModule.kt index f984eb8a38..a276992220 100644 --- a/apps/desktop/src/main/kotlin/com/flipcash/desktop/DesktopModule.kt +++ b/apps/desktop/src/main/kotlin/com/flipcash/desktop/DesktopModule.kt @@ -5,6 +5,8 @@ import com.flipcash.app.core.AppRoute import com.flipcash.app.core.chat.TipHistorySource import com.flipcash.app.core.storage.DirectoryPreferencesFiles import com.flipcash.app.core.storage.PreferencesFiles +import com.flipcash.app.devicelink.KeyringSeedVault +import com.flipcash.app.devicelink.SeedVault import com.flipcash.app.funding.PurchaseMethod import com.flipcash.app.funding.PurchaseMethodController import com.flipcash.app.funding.PurchaseMethodMetadata @@ -49,6 +51,10 @@ object DesktopModule { File(System.getProperty("user.home"), ".flipcash").apply { mkdirs() } } + @Provides + @Singleton + fun seedVault(): SeedVault = KeyringSeedVault() + @Provides @Singleton fun dispatchers(): DispatcherProvider = object : DispatcherProvider { diff --git a/apps/desktop/src/main/kotlin/com/flipcash/desktop/DesktopSession.kt b/apps/desktop/src/main/kotlin/com/flipcash/desktop/DesktopSession.kt new file mode 100644 index 0000000000..5c7254ecb9 --- /dev/null +++ b/apps/desktop/src/main/kotlin/com/flipcash/desktop/DesktopSession.kt @@ -0,0 +1,64 @@ +package com.flipcash.desktop + +import com.flipcash.app.devicelink.SeedVault +import com.flipcash.app.persistence.FlipcashDatabase +import com.flipcash.app.persistence.init +import com.flipcash.services.controllers.AccountController +import com.flipcash.services.user.AuthState +import com.flipcash.services.user.UserManager +import com.getcode.crypt.MnemonicPhrase +import java.io.File + +/** + * Signs the desktop in from a seed: the one a phone linked into the [SeedVault], or, for development, + * a recovery phrase in `FLIPCASH_DEV_MNEMONIC` (set by Gradle from `flipcash.test.mnemonic` in + * local.properties, only when present). The dev phrase is never written to the vault or logged. + * + * Kept in the desktop app: [FlipcashDatabase.init] takes a [File], and the app module is JVM-only. + */ +internal object DesktopSession { + private const val VARIABLE = "FLIPCASH_DEV_MNEMONIC" + + /** The dev phrase's entropy, or null when none is configured. */ + fun devEntropy(): String? { + val words = System.getenv(VARIABLE)?.trim()?.split(Regex("\\s+"))?.takeIf { it.size > 1 } ?: return null + return MnemonicPhrase.newInstance(words)?.getBase64EncodedEntropy() + ?: run { println("dev session: $VARIABLE is not a 12 or 24 word phrase"); null } + } + + /** The same steps `AuthManager.login` walks for an account that has finished onboarding. */ + suspend fun signIn( + entropyB64: String, + userManager: UserManager, + accountController: AccountController, + dataDir: File, + ): Result { + userManager.establish(entropyB64) + return accountController.login().map { accountId -> + FlipcashDatabase.init(dataDir, entropyB64) + userManager.set(accountId = accountId) + userManager.set(AuthState.Ready) + } + } +} + +internal suspend fun DesktopGraph.signIn(entropyB64: String): Result = + DesktopSession.signIn(entropyB64, userManager, accountController, DesktopModule.appDir) + +/** + * Signs in at launch with the dev phrase if one is configured, else with the seed a phone linked + * earlier. Returns false when neither is there, and the app shows the link screen. Run [startup] first. + */ +internal suspend fun DesktopGraph.restoreSession(): Boolean { + DesktopSession.devEntropy()?.let { entropy -> + return signIn(entropy) + .onSuccess { println("session: signed in (dev phrase)") } + .onFailure { println("session: dev sign-in failed (${it.message})") } + .isSuccess + } + val stored = seedVault.read() ?: return false.also { println("session: not linked") } + return signIn(stored) + .onSuccess { println("session: signed in (linked seed)") } + .onFailure { println("session: linked sign-in failed (${it.message})") } + .isSuccess +} diff --git a/apps/desktop/src/main/kotlin/com/flipcash/desktop/DevSession.kt b/apps/desktop/src/main/kotlin/com/flipcash/desktop/DevSession.kt deleted file mode 100644 index 5663043352..0000000000 --- a/apps/desktop/src/main/kotlin/com/flipcash/desktop/DevSession.kt +++ /dev/null @@ -1,45 +0,0 @@ -package com.flipcash.desktop - -import com.flipcash.app.persistence.FlipcashDatabase -import com.flipcash.app.persistence.init -import com.flipcash.services.controllers.AccountController -import com.flipcash.services.user.AuthState -import com.flipcash.services.user.UserManager -import com.getcode.crypt.MnemonicPhrase -import java.io.File - -/** - * Development-only sign-in until the link-from-phone flow lands: reads a recovery phrase from the - * `FLIPCASH_DEV_MNEMONIC` environment variable (set by Gradle from `flipcash.test.mnemonic` in - * local.properties, only when present) and walks the same steps `AuthManager.login` does for an - * account that has finished onboarding. The phrase is never logged. - */ -internal object DevSession { - private const val VARIABLE = "FLIPCASH_DEV_MNEMONIC" - - suspend fun signIn( - userManager: UserManager, - accountController: AccountController, - dataDir: File, - ): Result { - val words = System.getenv(VARIABLE)?.trim()?.split(Regex("\\s+")) - ?.takeIf { it.size > 1 } - ?: return Result.failure(IllegalStateException("$VARIABLE not set")) - val entropy = MnemonicPhrase.newInstance(words)?.getBase64EncodedEntropy() - ?: return Result.failure(IllegalArgumentException("$VARIABLE is not a 12 or 24 word phrase")) - - userManager.establish(entropy) - return accountController.login().map { accountId -> - FlipcashDatabase.init(dataDir, entropy) - userManager.set(accountId = accountId) - userManager.set(AuthState.Ready) - } - } -} - -/** Signs in with the dev phrase when one is configured; otherwise the wallet stays signed out. Run [startup] first. */ -internal suspend fun DesktopGraph.devSignIn() { - DevSession.signIn(userManager, accountController, DesktopModule.appDir) - .onSuccess { println("dev session: signed in") } - .onFailure { println("dev session: not signed in (${it.message})") } -} diff --git a/apps/desktop/src/main/kotlin/com/flipcash/desktop/Main.kt b/apps/desktop/src/main/kotlin/com/flipcash/desktop/Main.kt index df61615149..8bcda37187 100644 --- a/apps/desktop/src/main/kotlin/com/flipcash/desktop/Main.kt +++ b/apps/desktop/src/main/kotlin/com/flipcash/desktop/Main.kt @@ -11,9 +11,9 @@ import java.lang.management.ManagementFactory fun main() { val graph = createGraph() - runBlocking { + val signedIn = runBlocking { graph.startup() - graph.devSignIn() + graph.restoreSession() } application { Window( @@ -21,7 +21,7 @@ fun main() { title = "Flipcash", state = rememberWindowState(width = 420.dp, height = 860.dp), ) { - DesktopWalletContent(graph) + DesktopApp(graph, signedIn) LaunchedEffect(Unit) { val sinceJvmStart = System.currentTimeMillis() - ManagementFactory.getRuntimeMXBean().startTime diff --git a/apps/desktop/src/main/kotlin/com/flipcash/desktop/SnapshotMain.kt b/apps/desktop/src/main/kotlin/com/flipcash/desktop/SnapshotMain.kt index fa8d2dac4b..3f30a1de54 100644 --- a/apps/desktop/src/main/kotlin/com/flipcash/desktop/SnapshotMain.kt +++ b/apps/desktop/src/main/kotlin/com/flipcash/desktop/SnapshotMain.kt @@ -11,17 +11,19 @@ import org.jetbrains.skia.EncodedImageFormat /** * Renders the wallet screen off-screen through the same graph as [main] and writes a PNG. - * Usage: `./gradlew :apps:desktop:snapshot -Pout=`. + * Usage: `./gradlew :apps:desktop:snapshot -Pout=`; add `-Pscreen=link` for the link screen, + * which skips sign-in. */ fun main(args: Array) { val out = File(args.firstOrNull() ?: "wallet.png") + val linkScreen = args.getOrNull(1) == "link" val graph = createGraph() runBlocking { graph.startup() - graph.devSignIn() + if (!linkScreen) graph.restoreSession() } ImageComposeScene(width = 840, height = 1720, density = Density(2f)) { - DesktopWalletContent(graph) + if (linkScreen) DesktopLinkContent(graph, onSignedIn = {}) else DesktopWalletContent(graph) }.use { scene -> var nanos = 0L repeat(80) { diff --git a/apps/flipcash/shared/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/PhoneLinkController.kt b/apps/flipcash/shared/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/PhoneLinkController.kt new file mode 100644 index 0000000000..42a0118e16 --- /dev/null +++ b/apps/flipcash/shared/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/PhoneLinkController.kt @@ -0,0 +1,67 @@ +package com.flipcash.app.devicelink + +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.launch + +/** + * The phone's link flow as state: scan, compare codes, send. [seed] supplies the signed-in + * account's base64 entropy and is read only after the user confirms the codes match. + */ +class PhoneLinkController( + private val scope: CoroutineScope, + private val seed: suspend () -> String?, +) { + sealed interface State { + data object Scanning : State + data object Connecting : State + data class Confirm(val code: String) : State + data object Sending : State + data object Linked : State + data class Failed(val reason: String) : State + } + + private val _state = MutableStateFlow(State.Scanning) + val state: StateFlow = _state.asStateFlow() + private var pending: PhoneLinker.Pending? = null + + fun onScanned(text: String) { + if (_state.value != State.Scanning) return + val invite = LinkInvite.parse(text) ?: return + _state.value = State.Connecting + scope.launch { + PhoneLinker.connect(invite) + .onSuccess { + pending = it + _state.value = State.Confirm(it.code) + } + .onFailure { _state.value = State.Failed(it.message ?: "Couldn't reach the desktop") } + } + } + + fun confirm() { + val p = pending ?: return + pending = null + _state.value = State.Sending + scope.launch { + val entropy = seed() + if (entropy == null) { + p.cancel() + _state.value = State.Failed("This phone isn't signed in") + return@launch + } + p.confirm(entropy) + .onSuccess { _state.value = State.Linked } + .onFailure { _state.value = State.Failed(it.message ?: "The link failed") } + } + } + + fun cancel() { + val p = pending + pending = null + scope.launch { p?.cancel() } + _state.value = State.Scanning + } +} diff --git a/apps/flipcash/shared/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/ui/DesktopLinkScreen.kt b/apps/flipcash/shared/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/ui/DesktopLinkScreen.kt new file mode 100644 index 0000000000..0f94f2d2b7 --- /dev/null +++ b/apps/flipcash/shared/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/ui/DesktopLinkScreen.kt @@ -0,0 +1,83 @@ +package com.flipcash.app.devicelink.ui + +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.Button +import androidx.compose.material.CircularProgressIndicator +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import com.flipcash.app.devicelink.DesktopLinkHost +import com.getcode.theme.CodeTheme +import io.github.alexzhirkevich.qrose.rememberQrCodePainter + +/** What the desktop shows while linking: the QR code, then the code to compare with the phone. */ +@Composable +fun DesktopLinkScreen(state: DesktopLinkHost.State?, onRetry: () -> Unit, modifier: Modifier = Modifier) { + Column( + modifier.fillMaxSize().padding(32.dp), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center, + ) { + when (state) { + null, is DesktopLinkHost.State.Linked -> CircularProgressIndicator(color = CodeTheme.colors.textMain) + is DesktopLinkHost.State.Waiting -> { + Title("Link this computer") + Body("On your phone, open Settings, tap Link a Desktop, and scan this code.") + Spacer(Modifier.height(24.dp)) + Image( + painter = rememberQrCodePainter(state.invite), + contentDescription = "Link code", + modifier = Modifier + .size(240.dp) + .background(Color.White, RoundedCornerShape(12.dp)) + .padding(12.dp), + ) + } + is DesktopLinkHost.State.Confirm -> { + Title("Check the code") + Body("Confirm on your phone that it shows the same code.") + Spacer(Modifier.height(24.dp)) + Code(state.code) + } + is DesktopLinkHost.State.Failed -> { + Title("Couldn't link") + Body(state.reason) + Spacer(Modifier.height(24.dp)) + Button(onClick = onRetry) { Text("Try again") } + } + } + } +} + +@Composable +internal fun Title(text: String) { + Text(text, style = CodeTheme.typography.displaySmall, color = CodeTheme.colors.textMain, textAlign = TextAlign.Center) + Spacer(Modifier.height(12.dp)) +} + +@Composable +internal fun Body(text: String) { + Text(text, style = CodeTheme.typography.textMedium, color = CodeTheme.colors.textSecondary, textAlign = TextAlign.Center) +} + +@Composable +internal fun Code(code: String) { + Text( + "${code.take(3)} ${code.drop(3)}", + style = CodeTheme.typography.displayLarge, + color = CodeTheme.colors.textMain, + ) +} diff --git a/apps/flipcash/shared/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/ui/PhoneLinkScreen.kt b/apps/flipcash/shared/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/ui/PhoneLinkScreen.kt new file mode 100644 index 0000000000..5d4a1daaeb --- /dev/null +++ b/apps/flipcash/shared/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/ui/PhoneLinkScreen.kt @@ -0,0 +1,81 @@ +package com.flipcash.app.devicelink.ui + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.width +import androidx.compose.material.Button +import androidx.compose.material.CircularProgressIndicator +import androidx.compose.material.OutlinedButton +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import com.flipcash.app.devicelink.PhoneLinkController +import com.getcode.theme.CodeTheme + +/** + * The phone's "Link a Desktop" screen. [scanner] is the platform camera: it calls its argument with + * each QR payload it reads. Everything else here is common. + */ +@Composable +fun PhoneLinkScreen( + controller: PhoneLinkController, + scanner: @Composable (onScanned: (String) -> Unit) -> Unit, + onDone: () -> Unit, + modifier: Modifier = Modifier, +) { + val state by controller.state.collectAsState() + when (val s = state) { + PhoneLinkController.State.Scanning -> Box(modifier.fillMaxSize()) { + scanner(controller::onScanned) + Column(Modifier.align(Alignment.TopCenter).padding(32.dp), horizontalAlignment = Alignment.CenterHorizontally) { + Title("Link a Desktop") + Body("Scan the code shown on your computer.") + } + } + else -> Column( + modifier.fillMaxSize().padding(32.dp), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center, + ) { + when (s) { + PhoneLinkController.State.Connecting, PhoneLinkController.State.Sending -> + CircularProgressIndicator(color = CodeTheme.colors.textMain) + is PhoneLinkController.State.Confirm -> { + Title("Does your computer show this code?") + Body("Only confirm if the codes match. Confirming gives the computer full access to this account.") + Spacer(Modifier.height(24.dp)) + Code(s.code) + Spacer(Modifier.height(32.dp)) + Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.Center) { + OutlinedButton(onClick = controller::cancel) { Text("They don't match") } + Spacer(Modifier.width(12.dp)) + Button(onClick = controller::confirm) { Text("Codes match") } + } + } + PhoneLinkController.State.Linked -> { + Title("Desktop linked") + Spacer(Modifier.height(24.dp)) + Button(onClick = onDone) { Text("Done") } + } + is PhoneLinkController.State.Failed -> { + Title("Couldn't link") + Body(s.reason) + Spacer(Modifier.height(24.dp)) + Button(onClick = controller::cancel) { Text("Scan again") } + } + PhoneLinkController.State.Scanning -> Unit + } + } + } +} diff --git a/apps/flipcash/shared/device-link/src/jvmTest/kotlin/com/flipcash/app/devicelink/LinkProtocolTest.kt b/apps/flipcash/shared/device-link/src/jvmTest/kotlin/com/flipcash/app/devicelink/LinkProtocolTest.kt index 78ef00f92b..b7c19b74b8 100644 --- a/apps/flipcash/shared/device-link/src/jvmTest/kotlin/com/flipcash/app/devicelink/LinkProtocolTest.kt +++ b/apps/flipcash/shared/device-link/src/jvmTest/kotlin/com/flipcash/app/devicelink/LinkProtocolTest.kt @@ -7,6 +7,7 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.async import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.collect +import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking @@ -133,6 +134,26 @@ class LinkProtocolTest { vault.clear() assertNull(vault.read()) } + + @Test + fun `the phone controller reads the seed only after confirm`() { + var seedReads = 0 + val states = runLink { invite -> + kotlinx.coroutines.coroutineScope { + val controller = PhoneLinkController(this) { seedReads++; seed } + controller.onScanned(invite.encode()) + val confirm = withTimeout(10_000) { + controller.state.first { it is PhoneLinkController.State.Confirm } + } + assertIs(confirm) + assertEquals(0, seedReads) + controller.confirm() + withTimeout(10_000) { controller.state.first { it == PhoneLinkController.State.Linked } } + } + } + assertEquals(1, seedReads) + assertEquals(seed, assertIs(states.last()).entropyB64) + } } internal class InMemorySeedVault : SeedVault { From 0be26c7f7a221e4e131161c09c8e0f9d418f9f71 Mon Sep 17 00:00:00 2001 From: Brandon McAnsh Date: Sat, 24 Oct 2026 16:52:39 -0400 Subject: [PATCH 37/50] feat(myaccount): add Link a Desktop behind the LinkDesktop flag Settings > Advanced shows Link a Desktop when FeatureFlag.LinkDesktop is on (default off, Internal track). The screen is device-link's common PhoneLinkScreen and PhoneLinkController; LinkDesktopScreen only adds the Android pieces: a Hilt view model that reads the entropy from UserManager on confirm, the camera permission, and the ML Kit CodeScanner from ui:scanner. It lives in features/myaccount rather than device-link's androidMain because the scanner, the permission helpers and the settings navigation are all Android-only modules that myaccount already sits on. --- .../ui/navigation/AppScreenContent.kt | 2 + .../kotlin/com/flipcash/app/core/AppRoute.kt | 2 + .../features/myaccount/build.gradle.kts | 3 ++ .../app/myaccount/LinkDesktopScreen.kt | 49 +++++++++++++++++++ .../linkdesktop/LinkDesktopViewModel.kt | 20 ++++++++ .../internal/settings/SettingsMenuItems.kt | 12 +++++ .../internal/settings/SettingsViewModel.kt | 2 +- .../flipcash/app/featureflags/FeatureFlag.kt | 12 +++++ 8 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 apps/flipcash/features/myaccount/src/main/kotlin/com/flipcash/app/myaccount/LinkDesktopScreen.kt create mode 100644 apps/flipcash/features/myaccount/src/main/kotlin/com/flipcash/app/myaccount/internal/linkdesktop/LinkDesktopViewModel.kt diff --git a/apps/flipcash/app/src/main/kotlin/com/flipcash/app/internal/ui/navigation/AppScreenContent.kt b/apps/flipcash/app/src/main/kotlin/com/flipcash/app/internal/ui/navigation/AppScreenContent.kt index 76d35f1a3f..4d247dd7a8 100644 --- a/apps/flipcash/app/src/main/kotlin/com/flipcash/app/internal/ui/navigation/AppScreenContent.kt +++ b/apps/flipcash/app/src/main/kotlin/com/flipcash/app/internal/ui/navigation/AppScreenContent.kt @@ -20,6 +20,7 @@ import androidx.navigation3.runtime.NavBackStack import androidx.navigation3.scene.OverlayScene import androidx.navigation3.scene.SinglePaneSceneStrategy import com.flipcash.app.devicelogs.DeviceLogsScreen +import com.flipcash.app.myaccount.LinkDesktopScreen import com.flipcash.app.backupkey.BackupKeyScreen import com.flipcash.app.balance.WalletScreen import com.flipcash.app.cash.CashScreen @@ -219,6 +220,7 @@ internal fun appEntryProvider( annotatedEntry { TrustedWebsitesScreen() } annotatedEntry { BackupKeyScreen() } annotatedEntry { DeviceLogsScreen() } + annotatedEntry { LinkDesktopScreen() } annotatedEntry { AccountSelectionScreen() } annotatedEntry { UserFlagsScreen() } diff --git a/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/AppRoute.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/AppRoute.kt index 52b268b1d9..02fef9e993 100644 --- a/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/AppRoute.kt +++ b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/AppRoute.kt @@ -332,6 +332,8 @@ sealed interface AppRoute : NavKey, Parcelable { @Serializable data object DeviceLogs : Menu @Serializable + data object LinkDesktop : Menu + @Serializable data object AccountSelection : Menu @Serializable data object UserProfile : Menu diff --git a/apps/flipcash/features/myaccount/build.gradle.kts b/apps/flipcash/features/myaccount/build.gradle.kts index 781f5d7348..ea775c6bae 100644 --- a/apps/flipcash/features/myaccount/build.gradle.kts +++ b/apps/flipcash/features/myaccount/build.gradle.kts @@ -24,6 +24,7 @@ dependencies { implementation(project(":apps:flipcash:shared:chat")) implementation(project(":apps:flipcash:shared:common-ui")) implementation(project(":apps:flipcash:shared:contacts")) + implementation(project(":apps:flipcash:shared:device-link")) implementation(project(":apps:flipcash:shared:featureflags")) implementation(project(":apps:flipcash:shared:funding")) implementation(project(":apps:flipcash:shared:menu")) @@ -36,4 +37,6 @@ dependencies { implementation(project(":libs:messaging")) implementation(project(":libs:permissions:bindings")) implementation(project(":ui:biometrics")) + implementation(project(":ui:scanner")) + implementation(project(":libs:code-detection")) } diff --git a/apps/flipcash/features/myaccount/src/main/kotlin/com/flipcash/app/myaccount/LinkDesktopScreen.kt b/apps/flipcash/features/myaccount/src/main/kotlin/com/flipcash/app/myaccount/LinkDesktopScreen.kt new file mode 100644 index 0000000000..c96fccbf2f --- /dev/null +++ b/apps/flipcash/features/myaccount/src/main/kotlin/com/flipcash/app/myaccount/LinkDesktopScreen.kt @@ -0,0 +1,49 @@ +package com.flipcash.app.myaccount + +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.hilt.navigation.compose.hiltViewModel +import com.flipcash.app.devicelink.ui.PhoneLinkScreen +import com.flipcash.app.myaccount.internal.linkdesktop.LinkDesktopViewModel +import com.getcode.libs.code.detection.CodeScanResult +import com.getcode.navigation.core.LocalCodeNavigator +import com.getcode.ui.scanner.CodeScanner +import com.getcode.ui.scanner.views.CameraDisabledView +import com.getcode.util.permissions.PermissionResult +import com.getcode.util.permissions.rememberCameraPermission + +/** + * Android entry for linking a desktop. The flow and screens are common (device-link); this file + * only supplies what is Android-specific: the Hilt view model, the camera permission and the ML Kit + * scanner. + */ +@Composable +fun LinkDesktopScreen() { + val navigator = LocalCodeNavigator.current + val viewModel = hiltViewModel() + PhoneLinkScreen( + controller = viewModel.controller, + scanner = { onScanned -> QrScanner(onScanned) }, + onDone = { navigator.pop() }, + ) +} + +@Composable +private fun QrScanner(onScanned: (String) -> Unit) { + val camera = rememberCameraPermission() + if (camera.status != PermissionResult.Granted) { + CameraDisabledView(modifier = Modifier.fillMaxSize()) { camera.launch() } + return + } + CodeScanner( + scanningEnabled = true, + cameraGesturesEnabled = false, + modifier = Modifier.fillMaxSize(), + onPinchStateChanged = { _, _ -> }, + onPreviewStateChanged = { }, + onCodeScanned = { result -> + if (result is CodeScanResult.QrCode) result.results.forEach(onScanned) + }, + ) +} diff --git a/apps/flipcash/features/myaccount/src/main/kotlin/com/flipcash/app/myaccount/internal/linkdesktop/LinkDesktopViewModel.kt b/apps/flipcash/features/myaccount/src/main/kotlin/com/flipcash/app/myaccount/internal/linkdesktop/LinkDesktopViewModel.kt new file mode 100644 index 0000000000..5989b04096 --- /dev/null +++ b/apps/flipcash/features/myaccount/src/main/kotlin/com/flipcash/app/myaccount/internal/linkdesktop/LinkDesktopViewModel.kt @@ -0,0 +1,20 @@ +package com.flipcash.app.myaccount.internal.linkdesktop + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.flipcash.app.devicelink.PhoneLinkController +import com.flipcash.services.user.UserManager +import dagger.hilt.android.lifecycle.HiltViewModel +import javax.inject.Inject + +/** Holds the common [PhoneLinkController] for the screen's lifetime; the seed is read on confirm. */ +@HiltViewModel +internal class LinkDesktopViewModel @Inject constructor( + userManager: UserManager, +) : ViewModel() { + val controller = PhoneLinkController(viewModelScope) { userManager.state.value.entropy } + + override fun onCleared() { + controller.cancel() + } +} diff --git a/apps/flipcash/features/myaccount/src/main/kotlin/com/flipcash/app/myaccount/internal/settings/SettingsMenuItems.kt b/apps/flipcash/features/myaccount/src/main/kotlin/com/flipcash/app/myaccount/internal/settings/SettingsMenuItems.kt index 9e88254eb9..08ea883be5 100644 --- a/apps/flipcash/features/myaccount/src/main/kotlin/com/flipcash/app/myaccount/internal/settings/SettingsMenuItems.kt +++ b/apps/flipcash/features/myaccount/src/main/kotlin/com/flipcash/app/myaccount/internal/settings/SettingsMenuItems.kt @@ -4,6 +4,7 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.ContactMail import androidx.compose.material.icons.filled.Science import androidx.compose.material.icons.outlined.Block +import androidx.compose.material.icons.outlined.Computer import androidx.compose.material.icons.outlined.Description import androidx.compose.material.icons.outlined.Language import androidx.compose.material.icons.outlined.Palette @@ -14,6 +15,7 @@ import androidx.compose.ui.graphics.vector.rememberVectorPainter import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import com.flipcash.app.core.AppRoute +import com.flipcash.app.featureflags.FeatureFlag import com.flipcash.app.menu.FullMenuItem import com.flipcash.app.menu.StaffMenuItem import com.flipcash.core.R as CoreR @@ -74,6 +76,16 @@ internal data object DeviceLogs : FullMenuItem() { override val action: SettingsViewModel.Event = SettingsViewModel.Event.OpenScreen(AppRoute.Menu.DeviceLogs) } +internal data object LinkDesktop : FullMenuItem( + featureFlag = FeatureFlag.LinkDesktop, +) { + override val icon: Painter + @Composable get() = rememberVectorPainter(Icons.Outlined.Computer) + override val name: String + @Composable get() = "Link a Desktop" + override val action: SettingsViewModel.Event = SettingsViewModel.Event.OpenScreen(AppRoute.Menu.LinkDesktop) +} + internal data object BetaFlags : FullMenuItem() { override val icon: Painter @Composable get() = rememberVectorPainter(Icons.Filled.Science) diff --git a/apps/flipcash/features/myaccount/src/main/kotlin/com/flipcash/app/myaccount/internal/settings/SettingsViewModel.kt b/apps/flipcash/features/myaccount/src/main/kotlin/com/flipcash/app/myaccount/internal/settings/SettingsViewModel.kt index 1be724447e..82397364da 100644 --- a/apps/flipcash/features/myaccount/src/main/kotlin/com/flipcash/app/myaccount/internal/settings/SettingsViewModel.kt +++ b/apps/flipcash/features/myaccount/src/main/kotlin/com/flipcash/app/myaccount/internal/settings/SettingsViewModel.kt @@ -289,7 +289,7 @@ internal class SettingsViewModel @Inject constructor( SettingsSection(R.string.title_settingsSectionPrivacy, listOf(Blocklist, TrustedWebsites)), SettingsSection( R.string.title_advancedFeatures, - listOf(/* BillCustomizer, */ DeviceLogs, BetaFlags, SwitchAccount), + listOf(/* BillCustomizer, */ DeviceLogs, LinkDesktop, BetaFlags, SwitchAccount), ), SettingsSection( R.string.title_settingsSectionAccount, diff --git a/apps/flipcash/shared/featureflags/src/main/kotlin/com/flipcash/app/featureflags/FeatureFlag.kt b/apps/flipcash/shared/featureflags/src/main/kotlin/com/flipcash/app/featureflags/FeatureFlag.kt index 00e330d8dc..d1cee81833 100644 --- a/apps/flipcash/shared/featureflags/src/main/kotlin/com/flipcash/app/featureflags/FeatureFlag.kt +++ b/apps/flipcash/shared/featureflags/src/main/kotlin/com/flipcash/app/featureflags/FeatureFlag.kt @@ -88,6 +88,16 @@ sealed interface FeatureFlag { override val persistLogOut: Boolean = false } + /** Settings > Link a Desktop: hands this account's seed to a desktop over the LAN. */ + @FeatureFlagMarker + data object LinkDesktop: FeatureFlag { + override val key: String = "link_desktop_enabled" + override val default: Boolean = false + override val launched: Boolean = false + override val visible: Boolean = true + override val persistLogOut: Boolean = false + } + companion object { val entries: List> get() = FeatureFlagEntries.entries @@ -107,6 +117,7 @@ val FeatureFlag<*>.title: String FeatureFlag.BillTextures -> "Bill Textures" FeatureFlag.BackgroundReset -> "Background Reset" FeatureFlag.ShowNetworkState -> "Network Offline Indicator" + FeatureFlag.LinkDesktop -> "Link a Desktop" } val FeatureFlag<*>.message: String @@ -117,4 +128,5 @@ val FeatureFlag<*>.message: String FeatureFlag.BillTextures -> "When enabled, you'll gain the ability to select textures for bills during currency creation" FeatureFlag.BackgroundReset -> "Automatically returns the app to the camera screen after a period of inactivity with the app in the background" FeatureFlag.ShowNetworkState -> "When enabled, you'll gain the ability to see the network state on the Scanner when offline" + FeatureFlag.LinkDesktop -> "When enabled, Settings shows Link a Desktop, which sends this account to the Flipcash desktop app over your local network" } From b30bed1e0a74c2a3182c0e3cf0449dac3b9cd264 Mon Sep 17 00:00:00 2001 From: Brandon McAnsh Date: Sat, 24 Oct 2026 16:54:12 -0400 Subject: [PATCH 38/50] refactor(login): take the onboarding purchase step from the app features/login imported two internal symbols from features/purchase (PurchaseAccountScreenContent and PurchaseAccountViewModel) to show the registration purchase inside onboarding. OnboardingFlowScreen now takes an OnboardingPurchaseStep composable, the app passes purchase's new OnboardingPurchaseStep, and login no longer depends on the purchase module. Both modules stay src/main: neither is KMP yet, and converting them is outside this cut. --- .../ui/navigation/AppScreenContent.kt | 7 +++- apps/flipcash/features/login/build.gradle.kts | 1 - .../app/login/OnboardingFlowScreen.kt | 36 +++++++++---------- .../app/purchase/PurchaseAccountScreen.kt | 26 ++++++++++++++ 4 files changed, 49 insertions(+), 21 deletions(-) diff --git a/apps/flipcash/app/src/main/kotlin/com/flipcash/app/internal/ui/navigation/AppScreenContent.kt b/apps/flipcash/app/src/main/kotlin/com/flipcash/app/internal/ui/navigation/AppScreenContent.kt index 4d247dd7a8..8ed8e6f0f5 100644 --- a/apps/flipcash/app/src/main/kotlin/com/flipcash/app/internal/ui/navigation/AppScreenContent.kt +++ b/apps/flipcash/app/src/main/kotlin/com/flipcash/app/internal/ui/navigation/AppScreenContent.kt @@ -21,6 +21,7 @@ import androidx.navigation3.scene.OverlayScene import androidx.navigation3.scene.SinglePaneSceneStrategy import com.flipcash.app.devicelogs.DeviceLogsScreen import com.flipcash.app.myaccount.LinkDesktopScreen +import com.flipcash.app.purchase.OnboardingPurchaseStep import com.flipcash.app.backupkey.BackupKeyScreen import com.flipcash.app.balance.WalletScreen import com.flipcash.app.cash.CashScreen @@ -103,7 +104,11 @@ internal fun appEntryProvider( // Onboarding flow annotatedEntry { key -> - OnboardingFlowScreen(route = key, resultStateRegistry = resultStateRegistry) + OnboardingFlowScreen( + route = key, + resultStateRegistry = resultStateRegistry, + purchaseStep = { onAccountCreated -> OnboardingPurchaseStep(onAccountCreated) }, + ) } // Main diff --git a/apps/flipcash/features/login/build.gradle.kts b/apps/flipcash/features/login/build.gradle.kts index 0fffe64486..328ab6e8fa 100644 --- a/apps/flipcash/features/login/build.gradle.kts +++ b/apps/flipcash/features/login/build.gradle.kts @@ -21,7 +21,6 @@ dependencies { implementation(project(":apps:flipcash:shared:featureflags")) implementation(project(":apps:flipcash:shared:permissions")) implementation(project(":apps:flipcash:shared:userflags")) - implementation(project(":apps:flipcash:features:purchase")) implementation(project(":libs:datetime")) implementation(project(":libs:messaging")) implementation(project(":libs:permissions:bindings")) diff --git a/apps/flipcash/features/login/src/main/kotlin/com/flipcash/app/login/OnboardingFlowScreen.kt b/apps/flipcash/features/login/src/main/kotlin/com/flipcash/app/login/OnboardingFlowScreen.kt index 489a50c9e3..a5dff56979 100644 --- a/apps/flipcash/features/login/src/main/kotlin/com/flipcash/app/login/OnboardingFlowScreen.kt +++ b/apps/flipcash/features/login/src/main/kotlin/com/flipcash/app/login/OnboardingFlowScreen.kt @@ -50,8 +50,6 @@ import com.flipcash.app.permissions.asContactAccessHandle import com.flipcash.app.permissions.internal.contacts.ContactScreenContent import com.flipcash.app.permissions.internal.notifications.NotificationRationalePermissionContent import com.flipcash.app.permissions.internal.notifications.NotificationScreenContent -import com.flipcash.app.purchase.internal.PurchaseAccountScreenContent -import com.flipcash.app.purchase.internal.PurchaseAccountViewModel import com.flipcash.features.login.R import com.flipcash.services.user.AuthState import com.flipcash.services.user.UserManager @@ -118,17 +116,24 @@ import kotlin.time.Duration.Companion.milliseconds fun OnboardingFlowScreen( route: AppRoute.OnboardingFlow, resultStateRegistry: NavResultStateRegistry, + purchaseStep: OnboardingPurchaseStep, ) { when { route.phase == AppRoute.OnboardingFlow.Phase.Permissions -> - PermissionsPhaseFlowHost(route, resultStateRegistry) + PermissionsPhaseFlowHost(route, resultStateRegistry, purchaseStep) route.resumeAt == AppRoute.OnboardingFlow.ResumePoint.PostAccessKey -> CompleteExistingUserOnboarding() else -> - AccountPhaseFlowHost(route, resultStateRegistry) + AccountPhaseFlowHost(route, resultStateRegistry, purchaseStep) } } +/** + * The registration purchase screen, supplied by the app so this module doesn't depend on + * features/purchase. It calls `onAccountCreated` once the account is paid for. + */ +typealias OnboardingPurchaseStep = @Composable (onAccountCreated: () -> Unit) -> Unit + @Composable private fun CompleteExistingUserOnboarding() { val navigator = LocalCodeNavigator.current @@ -147,6 +152,7 @@ private fun CompleteExistingUserOnboarding() { private fun PermissionsPhaseFlowHost( route: AppRoute.OnboardingFlow, resultStateRegistry: NavResultStateRegistry, + purchaseStep: OnboardingPurchaseStep, ) { val outerNavigator = LocalCodeNavigator.current val checker = LocalPermissionChecker.current @@ -208,7 +214,7 @@ private fun PermissionsPhaseFlowHost( FlowExitReason.Canceled -> Unit } }, - entryProvider = onboardingEntryProvider(route), + entryProvider = onboardingEntryProvider(route, purchaseStep), ) } @@ -216,6 +222,7 @@ private fun PermissionsPhaseFlowHost( private fun AccountPhaseFlowHost( route: AppRoute.OnboardingFlow, resultStateRegistry: NavResultStateRegistry, + purchaseStep: OnboardingPurchaseStep, ) { val outerNavigator = LocalCodeNavigator.current @@ -235,7 +242,7 @@ private fun AccountPhaseFlowHost( FlowExitReason.Canceled -> Unit } }, - entryProvider = onboardingEntryProvider(route), + entryProvider = onboardingEntryProvider(route, purchaseStep), ) } @@ -294,6 +301,7 @@ private fun FlowNavigator.proceedToNameOrPermi private fun onboardingEntryProvider( route: AppRoute.OnboardingFlow, + purchaseStep: OnboardingPurchaseStep, ): (NavKey) -> NavEntry = entryProvider { // The pre-login landing; flows/screenshots anchor on `login_screen` rather than // the step-derived `start_screen`. @@ -313,7 +321,7 @@ private fun onboardingEntryProvider( PhotoAccessKeyScreen() } annotatedEntry { - PurchaseStepContent() + PurchaseStepContent(purchaseStep) } annotatedEntry { ContactPermissionStepContent() @@ -539,25 +547,15 @@ private fun AccessKeyStepContent() { } @Composable -private fun PurchaseStepContent() { - val viewModel = hiltViewModel() +private fun PurchaseStepContent(purchaseStep: OnboardingPurchaseStep) { val flowNavigator = rememberFlowNavigator() - val state by viewModel.stateFlow.collectAsStateWithLifecycle() val userManager = LocalUserManager.current - LaunchedEffect(viewModel) { - viewModel.eventFlow - .filterIsInstance() - .onEach { flowNavigator.proceedToNameOrPermissions(userManager) } - .launchIn(this) - } - Column { AppBarWithTitle() - PurchaseAccountScreenContent(state, viewModel::dispatchEvent) + purchaseStep { flowNavigator.proceedToNameOrPermissions(userManager) } } - BackHandler { /* swallow back during onboarding permissions */ } } diff --git a/apps/flipcash/features/purchase/src/main/kotlin/com/flipcash/app/purchase/PurchaseAccountScreen.kt b/apps/flipcash/features/purchase/src/main/kotlin/com/flipcash/app/purchase/PurchaseAccountScreen.kt index 5ae4a70f4f..afccad1cd3 100644 --- a/apps/flipcash/features/purchase/src/main/kotlin/com/flipcash/app/purchase/PurchaseAccountScreen.kt +++ b/apps/flipcash/features/purchase/src/main/kotlin/com/flipcash/app/purchase/PurchaseAccountScreen.kt @@ -2,6 +2,15 @@ package com.flipcash.app.purchase import androidx.compose.foundation.layout.Column import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.rememberUpdatedState +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.flipcash.app.purchase.internal.PurchaseAccountScreenContent +import com.flipcash.app.purchase.internal.PurchaseAccountViewModel +import kotlinx.coroutines.flow.filterIsInstance +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach import androidx.hilt.navigation.compose.hiltViewModel import com.flipcash.app.purchase.internal.PurchaseAccountScreen import com.getcode.navigation.core.LocalCodeNavigator @@ -25,3 +34,20 @@ fun PurchaseAccountScreen( PurchaseAccountScreen(hiltViewModel()) } } + +/** The purchase step inside onboarding; the app passes it to OnboardingFlowScreen. */ +@Composable +fun OnboardingPurchaseStep(onAccountCreated: () -> Unit) { + val viewModel = hiltViewModel() + val state by viewModel.stateFlow.collectAsStateWithLifecycle() + val currentOnAccountCreated by rememberUpdatedState(onAccountCreated) + + LaunchedEffect(viewModel) { + viewModel.eventFlow + .filterIsInstance() + .onEach { currentOnAccountCreated() } + .launchIn(this) + } + + PurchaseAccountScreenContent(state, viewModel::dispatchEvent) +} From d816647ec8a926620edbcd081c455860d3bec014 Mon Sep 17 00:00:00 2001 From: Brandon McAnsh Date: Sat, 24 Oct 2026 16:59:16 -0400 Subject: [PATCH 39/50] test(login): mock Base64.encode as well as encodeToString encodeBase64 now goes through android.util.Base64.encode (the shared base64Encode actual from the desktop spike's jvm target). The login view model tests only mocked encodeToString, so the Android stub returned null and the wrong-entropy-size test never saw its error. It passes on code/cash. --- .../flipcash/app/login/router/LoginViewModelCreateAccountTest.kt | 1 + .../com/flipcash/app/login/router/LoginViewModelErrorTest.kt | 1 + 2 files changed, 2 insertions(+) diff --git a/apps/flipcash/features/login/src/test/kotlin/com/flipcash/app/login/router/LoginViewModelCreateAccountTest.kt b/apps/flipcash/features/login/src/test/kotlin/com/flipcash/app/login/router/LoginViewModelCreateAccountTest.kt index 4460ca1a51..6c89de23b3 100644 --- a/apps/flipcash/features/login/src/test/kotlin/com/flipcash/app/login/router/LoginViewModelCreateAccountTest.kt +++ b/apps/flipcash/features/login/src/test/kotlin/com/flipcash/app/login/router/LoginViewModelCreateAccountTest.kt @@ -58,6 +58,7 @@ class LoginViewModelCreateAccountTest { BottomBarManager.clear() mockkStatic(android.util.Base64::class) every { android.util.Base64.encodeToString(any(), any()) } answers { java.util.Base64.getEncoder().encodeToString(firstArg()) } + every { android.util.Base64.encode(any(), any()) } answers { java.util.Base64.getEncoder().encode(firstArg()) } // LoginViewModel.init checks the stored account list on construction. whenever(authManager.accounts).thenReturn(accountStore) } diff --git a/apps/flipcash/features/login/src/test/kotlin/com/flipcash/app/login/router/LoginViewModelErrorTest.kt b/apps/flipcash/features/login/src/test/kotlin/com/flipcash/app/login/router/LoginViewModelErrorTest.kt index 9af3cb41df..d47817f103 100644 --- a/apps/flipcash/features/login/src/test/kotlin/com/flipcash/app/login/router/LoginViewModelErrorTest.kt +++ b/apps/flipcash/features/login/src/test/kotlin/com/flipcash/app/login/router/LoginViewModelErrorTest.kt @@ -54,6 +54,7 @@ class LoginViewModelErrorTest { // android.util.Base64 is stubbed in unit tests; mock it so encodeBase64() doesn't NPE mockkStatic(android.util.Base64::class) every { android.util.Base64.encodeToString(any(), any()) } answers { java.util.Base64.getEncoder().encodeToString(firstArg()) } + every { android.util.Base64.encode(any(), any()) } answers { java.util.Base64.getEncoder().encode(firstArg()) } // LoginViewModel.init checks the stored account list on construction. whenever(authManager.accounts).thenReturn(accountStore) } From 3b1580d9d149b4eee573748b9f97746ae2249bfe Mon Sep 17 00:00:00 2001 From: Brandon McAnsh Date: Sat, 24 Oct 2026 18:53:07 -0400 Subject: [PATCH 40/50] refactor(device-link): move the link protocol into a UI-free :libs:device-link iOS needs the protocol through SharedCore, which can't take Compose or :ui:theme. The protocol, crypto, invite, PhoneLinker and PhoneLinkController move as-is, same package, so callers in apps/desktop and features/myaccount don't change. :apps:flipcash:shared:device-link keeps the screens, SeedVault and the keyring store. SeedVault isn't UI, but it is desktop storage; iOS passes its seed in rather than reading a vault. The fake-vault test moves with SeedVault into its own file. --- .../shared/device-link/build.gradle.kts | 14 +++++----- .../app/devicelink/InMemorySeedVaultTest.kt | 27 +++++++++++++++++++ libs/device-link/build.gradle.kts | 24 +++++++++++++++++ .../app/devicelink/DesktopLinkHost.kt | 0 .../flipcash/app/devicelink/LinkChannel.kt | 0 .../com/flipcash/app/devicelink/LinkCrypto.kt | 0 .../com/flipcash/app/devicelink/LinkInvite.kt | 0 .../app/devicelink/PhoneLinkController.kt | 0 .../flipcash/app/devicelink/PhoneLinker.kt | 0 .../app/devicelink/LinkProtocolTest.kt | 17 ------------ settings.gradle.kts | 5 +++- 11 files changed, 61 insertions(+), 26 deletions(-) create mode 100644 apps/flipcash/shared/device-link/src/jvmTest/kotlin/com/flipcash/app/devicelink/InMemorySeedVaultTest.kt create mode 100644 libs/device-link/build.gradle.kts rename {apps/flipcash/shared => libs}/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/DesktopLinkHost.kt (100%) rename {apps/flipcash/shared => libs}/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/LinkChannel.kt (100%) rename {apps/flipcash/shared => libs}/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/LinkCrypto.kt (100%) rename {apps/flipcash/shared => libs}/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/LinkInvite.kt (100%) rename {apps/flipcash/shared => libs}/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/PhoneLinkController.kt (100%) rename {apps/flipcash/shared => libs}/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/PhoneLinker.kt (100%) rename {apps/flipcash/shared => libs}/device-link/src/jvmTest/kotlin/com/flipcash/app/devicelink/LinkProtocolTest.kt (92%) diff --git a/apps/flipcash/shared/device-link/build.gradle.kts b/apps/flipcash/shared/device-link/build.gradle.kts index d8dc6fe88c..42286691dc 100644 --- a/apps/flipcash/shared/device-link/build.gradle.kts +++ b/apps/flipcash/shared/device-link/build.gradle.kts @@ -4,9 +4,10 @@ plugins { alias(libs.plugins.jetbrains.compose) } -// Link a desktop to a phone over the LAN. The protocol, crypto, state and screens are common; the -// platform pieces are the seed store (jvmMain: OS keyring) and the camera, which the Android app -// passes into the phone screen. +// The link screens and the desktop seed store. The protocol, crypto and phone state are in +// :libs:device-link, which has no UI so iOS can use it through SharedCore. The platform pieces here +// are the seed store (jvmMain: OS keyring) and the camera, which the Android app passes into the +// phone screen. kotlin { android { namespace = "${Gradle.flipcashNamespace}.shared.devicelink" @@ -15,8 +16,7 @@ kotlin { sourceSets { commonMain.dependencies { implementation(libs.kotlinx.coroutines.core) - implementation(libs.sodium.bindings.kmp) - implementation(libs.ktor.network) + api(project(":libs:device-link")) implementation(libs.qrose) implementation(libs.jetbrains.compose.runtime) implementation(libs.jetbrains.compose.foundation) @@ -27,11 +27,9 @@ kotlin { jvmMain.dependencies { implementation(libs.java.keyring) } - // jvmTest, not commonTest: libsodium's Android binding loads its .so from an APK, so the - // protocol can't run in an Android host test (the same reason chat-cipher has no host test). + // jvmTest only for the keyring test, which needs a desktop OS keyring. jvmTest.dependencies { implementation(kotlin("test")) - implementation(libs.kotlinx.coroutines.test) } } } diff --git a/apps/flipcash/shared/device-link/src/jvmTest/kotlin/com/flipcash/app/devicelink/InMemorySeedVaultTest.kt b/apps/flipcash/shared/device-link/src/jvmTest/kotlin/com/flipcash/app/devicelink/InMemorySeedVaultTest.kt new file mode 100644 index 0000000000..641865785a --- /dev/null +++ b/apps/flipcash/shared/device-link/src/jvmTest/kotlin/com/flipcash/app/devicelink/InMemorySeedVaultTest.kt @@ -0,0 +1,27 @@ +package com.flipcash.app.devicelink + +import kotlinx.coroutines.runBlocking +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertNull + +class InMemorySeedVaultTest { + private val seed = "c2VlZC1mb3ItdGVzdHMtb25seQ==" + + @Test + fun `vault round-trips through the fake`() = runBlocking { + val vault = InMemorySeedVault() + assertNull(vault.read()) + vault.write(seed) + assertEquals(seed, vault.read()) + vault.clear() + assertNull(vault.read()) + } +} + +internal class InMemorySeedVault : SeedVault { + private var value: String? = null + override suspend fun read() = value + override suspend fun write(entropyB64: String) { value = entropyB64 } + override suspend fun clear() { value = null } +} diff --git a/libs/device-link/build.gradle.kts b/libs/device-link/build.gradle.kts new file mode 100644 index 0000000000..f30a621c42 --- /dev/null +++ b/libs/device-link/build.gradle.kts @@ -0,0 +1,24 @@ +plugins { + alias(libs.plugins.flipcash.kmp.library) +} + +// The link protocol, crypto and phone-side state, with no UI, so iOS can drive it through +// SharedCore. The Compose screens and the desktop seed store live in :apps:flipcash:shared:device-link. +kotlin { + android { + namespace = "com.flipcash.libs.devicelink" + } + + sourceSets { + commonMain.dependencies { + // StateFlow is part of PhoneLinkController's API. + api(libs.kotlinx.coroutines.core) + implementation(libs.sodium.bindings.kmp) + implementation(libs.ktor.network) + } + jvmTest.dependencies { + implementation(kotlin("test")) + implementation(libs.kotlinx.coroutines.test) + } + } +} diff --git a/apps/flipcash/shared/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/DesktopLinkHost.kt b/libs/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/DesktopLinkHost.kt similarity index 100% rename from apps/flipcash/shared/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/DesktopLinkHost.kt rename to libs/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/DesktopLinkHost.kt diff --git a/apps/flipcash/shared/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/LinkChannel.kt b/libs/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/LinkChannel.kt similarity index 100% rename from apps/flipcash/shared/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/LinkChannel.kt rename to libs/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/LinkChannel.kt diff --git a/apps/flipcash/shared/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/LinkCrypto.kt b/libs/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/LinkCrypto.kt similarity index 100% rename from apps/flipcash/shared/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/LinkCrypto.kt rename to libs/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/LinkCrypto.kt diff --git a/apps/flipcash/shared/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/LinkInvite.kt b/libs/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/LinkInvite.kt similarity index 100% rename from apps/flipcash/shared/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/LinkInvite.kt rename to libs/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/LinkInvite.kt diff --git a/apps/flipcash/shared/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/PhoneLinkController.kt b/libs/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/PhoneLinkController.kt similarity index 100% rename from apps/flipcash/shared/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/PhoneLinkController.kt rename to libs/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/PhoneLinkController.kt diff --git a/apps/flipcash/shared/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/PhoneLinker.kt b/libs/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/PhoneLinker.kt similarity index 100% rename from apps/flipcash/shared/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/PhoneLinker.kt rename to libs/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/PhoneLinker.kt diff --git a/apps/flipcash/shared/device-link/src/jvmTest/kotlin/com/flipcash/app/devicelink/LinkProtocolTest.kt b/libs/device-link/src/jvmTest/kotlin/com/flipcash/app/devicelink/LinkProtocolTest.kt similarity index 92% rename from apps/flipcash/shared/device-link/src/jvmTest/kotlin/com/flipcash/app/devicelink/LinkProtocolTest.kt rename to libs/device-link/src/jvmTest/kotlin/com/flipcash/app/devicelink/LinkProtocolTest.kt index b7c19b74b8..a607650a03 100644 --- a/apps/flipcash/shared/device-link/src/jvmTest/kotlin/com/flipcash/app/devicelink/LinkProtocolTest.kt +++ b/libs/device-link/src/jvmTest/kotlin/com/flipcash/app/devicelink/LinkProtocolTest.kt @@ -125,16 +125,6 @@ class LinkProtocolTest { assertNull(LinkInvite.parse(invite.encode().replace("p=50123", "p=0"))) } - @Test - fun `vault round-trips through the fake`() = runBlocking { - val vault = InMemorySeedVault() - assertNull(vault.read()) - vault.write(seed) - assertEquals(seed, vault.read()) - vault.clear() - assertNull(vault.read()) - } - @Test fun `the phone controller reads the seed only after confirm`() { var seedReads = 0 @@ -155,10 +145,3 @@ class LinkProtocolTest { assertEquals(seed, assertIs(states.last()).entropyB64) } } - -internal class InMemorySeedVault : SeedVault { - private var value: String? = null - override suspend fun read() = value - override suspend fun write(entropyB64: String) { value = entropyB64 } - override suspend fun clear() { value = null } -} diff --git a/settings.gradle.kts b/settings.gradle.kts index 567d7bca20..d57728a4be 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -213,6 +213,7 @@ include( ":libs:currency-math", ":libs:currency-math:discrete-curve", ":libs:datetime", + ":libs:device-link", ":libs:emojis", ":libs:encryption:base58", ":libs:encryption:chat-cipher", @@ -342,10 +343,12 @@ val kmpUnitTestModules = setOf( // ed25519 and mnemonic excluded: both pull in the JNI-backed Ed25519Kmp Android actual for their // host vector tests, which can't load on the Linux CI runner (see kmpUnitTestModules). chat-cipher // has no host test for the same reason, plus libsodium's Android binding; its vectors run on the -// iOS simulator in the SharedCore tests workflow and as a device test. +// iOS simulator in the SharedCore tests workflow and as a device test. device-link is the same: +// its protocol tests need libsodium, so they run on jvm and the iOS simulator. val noUnitTestModules = setOf( ":apps:flipcash:benchmark", ":kmp:shared-core", + ":libs:device-link", ":libs:encryption:chat-cipher", ":libs:encryption:ed25519", ":libs:encryption:mnemonic", From f16663fc0b9c7f7882069e5f1759564475c20786 Mon Sep 17 00:00:00 2001 From: Brandon McAnsh Date: Sat, 24 Oct 2026 18:54:26 -0400 Subject: [PATCH 41/50] test(device-link): run the link protocol tests on every target LinkProtocolTest moves from jvmTest to commonTest and now also runs on iosSimulatorArm64 (7/7, real loopback sockets and the native libsodium). Android gets a device-test source set instead of a host test, because libsodium's Android binding loads its .so from the APK; chat-cipher has the same limit. shared-core-tests runs the iOS target. --- .github/workflows/shared-core-tests.yml | 2 ++ libs/device-link/build.gradle.kts | 19 +++++++++++++++++-- .../app/devicelink/LinkProtocolTest.kt | 14 +++++++------- 3 files changed, 26 insertions(+), 9 deletions(-) rename libs/device-link/src/{jvmTest => commonTest}/kotlin/com/flipcash/app/devicelink/LinkProtocolTest.kt (94%) diff --git a/.github/workflows/shared-core-tests.yml b/.github/workflows/shared-core-tests.yml index 2a28273337..e50e36421e 100644 --- a/.github/workflows/shared-core-tests.yml +++ b/.github/workflows/shared-core-tests.yml @@ -10,6 +10,7 @@ on: - 'kmp/shared-core/**' - 'libs/codes/kikcode/**' - 'libs/currency-math/**' + - 'libs/device-link/**' - 'libs/encryption/**' - 'libs/reporting/**' - 'libs/analytics-events/**' @@ -72,6 +73,7 @@ jobs: :libs:analytics-events:iosSimulatorArm64Test \ :libs:codes:kikcode:iosSimulatorArm64Test \ :libs:currency-math:discrete-curve:iosSimulatorArm64Test \ + :libs:device-link:iosSimulatorArm64Test \ :libs:encryption:base58:iosSimulatorArm64Test \ :libs:encryption:chat-cipher:iosSimulatorArm64Test \ :libs:encryption:ed25519:iosSimulatorArm64Test \ diff --git a/libs/device-link/build.gradle.kts b/libs/device-link/build.gradle.kts index f30a621c42..e9b1d588aa 100644 --- a/libs/device-link/build.gradle.kts +++ b/libs/device-link/build.gradle.kts @@ -1,3 +1,5 @@ +import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSetTree + plugins { alias(libs.plugins.flipcash.kmp.library) } @@ -7,6 +9,14 @@ plugins { kotlin { android { namespace = "com.flipcash.libs.devicelink" + // No host test: libsodium's Android binding loads its .so from the APK, so it doesn't load + // on a JVM host (chat-cipher has the same limit). commonTest runs on jvm, on the Apple + // targets natively, and on Android as a device test. + withDeviceTestBuilder { + sourceSetTreeName = KotlinSourceSetTree.test.name + }.configure { + instrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + } } sourceSets { @@ -16,9 +26,14 @@ kotlin { implementation(libs.sodium.bindings.kmp) implementation(libs.ktor.network) } - jvmTest.dependencies { + commonTest.dependencies { implementation(kotlin("test")) - implementation(libs.kotlinx.coroutines.test) + } + getByName("androidDeviceTest") { + dependencies { + implementation(libs.androidx.junit) + implementation(libs.androidx.test.runner) + } } } } diff --git a/libs/device-link/src/jvmTest/kotlin/com/flipcash/app/devicelink/LinkProtocolTest.kt b/libs/device-link/src/commonTest/kotlin/com/flipcash/app/devicelink/LinkProtocolTest.kt similarity index 94% rename from libs/device-link/src/jvmTest/kotlin/com/flipcash/app/devicelink/LinkProtocolTest.kt rename to libs/device-link/src/commonTest/kotlin/com/flipcash/app/devicelink/LinkProtocolTest.kt index a607650a03..4ba34b6b82 100644 --- a/libs/device-link/src/jvmTest/kotlin/com/flipcash/app/devicelink/LinkProtocolTest.kt +++ b/libs/device-link/src/commonTest/kotlin/com/flipcash/app/devicelink/LinkProtocolTest.kt @@ -43,7 +43,7 @@ class LinkProtocolTest { } @Test - fun `codes match and the seed arrives`() { + fun codesMatchAndTheSeedArrives() { var phoneCode: String? = null val states = runLink { invite -> val pending = PhoneLinker.connect(invite).getOrThrow() @@ -57,13 +57,13 @@ class LinkProtocolTest { } @Test - fun `cancelling on the phone sends nothing`() { + fun cancellingOnThePhoneSendsNothing() { val states = runLink { invite -> PhoneLinker.connect(invite).getOrThrow().cancel() } assertEquals(DesktopLinkHost.State.Failed("Cancelled on the phone"), states.last()) } @Test - fun `a swapped phone key changes the desktop's code`() { + fun aSwappedPhoneKeyChangesTheDesktopSCode() { // A man in the middle replaces the phone's key on the way to the desktop with one of its own. var phoneCode: String? = null val states = runLink { invite -> @@ -85,7 +85,7 @@ class LinkProtocolTest { } @Test - fun `tampered seed is rejected`() { + fun tamperedSeedIsRejected() { val states = runLink { invite -> val phone = LinkCrypto.ephemeral() val session = LinkCrypto.phoneSession(phone, invite.publicKey, invite.secret) @@ -103,7 +103,7 @@ class LinkProtocolTest { } @Test - fun `a device without the QR secret can't link`() { + fun aDeviceWithoutTheQRSecretCanTLink() { val states = runLink { invite -> val pending = PhoneLinker.connect( LinkInvite(invite.host, invite.port, invite.publicKey, LinkCrypto.secret()), @@ -114,7 +114,7 @@ class LinkProtocolTest { } @Test - fun `invite round-trips and rejects junk`() { + fun inviteRoundTripsAndRejectsJunk() { val invite = LinkInvite("192.168.1.20", 50123, ByteArray(32) { it.toByte() }, ByteArray(16) { 7 }) val parsed = LinkInvite.parse(invite.encode())!! assertEquals(invite.host, parsed.host) @@ -126,7 +126,7 @@ class LinkProtocolTest { } @Test - fun `the phone controller reads the seed only after confirm`() { + fun thePhoneControllerReadsTheSeedOnlyAfterConfirm() { var seedReads = 0 val states = runLink { invite -> kotlinx.coroutines.coroutineScope { From bdf1d484340757ed0744ba91d7b325d78d845391 Mon Sep 17 00:00:00 2001 From: Brandon McAnsh Date: Sat, 24 Oct 2026 18:56:51 -0400 Subject: [PATCH 42/50] test(device-link): check the link against fixed vectors device_link.json (canonical copy in the orchestrator's test-vectors/, from gen_device_link.py over PyNaCl) fixes keys, secret, transcript, both session keys, the six-digit code, and the sealed seed and ack frames for three cases, plus tampered seeds and bad invites. DeviceLinkVectorTest reproduces all of it on jvm and iosSimulatorArm64. LinkCrypto.seal gains an internal fixed-nonce overload for the test; production still draws a fresh nonce. --- libs/device-link/build.gradle.kts | 8 ++ .../com/flipcash/app/devicelink/LinkCrypto.kt | 12 ++- .../app/devicelink/DeviceLinkVectorTest.kt | 79 +++++++++++++++ .../src/commonTest/resources/device_link.json | 96 +++++++++++++++++++ 4 files changed, 192 insertions(+), 3 deletions(-) create mode 100644 libs/device-link/src/commonTest/kotlin/com/flipcash/app/devicelink/DeviceLinkVectorTest.kt create mode 100644 libs/device-link/src/commonTest/resources/device_link.json diff --git a/libs/device-link/build.gradle.kts b/libs/device-link/build.gradle.kts index e9b1d588aa..498b4a41cc 100644 --- a/libs/device-link/build.gradle.kts +++ b/libs/device-link/build.gradle.kts @@ -2,6 +2,13 @@ import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSetTree plugins { alias(libs.plugins.flipcash.kmp.library) + alias(libs.plugins.flipcash.kmp.test.fixtures) +} + +// Compiles `src/commonTest/resources` (device_link.json, canonical copy in the orchestrator's +// `test-vectors/`) into a generated `TestFixtures.kt` on `commonTest`, readable from every target. +testFixtures { + packageName = "com.flipcash.app.devicelink" } // The link protocol, crypto and phone-side state, with no UI, so iOS can drive it through @@ -28,6 +35,7 @@ kotlin { } commonTest.dependencies { implementation(kotlin("test")) + implementation(libs.kotlinx.serialization.json) } getByName("androidDeviceTest") { dependencies { diff --git a/libs/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/LinkCrypto.kt b/libs/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/LinkCrypto.kt index 6663337bce..4ef804cbb8 100644 --- a/libs/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/LinkCrypto.kt +++ b/libs/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/LinkCrypto.kt @@ -84,11 +84,17 @@ internal object LinkCrypto { fun seal(key: ByteArray, plaintext: ByteArray, transcript: ByteArray): ByteArray { ensureSodium() - val nonce = LibsodiumRandom.buf(NONCE_BYTES) + return seal(key, plaintext, transcript, LibsodiumRandom.buf(NONCE_BYTES).toByteArray()) + } + + /** Fixed-nonce form for the vectors only; production always draws a fresh nonce. */ + internal fun seal(key: ByteArray, plaintext: ByteArray, transcript: ByteArray, nonce: ByteArray): ByteArray { + require(nonce.size == NONCE_BYTES) + ensureSodium() val ct = AuthenticatedEncryptionWithAssociatedData.xChaCha20Poly1305IetfEncrypt( - plaintext.toUByteArray(), transcript.toUByteArray(), nonce, key.toUByteArray(), + plaintext.toUByteArray(), transcript.toUByteArray(), nonce.toUByteArray(), key.toUByteArray(), ) - return nonce.toByteArray() + ct.toByteArray() + return nonce + ct.toByteArray() } /** Null when the ciphertext was tampered with or sealed under another key or transcript. */ diff --git a/libs/device-link/src/commonTest/kotlin/com/flipcash/app/devicelink/DeviceLinkVectorTest.kt b/libs/device-link/src/commonTest/kotlin/com/flipcash/app/devicelink/DeviceLinkVectorTest.kt new file mode 100644 index 0000000000..b062e000c8 --- /dev/null +++ b/libs/device-link/src/commonTest/kotlin/com/flipcash/app/devicelink/DeviceLinkVectorTest.kt @@ -0,0 +1,79 @@ +package com.flipcash.app.devicelink + +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.JsonObject +import kotlinx.serialization.json.int +import kotlinx.serialization.json.jsonArray +import kotlinx.serialization.json.jsonObject +import kotlinx.serialization.json.jsonPrimitive +import kotlin.io.encoding.Base64 +import kotlin.test.Test +import kotlin.test.assertContentEquals +import kotlin.test.assertEquals +import kotlin.test.assertNotNull +import kotlin.test.assertNull + +/** GATE: reproduces every vector in `device_link.json` (canonical: test-vectors/device_link.json). */ +class DeviceLinkVectorTest { + private val root = Json.parseToJsonElement(readTestResource("device_link.json")).jsonObject + private val cases = root["cases"]!!.jsonArray.map { it.jsonObject } + private val rejects = root["rejects"]!!.jsonObject + + private fun JsonObject.str(key: String) = getValue(key).jsonPrimitive.content + private fun JsonObject.hex(key: String) = str(key).hexToByteArray() + + private fun JsonObject.sessions(): Pair { + val desktop = LinkCrypto.Ephemeral(hex("desktopPublicKey"), hex("desktopSecretKey")) + val phone = LinkCrypto.Ephemeral(hex("phonePublicKey"), hex("phoneSecretKey")) + return LinkCrypto.phoneSession(phone, desktop.publicKey, hex("secret")) to + LinkCrypto.desktopSession(desktop, phone.publicKey, hex("secret")) + } + + @Test + fun inviteEncodesAndParses() = cases.forEach { c -> + val invite = LinkInvite(c.str("host"), c.getValue("port").jsonPrimitive.int, c.hex("desktopPublicKey"), c.hex("secret")) + assertEquals(c.str("invite"), invite.encode(), c.str("name")) + val parsed = assertNotNull(LinkInvite.parse(c.str("invite")), c.str("name")) + assertEquals(c.str("host"), parsed.host) + assertContentEquals(c.hex("desktopPublicKey"), parsed.publicKey) + assertContentEquals(c.hex("secret"), parsed.secret) + } + + @Test + fun bothSidesDeriveTheVectorKeysAndCode() = cases.forEach { c -> + val (phone, desktop) = c.sessions() + for (s in listOf(phone, desktop)) { + assertContentEquals(c.hex("transcript"), s.transcript, c.str("name")) + assertContentEquals(c.hex("phoneToDesktop"), s.phoneToDesktop, c.str("name")) + assertContentEquals(c.hex("desktopToPhone"), s.desktopToPhone, c.str("name")) + assertEquals(c.str("code"), LinkCrypto.shortCode(s), c.str("name")) + } + } + + @Test + fun sealedFramesMatchAndOpen() = cases.forEach { c -> + val (phone, desktop) = c.sessions() + val seed = c.hex("sealedSeed") + val ack = c.hex("sealedAck") + assertContentEquals(seed, LinkCrypto.seal(phone.phoneToDesktop, c.hex("entropy"), phone.transcript, seed.copyOf(24))) + assertContentEquals(ack, LinkCrypto.seal(desktop.desktopToPhone, DesktopLinkHost.ACK_BODY, desktop.transcript, ack.copyOf(24))) + val opened = assertNotNull(LinkCrypto.open(desktop.phoneToDesktop, seed, desktop.transcript)) + assertEquals(c.str("entropyBase64"), Base64.encode(opened)) + assertContentEquals(DesktopLinkHost.ACK_BODY, LinkCrypto.open(phone.desktopToPhone, ack, phone.transcript)) + } + + @Test + fun rejectsTamperedSeeds() { + val c = cases.first() + val (_, desktop) = c.sessions() + rejects.getValue("seed").jsonArray.map { it.jsonObject }.forEach { r -> + val transcript = r["transcript"]?.let { r.hex("transcript") } ?: desktop.transcript + assertNull(LinkCrypto.open(desktop.phoneToDesktop, r.hex("sealedSeed"), transcript), r.str("why")) + } + } + + @Test + fun rejectsBadInvites() = rejects.getValue("invite").jsonArray.forEach { + assertNull(LinkInvite.parse(it.jsonPrimitive.content), it.jsonPrimitive.content) + } +} diff --git a/libs/device-link/src/commonTest/resources/device_link.json b/libs/device-link/src/commonTest/resources/device_link.json new file mode 100644 index 0000000000..8adadcd7f2 --- /dev/null +++ b/libs/device-link/src/commonTest/resources/device_link.json @@ -0,0 +1,96 @@ +{ + "description": "Phone-to-desktop link over the LAN: invite text, crypto_kx session keys, the six-digit code and the sealed seed and ack frames. See gen_device_link.py.", + "cases": [ + { + "name": "lan-12-words", + "invite": "flipcash-link:1?h=192.168.1.20&p=48123&k=BveKUyVTv3TssQTfYUh9fwxUGVZFu9M6CaV9W5Jm3ho&s=_sUgkjbGPHWQncScGrll1w", + "host": "192.168.1.20", + "port": 48123, + "desktopPublicKey": "06f78a532553bf74ecb104df61487d7f0c54195645bbd33a09a57d5b9266de1a", + "desktopSecretKey": "9897dc660c9483807e828e85e8843a8f0b5a71fa7fa7911e57cbcfea27061cd8", + "phonePublicKey": "7cee7d3d7029de3850edcbc8b6b06e44dc4cd8a3b23a936f29c1ee6608b9b828", + "phoneSecretKey": "5ea66d564704cf66d7fa188a0af0fec2729ed6c602944ecb305f6ea4a52a4ece", + "secret": "fec5209236c63c75909dc49c1ab965d7", + "transcript": "666c6970636173682d6c696e6b2d763106f78a532553bf74ecb104df61487d7f0c54195645bbd33a09a57d5b9266de1a7cee7d3d7029de3850edcbc8b6b06e44dc4cd8a3b23a936f29c1ee6608b9b828fec5209236c63c75909dc49c1ab965d7", + "phoneToDesktop": "82b5be733101fa50aaa99d09e6fb4e339c1012ae5e5f524c57dd3f137bd478b4", + "desktopToPhone": "f94df86ba1b61ccf06b32a0147958ba533197c910edfb2de70978837883c9600", + "code": "265450", + "entropy": "41174807528bbed5b2a26ac66f5d3473", + "entropyBase64": "QRdIB1KLvtWyomrGb100cw==", + "sealedSeed": "6b8b996d6558ebd2e59af43cf171f158e28317fb33eb01f94b6a7788410f496c75c49131e7d02b7f378736d4cc19dcd3c6159b278d5b357a", + "sealedAck": "eeebf9fc022a7c16e7845f4b4c86cb24b8b1ddbd0a0486c6aeeb03a2ebb2083b97378785eac41dc89d35fb3bcdf1" + }, + { + "name": "lan-24-words", + "invite": "flipcash-link:1?h=10.0.0.7&p=51000&k=q1O5O-eoLNjq4-zPIlPq_1TEqBfmvNms_cGgiyd59Go&s=iGLauo8IGnv18Ec4pq9-ZQ", + "host": "10.0.0.7", + "port": 51000, + "desktopPublicKey": "ab53b93be7a82cd8eae3eccf2253eaff54c4a817e6bcd9acfdc1a08b2779f46a", + "desktopSecretKey": "237dbe196eaf4b0f5e116e13cd448954a75455cb8bb35bca2da766f42e1ab224", + "phonePublicKey": "cb609a0e9fcc6ca6114647b58bddcd81813e30b4ca919552a132952296c68b05", + "phoneSecretKey": "64418c44786ff49dac046376034841ce9fa8b81e1e57d912c2e210aa7a0ec7d5", + "secret": "8862daba8f081a7bf5f04738a6af7e65", + "transcript": "666c6970636173682d6c696e6b2d7631ab53b93be7a82cd8eae3eccf2253eaff54c4a817e6bcd9acfdc1a08b2779f46acb609a0e9fcc6ca6114647b58bddcd81813e30b4ca919552a132952296c68b058862daba8f081a7bf5f04738a6af7e65", + "phoneToDesktop": "aca9e0e6b37a075c0a7490cccbd2f698e1c306f7b18bc67d7ca6f637b382c154", + "desktopToPhone": "0829fc1606ba542001f64145d13be2df9ca0a314a37a725bd0797eb8dd3ba003", + "code": "368657", + "entropy": "a8cfe6841fc2f081c767df1785e03b0b328033f3463b85331c4fcc506e8120cb", + "entropyBase64": "qM/mhB/C8IHHZ98XheA7CzKAM/NGO4UzHE/MUG6BIMs=", + "sealedSeed": "ab169ff6c65b4ab1a467fbd4e1dac11b393b8cd81438621eb1ef9182b278493c3d651a2e7e6b8ae25a6d287f6b876352d565fbd0a6a50410b8a4efa8380f539ad20b5af05a593cc1", + "sealedAck": "b9e51046ffb8b8eb837ff9fb202809b859ad9724741d368355e222b6deef21fc1072024e900bafe435d621c77675" + }, + { + "name": "ipv6-host", + "invite": "flipcash-link:1?h=fe80::1&p=1&k=GeWVIsqc92ADe5heL2c3qmsUdDdq9-fAQxd6GZ06vVU&s=ng6Vmpi7qI-z4Kb31_Ca2g", + "host": "fe80::1", + "port": 1, + "desktopPublicKey": "19e59522ca9cf760037b985e2f6737aa6b1474376af7e7c043177a199d3abd55", + "desktopSecretKey": "e8205bee98a257fddc3f50aa132a2738605fd0b0ea1c447582f39ae9b1a1c4b0", + "phonePublicKey": "2ce067837feb34304205c112225789df4ff75ce1b217b2714207336de56d4d3c", + "phoneSecretKey": "4e93a941037b76e32cd4c7c1cfe72a6bb927e215e3389d849759bc0d58cbc885", + "secret": "9e0e959a98bba88fb3e0a6f7d7f09ada", + "transcript": "666c6970636173682d6c696e6b2d763119e59522ca9cf760037b985e2f6737aa6b1474376af7e7c043177a199d3abd552ce067837feb34304205c112225789df4ff75ce1b217b2714207336de56d4d3c9e0e959a98bba88fb3e0a6f7d7f09ada", + "phoneToDesktop": "528a2c049fcbf66bb2d6d83f9498d1a7318511834adc9290cabee8bdb76977d3", + "desktopToPhone": "de1896076fc5e343db85c786b4e87570747c7eee2f8bfc0e3740c70293491e8c", + "code": "888568", + "entropy": "9c60110c42f90776a024c4ff2e1fb72c", + "entropyBase64": "nGARDEL5B3agJMT/Lh+3LA==", + "sealedSeed": "184bd6a0c00f21a1940576941450b6be0d84429a81c87b110217422a2eb78426b332a513b9fb746c8d3a0fcb751e930eb400045589a63cb9", + "sealedAck": "44042b75c90046d71bd48f04005894b21eb5f7bee6d523b218d0c6054479e2225a28c95d378d7df7443479f6c4ea" + } + ], + "rejects": { + "seed": [ + { + "why": "a flipped ciphertext byte", + "sealedSeed": "6b8b996d6558ebd2e59af43cf171f158e28317fb33eb01f94b6a7788410f486c75c49131e7d02b7f378736d4cc19dcd3c6159b278d5b357a" + }, + { + "why": "a flipped tag byte", + "sealedSeed": "6b8b996d6558ebd2e59af43cf171f158e28317fb33eb01f94b6a7788410f496c75c49131e7d02b7f378736d4cc19dcd3c6159b278d5b357b" + }, + { + "why": "a flipped nonce byte", + "sealedSeed": "6a8b996d6558ebd2e59af43cf171f158e28317fb33eb01f94b6a7788410f496c75c49131e7d02b7f378736d4cc19dcd3c6159b278d5b357a" + }, + { + "why": "nonce only, no ciphertext", + "sealedSeed": "6b8b996d6558ebd2e59af43cf171f158e28317fb33eb01f9" + }, + { + "why": "a transcript with another QR secret", + "sealedSeed": "6b8b996d6558ebd2e59af43cf171f158e28317fb33eb01f94b6a7788410f496c75c49131e7d02b7f378736d4cc19dcd3c6159b278d5b357a", + "transcript": "666c6970636173682d6c696e6b2d763106f78a532553bf74ecb104df61487d7f0c54195645bbd33a09a57d5b9266de1a7cee7d3d7029de3850edcbc8b6b06e44dc4cd8a3b23a936f29c1ee6608b9b82800000000000000000000000000000000" + } + ], + "invite": [ + "flipcash-link:2?h=192.168.1.20&p=48123&k=BveKUyVTv3TssQTfYUh9fwxUGVZFu9M6CaV9W5Jm3ho&s=_sUgkjbGPHWQncScGrll1w", + "flipcash-link:1?h=192.168.1.20&p=0&k=BveKUyVTv3TssQTfYUh9fwxUGVZFu9M6CaV9W5Jm3ho&s=_sUgkjbGPHWQncScGrll1w", + "flipcash-link:1?h=192.168.1.20&p=65536&k=BveKUyVTv3TssQTfYUh9fwxUGVZFu9M6CaV9W5Jm3ho&s=_sUgkjbGPHWQncScGrll1w", + "flipcash-link:1?h=&p=48123&k=BveKUyVTv3TssQTfYUh9fwxUGVZFu9M6CaV9W5Jm3ho&s=_sUgkjbGPHWQncScGrll1w", + "flipcash-link:1?h=192.168.1.20&p=48123&k=BveKUyVTv3TssQTfYUh9fwxUGVZFu9M6CaV9W5Jm3ho", + "flipcash-link:1?h=192.168.1.20&p=48123&k=BveKUyVTv3TssQTfYUh9fwxUGVZFu9M6CaV9W5Jm3ho&s=AAAAAAAAAAAAAAAAAAAA", + "https://flipcash.com/link" + ] + } +} From 4eb607f1a59e5f92cee669012d9d29a780c063f6 Mon Sep 17 00:00:00 2001 From: Brandon McAnsh Date: Sat, 24 Oct 2026 19:02:27 -0400 Subject: [PATCH 43/50] feat(shared-core): export the phone link to iOS PhoneLinkSession wraps PhoneLinkController for Swift: scanned(text:), confirm(entropyB64:), cancel(), close(), and an onState callback instead of a StateFlow and suspend functions. The seed is an argument to confirm, since iOS already holds it, and is kept only until the controller reads it after the user confirms the codes. PhoneLinker is now internal, so no ktor or Result types reach SharedCore.h. SharedCoreKit adds SharedDeviceLink, which maps the Kotlin states to a Swift enum on the main actor, and DeviceLinkTests, which check the code and seed opening against device_link.json through DeviceLinkVectors. --- kmp/shared-core/build.gradle.kts | 2 + .../Sources/SharedCoreKit/DeviceLink.swift | 64 +++++++++++++ .../SharedCoreKitTests/DeviceLinkTests.swift | 71 ++++++++++++++ .../Fixtures/device_link.json | 96 +++++++++++++++++++ .../app/devicelink/DeviceLinkVectors.kt | 32 +++++++ .../app/devicelink/PhoneLinkSession.kt | 49 ++++++++++ .../flipcash/app/devicelink/PhoneLinker.kt | 2 +- .../app/devicelink/DeviceLinkVectorTest.kt | 12 +++ .../app/devicelink/LinkProtocolTest.kt | 18 ++++ 9 files changed, 345 insertions(+), 1 deletion(-) create mode 100644 kmp/shared-core/spm/Sources/SharedCoreKit/DeviceLink.swift create mode 100644 kmp/shared-core/spm/Tests/SharedCoreKitTests/DeviceLinkTests.swift create mode 100644 kmp/shared-core/spm/Tests/SharedCoreKitTests/Fixtures/device_link.json create mode 100644 libs/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/DeviceLinkVectors.kt create mode 100644 libs/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/PhoneLinkSession.kt diff --git a/kmp/shared-core/build.gradle.kts b/kmp/shared-core/build.gradle.kts index 3bf85b67e9..fb7260fd73 100644 --- a/kmp/shared-core/build.gradle.kts +++ b/kmp/shared-core/build.gradle.kts @@ -43,6 +43,7 @@ kotlin { export(project(":libs:currency-math:discrete-curve")) export(project(":libs:reporting")) export(project(":libs:analytics-events")) + export(project(":libs:device-link")) } } @@ -61,6 +62,7 @@ kotlin { api(project(":libs:currency-math:discrete-curve")) api(project(":libs:reporting")) api(project(":libs:analytics-events")) + api(project(":libs:device-link")) } } } diff --git a/kmp/shared-core/spm/Sources/SharedCoreKit/DeviceLink.swift b/kmp/shared-core/spm/Sources/SharedCoreKit/DeviceLink.swift new file mode 100644 index 0000000000..f0fceb1cd6 --- /dev/null +++ b/kmp/shared-core/spm/Sources/SharedCoreKit/DeviceLink.swift @@ -0,0 +1,64 @@ +import Foundation +import SharedCore + +/// The phone side of linking a desktop, run by the shared Kotlin: scan the desktop's QR code, +/// show the six-digit code, and send the seed once the user confirms both screens match. +/// +/// The seed is passed to `confirm(entropyBase64:)` and to nothing else, so nothing leaves the +/// phone before the user has compared the codes. Call `close()` when the screen goes away. +@MainActor +public final class SharedDeviceLink { + + public enum State: Equatable, Sendable { + case scanning + case connecting + case confirm(code: String) + case sending + case linked + case failed(reason: String) + } + + private let session: PhoneLinkSession + + /// `onState` is called on the main actor, starting with `.scanning`. + public init(onState: @escaping @MainActor (State) -> Void) { + session = PhoneLinkSession { state in + let mapped = State(state) + Task { @MainActor in onState(mapped) } + } + } + + /// Hands a scanned QR payload to the link. Returns false if it isn't a desktop link invite. + @discardableResult + public func scanned(_ text: String) -> Bool { + session.scanned(text: text) + } + + /// The user saw the same code on both screens: send the account's base64 entropy. + public func confirm(entropyBase64: String) { + session.confirm(entropyB64: entropyBase64) + } + + /// Drops the pending link, if any, and goes back to scanning. + public func cancel() { + session.cancel() + } + + public func close() { + session.close() + } +} + +extension SharedDeviceLink.State { + + init(_ state: PhoneLinkControllerState) { + switch state { + case let confirm as PhoneLinkControllerStateConfirm: self = .confirm(code: confirm.code) + case let failed as PhoneLinkControllerStateFailed: self = .failed(reason: failed.reason) + case is PhoneLinkControllerStateConnecting: self = .connecting + case is PhoneLinkControllerStateSending: self = .sending + case is PhoneLinkControllerStateLinked: self = .linked + default: self = .scanning + } + } +} diff --git a/kmp/shared-core/spm/Tests/SharedCoreKitTests/DeviceLinkTests.swift b/kmp/shared-core/spm/Tests/SharedCoreKitTests/DeviceLinkTests.swift new file mode 100644 index 0000000000..745f2a69b3 --- /dev/null +++ b/kmp/shared-core/spm/Tests/SharedCoreKitTests/DeviceLinkTests.swift @@ -0,0 +1,71 @@ +import Foundation +import SharedCore +import Testing +@testable import SharedCoreKit + +@Suite struct DeviceLinkTests { + + struct Fixture: Decodable { + struct Case: Decodable { + let name: String + let invite: String + let desktopPublicKey: String + let desktopSecretKey: String + let phonePublicKey: String + let phoneSecretKey: String + let secret: String + let code: String + let entropy: String + let sealedSeed: String + } + + struct Rejects: Decodable { + let invite: [String] + } + + let cases: [Case] + let rejects: Rejects + } + + @Test func derivesTheVectorCodeAndOpensTheVectorSeed() throws { + let fixture = try Fixtures.load("device_link", as: Fixture.self) + #expect(!fixture.cases.isEmpty) + + for c in fixture.cases { + func hex(_ s: String) throws -> Data { try #require(Data(hex: s), "\(c.name): bad fixture hex") } + + let code = DeviceLinkVectors.shared.phoneCode( + phonePublicKey: try hex(c.phonePublicKey).kotlinByteArray, + phoneSecretKey: try hex(c.phoneSecretKey).kotlinByteArray, + desktopPublicKey: try hex(c.desktopPublicKey).kotlinByteArray, + secret: try hex(c.secret).kotlinByteArray + ) + #expect(code == c.code, "\(c.name): code") + + let opened = DeviceLinkVectors.shared.desktopOpenSeed( + desktopPublicKey: try hex(c.desktopPublicKey).kotlinByteArray, + desktopSecretKey: try hex(c.desktopSecretKey).kotlinByteArray, + phonePublicKey: try hex(c.phonePublicKey).kotlinByteArray, + secret: try hex(c.secret).kotlinByteArray, + sealedSeed: try hex(c.sealedSeed).kotlinByteArray + ) + #expect(opened.map { Data($0) } == (try hex(c.entropy)), "\(c.name): seed") + } + } + + @MainActor + @Test func acceptsVectorInvitesAndRejectsTheRest() throws { + let fixture = try Fixtures.load("device_link", as: Fixture.self) + for c in fixture.cases { + // A fresh link per invite: scanning moves it to connecting, which ignores later scans. + let link = SharedDeviceLink { _ in } + #expect(link.scanned(c.invite), "\(c.name)") + link.close() + } + let link = SharedDeviceLink { _ in } + defer { link.close() } + for invite in fixture.rejects.invite { + #expect(!link.scanned(invite), "\(invite)") + } + } +} diff --git a/kmp/shared-core/spm/Tests/SharedCoreKitTests/Fixtures/device_link.json b/kmp/shared-core/spm/Tests/SharedCoreKitTests/Fixtures/device_link.json new file mode 100644 index 0000000000..8adadcd7f2 --- /dev/null +++ b/kmp/shared-core/spm/Tests/SharedCoreKitTests/Fixtures/device_link.json @@ -0,0 +1,96 @@ +{ + "description": "Phone-to-desktop link over the LAN: invite text, crypto_kx session keys, the six-digit code and the sealed seed and ack frames. See gen_device_link.py.", + "cases": [ + { + "name": "lan-12-words", + "invite": "flipcash-link:1?h=192.168.1.20&p=48123&k=BveKUyVTv3TssQTfYUh9fwxUGVZFu9M6CaV9W5Jm3ho&s=_sUgkjbGPHWQncScGrll1w", + "host": "192.168.1.20", + "port": 48123, + "desktopPublicKey": "06f78a532553bf74ecb104df61487d7f0c54195645bbd33a09a57d5b9266de1a", + "desktopSecretKey": "9897dc660c9483807e828e85e8843a8f0b5a71fa7fa7911e57cbcfea27061cd8", + "phonePublicKey": "7cee7d3d7029de3850edcbc8b6b06e44dc4cd8a3b23a936f29c1ee6608b9b828", + "phoneSecretKey": "5ea66d564704cf66d7fa188a0af0fec2729ed6c602944ecb305f6ea4a52a4ece", + "secret": "fec5209236c63c75909dc49c1ab965d7", + "transcript": "666c6970636173682d6c696e6b2d763106f78a532553bf74ecb104df61487d7f0c54195645bbd33a09a57d5b9266de1a7cee7d3d7029de3850edcbc8b6b06e44dc4cd8a3b23a936f29c1ee6608b9b828fec5209236c63c75909dc49c1ab965d7", + "phoneToDesktop": "82b5be733101fa50aaa99d09e6fb4e339c1012ae5e5f524c57dd3f137bd478b4", + "desktopToPhone": "f94df86ba1b61ccf06b32a0147958ba533197c910edfb2de70978837883c9600", + "code": "265450", + "entropy": "41174807528bbed5b2a26ac66f5d3473", + "entropyBase64": "QRdIB1KLvtWyomrGb100cw==", + "sealedSeed": "6b8b996d6558ebd2e59af43cf171f158e28317fb33eb01f94b6a7788410f496c75c49131e7d02b7f378736d4cc19dcd3c6159b278d5b357a", + "sealedAck": "eeebf9fc022a7c16e7845f4b4c86cb24b8b1ddbd0a0486c6aeeb03a2ebb2083b97378785eac41dc89d35fb3bcdf1" + }, + { + "name": "lan-24-words", + "invite": "flipcash-link:1?h=10.0.0.7&p=51000&k=q1O5O-eoLNjq4-zPIlPq_1TEqBfmvNms_cGgiyd59Go&s=iGLauo8IGnv18Ec4pq9-ZQ", + "host": "10.0.0.7", + "port": 51000, + "desktopPublicKey": "ab53b93be7a82cd8eae3eccf2253eaff54c4a817e6bcd9acfdc1a08b2779f46a", + "desktopSecretKey": "237dbe196eaf4b0f5e116e13cd448954a75455cb8bb35bca2da766f42e1ab224", + "phonePublicKey": "cb609a0e9fcc6ca6114647b58bddcd81813e30b4ca919552a132952296c68b05", + "phoneSecretKey": "64418c44786ff49dac046376034841ce9fa8b81e1e57d912c2e210aa7a0ec7d5", + "secret": "8862daba8f081a7bf5f04738a6af7e65", + "transcript": "666c6970636173682d6c696e6b2d7631ab53b93be7a82cd8eae3eccf2253eaff54c4a817e6bcd9acfdc1a08b2779f46acb609a0e9fcc6ca6114647b58bddcd81813e30b4ca919552a132952296c68b058862daba8f081a7bf5f04738a6af7e65", + "phoneToDesktop": "aca9e0e6b37a075c0a7490cccbd2f698e1c306f7b18bc67d7ca6f637b382c154", + "desktopToPhone": "0829fc1606ba542001f64145d13be2df9ca0a314a37a725bd0797eb8dd3ba003", + "code": "368657", + "entropy": "a8cfe6841fc2f081c767df1785e03b0b328033f3463b85331c4fcc506e8120cb", + "entropyBase64": "qM/mhB/C8IHHZ98XheA7CzKAM/NGO4UzHE/MUG6BIMs=", + "sealedSeed": "ab169ff6c65b4ab1a467fbd4e1dac11b393b8cd81438621eb1ef9182b278493c3d651a2e7e6b8ae25a6d287f6b876352d565fbd0a6a50410b8a4efa8380f539ad20b5af05a593cc1", + "sealedAck": "b9e51046ffb8b8eb837ff9fb202809b859ad9724741d368355e222b6deef21fc1072024e900bafe435d621c77675" + }, + { + "name": "ipv6-host", + "invite": "flipcash-link:1?h=fe80::1&p=1&k=GeWVIsqc92ADe5heL2c3qmsUdDdq9-fAQxd6GZ06vVU&s=ng6Vmpi7qI-z4Kb31_Ca2g", + "host": "fe80::1", + "port": 1, + "desktopPublicKey": "19e59522ca9cf760037b985e2f6737aa6b1474376af7e7c043177a199d3abd55", + "desktopSecretKey": "e8205bee98a257fddc3f50aa132a2738605fd0b0ea1c447582f39ae9b1a1c4b0", + "phonePublicKey": "2ce067837feb34304205c112225789df4ff75ce1b217b2714207336de56d4d3c", + "phoneSecretKey": "4e93a941037b76e32cd4c7c1cfe72a6bb927e215e3389d849759bc0d58cbc885", + "secret": "9e0e959a98bba88fb3e0a6f7d7f09ada", + "transcript": "666c6970636173682d6c696e6b2d763119e59522ca9cf760037b985e2f6737aa6b1474376af7e7c043177a199d3abd552ce067837feb34304205c112225789df4ff75ce1b217b2714207336de56d4d3c9e0e959a98bba88fb3e0a6f7d7f09ada", + "phoneToDesktop": "528a2c049fcbf66bb2d6d83f9498d1a7318511834adc9290cabee8bdb76977d3", + "desktopToPhone": "de1896076fc5e343db85c786b4e87570747c7eee2f8bfc0e3740c70293491e8c", + "code": "888568", + "entropy": "9c60110c42f90776a024c4ff2e1fb72c", + "entropyBase64": "nGARDEL5B3agJMT/Lh+3LA==", + "sealedSeed": "184bd6a0c00f21a1940576941450b6be0d84429a81c87b110217422a2eb78426b332a513b9fb746c8d3a0fcb751e930eb400045589a63cb9", + "sealedAck": "44042b75c90046d71bd48f04005894b21eb5f7bee6d523b218d0c6054479e2225a28c95d378d7df7443479f6c4ea" + } + ], + "rejects": { + "seed": [ + { + "why": "a flipped ciphertext byte", + "sealedSeed": "6b8b996d6558ebd2e59af43cf171f158e28317fb33eb01f94b6a7788410f486c75c49131e7d02b7f378736d4cc19dcd3c6159b278d5b357a" + }, + { + "why": "a flipped tag byte", + "sealedSeed": "6b8b996d6558ebd2e59af43cf171f158e28317fb33eb01f94b6a7788410f496c75c49131e7d02b7f378736d4cc19dcd3c6159b278d5b357b" + }, + { + "why": "a flipped nonce byte", + "sealedSeed": "6a8b996d6558ebd2e59af43cf171f158e28317fb33eb01f94b6a7788410f496c75c49131e7d02b7f378736d4cc19dcd3c6159b278d5b357a" + }, + { + "why": "nonce only, no ciphertext", + "sealedSeed": "6b8b996d6558ebd2e59af43cf171f158e28317fb33eb01f9" + }, + { + "why": "a transcript with another QR secret", + "sealedSeed": "6b8b996d6558ebd2e59af43cf171f158e28317fb33eb01f94b6a7788410f496c75c49131e7d02b7f378736d4cc19dcd3c6159b278d5b357a", + "transcript": "666c6970636173682d6c696e6b2d763106f78a532553bf74ecb104df61487d7f0c54195645bbd33a09a57d5b9266de1a7cee7d3d7029de3850edcbc8b6b06e44dc4cd8a3b23a936f29c1ee6608b9b82800000000000000000000000000000000" + } + ], + "invite": [ + "flipcash-link:2?h=192.168.1.20&p=48123&k=BveKUyVTv3TssQTfYUh9fwxUGVZFu9M6CaV9W5Jm3ho&s=_sUgkjbGPHWQncScGrll1w", + "flipcash-link:1?h=192.168.1.20&p=0&k=BveKUyVTv3TssQTfYUh9fwxUGVZFu9M6CaV9W5Jm3ho&s=_sUgkjbGPHWQncScGrll1w", + "flipcash-link:1?h=192.168.1.20&p=65536&k=BveKUyVTv3TssQTfYUh9fwxUGVZFu9M6CaV9W5Jm3ho&s=_sUgkjbGPHWQncScGrll1w", + "flipcash-link:1?h=&p=48123&k=BveKUyVTv3TssQTfYUh9fwxUGVZFu9M6CaV9W5Jm3ho&s=_sUgkjbGPHWQncScGrll1w", + "flipcash-link:1?h=192.168.1.20&p=48123&k=BveKUyVTv3TssQTfYUh9fwxUGVZFu9M6CaV9W5Jm3ho", + "flipcash-link:1?h=192.168.1.20&p=48123&k=BveKUyVTv3TssQTfYUh9fwxUGVZFu9M6CaV9W5Jm3ho&s=AAAAAAAAAAAAAAAAAAAA", + "https://flipcash.com/link" + ] + } +} diff --git a/libs/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/DeviceLinkVectors.kt b/libs/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/DeviceLinkVectors.kt new file mode 100644 index 0000000000..c098c66b9f --- /dev/null +++ b/libs/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/DeviceLinkVectors.kt @@ -0,0 +1,32 @@ +package com.flipcash.app.devicelink + +/** + * The link crypto with fixed keys, so a caller outside Kotlin (the SharedCoreKit Swift tests) can + * be checked against `test-vectors/device_link.json`. These are pure functions; the real flow + * draws fresh keys for every link and never calls them. + */ +object DeviceLinkVectors { + + /** The six-digit code the phone shows. */ + fun phoneCode( + phonePublicKey: ByteArray, + phoneSecretKey: ByteArray, + desktopPublicKey: ByteArray, + secret: ByteArray, + ): String { + val session = LinkCrypto.phoneSession(LinkCrypto.Ephemeral(phonePublicKey, phoneSecretKey), desktopPublicKey, secret) + return LinkCrypto.shortCode(session).also { session.wipe() } + } + + /** What the desktop recovers from [sealedSeed], or null if it doesn't authenticate. */ + fun desktopOpenSeed( + desktopPublicKey: ByteArray, + desktopSecretKey: ByteArray, + phonePublicKey: ByteArray, + secret: ByteArray, + sealedSeed: ByteArray, + ): ByteArray? { + val session = LinkCrypto.desktopSession(LinkCrypto.Ephemeral(desktopPublicKey, desktopSecretKey), phonePublicKey, secret) + return LinkCrypto.open(session.phoneToDesktop, sealedSeed, session.transcript).also { session.wipe() } + } +} diff --git a/libs/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/PhoneLinkSession.kt b/libs/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/PhoneLinkSession.kt new file mode 100644 index 0000000000..59e154b891 --- /dev/null +++ b/libs/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/PhoneLinkSession.kt @@ -0,0 +1,49 @@ +package com.flipcash.app.devicelink + +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.cancel +import kotlinx.coroutines.launch + +/** + * [PhoneLinkController] for callers that can't collect a flow or call a suspend function, which in + * practice means Swift through SharedCore. It owns its own scope, so call [close] when the screen + * goes away. + * + * The seed comes from the caller at [confirm], not from a store: iOS already holds it. It is kept + * only until the controller reads it, which happens after the user has confirmed the codes match, + * so the read-after-confirm order of [PhoneLinkController] still holds. + * + * [onState] is called on a background thread; Swift callers hop to the main actor themselves. + */ +class PhoneLinkSession(private val onState: (PhoneLinkController.State) -> Unit) { + private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Default) + private var entropy: String? = null + private val controller = PhoneLinkController(scope) { entropy.also { entropy = null } } + + init { + scope.launch { controller.state.collect { onState(it) } } + } + + /** Hands a scanned QR payload to the flow. Returns false if it isn't a link invite. */ + fun scanned(text: String): Boolean { + if (LinkInvite.parse(text) == null) return false + controller.onScanned(text) + return true + } + + /** The user saw the same code on both screens: send [entropyB64] to the desktop. */ + fun confirm(entropyB64: String) { + entropy = entropyB64 + controller.confirm() + } + + /** Drops the pending link, if any, and goes back to scanning. */ + fun cancel() = controller.cancel() + + fun close() { + entropy = null + scope.cancel() + } +} diff --git a/libs/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/PhoneLinker.kt b/libs/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/PhoneLinker.kt index 2f385fa06b..b141be08b6 100644 --- a/libs/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/PhoneLinker.kt +++ b/libs/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/PhoneLinker.kt @@ -12,7 +12,7 @@ import kotlin.time.Duration.Companion.seconds * The phone side of a link. [connect] dials the invite's address and returns the code to compare; * the seed only leaves the phone through [Pending.confirm], after the user says the codes match. */ -object PhoneLinker { +internal object PhoneLinker { suspend fun connect(invite: LinkInvite): Result { val selector = SelectorManager(Dispatchers.Default) val phone = LinkCrypto.ephemeral() diff --git a/libs/device-link/src/commonTest/kotlin/com/flipcash/app/devicelink/DeviceLinkVectorTest.kt b/libs/device-link/src/commonTest/kotlin/com/flipcash/app/devicelink/DeviceLinkVectorTest.kt index b062e000c8..a3bdb5e7a4 100644 --- a/libs/device-link/src/commonTest/kotlin/com/flipcash/app/devicelink/DeviceLinkVectorTest.kt +++ b/libs/device-link/src/commonTest/kotlin/com/flipcash/app/devicelink/DeviceLinkVectorTest.kt @@ -62,6 +62,18 @@ class DeviceLinkVectorTest { assertContentEquals(DesktopLinkHost.ACK_BODY, LinkCrypto.open(phone.desktopToPhone, ack, phone.transcript)) } + @Test + fun theSwiftFacingEntryPointsMatchTheVectors() = cases.forEach { c -> + assertEquals( + c.str("code"), + DeviceLinkVectors.phoneCode(c.hex("phonePublicKey"), c.hex("phoneSecretKey"), c.hex("desktopPublicKey"), c.hex("secret")), + ) + val opened = DeviceLinkVectors.desktopOpenSeed( + c.hex("desktopPublicKey"), c.hex("desktopSecretKey"), c.hex("phonePublicKey"), c.hex("secret"), c.hex("sealedSeed"), + ) + assertContentEquals(c.hex("entropy"), opened) + } + @Test fun rejectsTamperedSeeds() { val c = cases.first() diff --git a/libs/device-link/src/commonTest/kotlin/com/flipcash/app/devicelink/LinkProtocolTest.kt b/libs/device-link/src/commonTest/kotlin/com/flipcash/app/devicelink/LinkProtocolTest.kt index 4ba34b6b82..998bde85cd 100644 --- a/libs/device-link/src/commonTest/kotlin/com/flipcash/app/devicelink/LinkProtocolTest.kt +++ b/libs/device-link/src/commonTest/kotlin/com/flipcash/app/devicelink/LinkProtocolTest.kt @@ -144,4 +144,22 @@ class LinkProtocolTest { assertEquals(1, seedReads) assertEquals(seed, assertIs(states.last()).entropyB64) } + + @Test + fun theSwiftFacingSessionLinksWithTheSeedGivenAtConfirm() { + val states = runLink { invite -> + val seen = Channel(Channel.UNLIMITED) + val session = PhoneLinkSession { seen.trySend(it) } + try { + assertEquals(false, session.scanned("not an invite")) + assertTrue(session.scanned(invite.encode())) + withTimeout(10_000) { while (seen.receive() !is PhoneLinkController.State.Confirm) Unit } + session.confirm(seed) + withTimeout(10_000) { while (seen.receive() != PhoneLinkController.State.Linked) Unit } + } finally { + session.close() + } + } + assertEquals(seed, assertIs(states.last()).entropyB64) + } } From 4574d2435ffc2404f391aba6baad6c6b86e8ee06 Mon Sep 17 00:00:00 2001 From: Brandon McAnsh Date: Thu, 29 Oct 2026 21:31:07 -0400 Subject: [PATCH 44/50] chore(desktop): keep android-only card action and submenu in androidMain --- .../shared/common/ui/profile/BalanceRequirementsCard.kt | 2 +- .../kotlin/com/flipcash/app/funding/BottomBarCardAction.kt | 0 .../kotlin/com/getcode/ui/components/SubmenuDropdownMenu.kt | 0 3 files changed, 1 insertion(+), 1 deletion(-) rename apps/flipcash/shared/funding/src/{commonMain => androidMain}/kotlin/com/flipcash/app/funding/BottomBarCardAction.kt (100%) rename ui/components/src/{commonMain => androidMain}/kotlin/com/getcode/ui/components/SubmenuDropdownMenu.kt (100%) diff --git a/apps/flipcash/shared/common-ui/src/commonMain/kotlin/com/flipcash/shared/common/ui/profile/BalanceRequirementsCard.kt b/apps/flipcash/shared/common-ui/src/commonMain/kotlin/com/flipcash/shared/common/ui/profile/BalanceRequirementsCard.kt index 0b1cdf7e40..38b018a3a2 100644 --- a/apps/flipcash/shared/common-ui/src/commonMain/kotlin/com/flipcash/shared/common/ui/profile/BalanceRequirementsCard.kt +++ b/apps/flipcash/shared/common-ui/src/commonMain/kotlin/com/flipcash/shared/common/ui/profile/BalanceRequirementsCard.kt @@ -207,7 +207,7 @@ private fun RequirementRow(label: String, value: String, compact: Boolean, onCli if (onClick != null) { Icon( modifier = Modifier.padding(start = 8.dp), - painter = painterResource(R.drawable.ic_chevron_right), + painter = painterResource(UiRes.drawable.ic_chevron_right), contentDescription = null, tint = CodeTheme.colors.textSecondary, ) diff --git a/apps/flipcash/shared/funding/src/commonMain/kotlin/com/flipcash/app/funding/BottomBarCardAction.kt b/apps/flipcash/shared/funding/src/androidMain/kotlin/com/flipcash/app/funding/BottomBarCardAction.kt similarity index 100% rename from apps/flipcash/shared/funding/src/commonMain/kotlin/com/flipcash/app/funding/BottomBarCardAction.kt rename to apps/flipcash/shared/funding/src/androidMain/kotlin/com/flipcash/app/funding/BottomBarCardAction.kt diff --git a/ui/components/src/commonMain/kotlin/com/getcode/ui/components/SubmenuDropdownMenu.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/components/SubmenuDropdownMenu.kt similarity index 100% rename from ui/components/src/commonMain/kotlin/com/getcode/ui/components/SubmenuDropdownMenu.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/components/SubmenuDropdownMenu.kt From 8082a8d9951c099fa47dd43d5f2ff2c85975ff82 Mon Sep 17 00:00:00 2001 From: Brandon McAnsh Date: Thu, 29 Oct 2026 21:34:46 -0400 Subject: [PATCH 45/50] fix(desktop): use ed25519kmp in payment request code and core-ui from tokens commonMain --- apps/flipcash/shared/tokens/build.gradle.kts | 2 +- .../internal/repositories/InternalChatRepositoryJoinTest.kt | 2 +- .../flipcash/services/internal/network/api/PaymentRequestApi.kt | 2 +- .../services/internal/network/services/PaymentRequestService.kt | 2 +- .../internal/repositories/InternalPaymentRequestRepository.kt | 2 +- .../flipcash/services/repository/PaymentRequestRepository.kt | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/flipcash/shared/tokens/build.gradle.kts b/apps/flipcash/shared/tokens/build.gradle.kts index e717bd4947..790b2bbaf8 100644 --- a/apps/flipcash/shared/tokens/build.gradle.kts +++ b/apps/flipcash/shared/tokens/build.gradle.kts @@ -24,6 +24,7 @@ kotlin { api(project(":apps:flipcash:shared:tokens:core")) implementation(project(":apps:flipcash:core")) + implementation(project(":apps:flipcash:core-ui")) implementation(project(":apps:flipcash:shared:persistence:sources")) implementation(project(":services:opencode")) implementation(project(":libs:coroutines")) @@ -44,7 +45,6 @@ kotlin { implementation(project(":ui:components")) implementation(project(":ui:resources")) implementation(project(":ui:theme")) - implementation(project(":apps:flipcash:core-ui")) implementation(project(":services:flipcash")) implementation(libs.androidx.datastore) diff --git a/services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/internal/repositories/InternalChatRepositoryJoinTest.kt b/services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/internal/repositories/InternalChatRepositoryJoinTest.kt index 68ca5f9c74..a0c5e3cc69 100644 --- a/services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/internal/repositories/InternalChatRepositoryJoinTest.kt +++ b/services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/internal/repositories/InternalChatRepositoryJoinTest.kt @@ -3,7 +3,7 @@ package com.flipcash.services.internal.repositories import com.flipcash.services.internal.network.services.ChatService import com.flipcash.services.models.JoinChatError import com.flipcash.services.models.chat.ChatId -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair import com.getcode.utils.ErrorUtils import io.mockk.coEvery import io.mockk.every diff --git a/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/api/PaymentRequestApi.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/api/PaymentRequestApi.kt index 7ee74ca143..ccc3d773f2 100644 --- a/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/api/PaymentRequestApi.kt +++ b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/api/PaymentRequestApi.kt @@ -12,7 +12,7 @@ import com.flipcash.services.internal.network.extensions.authenticate import com.flipcash.services.models.QueryOptions import com.flipcash.services.models.chat.ChatId import com.flipcash.services.models.paymentrequest.PaymentRequestSection -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.opencode.internal.network.core.GrpcApi import com.getcode.opencode.model.core.ID import dev.bmcreations.protovalidate.orThrow diff --git a/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/services/PaymentRequestService.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/services/PaymentRequestService.kt index f37c292347..dce0a48140 100644 --- a/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/services/PaymentRequestService.kt +++ b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/services/PaymentRequestService.kt @@ -22,7 +22,7 @@ import com.flipcash.services.models.paymentrequest.PaymentRequest import com.flipcash.services.models.paymentrequest.PaymentRequestDetails import com.flipcash.services.models.paymentrequest.PaymentRequestPage import com.flipcash.services.models.paymentrequest.PaymentRequestSection -import com.getcode.ed25519.Ed25519 +import com.getcode.ed25519kmp.Ed25519 import com.getcode.opencode.internal.network.extensions.foldWithSuppression import com.getcode.opencode.model.core.ID import com.getcode.opencode.utils.toValidationOrElse diff --git a/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/repositories/InternalPaymentRequestRepository.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/repositories/InternalPaymentRequestRepository.kt index 854f9b04ee..07b6cf7e34 100644 --- a/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/repositories/InternalPaymentRequestRepository.kt +++ b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/repositories/InternalPaymentRequestRepository.kt @@ -13,7 +13,7 @@ import com.flipcash.services.models.paymentrequest.PaymentRequestDetails import com.flipcash.services.models.paymentrequest.PaymentRequestPage import com.flipcash.services.models.paymentrequest.PaymentRequestSection import com.flipcash.services.repository.PaymentRequestRepository -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair import com.getcode.opencode.model.core.ID import com.getcode.utils.ErrorUtils diff --git a/services/flipcash/src/commonMain/kotlin/com/flipcash/services/repository/PaymentRequestRepository.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/repository/PaymentRequestRepository.kt index 9de5589934..a0fd2d9e30 100644 --- a/services/flipcash/src/commonMain/kotlin/com/flipcash/services/repository/PaymentRequestRepository.kt +++ b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/repository/PaymentRequestRepository.kt @@ -8,7 +8,7 @@ import com.flipcash.services.models.paymentrequest.PaymentRequest import com.flipcash.services.models.paymentrequest.PaymentRequestDetails import com.flipcash.services.models.paymentrequest.PaymentRequestPage import com.flipcash.services.models.paymentrequest.PaymentRequestSection -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519.KeyPair import com.getcode.opencode.model.core.ID /** From ed71b425043b3fe859562310276bd29951d44671 Mon Sep 17 00:00:00 2001 From: Brandon McAnsh Date: Thu, 29 Oct 2026 21:37:24 -0400 Subject: [PATCH 46/50] fix(messenger): invite preview resources implement AndroidResourceHelper --- .../app/messenger/internal/invites/InvitePreviews.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/flipcash/features/messenger/src/main/kotlin/com/flipcash/app/messenger/internal/invites/InvitePreviews.kt b/apps/flipcash/features/messenger/src/main/kotlin/com/flipcash/app/messenger/internal/invites/InvitePreviews.kt index 0285f6e0cd..745454f8ff 100644 --- a/apps/flipcash/features/messenger/src/main/kotlin/com/flipcash/app/messenger/internal/invites/InvitePreviews.kt +++ b/apps/flipcash/features/messenger/src/main/kotlin/com/flipcash/app/messenger/internal/invites/InvitePreviews.kt @@ -25,7 +25,9 @@ import com.flipcash.shared.chat.InviteUses import com.flipcash.shared.chat.ui.ConversationReference import com.getcode.manager.BottomBarManager import com.getcode.ui.components.bars.BottomBarView +import com.getcode.util.resources.AndroidResourceHelper import com.getcode.util.resources.ResourceHelper +import org.jetbrains.compose.resources.StringResource import com.getcode.util.resources.ResourceType import java.io.File import kotlin.time.Instant @@ -226,10 +228,11 @@ internal fun InviteFrame2eEmpty() = ManageInvitesContent( ) /** Strings only: a preview has no injected resources. */ -private class PreviewResources(private val context: Context) : ResourceHelper { +private class PreviewResources(private val context: Context) : AndroidResourceHelper { override fun getString(resourceId: Int): String = context.getString(resourceId) override fun getString(resourceId: Int, vararg formatArgs: Any): String = context.getString(resourceId, *formatArgs) + override fun getString(resource: StringResource, vararg formatArgs: Any): String = "" override fun getRawResource(resourceId: Int): String = "" override fun getQuantityString(id: Int, quantity: Int, vararg formatArgs: Any, default: String): String = default override fun getDimension(dimenId: Int, default: Float): Float = default From 3a8368478b9b45cc7ba9837c9a8b55b6bea747e9 Mon Sep 17 00:00:00 2001 From: Brandon McAnsh Date: Thu, 29 Oct 2026 21:38:58 -0400 Subject: [PATCH 47/50] fix(desktop): run host tests of KMP-layout modules in flipcashTestDebug --- .../notification-status/build.gradle.kts | 2 +- settings.gradle.kts | 16 ++++++++++++++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/apps/flipcash/features/notification-status/build.gradle.kts b/apps/flipcash/features/notification-status/build.gradle.kts index 0ad476a117..4bf9bc22d3 100644 --- a/apps/flipcash/features/notification-status/build.gradle.kts +++ b/apps/flipcash/features/notification-status/build.gradle.kts @@ -17,6 +17,6 @@ dependencies { testImplementation(kotlin("test")) testImplementation(libs.bundles.unit.testing) testImplementation(libs.grpc.stub) - testImplementation(testFixtures(project(":libs:coroutines"))) + testImplementation(project(":libs:coroutines:test-fixtures")) testImplementation(project(":apps:flipcash:shared:push")) } diff --git a/settings.gradle.kts b/settings.gradle.kts index 87872b1d96..455720743c 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -294,12 +294,21 @@ include( // Only real modules, not the intermediate container projects that Gradle // auto-creates for nested paths (e.g. `:apps:flipcash:shared`) — those have no // build script and must not receive a `kover(project(...))` / test dependency. +// Modules converted to Kotlin Multiplatform (src/commonMain or src/androidMain). They expose +// `testAndroidHostTest`, not `testDebugUnitTest`, so a module converted in the desktop stack lands +// here by its layout instead of by an entry in kmpUnitTestModules. +val kmpLayoutModules = mutableSetOf() val includedProjectPaths = buildList { fun collect(descriptor: ProjectDescriptor) { val hasBuildScript = descriptor.projectDir.resolve("build.gradle.kts").exists() || descriptor.projectDir.resolve("build.gradle").exists() if (descriptor.path != ":" && hasBuildScript) { add(descriptor.path) + if (descriptor.projectDir.resolve("src/commonMain").exists() || + descriptor.projectDir.resolve("src/androidMain").exists() + ) { + kmpLayoutModules.add(descriptor.path) + } } descriptor.children.forEach(::collect) } @@ -357,8 +366,11 @@ val noUnitTestModules = setOf( val unitTestCandidates = includedProjectPaths.filter { path -> unitTestPaths.any { path == it || path.startsWith("$it:") } && path !in noUnitTestModules } +val kmpHostTestModules = unitTestCandidates.filter { + it in kmpUnitTestModules || (it in kmpLayoutModules && it !in jvmUnitTestModules) +} val androidUnitTestModules = unitTestCandidates.filter { - it !in jvmUnitTestModules && it !in kmpUnitTestModules + it !in jvmUnitTestModules && it !in kmpHostTestModules } // Forced dependency versions for the per-project configuration below. The @@ -387,7 +399,7 @@ run { val koverModulesForRoot = koverModules.toList() val androidUnitTestForRoot = androidUnitTestModules.toList() val jvmUnitTestForRoot = jvmUnitTestModules.toList() - val kmpUnitTestForRoot = kmpUnitTestModules.toList() + val kmpUnitTestForRoot = kmpHostTestModules.toList() val forcedDependencies = listOf( "org.jetbrains.kotlinx:kotlinx-serialization-core:$serializationVersion", "org.jetbrains.kotlinx:kotlinx-serialization-json:$serializationVersion", From dc6e40fa0ce295c31c39422cf0b140ae75d17c5f Mon Sep 17 00:00:00 2001 From: Brandon McAnsh Date: Thu, 29 Oct 2026 21:59:59 -0400 Subject: [PATCH 48/50] fix(test): disambiguate ResourceHelper mocks and resolve ic_delete color for Compose resources --- .../kotlin/com/flipcash/app/login/OnboardingFlowScreenTest.kt | 2 +- .../app/messenger/internal/invites/InviteLinkViewModelTest.kt | 2 +- .../messenger/internal/invites/ManageInvitesViewModelTest.kt | 2 +- .../internal/payment/DefaultStartChattingPayerTest.kt | 2 +- .../internal/screens/profile/edit/GroupChangeDialogTest.kt | 2 +- .../com/flipcash/shared/chat/models/SystemMessageTextTest.kt | 4 ++-- .../kotlin/com/flipcash/app/router/internal/AppRouterTest.kt | 1 + ui/resources/src/androidMain/res/drawable/ic_delete.xml | 2 +- 8 files changed, 9 insertions(+), 8 deletions(-) diff --git a/apps/flipcash/features/login/src/test/kotlin/com/flipcash/app/login/OnboardingFlowScreenTest.kt b/apps/flipcash/features/login/src/test/kotlin/com/flipcash/app/login/OnboardingFlowScreenTest.kt index 71a44129ee..1cd7d179ef 100644 --- a/apps/flipcash/features/login/src/test/kotlin/com/flipcash/app/login/OnboardingFlowScreenTest.kt +++ b/apps/flipcash/features/login/src/test/kotlin/com/flipcash/app/login/OnboardingFlowScreenTest.kt @@ -49,7 +49,7 @@ class OnboardingFlowScreenTest { LocalCodeNavigator provides navigator, LocalPermissionChecker provides allGranted, ) { - OnboardingFlowScreen(onboarding, rememberNavResultStateRegistry()) + OnboardingFlowScreen(onboarding, rememberNavResultStateRegistry(), purchaseStep = {}) } } composeTestRule.waitForIdle() diff --git a/apps/flipcash/features/messenger/src/test/kotlin/com/flipcash/app/messenger/internal/invites/InviteLinkViewModelTest.kt b/apps/flipcash/features/messenger/src/test/kotlin/com/flipcash/app/messenger/internal/invites/InviteLinkViewModelTest.kt index 5ce4ca479d..f4507c1606 100644 --- a/apps/flipcash/features/messenger/src/test/kotlin/com/flipcash/app/messenger/internal/invites/InviteLinkViewModelTest.kt +++ b/apps/flipcash/features/messenger/src/test/kotlin/com/flipcash/app/messenger/internal/invites/InviteLinkViewModelTest.kt @@ -50,7 +50,7 @@ class InviteLinkViewModelTest { private val chatId = ChatId(ByteArray(32) { 5 }) private val hostInvites = mockk(relaxed = true) private val resources = mockk(relaxed = true) { - every { getString(any()) } returns "text" + every { getString(any()) } returns "text" } private val clipboard = ApplicationProvider.getApplicationContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager diff --git a/apps/flipcash/features/messenger/src/test/kotlin/com/flipcash/app/messenger/internal/invites/ManageInvitesViewModelTest.kt b/apps/flipcash/features/messenger/src/test/kotlin/com/flipcash/app/messenger/internal/invites/ManageInvitesViewModelTest.kt index be8c1fcbc0..8d401127d6 100644 --- a/apps/flipcash/features/messenger/src/test/kotlin/com/flipcash/app/messenger/internal/invites/ManageInvitesViewModelTest.kt +++ b/apps/flipcash/features/messenger/src/test/kotlin/com/flipcash/app/messenger/internal/invites/ManageInvitesViewModelTest.kt @@ -41,7 +41,7 @@ class ManageInvitesViewModelTest { private val chatId = ChatId(ByteArray(32) { 5 }) private val hostInvites = mockk() private val resources = mockk(relaxed = true) { - every { getString(any()) } returns "text" + every { getString(any()) } returns "text" } private val listed = MutableStateFlow>>(emptyMap()) diff --git a/apps/flipcash/features/messenger/src/test/kotlin/com/flipcash/app/messenger/internal/payment/DefaultStartChattingPayerTest.kt b/apps/flipcash/features/messenger/src/test/kotlin/com/flipcash/app/messenger/internal/payment/DefaultStartChattingPayerTest.kt index bdd469e290..cc81d87226 100644 --- a/apps/flipcash/features/messenger/src/test/kotlin/com/flipcash/app/messenger/internal/payment/DefaultStartChattingPayerTest.kt +++ b/apps/flipcash/features/messenger/src/test/kotlin/com/flipcash/app/messenger/internal/payment/DefaultStartChattingPayerTest.kt @@ -54,7 +54,7 @@ class DefaultStartChattingPayerTest { } private val analytics = RecordingAnalytics() private val resources = mockk(relaxed = true) { - every { getString(any()) } answers { "res:${firstArg()}" } + every { getString(any()) } answers { "res:${firstArg()}" } } private fun payer() = DefaultStartChattingPayer( diff --git a/apps/flipcash/features/messenger/src/test/kotlin/com/flipcash/app/messenger/internal/screens/profile/edit/GroupChangeDialogTest.kt b/apps/flipcash/features/messenger/src/test/kotlin/com/flipcash/app/messenger/internal/screens/profile/edit/GroupChangeDialogTest.kt index 5779135ec7..e7973c5987 100644 --- a/apps/flipcash/features/messenger/src/test/kotlin/com/flipcash/app/messenger/internal/screens/profile/edit/GroupChangeDialogTest.kt +++ b/apps/flipcash/features/messenger/src/test/kotlin/com/flipcash/app/messenger/internal/screens/profile/edit/GroupChangeDialogTest.kt @@ -21,7 +21,7 @@ class GroupChangeDialogTest { private val context = ApplicationProvider.getApplicationContext() private val resources = mockk().also { - every { it.getString(any()) } answers { context.getString(firstArg()) } + every { it.getString(any()) } answers { context.getString(firstArg()) } } @Before diff --git a/apps/flipcash/shared/chat-ui/src/test/kotlin/com/flipcash/shared/chat/models/SystemMessageTextTest.kt b/apps/flipcash/shared/chat-ui/src/test/kotlin/com/flipcash/shared/chat/models/SystemMessageTextTest.kt index a1f4b255e9..bc2ec80044 100644 --- a/apps/flipcash/shared/chat-ui/src/test/kotlin/com/flipcash/shared/chat/models/SystemMessageTextTest.kt +++ b/apps/flipcash/shared/chat-ui/src/test/kotlin/com/flipcash/shared/chat/models/SystemMessageTextTest.kt @@ -31,8 +31,8 @@ class SystemMessageTextTest { ) private val resources = mockk { - every { getString(any()) } answers { templates.getValue(firstArg()) } - every { getString(any(), *anyVararg()) } answers { + every { getString(any()) } answers { templates.getValue(firstArg()) } + every { getString(any(), *anyVararg()) } answers { templates.getValue(firstArg()).format(*(args[1] as Array<*>)) } } diff --git a/apps/flipcash/shared/router/src/test/kotlin/com/flipcash/app/router/internal/AppRouterTest.kt b/apps/flipcash/shared/router/src/test/kotlin/com/flipcash/app/router/internal/AppRouterTest.kt index ecc108cc47..92296991ef 100644 --- a/apps/flipcash/shared/router/src/test/kotlin/com/flipcash/app/router/internal/AppRouterTest.kt +++ b/apps/flipcash/shared/router/src/test/kotlin/com/flipcash/app/router/internal/AppRouterTest.kt @@ -27,6 +27,7 @@ import com.getcode.utils.BreadcrumbSink import com.getcode.utils.ErrorReporter import com.getcode.utils.ErrorUtils import com.getcode.utils.TraceManager +import com.getcode.utils.initialize import com.getcode.utils.TraceType import kotlin.test.assertEquals import kotlin.test.assertFalse diff --git a/ui/resources/src/androidMain/res/drawable/ic_delete.xml b/ui/resources/src/androidMain/res/drawable/ic_delete.xml index 282594cdb1..b59d62ff65 100644 --- a/ui/resources/src/androidMain/res/drawable/ic_delete.xml +++ b/ui/resources/src/androidMain/res/drawable/ic_delete.xml @@ -1,5 +1,5 @@ - + From 2bb3fa4101659f64fc117ed58bce51f9768733ed Mon Sep 17 00:00:00 2001 From: Brandon McAnsh Date: Thu, 29 Oct 2026 22:11:50 -0400 Subject: [PATCH 49/50] fix(test): FakeResourceHelper answers Compose StringResource from id stubs --- .../kotlin/com/getcode/util/resources/FakeResourceHelper.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ui/resources/test-fixtures/src/main/kotlin/com/getcode/util/resources/FakeResourceHelper.kt b/ui/resources/test-fixtures/src/main/kotlin/com/getcode/util/resources/FakeResourceHelper.kt index 84d9e73cc2..ed2adf0fc5 100644 --- a/ui/resources/test-fixtures/src/main/kotlin/com/getcode/util/resources/FakeResourceHelper.kt +++ b/ui/resources/test-fixtures/src/main/kotlin/com/getcode/util/resources/FakeResourceHelper.kt @@ -37,7 +37,11 @@ class FakeResourceHelper(vararg rClasses: Class<*>) : AndroidResourceHelper { } override fun getString(resource: StringResource, vararg formatArgs: Any): String { - val template = keyOverrides[resource.key] ?: return resource.key + // A Compose StringResource shares its key with the Android `R.string` name, so a stub made + // by id also answers for the resource. + val template = keyOverrides[resource.key] + ?: nameMap.entries.firstOrNull { it.value == resource.key }?.let { overrides[it.key] } + ?: return resource.key return runCatching { template.format(*formatArgs) }.getOrDefault(template) } From 4abd51fd24a6d829d8439f69f1bb198567c1da82 Mon Sep 17 00:00:00 2001 From: Brandon McAnsh Date: Thu, 29 Oct 2026 22:32:42 -0400 Subject: [PATCH 50/50] fix(desktop): use inTransaction and the Android init extension in new code/cash persistence code --- .../flipcash/shared/chat/PaymentRequestOfflineDecryptTest.kt | 1 + .../com/flipcash/shared/chat/PaymentRequestsStorageTest.kt | 1 + .../app/persistence/sources/ChatMetadataDataSource.kt | 4 ++-- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/flipcash/shared/chat/src/test/kotlin/com/flipcash/shared/chat/PaymentRequestOfflineDecryptTest.kt b/apps/flipcash/shared/chat/src/test/kotlin/com/flipcash/shared/chat/PaymentRequestOfflineDecryptTest.kt index f7f9ffee05..2120a8ba22 100644 --- a/apps/flipcash/shared/chat/src/test/kotlin/com/flipcash/shared/chat/PaymentRequestOfflineDecryptTest.kt +++ b/apps/flipcash/shared/chat/src/test/kotlin/com/flipcash/shared/chat/PaymentRequestOfflineDecryptTest.kt @@ -3,6 +3,7 @@ package com.flipcash.shared.chat import android.content.Context import androidx.test.core.app.ApplicationProvider import com.flipcash.app.persistence.FlipcashDatabase +import com.flipcash.app.persistence.init import com.flipcash.app.persistence.sources.GroupKeyEnvelopeDataSource import com.flipcash.app.persistence.sources.PaymentRequestDataSource import com.flipcash.services.chat.ChatKeySource diff --git a/apps/flipcash/shared/chat/src/test/kotlin/com/flipcash/shared/chat/PaymentRequestsStorageTest.kt b/apps/flipcash/shared/chat/src/test/kotlin/com/flipcash/shared/chat/PaymentRequestsStorageTest.kt index 46ace31970..2b1ae5a77d 100644 --- a/apps/flipcash/shared/chat/src/test/kotlin/com/flipcash/shared/chat/PaymentRequestsStorageTest.kt +++ b/apps/flipcash/shared/chat/src/test/kotlin/com/flipcash/shared/chat/PaymentRequestsStorageTest.kt @@ -3,6 +3,7 @@ package com.flipcash.shared.chat import android.content.Context import androidx.test.core.app.ApplicationProvider import com.flipcash.app.persistence.FlipcashDatabase +import com.flipcash.app.persistence.init import com.flipcash.app.persistence.sources.PaymentRequestDataSource import com.flipcash.services.chat.GroupContentCrypto import com.flipcash.services.controllers.PaymentRequestController diff --git a/apps/flipcash/shared/persistence/sources/src/commonMain/kotlin/com/flipcash/app/persistence/sources/ChatMetadataDataSource.kt b/apps/flipcash/shared/persistence/sources/src/commonMain/kotlin/com/flipcash/app/persistence/sources/ChatMetadataDataSource.kt index 48c839966a..2c0aaa2125 100644 --- a/apps/flipcash/shared/persistence/sources/src/commonMain/kotlin/com/flipcash/app/persistence/sources/ChatMetadataDataSource.kt +++ b/apps/flipcash/shared/persistence/sources/src/commonMain/kotlin/com/flipcash/app/persistence/sources/ChatMetadataDataSource.kt @@ -1,7 +1,7 @@ package com.flipcash.app.persistence.sources import androidx.paging.PagingSource -import androidx.room.withTransaction +import com.flipcash.app.persistence.inTransaction import com.flipcash.app.persistence.FlipcashDatabase import com.flipcash.app.persistence.entities.ChatMetadataEntity import com.flipcash.app.persistence.sources.mapper.chat.ChatEntityMapper @@ -98,7 +98,7 @@ class ChatMetadataDataSource @Inject constructor( suspend fun removeFromChat(chatIdHex: String) { val database = db ?: return - database.withTransaction { + database.inTransaction { database.chatMetadataDao().updateMembership(chatIdHex, false) database.groupKeyEnvelopeDao().deleteForChat(chatIdHex) database.paymentRequestDao().deleteForChat(chatIdHex)