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/apps/desktop/build.gradle.kts b/apps/desktop/build.gradle.kts new file mode 100644 index 0000000000..280c819fd3 --- /dev/null +++ b/apps/desktop/build.gradle.kts @@ -0,0 +1,92 @@ +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) +} + +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(project(":apps:flipcash:shared:device-link")) + implementation(libs.kotlinx.coroutines.swing) + implementation(libs.dagger) + 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 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() } + +compose.desktop { + application { + mainClass = "com.flipcash.desktop.MainKt" + nativeDistributions { + targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb) + packageName = "Flipcash" + packageVersion = "1.0.0" + } + } +} + +tasks.register("snapshot") { + group = "application" + 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), + providers.gradleProperty("screen").getOrElse("wallet"), + ) +} + +tasks.withType().configureEach { + devMnemonic?.let { environment("FLIPCASH_DEV_MNEMONIC", it) } +} 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 new file mode 100644 index 0000000000..43b60dd831 --- /dev/null +++ b/apps/desktop/src/main/kotlin/com/flipcash/desktop/DesktopGraph.kt @@ -0,0 +1,52 @@ +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 javax.inject.Singleton + +@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 walletViewModel: WalletViewModel + val selectTokenViewModel: SelectTokenViewModel + val exchange: Exchange + val resources: ResourceHelper + val networkObserver: NetworkConnectivityListener + 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. + 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/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/DesktopModule.kt b/apps/desktop/src/main/kotlin/com/flipcash/desktop/DesktopModule.kt new file mode 100644 index 0000000000..d603d3a2b9 --- /dev/null +++ b/apps/desktop/src/main/kotlin/com/flipcash/desktop/DesktopModule.kt @@ -0,0 +1,118 @@ +package com.flipcash.desktop + +import com.flipcash.app.analytics.FlipcashAnalytics +import com.flipcash.app.core.AppRoute +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 +import com.flipcash.app.funding.PurchaseMethodSelection +import com.flipcash.app.funding.PurchaseMethodState +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.SessionListener +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 dagger.multibindings.IntoSet +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 + +/** + * 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 { + /** 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() } + } + + @Provides + @Singleton + fun seedVault(): SeedVault = KeyringSeedVault() + + @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 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 { + 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/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/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/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 new file mode 100644 index 0000000000..8bcda37187 --- /dev/null +++ b/apps/desktop/src/main/kotlin/com/flipcash/desktop/Main.kt @@ -0,0 +1,32 @@ +package com.flipcash.desktop + +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 kotlinx.coroutines.runBlocking +import java.lang.management.ManagementFactory + +fun main() { + val graph = createGraph() + val signedIn = runBlocking { + graph.startup() + graph.restoreSession() + } + application { + Window( + onCloseRequest = ::exitApplication, + title = "Flipcash", + state = rememberWindowState(width = 420.dp, height = 860.dp), + ) { + DesktopApp(graph, signedIn) + LaunchedEffect(Unit) { + val sinceJvmStart = System.currentTimeMillis() - + ManagementFactory.getRuntimeMXBean().startTime + println("startup: first composition ${sinceJvmStart}ms after JVM start") + } + } + } +} 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..3f30a1de54 --- /dev/null +++ b/apps/desktop/src/main/kotlin/com/flipcash/desktop/SnapshotMain.kt @@ -0,0 +1,39 @@ +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 kotlinx.coroutines.runBlocking +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=`; 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() + if (!linkScreen) graph.restoreSession() + } + ImageComposeScene(width = 840, height = 1720, density = Density(2f)) { + if (linkScreen) DesktopLinkContent(graph, onSignedIn = {}) else 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/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 01a5005231..d7ef61b2d2 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 @@ -370,4 +376,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/main/kotlin/com/flipcash/app/inject/AppModule.kt b/apps/flipcash/app/src/main/kotlin/com/flipcash/app/inject/AppModule.kt index 5c811cedfb..9fbab84902 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/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/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/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/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 73331c8526..77d36fc1bb 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,8 @@ 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.purchase.OnboardingPurchaseStep import com.flipcash.app.notificationstatus.NotificationStatusScreen import com.flipcash.app.backupkey.BackupKeyScreen import com.flipcash.app.balance.WalletScreen @@ -107,7 +109,11 @@ internal fun appEntryProvider( // Onboarding flow annotatedEntry { key -> - OnboardingFlowScreen(route = key, resultStateRegistry = resultStateRegistry) + OnboardingFlowScreen( + route = key, + resultStateRegistry = resultStateRegistry, + purchaseStep = { onAccountCreated -> OnboardingPurchaseStep(onAccountCreated) }, + ) } // Main @@ -230,6 +236,7 @@ internal fun appEntryProvider( annotatedEntry { TrustedWebsitesScreen() } annotatedEntry { BackupKeyScreen() } annotatedEntry { DeviceLogsScreen() } + annotatedEntry { LinkDesktopScreen() } annotatedEntry { NotificationStatusScreen() } annotatedEntry { AccountSelectionScreen() } 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/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-ui/build.gradle.kts b/apps/flipcash/core-ui/build.gradle.kts index 8e3f3d0dff..d177e08c90 100644 --- a/apps/flipcash/core-ui/build.gradle.kts +++ b/apps/flipcash/core-ui/build.gradle.kts @@ -1,18 +1,64 @@ 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(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")) + implementation(project(":libs:encryption:keys")) + implementation(project(":ui:components")) + implementation(project(":ui:resources")) + implementation(project(":ui:theme")) + implementation(project(":apps:flipcash:shared: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.components.resources) + 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) + add("kspJvm", libs.dagger.compiler) + add("jvmMainImplementation", libs.dagger) } 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/ViewerAmountVectorsTest.kt b/apps/flipcash/core-ui/src/androidHostTest/kotlin/com/flipcash/app/core/ui/ViewerAmountVectorsTest.kt similarity index 100% rename from apps/flipcash/core-ui/src/test/kotlin/com/flipcash/app/core/ui/ViewerAmountVectorsTest.kt rename to apps/flipcash/core-ui/src/androidHostTest/kotlin/com/flipcash/app/core/ui/ViewerAmountVectorsTest.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/test/resources/viewer_amount.json b/apps/flipcash/core-ui/src/androidHostTest/resources/viewer_amount.json similarity index 100% rename from apps/flipcash/core-ui/src/test/resources/viewer_amount.json rename to apps/flipcash/core-ui/src/androidHostTest/resources/viewer_amount.json 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/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/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/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/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/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/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/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/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/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/main/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/main/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/main/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/main/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/main/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/main/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/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 84% 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..3a420dd8d8 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 @@ -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 @@ -10,10 +16,8 @@ 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.getcode.opencode.model.financial.Fiat import com.getcode.theme.CodeTheme import com.getcode.theme.White20 @@ -88,15 +92,15 @@ fun CurrencyAppreciationLabel( val label = when (style) { AppreciationStyle.Pill -> if (hasAppreciation) { - stringResource(R.string.label_fromAppreciation) + stringResource(Res.string.label_fromAppreciation) } else { - stringResource(R.string.label_fromDepreciation) + stringResource(Res.string.label_fromDepreciation) } AppreciationStyle.Classic -> if (hasAppreciation) { - stringResource(R.string.label_fromCurrencyAppreciation) + stringResource(Res.string.label_fromCurrencyAppreciation) } else { - stringResource(R.string.label_fromCurrencyDepreciation) + stringResource(Res.string.label_fromCurrencyDepreciation) } } Text( diff --git a/apps/flipcash/core-ui/src/main/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/main/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/main/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/main/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/main/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/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/main/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/main/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/main/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/main/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/main/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/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/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/main/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/main/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/main/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/main/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/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/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/main/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 2789f49c0a..d67777458d 100644 --- a/apps/flipcash/core-ui/src/main/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( @@ -68,7 +69,7 @@ fun TokenSelectionPill( Image( modifier = Modifier .size(CodeTheme.dimens.grid.x4), - painter = painterResource(R.drawable.ic_dropdown), + painter = painterResource(Res.drawable.ic_dropdown), contentDescription = "" ) } @@ -110,7 +111,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/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/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/main/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/main/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/main/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/main/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/main/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/main/kotlin/com/flipcash/app/core/ui/onboarding/AddMoneyRow.kt b/apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/onboarding/AddMoneyRow.kt similarity index 85% rename from apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/onboarding/AddMoneyRow.kt rename to apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/onboarding/AddMoneyRow.kt index 9ab4af6830..28b2eec39c 100644 --- a/apps/flipcash/core-ui/src/main/kotlin/com/flipcash/app/core/ui/onboarding/AddMoneyRow.kt +++ b/apps/flipcash/core-ui/src/commonMain/kotlin/com/flipcash/app/core/ui/onboarding/AddMoneyRow.kt @@ -16,9 +16,11 @@ 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.stringResource +import org.jetbrains.compose.resources.stringResource import androidx.compose.ui.unit.dp -import com.flipcash.core.R +import com.flipcash.core.resources.Res +import com.flipcash.core.resources.subtitle_addMoney +import com.flipcash.core.resources.title_addMoney import com.getcode.theme.CodeTheme import com.getcode.theme.extraSmall @@ -44,12 +46,12 @@ fun AddMoneyRow( ) Column(modifier = Modifier.weight(1f)) { Text( - text = stringResource(R.string.title_addMoney), + text = stringResource(Res.string.title_addMoney), style = CodeTheme.typography.textMedium, color = CodeTheme.colors.textMain, ) Text( - text = stringResource(R.string.subtitle_addMoney), + text = stringResource(Res.string.subtitle_addMoney), style = CodeTheme.typography.textSmall, color = CodeTheme.colors.textSecondary, ) diff --git a/apps/flipcash/core-ui/src/main/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/main/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/main/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-ui/src/main/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/main/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-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 f9e14795ad..6fac369089 100644 --- a/apps/flipcash/core/build.gradle.kts +++ b/apps/flipcash/core/build.gradle.kts @@ -1,49 +1,103 @@ -plugins { - alias(libs.plugins.flipcash.android.feature) -} +import com.getcode.buildlogic.resources.androidResAsComposeResources -android { - namespace = "${Gradle.flipcashNamespace}.core" +plugins { + alias(libs.plugins.flipcash.kmp.app.library) + alias(libs.plugins.compose.compiler) + alias(libs.plugins.jetbrains.compose) + alias(libs.plugins.kotlin.ksp) } -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) +kotlin { + android { + namespace = "${Gradle.flipcashNamespace}.core" + androidResources { + enable = true + } + } - implementation(libs.androidx.localbroadcastmanager) - implementation(libs.androidx.datastore) - implementation(libs.compose.material3) + 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) + 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) + implementation(libs.jetbrains.compose.components.resources) + implementation(project(":ui:resources")) + api(project(":libs:reporting")) - api(libs.coil3) - api(libs.coil3.network) + 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(":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")) + 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.androidx.lifecycle.process) + 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(":ui:core")) - api(libs.navigation3.runtime) +compose.resources { + publicResClass = true + packageOfResClass = "${Gradle.flipcashNamespace}.core.resources" + customDirectory( + sourceSetName = "commonMain", + directoryProvider = androidResAsComposeResources(), + ) +} - api(project(":vendor:tipkit:tipkit-m2")) +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/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/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/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/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/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/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/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/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/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/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/main/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/main/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/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/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/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/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/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/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/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/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/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_buy.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_currency_buy.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_currency_buy.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_currency_buy.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_currency_send.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_currency_send.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_currency_send.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_currency_send.xml diff --git a/apps/flipcash/core/src/main/res/drawable/ic_currency_transactions.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_currency_transactions.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_currency_transactions.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_currency_transactions.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_link_outlined.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_link_outlined.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_link_outlined.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_link_outlined.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_more_horizontal.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_more_horizontal.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_more_horizontal.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_more_horizontal.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_transactions.xml b/apps/flipcash/core/src/androidMain/res/drawable/ic_transactions.xml similarity index 100% rename from apps/flipcash/core/src/main/res/drawable/ic_transactions.xml rename to apps/flipcash/core/src/androidMain/res/drawable/ic_transactions.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/AppRoute.kt b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/AppRoute.kt similarity index 99% rename from apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/AppRoute.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/AppRoute.kt index e06c1df90a..f6c73b24f3 100644 --- a/apps/flipcash/core/src/main/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 @@ -352,6 +352,7 @@ sealed interface AppRoute : NavKey, Parcelable { @Serializable data object DeviceLogs : Menu @Serializable + data object LinkDesktop : Menu data object NotificationStatus : Menu @Serializable data object AccountSelection : Menu diff --git a/apps/flipcash/core/src/main/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/main/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/main/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/main/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/main/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/main/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/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/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/kotlin/com/flipcash/app/core/chat/ChatStep.kt rename to apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/chat/ChatStep.kt index 0b4cf623c1..edcdcf301c 100644 --- a/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/chat/ChatStep.kt +++ b/apps/flipcash/core/src/commonMain/kotlin/com/flipcash/app/core/chat/ChatStep.kt @@ -1,6 +1,6 @@ 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.flipcash.services.models.chat.GroupBalanceRole import com.getcode.solana.keys.Mint @@ -10,7 +10,7 @@ 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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/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/core/src/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/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 diff --git a/apps/flipcash/core/src/main/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/main/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/main/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/main/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/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/main/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/main/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/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/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/main/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/main/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/main/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/main/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/core/src/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/core/src/main/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/main/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/main/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/main/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/main/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/main/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/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/core/src/main/kotlin/com/flipcash/app/core/extensions/Boolean.kt b/apps/flipcash/core/src/main/kotlin/com/flipcash/app/core/extensions/Boolean.kt deleted file mode 100644 index fd1cd833fe..0000000000 --- a/apps/flipcash/core/src/main/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/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/balance/build.gradle.kts b/apps/flipcash/features/balance/build.gradle.kts index ad0201b7d6..5ee4523ab2 100644 --- a/apps/flipcash/features/balance/build.gradle.kts +++ b/apps/flipcash/features/balance/build.gradle.kts @@ -1,28 +1,67 @@ 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(testFixtures(project(":apps:flipcash:shared:analytics"))) - 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) + add("kspJvm", libs.dagger.compiler) + add("jvmMainImplementation", libs.dagger) } 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 100% 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 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 100% 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 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 88% 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 5bfd043f03..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,12 +7,14 @@ 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 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 @@ -26,8 +28,8 @@ fun WalletScreen() { modifier = Modifier.fillMaxSize(), horizontalAlignment = Alignment.CenterHorizontally, ) { - val viewModel = hiltViewModel() - val tokenViewModel = hiltViewModel() + val viewModel = hiltViewModel() + val tokenViewModel = hiltViewModel() WalletScreen(viewModel, tokenViewModel) LaunchedEffect(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..6fc32c8c25 --- /dev/null +++ b/apps/flipcash/features/balance/src/androidMain/kotlin/com/flipcash/app/balance/internal/HiltWalletViewModel.kt @@ -0,0 +1,34 @@ +package com.flipcash.app.balance.internal + +import com.flipcash.app.analytics.FlipcashAnalytics +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, + feedCoordinator: ActivityFeedCoordinator, + tokenCoordinator: TokenCoordinator, + walletReveal: WalletRevealCoordinator, +) : WalletViewModel( + userManager = userManager, + userFlags = userFlags, + dispatchers = dispatchers, + purchaseMethodController = purchaseMethodController, + analytics = analytics, + 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 92% 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 978dc1acd2..9d01f8ba60 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,16 @@ package com.flipcash.app.balance.internal -import androidx.activity.compose.ReportDrawnWhen +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 androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box @@ -32,8 +42,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 @@ -54,7 +62,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.features.balance.R import com.flipcash.shared.transactionhistory.recentActivitySection import com.getcode.theme.CodeTheme import com.getcode.ui.theme.CodeCircularProgressIndicator @@ -62,7 +69,7 @@ import com.getcode.ui.theme.CodeCircularProgressIndicator private const val TokenStackKey = "tokenStack" @Composable -internal fun WalletScreen( +fun WalletScreen( viewModel: WalletViewModel, tokenViewModel: SelectTokenViewModel, ) { @@ -85,7 +92,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 Add Money @@ -163,7 +170,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"), @@ -310,8 +317,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 = stringResource(Res.string.action_createYourOwnCurrency), + icon = painterResource(Res.drawable.ic_coins_add), ) { dispatchEvent(WalletViewModel.Event.OpenScreen(AppRoute.Token.CurrencyCreator)) } @@ -321,8 +328,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 = stringResource(Res.string.action_currencyLeaderboard), + icon = painterResource(Res.drawable.ic_globe), ) { dispatchEvent(WalletViewModel.Event.OpenScreen(AppRoute.Token.Discovery)) } @@ -339,8 +346,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 = stringResource(Res.string.action_addDollars), + icon = painterResource(Res.drawable.ic_menu_deposit), ) { dispatchEvent(WalletViewModel.Event.PresentDepositOptions) } @@ -350,8 +357,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 = 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/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 98% 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 155746e9b3..b93c8c3132 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 @@ -18,7 +18,6 @@ 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 @@ -28,8 +27,11 @@ 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, 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/features/cash/build.gradle.kts b/apps/flipcash/features/cash/build.gradle.kts index 750d1d06ee..6faa79e880 100644 --- a/apps/flipcash/features/cash/build.gradle.kts +++ b/apps/flipcash/features/cash/build.gradle.kts @@ -9,14 +9,14 @@ 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) 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/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/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/login/build.gradle.kts b/apps/flipcash/features/login/build.gradle.kts index 8b4a065713..328ab6e8fa 100644 --- a/apps/flipcash/features/login/build.gradle.kts +++ b/apps/flipcash/features/login/build.gradle.kts @@ -9,19 +9,18 @@ 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) 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")) 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 41ad745182..57ab513951 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 @@ -49,8 +49,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 @@ -115,17 +113,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 @@ -144,6 +149,7 @@ private fun CompleteExistingUserOnboarding() { private fun PermissionsPhaseFlowHost( route: AppRoute.OnboardingFlow, resultStateRegistry: NavResultStateRegistry, + purchaseStep: OnboardingPurchaseStep, ) { val outerNavigator = LocalCodeNavigator.current val checker = LocalPermissionChecker.current @@ -205,7 +211,7 @@ private fun PermissionsPhaseFlowHost( FlowExitReason.Canceled -> Unit } }, - entryProvider = onboardingEntryProvider(route), + entryProvider = onboardingEntryProvider(route, purchaseStep), ) } @@ -213,6 +219,7 @@ private fun PermissionsPhaseFlowHost( private fun AccountPhaseFlowHost( route: AppRoute.OnboardingFlow, resultStateRegistry: NavResultStateRegistry, + purchaseStep: OnboardingPurchaseStep, ) { val outerNavigator = LocalCodeNavigator.current @@ -232,7 +239,7 @@ private fun AccountPhaseFlowHost( FlowExitReason.Canceled -> Unit } }, - entryProvider = onboardingEntryProvider(route), + entryProvider = onboardingEntryProvider(route, purchaseStep), ) } @@ -281,6 +288,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`. @@ -300,7 +308,7 @@ private fun onboardingEntryProvider( PhotoAccessKeyScreen() } annotatedEntry { - PurchaseStepContent() + PurchaseStepContent(purchaseStep) } annotatedEntry { ContactPermissionStepContent() @@ -526,25 +534,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/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/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/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) } diff --git a/apps/flipcash/features/menu/build.gradle.kts b/apps/flipcash/features/menu/build.gradle.kts index 713a985c05..24767839f0 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/messenger/build.gradle.kts b/apps/flipcash/features/messenger/build.gradle.kts index 1c21aec922..1db86fa31d 100644 --- a/apps/flipcash/features/messenger/build.gradle.kts +++ b/apps/flipcash/features/messenger/build.gradle.kts @@ -8,8 +8,8 @@ android { dependencies { implementation(project(":apps:flipcash:shared:analytics")) - testImplementation(testFixtures(project(":apps:flipcash:shared:analytics"))) - testImplementation(testFixtures(project(":libs:coroutines"))) + 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")) implementation(project(":apps:flipcash:shared:blocklist")) 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 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 1761f1a0df..a5aec5b3ef 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 @@ -48,7 +49,7 @@ internal fun ReactionBoostCurrencySheet() { */ @Composable internal fun CurrencyPickerContent(onPicked: () -> Unit) { - val viewModel = hiltViewModel() + val viewModel = hiltViewModel() val state by viewModel.stateFlow.collectAsStateWithLifecycle() Column( 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/features/myaccount/build.gradle.kts b/apps/flipcash/features/myaccount/build.gradle.kts index 3362ff2d55..ea775c6bae 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) @@ -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 7137732177..13fdc37460 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.Notifications @@ -15,6 +16,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 @@ -75,6 +77,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 NotificationStatus : FullMenuItem() { override val icon: Painter @Composable get() = rememberVectorPainter(Icons.Outlined.Notifications) 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 4e031ce6e3..633c02bfed 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, NotificationStatus, BetaFlags, SwitchAccount), + listOf(/* BillCustomizer, */ DeviceLogs, LinkDesktop, NotificationStatus, BetaFlags, SwitchAccount), ), SettingsSection( R.string.title_settingsSectionAccount, 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/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) +} diff --git a/apps/flipcash/features/tipping/build.gradle.kts b/apps/flipcash/features/tipping/build.gradle.kts index db2603d881..9af93ef91c 100644 --- a/apps/flipcash/features/tipping/build.gradle.kts +++ b/apps/flipcash/features/tipping/build.gradle.kts @@ -9,8 +9,8 @@ android { dependencies { testImplementation(kotlin("test")) testImplementation(libs.bundles.unit.testing) - testImplementation(testFixtures(project(":ui:resources"))) - testImplementation(testFixtures(project(":apps:flipcash:shared:analytics"))) + testImplementation(project(":ui:resources:test-fixtures")) + testImplementation(project(":apps:flipcash:shared:analytics:test-fixtures")) testImplementation(libs.robolectric) implementation(project(":apps:flipcash:shared:analytics")) 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/build.gradle.kts b/apps/flipcash/features/tokens/build.gradle.kts index 86a8aeb45c..461e47cce9 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/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/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..1ae121ea60 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) @@ -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/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/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/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/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/analytics/build.gradle.kts b/apps/flipcash/shared/analytics/build.gradle.kts index 371f23ce36..a93d95a77b 100644 --- a/apps/flipcash/shared/analytics/build.gradle.kts +++ b/apps/flipcash/shared/analytics/build.gradle.kts @@ -1,31 +1,42 @@ 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(":services:flipcash")) - implementation(project(":services:opencode")) - - implementation(libs.mixpanel) - - implementation(libs.androidx.datastore) + 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/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 95% 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 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/androidMain/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/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/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 7dcec6ab9e..515100ebcc 100644 --- a/apps/flipcash/shared/authentication/build.gradle.kts +++ b/apps/flipcash/shared/authentication/build.gradle.kts @@ -27,5 +27,5 @@ dependencies { testImplementation(libs.bundles.unit.testing) testImplementation(libs.robolectric) testImplementation(libs.grpc.stub) - testImplementation(testFixtures(project(":libs:coroutines"))) + testImplementation(project(":libs:coroutines:test-fixtures")) } 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/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/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/chat/build.gradle.kts b/apps/flipcash/shared/chat/build.gradle.kts index fd45bb87cc..2bf81627f5 100644 --- a/apps/flipcash/shared/chat/build.gradle.kts +++ b/apps/flipcash/shared/chat/build.gradle.kts @@ -33,9 +33,9 @@ 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(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/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/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/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/common-ui/build.gradle.kts b/apps/flipcash/shared/common-ui/build.gradle.kts index a55a5b8f81..9d5e1a37f5 100644 --- a/apps/flipcash/shared/common-ui/build.gradle.kts +++ b/apps/flipcash/shared/common-ui/build.gradle.kts @@ -1,24 +1,62 @@ +import com.getcode.buildlogic.resources.androidResAsComposeResources + plugins { - alias(libs.plugins.flipcash.android.library.compose) + alias(libs.plugins.flipcash.kmp.app.library) + alias(libs.plugins.compose.compiler) + alias(libs.plugins.jetbrains.compose) } -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(libs.jetbrains.compose.components.resources) + 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")) + implementation(project(":services:flipcash")) + implementation(project(":services:opencode")) + implementation(project(":apps:flipcash:shared:theme")) + + 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.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) + } + } +} - implementation(libs.bundles.haze) - implementation(libs.compose.material) - implementation(libs.bundles.haze) - api(libs.compose.material.icons.extended) - testImplementation(libs.robolectric) +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/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/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/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/main/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/main/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/common-ui/src/main/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 84% 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/commonMain/kotlin/com/flipcash/shared/common/ui/profile/BalanceRequirementsCard.kt index f20fdcf262..38b018a3a2 100644 --- a/apps/flipcash/shared/common-ui/src/main/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 @@ -74,7 +82,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, ) @@ -89,15 +97,15 @@ 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, onClick = onJoinClick, ) 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, onClick = onChatClick, ) @@ -125,7 +133,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, ) @@ -161,13 +169,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, ) @@ -199,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/common-ui/src/main/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/main/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/main/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/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() 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..42286691dc --- /dev/null +++ b/apps/flipcash/shared/device-link/build.gradle.kts @@ -0,0 +1,39 @@ +plugins { + alias(libs.plugins.flipcash.kmp.app.library) + alias(libs.plugins.compose.compiler) + alias(libs.plugins.jetbrains.compose) +} + +// 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" + } + + sourceSets { + commonMain.dependencies { + implementation(libs.kotlinx.coroutines.core) + api(project(":libs:device-link")) + 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 only for the keyring test, which needs a desktop OS keyring. + jvmTest.dependencies { + implementation(kotlin("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/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/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/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/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/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/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" } diff --git a/apps/flipcash/shared/funding/build.gradle.kts b/apps/flipcash/shared/funding/build.gradle.kts index 178401e7f9..23ec4527ef 100644 --- a/apps/flipcash/shared/funding/build.gradle.kts +++ b/apps/flipcash/shared/funding/build.gradle.kts @@ -1,16 +1,51 @@ 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.funding" +kotlin { + android { + namespace = "${Gradle.flipcashNamespace}.shared.funding" + 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) + 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) + add("kspJvm", libs.dagger.compiler) + add("jvmMainImplementation", libs.dagger) } 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/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/main/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/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/funding/src/main/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/main/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/main/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/main/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/main/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/main/kotlin/com/flipcash/app/funding/PurchaseMethodState.kt rename to apps/flipcash/shared/funding/src/commonMain/kotlin/com/flipcash/app/funding/PurchaseMethodState.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/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/InviteGrantMigrationTest.kt b/apps/flipcash/shared/persistence/db/src/androidHostTest/kotlin/com/flipcash/app/persistence/InviteGrantMigrationTest.kt similarity index 100% rename from apps/flipcash/shared/persistence/db/src/test/kotlin/com/flipcash/app/persistence/InviteGrantMigrationTest.kt rename to apps/flipcash/shared/persistence/db/src/androidHostTest/kotlin/com/flipcash/app/persistence/InviteGrantMigrationTest.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/GroupKeyEnvelopeDaoTest.kt b/apps/flipcash/shared/persistence/db/src/androidHostTest/kotlin/com/flipcash/app/persistence/dao/GroupKeyEnvelopeDaoTest.kt similarity index 100% rename from apps/flipcash/shared/persistence/db/src/test/kotlin/com/flipcash/app/persistence/dao/GroupKeyEnvelopeDaoTest.kt rename to apps/flipcash/shared/persistence/db/src/androidHostTest/kotlin/com/flipcash/app/persistence/dao/GroupKeyEnvelopeDaoTest.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/PaymentRequestDaoTest.kt b/apps/flipcash/shared/persistence/db/src/androidHostTest/kotlin/com/flipcash/app/persistence/dao/PaymentRequestDaoTest.kt similarity index 100% rename from apps/flipcash/shared/persistence/db/src/test/kotlin/com/flipcash/app/persistence/dao/PaymentRequestDaoTest.kt rename to apps/flipcash/shared/persistence/db/src/androidHostTest/kotlin/com/flipcash/app/persistence/dao/PaymentRequestDaoTest.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/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/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 87% 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 abd5ce36e3..f19dce96a6 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 @@ -55,6 +54,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 = [ @@ -148,6 +148,7 @@ import com.getcode.utils.subByteArray version = 50, ) @TypeConverters(TokenTypeConverters::class, ChatTypeConverters::class) +@ConstructedBy(FlipcashDatabaseConstructor::class) abstract class FlipcashDatabase : RoomDatabase() { abstract fun messageDao(): MessageDao @@ -167,22 +168,22 @@ abstract class FlipcashDatabase : RoomDatabase() { abstract fun groupKeyEnvelopeDao(): GroupKeyEnvelopeDao 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") } } @@ -201,27 +202,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") } } @@ -233,9 +234,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") } } @@ -245,8 +246,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'") } } @@ -262,9 +263,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) { @@ -362,10 +362,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, " + @@ -383,45 +383,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") } } @@ -442,10 +442,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" @@ -464,9 +466,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) @@ -480,4 +482,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/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/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/GroupKeyEnvelopeDao.kt b/apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/dao/GroupKeyEnvelopeDao.kt similarity index 100% rename from apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/dao/GroupKeyEnvelopeDao.kt rename to apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/dao/GroupKeyEnvelopeDao.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/PaymentRequestDao.kt b/apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/dao/PaymentRequestDao.kt similarity index 100% rename from apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/dao/PaymentRequestDao.kt rename to apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/dao/PaymentRequestDao.kt 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/GroupKeyEnvelopeEntity.kt b/apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/entities/GroupKeyEnvelopeEntity.kt similarity index 100% rename from apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/entities/GroupKeyEnvelopeEntity.kt rename to apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/entities/GroupKeyEnvelopeEntity.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/PaymentRequestEntity.kt b/apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/entities/PaymentRequestEntity.kt similarity index 100% rename from apps/flipcash/shared/persistence/db/src/main/kotlin/com/flipcash/app/persistence/entities/PaymentRequestEntity.kt rename to apps/flipcash/shared/persistence/db/src/commonMain/kotlin/com/flipcash/app/persistence/entities/PaymentRequestEntity.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/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 5fa1f607cf..19d9c46e97 100644 --- a/apps/flipcash/shared/persistence/sources/build.gradle.kts +++ b/apps/flipcash/shared/persistence/sources/build.gradle.kts @@ -1,36 +1,46 @@ 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(testFixtures(project(":services:flipcash"))) - - 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) + add("kspJvm", libs.dagger.compiler) + add("jvmMainImplementation", libs.dagger) } 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/ChatRemovalDataTest.kt b/apps/flipcash/shared/persistence/sources/src/androidHostTest/kotlin/com/flipcash/app/persistence/sources/ChatRemovalDataTest.kt similarity index 100% rename from apps/flipcash/shared/persistence/sources/src/test/kotlin/com/flipcash/app/persistence/sources/ChatRemovalDataTest.kt rename to apps/flipcash/shared/persistence/sources/src/androidHostTest/kotlin/com/flipcash/app/persistence/sources/ChatRemovalDataTest.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 98% 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 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/androidHostTest/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/androidHostTest/kotlin/com/flipcash/app/persistence/sources/UserProfileDataSourceTest.kt similarity index 98% 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 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/androidHostTest/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/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 3054f7f79f..730e13bb14 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 @@ -345,7 +345,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 99% 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 index 48c839966a..2c0aaa2125 100644 --- 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 @@ -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) 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/GroupKeyEnvelopeDataSource.kt b/apps/flipcash/shared/persistence/sources/src/commonMain/kotlin/com/flipcash/app/persistence/sources/GroupKeyEnvelopeDataSource.kt similarity index 100% rename from apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/GroupKeyEnvelopeDataSource.kt rename to apps/flipcash/shared/persistence/sources/src/commonMain/kotlin/com/flipcash/app/persistence/sources/GroupKeyEnvelopeDataSource.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 98% 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 index 3cd7774ab4..62b47959b6 100644 --- 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 @@ -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/main/kotlin/com/flipcash/app/persistence/sources/PaymentRequestDataSource.kt b/apps/flipcash/shared/persistence/sources/src/commonMain/kotlin/com/flipcash/app/persistence/sources/PaymentRequestDataSource.kt similarity index 100% rename from apps/flipcash/shared/persistence/sources/src/main/kotlin/com/flipcash/app/persistence/sources/PaymentRequestDataSource.kt rename to apps/flipcash/shared/persistence/sources/src/commonMain/kotlin/com/flipcash/app/persistence/sources/PaymentRequestDataSource.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/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/apps/flipcash/shared/session/build.gradle.kts b/apps/flipcash/shared/session/build.gradle.kts index cbd954cd22..fe5f4fd58d 100644 --- a/apps/flipcash/shared/session/build.gradle.kts +++ b/apps/flipcash/shared/session/build.gradle.kts @@ -9,8 +9,8 @@ android { dependencies { testImplementation(kotlin("test")) testImplementation(libs.bundles.unit.testing) - testImplementation(testFixtures(project(":libs:coroutines"))) - testImplementation(testFixtures(project(":ui:resources"))) + testImplementation(project(":libs:coroutines:test-fixtures")) + testImplementation(project(":ui:resources:test-fixtures")) implementation(project(":apps:flipcash:shared:blob")) implementation(project(":apps:flipcash:shared:blocklist")) @@ -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/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/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 d6fae2d769..4a720f12d7 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/apps/flipcash/shared/theme/build.gradle.kts b/apps/flipcash/shared/theme/build.gradle.kts index f70ab124e6..a543099804 100644 --- a/apps/flipcash/shared/theme/build.gradle.kts +++ b/apps/flipcash/shared/theme/build.gradle.kts @@ -1,13 +1,26 @@ 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(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) + 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/commonMain/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/commonMain/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 9f65fd8f5f..790b2bbaf8 100644 --- a/apps/flipcash/shared/tokens/build.gradle.kts +++ b/apps/flipcash/shared/tokens/build.gradle.kts @@ -1,38 +1,82 @@ 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(testFixtures(project(":ui:resources"))) - testImplementation(testFixtures(project(":libs:currency-math"))) - testImplementation(libs.mockito.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")) - 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")) + 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(":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(testFixtures(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: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) + add("kspJvm", libs.dagger.compiler) + add("jvmMainImplementation", libs.dagger) } 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")) + } + } } 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 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/CommunityChatsTest.kt b/apps/flipcash/shared/tokens/src/androidHostTest/kotlin/com/flipcash/app/tokens/ui/CommunityChatsTest.kt similarity index 100% rename from apps/flipcash/shared/tokens/src/test/kotlin/com/flipcash/app/tokens/ui/CommunityChatsTest.kt rename to apps/flipcash/shared/tokens/src/androidHostTest/kotlin/com/flipcash/app/tokens/ui/CommunityChatsTest.kt diff --git a/apps/flipcash/shared/tokens/src/test/kotlin/com/flipcash/app/tokens/ui/CurrencyActionsTest.kt b/apps/flipcash/shared/tokens/src/androidHostTest/kotlin/com/flipcash/app/tokens/ui/CurrencyActionsTest.kt similarity index 100% rename from apps/flipcash/shared/tokens/src/test/kotlin/com/flipcash/app/tokens/ui/CurrencyActionsTest.kt rename to apps/flipcash/shared/tokens/src/androidHostTest/kotlin/com/flipcash/app/tokens/ui/CurrencyActionsTest.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/TokenInfoViewModelCommunityLeaderTest.kt b/apps/flipcash/shared/tokens/src/androidHostTest/kotlin/com/flipcash/app/tokens/ui/TokenInfoViewModelCommunityLeaderTest.kt similarity index 100% rename from apps/flipcash/shared/tokens/src/test/kotlin/com/flipcash/app/tokens/ui/TokenInfoViewModelCommunityLeaderTest.kt rename to apps/flipcash/shared/tokens/src/androidHostTest/kotlin/com/flipcash/app/tokens/ui/TokenInfoViewModelCommunityLeaderTest.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/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/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/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/main/kotlin/com/flipcash/app/tokens/ui/CommunityChats.kt b/apps/flipcash/shared/tokens/src/androidMain/kotlin/com/flipcash/app/tokens/ui/CommunityChats.kt similarity index 100% rename from apps/flipcash/shared/tokens/src/main/kotlin/com/flipcash/app/tokens/ui/CommunityChats.kt rename to apps/flipcash/shared/tokens/src/androidMain/kotlin/com/flipcash/app/tokens/ui/CommunityChats.kt diff --git a/apps/flipcash/shared/tokens/src/main/kotlin/com/flipcash/app/tokens/ui/CommunityChatsViewModel.kt b/apps/flipcash/shared/tokens/src/androidMain/kotlin/com/flipcash/app/tokens/ui/CommunityChatsViewModel.kt similarity index 100% rename from apps/flipcash/shared/tokens/src/main/kotlin/com/flipcash/app/tokens/ui/CommunityChatsViewModel.kt rename to apps/flipcash/shared/tokens/src/androidMain/kotlin/com/flipcash/app/tokens/ui/CommunityChatsViewModel.kt diff --git a/apps/flipcash/shared/tokens/src/main/kotlin/com/flipcash/app/tokens/ui/CurrencyActions.kt b/apps/flipcash/shared/tokens/src/androidMain/kotlin/com/flipcash/app/tokens/ui/CurrencyActions.kt similarity index 100% rename from apps/flipcash/shared/tokens/src/main/kotlin/com/flipcash/app/tokens/ui/CurrencyActions.kt rename to apps/flipcash/shared/tokens/src/androidMain/kotlin/com/flipcash/app/tokens/ui/CurrencyActions.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/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/main/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/main/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/main/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/main/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/main/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/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/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/main/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/main/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/main/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/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/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/main/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/main/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/main/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/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 98% 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 a1b8f23d2d..81b4805aea 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 @@ -17,7 +17,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 @@ -28,8 +27,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, diff --git a/apps/flipcash/shared/transaction-history/build.gradle.kts b/apps/flipcash/shared/transaction-history/build.gradle.kts index e79a443160..5e5ccc3462 100644 --- a/apps/flipcash/shared/transaction-history/build.gradle.kts +++ b/apps/flipcash/shared/transaction-history/build.gradle.kts @@ -1,30 +1,86 @@ -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(testFixtures(project(":ui:resources"))) - // 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) + add("kspJvm", libs.dagger.compiler) + add("jvmMainImplementation", libs.dagger) } 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/ResolveHasReceivedMoneyTest.kt b/apps/flipcash/shared/transaction-history/src/androidHostTest/kotlin/com/flipcash/shared/transactionhistory/ResolveHasReceivedMoneyTest.kt similarity index 100% rename from apps/flipcash/shared/transaction-history/src/test/kotlin/com/flipcash/shared/transactionhistory/ResolveHasReceivedMoneyTest.kt rename to apps/flipcash/shared/transaction-history/src/androidHostTest/kotlin/com/flipcash/shared/transactionhistory/ResolveHasReceivedMoneyTest.kt 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/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 98% 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 index 770de4afe8..75f1e6952a 100644 --- 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 @@ -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 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 98% 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 index bd830104f6..91131e1b30 100644 --- 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 @@ -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 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 98% 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 index ff03c9ade5..c9231ed31d 100644 --- 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 @@ -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 @@ -179,7 +180,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, @@ -277,7 +278,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, ) } @@ -298,7 +299,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/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 88% 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 1bc6d3b2f5..922c447d45 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,10 @@ package com.flipcash.shared.transactionhistory -import android.text.format.DateFormat +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 @@ -11,8 +15,6 @@ 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 androidx.compose.ui.text.style.TextOverflow import com.flipcash.app.core.ui.ActivityAmount import com.flipcash.app.core.ui.inDisplayCurrency @@ -83,7 +85,7 @@ fun ActivityFeedRow( maxLines = 1, ) Text( - text = stringResource(R.string.label_activity_convertFee, fee.inDisplayCurrency().formatted()), + text = stringResource(TxRes.string.label_activity_convertFee, fee.inDisplayCurrency().formatted()), style = CodeTheme.typography.textSmall, color = CodeTheme.colors.textSecondary, maxLines = 1, @@ -107,8 +109,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 @@ -116,7 +117,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 -> 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/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 86% 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..3129a06f38 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,11 @@ package com.flipcash.shared.transactionhistory +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 @@ -14,10 +20,7 @@ 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.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 +66,13 @@ private fun LazyItemScope.RecentActivityHeader(modifier: Modifier) { verticalAlignment = Alignment.CenterVertically, ) { Text( - text = stringResource(com.flipcash.core.R.string.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 = 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/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 64% 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 9cf55b2f5f..9938b4c4b7 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,8 +1,30 @@ package com.flipcash.shared.transactionhistory -import androidx.annotation.StringRes import com.flipcash.services.models.BoostedReaction import com.flipcash.services.models.RequestedPayment +import com.flipcash.shared.transactionhistory.generated.resources.Res +import com.flipcash.shared.transactionhistory.generated.resources.title_txnDetails_boostReceived +import com.flipcash.shared.transactionhistory.generated.resources.title_txnDetails_youBoosted +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.LocalFiat import com.getcode.opencode.model.financial.Token @@ -24,22 +46,22 @@ 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) { - Boosted(R.string.title_txnDetails_youBoosted), - BoostReceived(R.string.title_txnDetails_boostReceived), - 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), +enum class TransactionKind(val headingRes: StringResource) { + Boosted(Res.string.title_txnDetails_youBoosted), + BoostReceived(Res.string.title_txnDetails_boostReceived), + 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), } /** @@ -53,9 +75,9 @@ data class TransactionAccount( val address: String, val direction: Direction, ) { - enum class Direction(@StringRes val labelRes: Int) { - To(R.string.label_txnDetails_to), - From(R.string.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. */ @@ -69,11 +91,11 @@ 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), +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/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 74% 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..179b716cfa 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,10 @@ 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.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 /** @@ -27,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(R.string.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(R.string.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(R.string.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(R.string.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/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 92% 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 index feaccece0e..ff8557b56f 100644 --- 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 @@ -5,7 +5,6 @@ import com.flipcash.app.core.feed.MessageMetadata import com.flipcash.app.core.feed.MessageState import com.flipcash.app.core.feed.SwapState import com.flipcash.services.models.UserProfile -import com.flipcash.shared.transactionhistory.R import com.flipcash.shared.transactionhistory.TransactionAvatar import com.flipcash.shared.transactionhistory.TransactionDetails import com.flipcash.shared.transactionhistory.TransactionKind @@ -20,6 +19,11 @@ import com.getcode.util.resources.ResourceHelper import com.getcode.utils.base58 import com.getcode.utils.hexEncodedString import javax.inject.Inject +import com.flipcash.shared.transactionhistory.generated.resources.Res +import com.flipcash.shared.transactionhistory.generated.resources.title_txnDetails_boostReceived +import com.flipcash.shared.transactionhistory.generated.resources.title_txnDetails_boostReceivedIn +import com.flipcash.shared.transactionhistory.generated.resources.title_txnDetails_youBoosted +import com.flipcash.shared.transactionhistory.generated.resources.title_txnDetails_youBoostedIn /** * Maps a feed entry to the details screen's resolved state — the same entry the activity row draws, @@ -118,10 +122,10 @@ internal class TransactionDetailsMapper @Inject constructor( val received = meta is MessageMetadata.ReceivedCrypto return when { received && chat != null -> - resources.getString(R.string.title_txnDetails_boostReceivedIn, emoji, chat) - received -> resources.getString(R.string.title_txnDetails_boostReceived, emoji) - chat != null -> resources.getString(R.string.title_txnDetails_youBoostedIn, emoji, chat) - else -> resources.getString(R.string.title_txnDetails_youBoosted, emoji) + resources.getString(Res.string.title_txnDetails_boostReceivedIn, emoji, chat) + received -> resources.getString(Res.string.title_txnDetails_boostReceived, emoji) + chat != null -> resources.getString(Res.string.title_txnDetails_youBoostedIn, emoji, chat) + else -> resources.getString(Res.string.title_txnDetails_youBoosted, emoji) } } 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 87% 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 3c21e005bf..10a0ee7b3e 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,12 +1,16 @@ package com.flipcash.shared.transactionhistory.internal +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 import com.flipcash.services.models.BoostedReaction import com.flipcash.services.models.RequestedPayment 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 @@ -15,6 +19,11 @@ import com.getcode.opencode.model.core.ID import com.getcode.util.resources.ResourceHelper import com.getcode.utils.hexEncodedString import javax.inject.Inject +import com.flipcash.shared.transactionhistory.generated.resources.title_activity_boostFrom +import com.flipcash.shared.transactionhistory.generated.resources.title_activity_boostReceived +import com.flipcash.shared.transactionhistory.generated.resources.title_activity_boosted +import com.flipcash.shared.transactionhistory.generated.resources.title_activity_boostedFor +import com.flipcash.shared.transactionhistory.generated.resources.title_activity_boostedIn /** * Maps a feed item to a presentation item, resolving the counterparty avatar and title from the @@ -85,7 +94,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(Res.string.title_activity_convert, from, to) } /** @@ -111,11 +120,11 @@ internal fun boostTitle( val isReceived = meta is MessageMetadata.ReceivedCrypto val chat = chatName?.takeIf { it.isNotBlank() && isSplitBoost(meta) } return when { - isReceived && name != null -> resources.getString(R.string.title_activity_boostFrom, emoji, name) - isReceived -> resources.getString(R.string.title_activity_boostReceived, emoji) - name != null -> resources.getString(R.string.title_activity_boostedFor, emoji, name) - chat != null -> resources.getString(R.string.title_activity_boostedIn, emoji, chat) - else -> resources.getString(R.string.title_activity_boosted, emoji) + isReceived && name != null -> resources.getString(Res.string.title_activity_boostFrom, emoji, name) + isReceived -> resources.getString(Res.string.title_activity_boostReceived, emoji) + name != null -> resources.getString(Res.string.title_activity_boostedFor, emoji, name) + chat != null -> resources.getString(Res.string.title_activity_boostedIn, emoji, chat) + else -> resources.getString(Res.string.title_activity_boosted, emoji) } } @@ -184,12 +193,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(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(R.string.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/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/userflags/build.gradle.kts b/apps/flipcash/shared/userflags/build.gradle.kts index 38e90ecf0e..68416a6e07 100644 --- a/apps/flipcash/shared/userflags/build.gradle.kts +++ b/apps/flipcash/shared/userflags/build.gradle.kts @@ -1,27 +1,59 @@ +import com.getcode.buildlogic.resources.androidResAsComposeResources + 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.jetbrains.compose) + 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.jetbrains.compose.components.resources) + 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) +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) + add("kspJvm", libs.dagger.compiler) + add("jvmMainImplementation", libs.dagger) } 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/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/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/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 76% 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 index 833a8bf162..6579f2d0b9 100644 --- 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 @@ -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 @@ -14,7 +35,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 @@ -23,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, @@ -35,7 +55,7 @@ sealed class Field( stringPreferencesKey("override_preferred_provider"), encode = { it?.encode() ?: "None" }, decode = { decodeOnRampProvider(it) }, - label = R.string.label_flag_preferredProvider, + label = Res.string.label_flag_preferredProvider, format = { provider -> provider?.displayName() ?: "None" }, editor = FieldEditor.SingleSelect( options = listOf( @@ -57,7 +77,7 @@ sealed class Field( else -> "${providers.size} selected" } }, - label = R.string.label_flag_supportedOnRampProviders, + label = Res.string.label_flag_supportedOnRampProviders, editor = FieldEditor.MultiSelect( options = listOf( "Manual Deposit" to OnRampProvider.ManualDeposit, @@ -71,8 +91,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 = Res.string.label_flag_minimumVersion, + hint = Res.string.hint_flag_minimumVersion, format = { it.toString() }, editor = FieldEditor.TextInput( keyboard = KeyboardType.Number, @@ -87,8 +107,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 = 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( @@ -109,8 +129,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 = 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( @@ -126,8 +146,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 = 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( @@ -143,8 +163,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 = 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( @@ -162,8 +182,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 = 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( @@ -181,8 +201,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 = 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( @@ -200,7 +220,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 = Res.string.label_flag_preferredUsdcLiquidityPool, format = { provider -> provider.displayName() }, editor = FieldEditor.SingleSelect( options = listOf( @@ -214,7 +234,7 @@ sealed class Field( booleanPreferencesKey("override_require_coinbase_email_verification"), encode = { it }, decode = { it }, - label = R.string.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) @@ -225,8 +245,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 = 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/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 96% 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 index 04a5c91e03..fb9bb49c9c 100644 --- 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 @@ -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/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/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/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..30e9766e70 --- /dev/null +++ b/build-logic/convention/src/main/kotlin/KmpAppLibraryConventionPlugin.kt @@ -0,0 +1,140 @@ +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` + * - `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 + * 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") + apply("org.jetbrains.kotlin.plugin.parcelize") + } + + 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 + // 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 + } + compilerOptions { + jvmTarget.set(JvmTarget.fromTarget(javaVersion)) + } + } + + jvm { + compilerOptions { + jvmTarget.set(JvmTarget.fromTarget(javaVersion)) + } + } + + compilerOptions { + optIn.addAll( + "kotlin.time.ExperimentalTime", + "kotlin.ExperimentalUnsignedTypes", + "kotlin.RequiresOptIn", + "kotlin.ExperimentalMultiplatform" + ) + freeCompilerArgs.addAll( + "-Xexpect-actual-classes", + "-P", + "plugin:org.jetbrains.kotlin.parcelize:additionalAnnotation=com.getcode.libs.parcelable.Parcelize" + ) + } + + 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/build-logic/convention/src/main/kotlin/KmpLibraryConventionPlugin.kt b/build-logic/convention/src/main/kotlin/KmpLibraryConventionPlugin.kt index 4d394bce85..94efac5553 100644 --- a/build-logic/convention/src/main/kotlin/KmpLibraryConventionPlugin.kt +++ b/build-logic/convention/src/main/kotlin/KmpLibraryConventionPlugin.kt @@ -1,5 +1,12 @@ +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.JvmTarget +import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension /** * Convention plugin for KMP library modules. @@ -8,14 +15,26 @@ 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 + * - `jvm` -- the desktop client + * + * 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 +44,35 @@ 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() + val javaVersion = libs.findVersion("android-java").get().requiredVersion + + extensions.configure { + (this as ExtensionAware).extensions.configure { + compileSdk { + version = release(compileSdkVersion) { + minorApiLevel = compileSdkMinorVersion + } + } + minSdk = minSdkVersion + } + + iosArm64() + iosSimulatorArm64() + iosX64() + macosArm64() + macosX64() + + jvm { + compilerOptions { + jvmTarget.set(JvmTarget.fromTarget(javaVersion)) + } + } + } } } } 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 03ef04ed1b..7b423c7813 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.12.0" kotlinx-datetime = "0.8.0" @@ -30,6 +31,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" @@ -45,6 +47,10 @@ 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" @@ -78,6 +84,9 @@ flipcash2-client-protocol = "0.24.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" @@ -141,10 +150,14 @@ 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" } 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" } @@ -152,9 +165,11 @@ 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" } +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" } @@ -169,6 +184,10 @@ 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" } +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" } @@ -182,6 +201,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" } @@ -265,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" } @@ -330,10 +353,23 @@ 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-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" } +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] 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"] @@ -349,6 +385,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" } @@ -369,4 +406,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/kmp/shared-core/build.gradle.kts b/kmp/shared-core/build.gradle.kts index a9bfafc66e..fb7260fd73 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")) @@ -49,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")) } } @@ -67,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/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/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/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/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/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/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/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 97% rename from libs/datetime/src/main/kotlin/com/getcode/util/DateUtils.kt rename to libs/datetime/src/androidMain/kotlin/com/getcode/util/DateUtils.kt index fd9c3eaf55..0e0f863d71 100644 --- a/libs/datetime/src/main/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/main/kotlin/com/getcode/util/Instant.kt b/libs/datetime/src/commonMain/kotlin/com/getcode/util/Instant.kt similarity index 94% rename from libs/datetime/src/main/kotlin/com/getcode/util/Instant.kt rename to libs/datetime/src/commonMain/kotlin/com/getcode/util/Instant.kt index c966ff01bb..7d56a70cb9 100644 --- a/libs/datetime/src/main/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/device-link/build.gradle.kts b/libs/device-link/build.gradle.kts new file mode 100644 index 0000000000..498b4a41cc --- /dev/null +++ b/libs/device-link/build.gradle.kts @@ -0,0 +1,47 @@ +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 +// SharedCore. The Compose screens and the desktop seed store live in :apps:flipcash:shared:device-link. +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 { + commonMain.dependencies { + // StateFlow is part of PhoneLinkController's API. + api(libs.kotlinx.coroutines.core) + implementation(libs.sodium.bindings.kmp) + implementation(libs.ktor.network) + } + commonTest.dependencies { + implementation(kotlin("test")) + implementation(libs.kotlinx.serialization.json) + } + getByName("androidDeviceTest") { + dependencies { + implementation(libs.androidx.junit) + implementation(libs.androidx.test.runner) + } + } + } +} diff --git a/libs/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/DesktopLinkHost.kt b/libs/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/DesktopLinkHost.kt new file mode 100644 index 0000000000..b416752b56 --- /dev/null +++ b/libs/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/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/LinkChannel.kt b/libs/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/LinkChannel.kt new file mode 100644 index 0000000000..974d9b8c3a --- /dev/null +++ b/libs/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/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 new file mode 100644 index 0000000000..4ef804cbb8 --- /dev/null +++ b/libs/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/LinkCrypto.kt @@ -0,0 +1,121 @@ +@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() + 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.toUByteArray(), key.toUByteArray(), + ) + return nonce + 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/libs/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/LinkInvite.kt b/libs/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/LinkInvite.kt new file mode 100644 index 0000000000..d924be8dae --- /dev/null +++ b/libs/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/libs/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/PhoneLinkController.kt b/libs/device-link/src/commonMain/kotlin/com/flipcash/app/devicelink/PhoneLinkController.kt new file mode 100644 index 0000000000..42a0118e16 --- /dev/null +++ b/libs/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/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 new file mode 100644 index 0000000000..b141be08b6 --- /dev/null +++ b/libs/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. + */ +internal 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/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..a3bdb5e7a4 --- /dev/null +++ b/libs/device-link/src/commonTest/kotlin/com/flipcash/app/devicelink/DeviceLinkVectorTest.kt @@ -0,0 +1,91 @@ +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 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() + 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/kotlin/com/flipcash/app/devicelink/LinkProtocolTest.kt b/libs/device-link/src/commonTest/kotlin/com/flipcash/app/devicelink/LinkProtocolTest.kt new file mode 100644 index 0000000000..998bde85cd --- /dev/null +++ b/libs/device-link/src/commonTest/kotlin/com/flipcash/app/devicelink/LinkProtocolTest.kt @@ -0,0 +1,165 @@ +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.first +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 codesMatchAndTheSeedArrives() { + 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 cancellingOnThePhoneSendsNothing() { + val states = runLink { invite -> PhoneLinker.connect(invite).getOrThrow().cancel() } + assertEquals(DesktopLinkHost.State.Failed("Cancelled on the phone"), states.last()) + } + + @Test + 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 -> + 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 tamperedSeedIsRejected() { + 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 aDeviceWithoutTheQRSecretCanTLink() { + 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 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) + 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 thePhoneControllerReadsTheSeedOnlyAfterConfirm() { + 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) + } + + @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) + } +} 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" + ] + } +} 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 7f42fb2702..f483315997 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..7ec3b4596d 100644 --- a/libs/encryption/ed25519/build.gradle.kts +++ b/libs/encryption/ed25519/build.gradle.kts @@ -1,8 +1,8 @@ +import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType 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 +79,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 } @@ -125,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 @@ -138,6 +142,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/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/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/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/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/keys/build.gradle.kts b/libs/encryption/keys/build.gradle.kts index 4e4c81f68c..14c70fec7a 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")) + api(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 79% 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..fbdb8bf627 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,14 +1,15 @@ package com.getcode.solana.keys -import android.os.Parcel -import android.os.Parcelable +import com.getcode.libs.parcelable.Parcel +import com.getcode.libs.parcelable.ManualParcelable +import com.getcode.libs.parcelable.parcelableCreator import com.getcode.utils.serializer.PublicKeyAsStringSerializer import com.getcode.vendor.Base58 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()) @@ -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/mnemonic/build.gradle.kts b/libs/encryption/mnemonic/build.gradle.kts index fa0c0dd626..812aba854b 100644 --- a/libs/encryption/mnemonic/build.gradle.kts +++ b/libs/encryption/mnemonic/build.gradle.kts @@ -1,6 +1,7 @@ +import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType + plugins { - kotlin("multiplatform") - id("com.android.kotlin.multiplatform.library") + alias(libs.plugins.flipcash.kmp.library) alias(libs.plugins.flipcash.kmp.test.fixtures) } @@ -10,25 +11,24 @@ testFixtures { packageName = "com.getcode.crypt" } +@OptIn(org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi::class) kotlin { - android { - namespace = "com.getcode.encryption.mnemonic" - compileSdk { - version = release(libs.versions.android.compileSdk.get().toInt()) { - minorApiLevel = libs.versions.android.compileSdkMinor.get().toInt() + // jvmShared: key and phrase types for both JVM targets (Android and desktop). + applyDefaultHierarchyTemplate { + common { + group("jvmShared") { + withJvm() + withCompilations { it.platformType == KotlinPlatformType.androidJvm } } } - minSdk = 29 + } + + android { + namespace = "com.getcode.encryption.mnemonic" withHostTest {} withDeviceTest {} } - iosArm64() - iosSimulatorArm64() - iosX64() - macosArm64() - macosX64() - sourceSets { commonMain { dependencies { @@ -45,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/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/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 } diff --git a/libs/encryption/utils/build.gradle.kts b/libs/encryption/utils/build.gradle.kts index 6b5bc632f3..e8e693884c 100644 --- a/libs/encryption/utils/build.gradle.kts +++ b/libs/encryption/utils/build.gradle.kts @@ -1,25 +1,25 @@ +import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType + plugins { - kotlin("multiplatform") - id("com.android.kotlin.multiplatform.library") + alias(libs.plugins.flipcash.kmp.library) } +@OptIn(org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi::class) kotlin { - android { - namespace = "com.getcode.encryption.utils" - compileSdk { - version = release(libs.versions.android.compileSdk.get().toInt()) { - minorApiLevel = libs.versions.android.compileSdkMinor.get().toInt() + // jvmShared: code for both JVM targets (Android and desktop) that needs java.* or protobuf. + applyDefaultHierarchyTemplate { + common { + group("jvmShared") { + withJvm() + withCompilations { it.platformType == KotlinPlatformType.androidJvm } } } - minSdk = 29 - withHostTest {} } - iosArm64() - iosSimulatorArm64() - iosX64() - macosArm64() - macosX64() + android { + namespace = "com.getcode.encryption.utils" + withHostTest {} + } sourceSets { commonMain { @@ -27,10 +27,14 @@ kotlin { implementation(project(":libs:encryption:base58")) } } - androidMain { + getByName("jvmSharedMain") { dependencies { - implementation(project(":libs:encryption:ed25519")) implementation(libs.protobuf.kotlin.lite) + implementation(project(":libs:encryption:ed25519")) + } + } + androidMain { + dependencies { 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/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/Ed25519Extensions.kt b/libs/encryption/utils/src/jvmSharedMain/kotlin/com/getcode/utils/Ed25519Extensions.kt new file mode 100644 index 0000000000..fc2be84b77 --- /dev/null +++ b/libs/encryption/utils/src/jvmSharedMain/kotlin/com/getcode/utils/Ed25519Extensions.kt @@ -0,0 +1,6 @@ +package com.getcode.utils + +import com.getcode.ed25519kmp.Ed25519 +import com.getcode.vendor.Base58 + +fun Ed25519.KeyPair.getPublicKeyBase58(): String = Base58.encode(publicKeyBytes) 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/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/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/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/LiveSecretsTest.kt b/libs/logging/src/androidHostTest/kotlin/com/getcode/utils/LiveSecretsTest.kt similarity index 100% rename from libs/logging/src/test/kotlin/com/getcode/utils/LiveSecretsTest.kt rename to libs/logging/src/androidHostTest/kotlin/com/getcode/utils/LiveSecretsTest.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 96% rename from libs/logging/src/main/kotlin/com/getcode/utils/FileTree.kt rename to libs/logging/src/androidMain/kotlin/com/getcode/utils/FileTree.kt index 19f9437eec..e7405364a6 100644 --- a/libs/logging/src/main/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..2e5b41e2a7 --- /dev/null +++ b/libs/logging/src/androidMain/kotlin/com/getcode/utils/PlatformLog.android.kt @@ -0,0 +1,36 @@ +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) + } + + actual fun error(throwable: Throwable, message: String?) { + Timber.e(throwable, message) + } +} + +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/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/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/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 94% rename from libs/logging/src/main/kotlin/com/getcode/utils/ErrorUtils.kt rename to libs/logging/src/commonMain/kotlin/com/getcode/utils/ErrorUtils.kt index 5fa512d292..01a3d10e75 100644 --- a/libs/logging/src/main/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/main/kotlin/com/getcode/utils/LiveSecrets.kt b/libs/logging/src/commonMain/kotlin/com/getcode/utils/LiveSecrets.kt similarity index 100% rename from libs/logging/src/main/kotlin/com/getcode/utils/LiveSecrets.kt rename to libs/logging/src/commonMain/kotlin/com/getcode/utils/LiveSecrets.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 88% rename from libs/logging/src/main/kotlin/com/getcode/utils/Logging.kt rename to libs/logging/src/commonMain/kotlin/com/getcode/utils/Logging.kt index 636d9e5681..e4e39fe8b2 100644 --- a/libs/logging/src/main/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/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/commonMain/kotlin/com/getcode/utils/PlatformLog.kt b/libs/logging/src/commonMain/kotlin/com/getcode/utils/PlatformLog.kt new file mode 100644 index 0000000000..d92204d232 --- /dev/null +++ b/libs/logging/src/commonMain/kotlin/com/getcode/utils/PlatformLog.kt @@ -0,0 +1,46 @@ +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) + fun error(throwable: Throwable, message: String?) +} + +/** 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() +} + +/** + * 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/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/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..9ac65d65a6 --- /dev/null +++ b/libs/logging/src/jvmMain/kotlin/com/getcode/utils/PlatformLog.jvm.kt @@ -0,0 +1,29 @@ +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() + } + + 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 + +internal actual fun elapsedRealtimeMillis(): Long = System.nanoTime() / 1_000_000 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/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 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..f06cb51e54 --- /dev/null +++ b/libs/parcelable/src/androidMain/kotlin/com/getcode/libs/parcelable/Parcelable.android.kt @@ -0,0 +1,20 @@ +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 = + 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..c36000ae8c --- /dev/null +++ b/libs/parcelable/src/commonMain/kotlin/com/getcode/libs/parcelable/Parcelable.kt @@ -0,0 +1,45 @@ +package com.getcode.libs.parcelable + +/** + * `android.os.Parcelable` on Android; on the desktop JVM a marker interface nothing reads. + * + * 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 + +/** + * 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) +} + +/** `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/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 new file mode 100644 index 0000000000..4e8741c5c6 --- /dev/null +++ b/libs/parcelable/src/jvmMain/kotlin/com/getcode/libs/parcelable/Parcelable.jvm.kt @@ -0,0 +1,15 @@ +package com.getcode.libs.parcelable + +actual interface Parcelable + +actual interface ManualParcelable : 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/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. diff --git a/services/flipcash/build.gradle.kts b/services/flipcash/build.gradle.kts index b4340e0861..63add2ec99 100644 --- a/services/flipcash/build.gradle.kts +++ b/services/flipcash/build.gradle.kts @@ -1,81 +1,68 @@ 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.grpc.stub) + 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.grpc.stub) - 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) + add("kspJvm", libs.dagger.compiler) + add("jvmMainImplementation", libs.dagger) } 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/chat/WrongKeyChatsTest.kt b/services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/chat/WrongKeyChatsTest.kt similarity index 100% rename from services/flipcash/src/test/kotlin/com/flipcash/services/chat/WrongKeyChatsTest.kt rename to services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/chat/WrongKeyChatsTest.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 99% 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 index f0c7fac5c0..fb61b682e1 100644 --- a/services/flipcash/src/test/kotlin/com/flipcash/services/controllers/BlobStorageControllerChatMediaTest.kt +++ b/services/flipcash/src/androidHostTest/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/androidHostTest/kotlin/com/flipcash/services/controllers/BlobStorageControllerTest.kt similarity index 99% 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 index 6199bde5b0..9d3d17dcfc 100644 --- a/services/flipcash/src/test/kotlin/com/flipcash/services/controllers/BlobStorageControllerTest.kt +++ b/services/flipcash/src/androidHostTest/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/androidHostTest/kotlin/com/flipcash/services/controllers/ChatControllerTest.kt similarity index 99% 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 index d4b697f673..812185455a 100644 --- a/services/flipcash/src/test/kotlin/com/flipcash/services/controllers/ChatControllerTest.kt +++ b/services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/controllers/ChatControllerTest.kt @@ -35,7 +35,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/androidHostTest/kotlin/com/flipcash/services/controllers/ChatMessagingControllerTest.kt similarity index 99% 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 index 3ddd48f844..1da44fb5b1 100644 --- a/services/flipcash/src/test/kotlin/com/flipcash/services/controllers/ChatMessagingControllerTest.kt +++ b/services/flipcash/src/androidHostTest/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/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 99% 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 index 0cd2a4ad36..21db53db5a 100644 --- a/services/flipcash/src/test/kotlin/com/flipcash/services/controllers/EventStreamingControllerTest.kt +++ b/services/flipcash/src/androidHostTest/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/androidHostTest/kotlin/com/flipcash/services/controllers/ProfileControllerTest.kt similarity index 99% 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 index 8118af6d55..f97941216a 100644 --- a/services/flipcash/src/test/kotlin/com/flipcash/services/controllers/ProfileControllerTest.kt +++ b/services/flipcash/src/androidHostTest/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/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 98% 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 index 34861e284a..eac29fe23d 100644 --- 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 @@ -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/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/PinMappingTest.kt b/services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/internal/network/extensions/PinMappingTest.kt similarity index 100% rename from services/flipcash/src/test/kotlin/com/flipcash/services/internal/network/extensions/PinMappingTest.kt rename to services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/internal/network/extensions/PinMappingTest.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 99% 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 index 5fe017e87b..384b7cf66e 100644 --- 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 @@ -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/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/internal/repositories/InternalChatRepositoryJoinTest.kt b/services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/internal/repositories/InternalChatRepositoryJoinTest.kt similarity index 97% rename from services/flipcash/src/test/kotlin/com/flipcash/services/internal/repositories/InternalChatRepositoryJoinTest.kt rename to services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/internal/repositories/InternalChatRepositoryJoinTest.kt index 68ca5f9c74..a0c5e3cc69 100644 --- a/services/flipcash/src/test/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/test/kotlin/com/flipcash/services/internal/repositories/InviteFailureTest.kt b/services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/internal/repositories/InviteFailureTest.kt similarity index 100% rename from services/flipcash/src/test/kotlin/com/flipcash/services/internal/repositories/InviteFailureTest.kt rename to services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/internal/repositories/InviteFailureTest.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/models/chat/SilenceStateTest.kt b/services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/models/chat/SilenceStateTest.kt similarity index 100% rename from services/flipcash/src/test/kotlin/com/flipcash/services/models/chat/SilenceStateTest.kt rename to services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/models/chat/SilenceStateTest.kt diff --git a/services/flipcash/src/test/kotlin/com/flipcash/services/models/paymentrequest/PaymentRequestStorageTest.kt b/services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/models/paymentrequest/PaymentRequestStorageTest.kt similarity index 100% rename from services/flipcash/src/test/kotlin/com/flipcash/services/models/paymentrequest/PaymentRequestStorageTest.kt rename to services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/models/paymentrequest/PaymentRequestStorageTest.kt diff --git a/services/flipcash/src/test/kotlin/com/flipcash/services/models/paymentrequest/PaymentRequestTest.kt b/services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/models/paymentrequest/PaymentRequestTest.kt similarity index 100% rename from services/flipcash/src/test/kotlin/com/flipcash/services/models/paymentrequest/PaymentRequestTest.kt rename to services/flipcash/src/androidHostTest/kotlin/com/flipcash/services/models/paymentrequest/PaymentRequestTest.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/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/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/GroupKeyEnvelopeStore.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/chat/GroupKeyEnvelopeStore.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/chat/GroupKeyEnvelopeStore.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/chat/GroupKeyEnvelopeStore.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/InviteEnvelopes.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/chat/InviteEnvelopes.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/chat/InviteEnvelopes.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/chat/InviteEnvelopes.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/chat/WrongKeyChats.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/chat/WrongKeyChats.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/chat/WrongKeyChats.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/chat/WrongKeyChats.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 99% 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 index 804a34410b..a4fdb8cffd 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/controllers/BlobStorageController.kt +++ b/services/flipcash/src/commonMain/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/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/PaymentRequestController.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/controllers/PaymentRequestController.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/controllers/PaymentRequestController.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/controllers/PaymentRequestController.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 65% 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 445a8833e3..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.ed25519.Ed25519 -import com.getcode.ed25519.Ed25519.KeyPair +import com.getcode.ed25519kmp.Ed25519 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 79% 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 index 5d04fb7df3..9ca81e2d13 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/inject/ChatCryptoModule.kt +++ b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/inject/ChatCryptoModule.kt @@ -16,13 +16,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/main/kotlin/com/flipcash/services/inject/FlipcashModule.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/inject/FlipcashModule.kt similarity index 77% rename from services/flipcash/src/main/kotlin/com/flipcash/services/inject/FlipcashModule.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/inject/FlipcashModule.kt index 934c174576..a94abbb82d 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/inject/FlipcashModule.kt +++ b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/inject/FlipcashModule.kt @@ -1,6 +1,6 @@ package com.flipcash.services.inject -import android.content.Context +import com.flipcash.services.user.AnalyticsIdentifier import com.flipcash.services.internal.annotations.FlipcashManagedChannel import com.flipcash.services.internal.annotations.FlipcashManagedStreamingChannel import com.flipcash.services.internal.annotations.FlipcashProtocol @@ -15,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 @@ -83,92 +82,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 { - @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, @@ -176,22 +100,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, @@ -199,64 +127,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, @@ -264,6 +198,7 @@ internal object FlipcashModule { InternalContactVerificationRepository(emailService, phoneService) @Provides + @JvmName("providesProfileRepository") internal fun providesProfileRepository( service: ProfileService, userProfileMapper: UserProfileMapper, @@ -272,16 +207,19 @@ internal object FlipcashModule { InternalProfileRepository(service, userProfileMapper, socialAccountMapper) @Provides + @JvmName("providesPollRepository") internal fun providesPollRepository( service: PollService, ): PollRepository = InternalPollRepository(service) @Provides + @JvmName("providesPaymentRequestRepository") internal fun providesPaymentRequestRepository( service: PaymentRequestService, ): PaymentRequestRepository = InternalPaymentRequestRepository(service) @Provides + @JvmName("providesModerationRepository") internal fun providesModerationRepository( service: ModerationService, textModerationResponseMapper: TextModerationResponseMapper, @@ -293,7 +231,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/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 80% 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 index 727cb06c3f..c48ed2738b 100644 --- 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 @@ -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/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 98% 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 index fd6c0b52d6..987d1d8cab 100644 --- 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 @@ -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/commonMain/kotlin/com/flipcash/services/internal/network/api/ActivityFeedApi.kt similarity index 98% 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 index 27c4815e4a..92c55c6150 100644 --- 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 @@ -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/commonMain/kotlin/com/flipcash/services/internal/network/api/BlobStorageApi.kt similarity index 99% 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 index 2f4a7f4654..66d4f657a7 100644 --- 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 @@ -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/commonMain/kotlin/com/flipcash/services/internal/network/api/BlocklistApi.kt similarity index 98% 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 index 829de957a5..6f53872b87 100644 --- 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 @@ -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/commonMain/kotlin/com/flipcash/services/internal/network/api/ChatApi.kt similarity index 99% 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 index 04622eb45b..701b92e04e 100644 --- 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 @@ -41,7 +41,7 @@ import com.flipcash.services.models.chat.StartChatParameters import com.flipcash.services.models.chat.ViewMode import com.getcode.utils.toByteString import kotlin.time.Instant -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/commonMain/kotlin/com/flipcash/services/internal/network/api/ChatMessagingApi.kt similarity index 99% 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 index 3563dfd296..90837231bc 100644 --- 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 @@ -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/commonMain/kotlin/com/flipcash/services/internal/network/api/CommunityApi.kt similarity index 97% 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 index 837140bdce..3537dba74f 100644 --- 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 @@ -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/commonMain/kotlin/com/flipcash/services/internal/network/api/ContactListApi.kt similarity index 98% 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 index 46dfb6272d..84a95cf134 100644 --- 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 @@ -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/commonMain/kotlin/com/flipcash/services/internal/network/api/EmailVerificationApi.kt similarity index 98% 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 index e8ca56740d..dc9b764be6 100644 --- 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 @@ -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/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 97% 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 index d5a28fb07b..9a75bace9a 100644 --- 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 @@ -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/PaymentRequestApi.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/api/PaymentRequestApi.kt similarity index 99% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/api/PaymentRequestApi.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/api/PaymentRequestApi.kt index 7ee74ca143..ccc3d773f2 100644 --- a/services/flipcash/src/main/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/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 99% 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 index 0cf8fc42a3..d97f5ed07a 100644 --- 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 @@ -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/commonMain/kotlin/com/flipcash/services/internal/network/api/PollApi.kt similarity index 98% 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 index fa14b13aa5..f75cbc2d87 100644 --- 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 @@ -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/commonMain/kotlin/com/flipcash/services/internal/network/api/ProfileApi.kt similarity index 99% 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 index 0da8ac1a53..25be394dea 100644 --- 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 @@ -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/commonMain/kotlin/com/flipcash/services/internal/network/api/PurchaseApi.kt similarity index 97% 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 index e357917859..a5285af4c8 100644 --- 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 @@ -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/commonMain/kotlin/com/flipcash/services/internal/network/api/PushApi.kt similarity index 98% 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 index bbafd0195f..35343f5f31 100644 --- 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 @@ -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/commonMain/kotlin/com/flipcash/services/internal/network/api/ReportingApi.kt similarity index 98% 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 index 1e000b00c2..7e840ce700 100644 --- 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 @@ -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/commonMain/kotlin/com/flipcash/services/internal/network/api/ResolverApi.kt similarity index 97% 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 index 36ee7fa64a..cb5a3a173b 100644 --- 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 @@ -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/commonMain/kotlin/com/flipcash/services/internal/network/api/SettingsApi.kt similarity index 97% 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 index 13db7db1dc..df32d27e61 100644 --- 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 @@ -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/commonMain/kotlin/com/flipcash/services/internal/network/api/ThirdPartyApi.kt similarity index 97% 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 index 157c7b8a8f..17218c4c4f 100644 --- 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 @@ -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/commonMain/kotlin/com/flipcash/services/internal/network/extensions/AuthenticateMessage.kt similarity index 96% 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 index 4ac8d6eece..4cb8ad9969 100644 --- 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 @@ -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/InviteMappers.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/extensions/InviteMappers.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/extensions/InviteMappers.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/extensions/InviteMappers.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 99% 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 index 77d29e7b8f..6a20150836 100644 --- 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 @@ -20,7 +20,7 @@ import com.flipcash.services.models.chat.PointerType import com.flipcash.services.models.chat.TypingState import com.flipcash.services.models.chat.ViewMode import com.flipcash.services.models.chat.WidgetContent -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/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 95% 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 index 5a7771f207..ff5f1184e9 100644 --- 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 @@ -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/commonMain/kotlin/com/flipcash/services/internal/network/services/AccountService.kt similarity index 98% 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 index 31ff0cd3b6..509bb4ac68 100644 --- 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 @@ -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/commonMain/kotlin/com/flipcash/services/internal/network/services/ActivityFeedService.kt similarity index 98% 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 index 0760eae2be..dc22d083f7 100644 --- 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 @@ -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/commonMain/kotlin/com/flipcash/services/internal/network/services/BlobStorageService.kt similarity index 99% 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 index cdb154b747..c5bbb738fb 100644 --- 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 @@ -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/commonMain/kotlin/com/flipcash/services/internal/network/services/BlocklistService.kt similarity index 98% 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 index 8ecf02657f..2ad5ab4ea7 100644 --- 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 @@ -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/commonMain/kotlin/com/flipcash/services/internal/network/services/ChatMessagingService.kt similarity index 99% 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 index 4b331bd4f1..b275c397fc 100644 --- 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 @@ -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/commonMain/kotlin/com/flipcash/services/internal/network/services/ChatService.kt similarity index 99% 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 index 3422bcc26c..4e435af45b 100644 --- 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 @@ -52,7 +52,7 @@ import com.flipcash.services.models.chat.SilenceState 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/commonMain/kotlin/com/flipcash/services/internal/network/services/CommunityService.kt similarity index 97% 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 index 734835b67b..e435bab7f0 100644 --- 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 @@ -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/commonMain/kotlin/com/flipcash/services/internal/network/services/ContactListService.kt similarity index 99% 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 index eb531ef5cf..f557a79186 100644 --- 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 @@ -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/commonMain/kotlin/com/flipcash/services/internal/network/services/EmailVerificationService.kt similarity index 99% 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 index 662a69ee25..68612a47c8 100644 --- 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 @@ -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/commonMain/kotlin/com/flipcash/services/internal/network/services/EventStreamingService.kt similarity index 99% 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 index 6147f3a773..5c12725f8e 100644 --- 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 @@ -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/commonMain/kotlin/com/flipcash/services/internal/network/services/ModerationService.kt similarity index 98% 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 index ad53cba74e..542e804718 100644 --- 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 @@ -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/PaymentRequestService.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/services/PaymentRequestService.kt similarity index 99% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/network/services/PaymentRequestService.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/network/services/PaymentRequestService.kt index f37c292347..dce0a48140 100644 --- a/services/flipcash/src/main/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/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 99% 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 index 1f91754338..25126929bb 100644 --- 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 @@ -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/commonMain/kotlin/com/flipcash/services/internal/network/services/PollService.kt similarity index 99% 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 index 153369ada4..dd6c93282e 100644 --- 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 @@ -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/commonMain/kotlin/com/flipcash/services/internal/network/services/ProfileService.kt similarity index 99% 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 index 8c4ab55269..7c607e07dd 100644 --- 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 @@ -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/commonMain/kotlin/com/flipcash/services/internal/network/services/PurchaseService.kt similarity index 97% 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 index 1cded8a70e..ff831d66e2 100644 --- 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 @@ -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/commonMain/kotlin/com/flipcash/services/internal/network/services/PushService.kt similarity index 98% 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 index 7a55d4fec4..f447fc14d9 100644 --- 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 @@ -6,7 +6,7 @@ import com.getcode.opencode.internal.network.extensions.foldWithSuppression import com.flipcash.services.models.AddTokenError import com.flipcash.services.models.DeleteTokenError import com.flipcash.services.models.SendTestPushError -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/commonMain/kotlin/com/flipcash/services/internal/network/services/ReportingService.kt similarity index 97% 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 index 2c175aa065..e39c90c848 100644 --- 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 @@ -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/commonMain/kotlin/com/flipcash/services/internal/network/services/ResolverService.kt similarity index 97% 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 index 6b108116e8..25dec988be 100644 --- 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 @@ -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/commonMain/kotlin/com/flipcash/services/internal/network/services/SettingsService.kt similarity index 97% 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 index bc1aef9cc0..d1a63aa1bc 100644 --- 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 @@ -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/commonMain/kotlin/com/flipcash/services/internal/network/services/ThirdPartyService.kt similarity index 98% 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 index 949abe7613..58613e8594 100644 --- 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 @@ -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/commonMain/kotlin/com/flipcash/services/internal/repositories/InternalAccountRepository.kt similarity index 96% 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 index 1fc023cd1b..aa0cddf95f 100644 --- 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 @@ -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/commonMain/kotlin/com/flipcash/services/internal/repositories/InternalActivityFeedRepository.kt similarity index 97% 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 index 462960041b..01c7c2182c 100644 --- 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 @@ -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/commonMain/kotlin/com/flipcash/services/internal/repositories/InternalBlobStorageRepository.kt similarity index 97% 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 index 12333c5b2c..e53231a493 100644 --- 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 @@ -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/commonMain/kotlin/com/flipcash/services/internal/repositories/InternalBlocklistRepository.kt similarity index 97% 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 index ef4a5cac06..053d0c8aa1 100644 --- 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 @@ -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/commonMain/kotlin/com/flipcash/services/internal/repositories/InternalChatMessagingRepository.kt similarity index 99% 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 index 1e8ae54c97..5d78af8f7f 100644 --- 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 @@ -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/commonMain/kotlin/com/flipcash/services/internal/repositories/InternalChatRepository.kt similarity index 99% 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 index f26b9c0efb..e03699de9e 100644 --- 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 @@ -58,7 +58,7 @@ import com.flipcash.services.models.chat.ViewerState import com.flipcash.services.models.chat.ViewMode import com.flipcash.services.repository.ChatRepository import com.codeinc.flipcash.gen.chat.v1.ChatService as RpcChatService -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/commonMain/kotlin/com/flipcash/services/internal/repositories/InternalCommunityRepository.kt similarity index 96% 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 index f036295c6f..76a5a055b2 100644 --- 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 @@ -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/commonMain/kotlin/com/flipcash/services/internal/repositories/InternalContactListRepository.kt similarity index 97% 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 index 899f75f7ae..747eed4988 100644 --- 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 @@ -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/commonMain/kotlin/com/flipcash/services/internal/repositories/InternalContactVerificationRepository.kt similarity index 98% 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 index a39028866d..29abda4825 100644 --- 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 @@ -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/commonMain/kotlin/com/flipcash/services/internal/repositories/InternalEventStreamingRepository.kt similarity index 95% 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 index 962cf1949a..35c0a84e83 100644 --- 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 @@ -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/commonMain/kotlin/com/flipcash/services/internal/repositories/InternalModerationRepository.kt similarity index 97% 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 index 6f57a1fa66..fed70d6845 100644 --- 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 @@ -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/InternalPaymentRequestRepository.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/repositories/InternalPaymentRequestRepository.kt similarity index 98% rename from services/flipcash/src/main/kotlin/com/flipcash/services/internal/repositories/InternalPaymentRequestRepository.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/repositories/InternalPaymentRequestRepository.kt index 854f9b04ee..07b6cf7e34 100644 --- a/services/flipcash/src/main/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/main/kotlin/com/flipcash/services/internal/repositories/InternalPollRepository.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/internal/repositories/InternalPollRepository.kt similarity index 97% 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 index ff3c08da78..64cc033afb 100644 --- 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 @@ -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/commonMain/kotlin/com/flipcash/services/internal/repositories/InternalProfileRepository.kt similarity index 99% 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 index 053fe18879..5e18d12b54 100644 --- 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 @@ -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/commonMain/kotlin/com/flipcash/services/internal/repositories/InternalPurchaseRepository.kt similarity index 94% 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 index 5ed5454830..afa33010c0 100644 --- 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 @@ -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/commonMain/kotlin/com/flipcash/services/internal/repositories/InternalPushRepository.kt similarity index 96% 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 index 2a80947c34..93b550f3a3 100644 --- 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 @@ -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/commonMain/kotlin/com/flipcash/services/internal/repositories/InternalReportingRepository.kt similarity index 94% 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 index 8fa313459b..2814e6ca1b 100644 --- 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 @@ -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/commonMain/kotlin/com/flipcash/services/internal/repositories/InternalResolverRepository.kt similarity index 94% 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 index a30a5e2889..2368a72356 100644 --- 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 @@ -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/commonMain/kotlin/com/flipcash/services/internal/repositories/InternalSettingsRepository.kt similarity index 93% 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 index e9a0982b6f..953326461e 100644 --- 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 @@ -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/commonMain/kotlin/com/flipcash/services/internal/repositories/InternalThirdPartyRepository.kt similarity index 94% 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 index 27de642c1c..3053735059 100644 --- 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 @@ -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/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/GroupPaymentMetadata.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/GroupPaymentMetadata.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/GroupPaymentMetadata.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/GroupPaymentMetadata.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/RequestedPaymentMetadata.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/RequestedPaymentMetadata.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/RequestedPaymentMetadata.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/RequestedPaymentMetadata.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/Invite.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/Invite.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/Invite.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/Invite.kt 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/Moderation.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/Moderation.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/Moderation.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/Moderation.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/Pin.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/Pin.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/Pin.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/Pin.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/PinSummaryStorage.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/PinSummaryStorage.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/chat/PinSummaryStorage.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/chat/PinSummaryStorage.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/models/paymentrequest/PaymentRequest.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/paymentrequest/PaymentRequest.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/paymentrequest/PaymentRequest.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/paymentrequest/PaymentRequest.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/paymentrequest/PaymentRequestModels.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/paymentrequest/PaymentRequestModels.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/paymentrequest/PaymentRequestModels.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/paymentrequest/PaymentRequestModels.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/paymentrequest/PaymentRequestStorage.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/paymentrequest/PaymentRequestStorage.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/paymentrequest/PaymentRequestStorage.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/paymentrequest/PaymentRequestStorage.kt diff --git a/services/flipcash/src/main/kotlin/com/flipcash/services/models/paymentrequest/PaymentRequestUpdate.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/paymentrequest/PaymentRequestUpdate.kt similarity index 100% rename from services/flipcash/src/main/kotlin/com/flipcash/services/models/paymentrequest/PaymentRequestUpdate.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/models/paymentrequest/PaymentRequestUpdate.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 88% 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 index b74ef73ec8..8cf4f97cbd 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/AccountRepository.kt +++ b/services/flipcash/src/commonMain/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/commonMain/kotlin/com/flipcash/services/repository/ActivityFeedRepository.kt similarity index 94% 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 index df6b4a13ad..a6f3568e1c 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/ActivityFeedRepository.kt +++ b/services/flipcash/src/commonMain/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/commonMain/kotlin/com/flipcash/services/repository/BlobStorageRepository.kt similarity index 96% 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 index 9b743e830d..91e7058c88 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/BlobStorageRepository.kt +++ b/services/flipcash/src/commonMain/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/commonMain/kotlin/com/flipcash/services/repository/BlocklistRepository.kt similarity index 91% 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 index 74d3cb391c..e356a47bbb 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/BlocklistRepository.kt +++ b/services/flipcash/src/commonMain/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/commonMain/kotlin/com/flipcash/services/repository/ChatMessagingRepository.kt similarity index 98% 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 index 56a5086347..a2890da48a 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/ChatMessagingRepository.kt +++ b/services/flipcash/src/commonMain/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/commonMain/kotlin/com/flipcash/services/repository/ChatRepository.kt similarity index 99% 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 index f3fa54c23a..771fe3c6b7 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/ChatRepository.kt +++ b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/repository/ChatRepository.kt @@ -32,7 +32,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 import kotlin.time.Instant 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 83% 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 index 1a542b9d01..5d89f1ccdd 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/CommunityRepository.kt +++ b/services/flipcash/src/commonMain/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/commonMain/kotlin/com/flipcash/services/repository/ContactListRepository.kt similarity index 95% 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 index d637bf49f1..3f0b4239e6 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/ContactListRepository.kt +++ b/services/flipcash/src/commonMain/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/commonMain/kotlin/com/flipcash/services/repository/ContactVerificationRepository.kt similarity index 93% 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 index 54dbf6c330..abc94a7556 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/ContactVerificationRepository.kt +++ b/services/flipcash/src/commonMain/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/commonMain/kotlin/com/flipcash/services/repository/EventStreamingRepository.kt similarity index 92% 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 index 3cb761ee6d..187805db92 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/EventStreamingRepository.kt +++ b/services/flipcash/src/commonMain/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/commonMain/kotlin/com/flipcash/services/repository/ModerationRepository.kt similarity index 89% 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 index c58e152b63..181846f831 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/ModerationRepository.kt +++ b/services/flipcash/src/commonMain/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/PaymentRequestRepository.kt b/services/flipcash/src/commonMain/kotlin/com/flipcash/services/repository/PaymentRequestRepository.kt similarity index 97% rename from services/flipcash/src/main/kotlin/com/flipcash/services/repository/PaymentRequestRepository.kt rename to services/flipcash/src/commonMain/kotlin/com/flipcash/services/repository/PaymentRequestRepository.kt index 9de5589934..a0fd2d9e30 100644 --- a/services/flipcash/src/main/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 /** 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 94% 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 index 014d67b143..bd42a695e4 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/PollRepository.kt +++ b/services/flipcash/src/commonMain/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/commonMain/kotlin/com/flipcash/services/repository/ProfileRepository.kt similarity index 97% 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 index 13a175663b..4e20508129 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/ProfileRepository.kt +++ b/services/flipcash/src/commonMain/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/commonMain/kotlin/com/flipcash/services/repository/PurchaseRepository.kt similarity index 87% 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 index 7ee1032aae..7a764f8a14 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/PurchaseRepository.kt +++ b/services/flipcash/src/commonMain/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/commonMain/kotlin/com/flipcash/services/repository/PushRepository.kt similarity index 90% 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 index 2d8ce3725b..cb6558ef0c 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/PushRepository.kt +++ b/services/flipcash/src/commonMain/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/commonMain/kotlin/com/flipcash/services/repository/ReportingRepository.kt similarity index 88% 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 index 071ceb7093..a502b3ddfc 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/ReportingRepository.kt +++ b/services/flipcash/src/commonMain/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/commonMain/kotlin/com/flipcash/services/repository/ResolverRepository.kt similarity index 85% 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 index 5e2b7ecf6a..fb06119465 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/ResolverRepository.kt +++ b/services/flipcash/src/commonMain/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/commonMain/kotlin/com/flipcash/services/repository/SettingsRepository.kt similarity index 81% 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 index 3871d4aa20..dcc3e3c81b 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/SettingsRepository.kt +++ b/services/flipcash/src/commonMain/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/commonMain/kotlin/com/flipcash/services/repository/ThirdPartyRepository.kt similarity index 88% 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 index 861fb273c5..1a8a298d13 100644 --- a/services/flipcash/src/main/kotlin/com/flipcash/services/repository/ThirdPartyRepository.kt +++ b/services/flipcash/src/commonMain/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/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 97% 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 2496834fb9..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 @@ -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,11 +15,9 @@ 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 -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, ) { @@ -218,12 +217,12 @@ 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() 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/services/flipcash/src/testFixtures/kotlin/com/flipcash/services/chat/FakeInviteCipher.kt b/services/flipcash/test-fixtures/src/commonMain/kotlin/com/flipcash/services/chat/FakeInviteCipher.kt similarity index 100% rename from services/flipcash/src/testFixtures/kotlin/com/flipcash/services/chat/FakeInviteCipher.kt rename to services/flipcash/test-fixtures/src/commonMain/kotlin/com/flipcash/services/chat/FakeInviteCipher.kt diff --git a/services/flipcash/src/testFixtures/kotlin/com/flipcash/services/chat/InMemoryGroupKeyEnvelopeStore.kt b/services/flipcash/test-fixtures/src/commonMain/kotlin/com/flipcash/services/chat/InMemoryGroupKeyEnvelopeStore.kt similarity index 100% rename from services/flipcash/src/testFixtures/kotlin/com/flipcash/services/chat/InMemoryGroupKeyEnvelopeStore.kt rename to services/flipcash/test-fixtures/src/commonMain/kotlin/com/flipcash/services/chat/InMemoryGroupKeyEnvelopeStore.kt 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 diff --git a/services/opencode/build.gradle.kts b/services/opencode/build.gradle.kts index 538849797b..9b4d01b18f 100644 --- a/services/opencode/build.gradle.kts +++ b/services/opencode/build.gradle.kts @@ -1,99 +1,105 @@ 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") + alias(libs.plugins.metro) } -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")}\"" - ) +// 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() } +} - buildFeatures { - buildConfig = true +kotlin { + android { + namespace = "${Gradle.codeNamespace}.services.opencode" + androidResources { enable = 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.grpc.stub) + 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")) + // formatProto tests render a flipcash2 response that carries a payment_intent_id. + implementation(libs.flipcash2.client.protocol) + } + 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.grpc.stub) - 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) + add("jvmMainImplementation", libs.dagger) +} - testImplementation(kotlin("test")) - testImplementation(libs.bundles.unit.testing) - testImplementation(testFixtures(project(":libs:currency-math"))) - // formatProto tests render a flipcash2 response that carries a payment_intent_id. - testImplementation(libs.flipcash2.client.protocol) +// 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/kotlin/com/getcode/opencode/utils/logging/FormatProtoTest.kt b/services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/utils/logging/FormatProtoTest.kt similarity index 100% rename from services/opencode/src/test/kotlin/com/getcode/opencode/utils/logging/FormatProtoTest.kt rename to services/opencode/src/androidHostTest/kotlin/com/getcode/opencode/utils/logging/FormatProtoTest.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 90% rename from services/opencode/src/main/kotlin/com/getcode/opencode/RepositoryFactory.kt rename to services/opencode/src/androidMain/kotlin/com/getcode/opencode/RepositoryFactory.kt index 4d0fa240ea..4502e51c25 100644 --- a/services/opencode/src/main/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/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 b78023e0cd..4c8c8aad4c 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/inject/OpenCodeModule.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/inject/OpenCodeModule.kt similarity index 62% rename from services/opencode/src/main/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/main/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/main/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/main/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/main/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/main/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/main/kotlin/com/getcode/opencode/internal/annotations/OpenCodeManagedChannel.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/annotations/OpenCodeManagedChannel.kt similarity index 81% 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 index 00a4dfd2bb..6dabebc73d 100644 --- 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 @@ -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/main/kotlin/com/getcode/opencode/internal/annotations/Protocol.kt b/services/opencode/src/commonMain/kotlin/com/getcode/opencode/internal/annotations/Protocol.kt similarity index 86% 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 index bbb968bbc9..8437d347ed 100644 --- 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 @@ -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/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..8ab1a82e63 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,43 +30,38 @@ 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 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 { - // 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 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 { @@ -84,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() 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 ca61a3569d..2996636c7f 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.LiveSecrets @@ -164,7 +164,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..381064e457 --- /dev/null +++ b/services/opencode/src/jvmMain/kotlin/com/getcode/opencode/internal/platform/ProcessLifecycle.jvm.kt @@ -0,0 +1,21 @@ +package com.getcode.opencode.internal.platform + +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/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 diff --git a/settings.gradle.kts b/settings.gradle.kts index 8d1509095b..455720743c 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", @@ -118,11 +119,14 @@ include( ":apps:flipcash:core", ":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", ":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", @@ -201,12 +205,16 @@ include( ":libs:code-detection", ":libs:codes:kikcode", ":libs:coroutines", + ":libs:coroutines:test-fixtures", + ":libs:parcelable", + ":libs:currency-math:test-fixtures", ":libs:crypto:kin", ":libs:crypto:solana", ":libs:currency", ":libs:currency-math", ":libs:currency-math:discrete-curve", ":libs:datetime", + ":libs:device-link", ":libs:emojis", ":libs:encryption:base58", ":libs:encryption:chat-cipher", @@ -252,6 +260,7 @@ include( ":services:opencode", ":services:opencode-compose", ":services:flipcash", + ":services:flipcash:test-fixtures", ":services:flipcash-compose", // common UI @@ -260,6 +269,7 @@ include( ":ui:components", ":ui:navigation", ":ui:resources", + ":ui:resources:test-fixtures", ":ui:scanner", ":ui:testing", ":ui:theme", @@ -284,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) } @@ -334,10 +353,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", @@ -345,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 @@ -375,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", diff --git a/ui/components/build.gradle.kts b/ui/components/build.gradle.kts index b66710c0a1..8b0494ea60 100644 --- a/ui/components/build.gradle.kts +++ b/ui/components/build.gradle.kts @@ -1,48 +1,74 @@ +import com.getcode.buildlogic.resources.androidResAsComposeResources + plugins { - alias(libs.plugins.flipcash.android.library.compose) + alias(libs.plugins.flipcash.kmp.app.library) + alias(libs.plugins.compose.compiler) + alias(libs.plugins.jetbrains.compose) 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) + 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) + 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) +compose.resources { + publicResClass = true + packageOfResClass = "${Gradle.codeNamespace}.ui.components.resources" + customDirectory( + sourceSetName = "commonMain", + directoryProvider = androidResAsComposeResources(), + ) } 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/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/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/SlidingChipRowTest.kt b/ui/components/src/androidHostTest/kotlin/com/getcode/ui/components/SlidingChipRowTest.kt similarity index 100% rename from ui/components/src/test/kotlin/com/getcode/ui/components/SlidingChipRowTest.kt rename to ui/components/src/androidHostTest/kotlin/com/getcode/ui/components/SlidingChipRowTest.kt diff --git a/ui/components/src/test/kotlin/com/getcode/ui/components/SubmenuDropdownMenuTest.kt b/ui/components/src/androidHostTest/kotlin/com/getcode/ui/components/SubmenuDropdownMenuTest.kt similarity index 100% rename from ui/components/src/test/kotlin/com/getcode/ui/components/SubmenuDropdownMenuTest.kt rename to ui/components/src/androidHostTest/kotlin/com/getcode/ui/components/SubmenuDropdownMenuTest.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/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/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/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/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/SubmenuDropdownMenu.kt b/ui/components/src/androidMain/kotlin/com/getcode/ui/components/SubmenuDropdownMenu.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/components/SubmenuDropdownMenu.kt rename to ui/components/src/androidMain/kotlin/com/getcode/ui/components/SubmenuDropdownMenu.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/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/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/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/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/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/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/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/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/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/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/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/Locals.kt b/ui/components/src/commonMain/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/commonMain/kotlin/com/getcode/ui/Locals.kt 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/BetaIndicator.kt b/ui/components/src/commonMain/kotlin/com/getcode/ui/components/BetaIndicator.kt similarity index 84% rename from ui/components/src/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/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/EmptyState.kt b/ui/components/src/commonMain/kotlin/com/getcode/ui/components/EmptyState.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/components/EmptyState.kt rename to ui/components/src/commonMain/kotlin/com/getcode/ui/components/EmptyState.kt diff --git a/ui/components/src/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/kotlin/com/getcode/ui/components/SlidingChipRow.kt b/ui/components/src/commonMain/kotlin/com/getcode/ui/components/SlidingChipRow.kt similarity index 100% rename from ui/components/src/main/kotlin/com/getcode/ui/components/SlidingChipRow.kt rename to ui/components/src/commonMain/kotlin/com/getcode/ui/components/SlidingChipRow.kt diff --git a/ui/components/src/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/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/ExpandableText.kt b/ui/components/src/commonMain/kotlin/com/getcode/ui/components/text/ExpandableText.kt similarity index 93% rename from ui/components/src/main/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/main/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, ) 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/SectionHeader.kt b/ui/components/src/commonMain/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/commonMain/kotlin/com/getcode/ui/components/text/SectionHeader.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/DigitContainer.kt b/ui/components/src/commonMain/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/commonMain/kotlin/com/getcode/ui/components/text/animated/DigitContainer.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/CodeBillSwipeToDismiss.kt b/ui/components/src/commonMain/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/commonMain/kotlin/com/getcode/ui/theme/CodeBillSwipeToDismiss.kt diff --git a/ui/components/src/main/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/main/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/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/theme/CodeRadioButton.kt b/ui/components/src/commonMain/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/commonMain/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/commonMain/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/commonMain/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/commonMain/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/commonMain/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/commonMain/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/commonMain/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/commonMain/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/commonMain/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/commonMain/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/commonMain/kotlin/com/getcode/ui/utils/AnimationUtils.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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/main/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/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/TextStyle.kt b/ui/components/src/commonMain/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/commonMain/kotlin/com/getcode/ui/utils/TextStyle.kt 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/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/ContextMenuAction.kt b/ui/core/src/commonMain/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/commonMain/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/commonMain/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/commonMain/kotlin/com/getcode/ui/core/ExpandedTouchTarget.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/core/src/main/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/main/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/main/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/main/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/main/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/main/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 6e8e974f1f..27266d9bf8 100644 --- a/ui/navigation/build.gradle.kts +++ b/ui/navigation/build.gradle.kts @@ -1,40 +1,61 @@ 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 { + 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")) + 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) + add("kspJvm", libs.dagger.compiler) + add("jvmMainImplementation", libs.dagger) } 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/test/kotlin/com/getcode/view/HoldPaymentSuccessTest.kt b/ui/navigation/src/androidHostTest/kotlin/com/getcode/view/HoldPaymentSuccessTest.kt similarity index 100% rename from ui/navigation/src/test/kotlin/com/getcode/view/HoldPaymentSuccessTest.kt rename to ui/navigation/src/androidHostTest/kotlin/com/getcode/view/HoldPaymentSuccessTest.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/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/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/InWindowBottomSheet.kt b/ui/navigation/src/androidMain/kotlin/com/getcode/navigation/scenes/InWindowBottomSheet.kt similarity index 100% rename from ui/navigation/src/main/kotlin/com/getcode/navigation/scenes/InWindowBottomSheet.kt rename to ui/navigation/src/androidMain/kotlin/com/getcode/navigation/scenes/InWindowBottomSheet.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 f4f906a8cc..d50c80772c 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/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/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/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/FlowDismissStyle.kt b/ui/navigation/src/commonMain/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/commonMain/kotlin/com/getcode/navigation/flow/FlowDismissStyle.kt diff --git a/ui/navigation/src/main/kotlin/com/getcode/navigation/flow/FlowRoute.kt b/ui/navigation/src/commonMain/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/commonMain/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/commonMain/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/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/scrim/Scrim.kt b/ui/navigation/src/commonMain/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/commonMain/kotlin/com/getcode/navigation/scrim/Scrim.kt 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 diff --git a/ui/navigation/src/main/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/main/kotlin/com/getcode/ui/utils/SheetExpansion.kt rename to ui/navigation/src/commonMain/kotlin/com/getcode/ui/utils/SheetExpansion.kt diff --git a/ui/navigation/src/main/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/main/kotlin/com/getcode/view/BaseViewModel.kt rename to ui/navigation/src/commonMain/kotlin/com/getcode/view/BaseViewModel.kt diff --git a/ui/resources/build.gradle.kts b/ui/resources/build.gradle.kts index cd0dc3c181..2c59e04111 100644 --- a/ui/resources/build.gradle.kts +++ b/ui/resources/build.gradle.kts @@ -1,22 +1,42 @@ +import com.getcode.buildlogic.resources.androidResAsComposeResources + plugins { - alias(libs.plugins.flipcash.android.library.compose) + alias(libs.plugins.flipcash.kmp.app.library) + alias(libs.plugins.compose.compiler) + alias(libs.plugins.jetbrains.compose) } -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) + 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) + api(libs.jetbrains.compose.components.resources) + } + androidMain.dependencies { + api(libs.androidx.appcompat) + api(libs.androidx.core) + implementation(libs.androidx.exifinterface) + implementation(libs.timber) + } + } +} - 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) +compose.resources { + publicResClass = true + packageOfResClass = "${Gradle.codeNamespace}.util.resources" + customDirectory( + sourceSetName = "commonMain", + directoryProvider = androidResAsComposeResources(), + ) } 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 86% 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..c1b7463d3b 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 @@ -10,12 +10,13 @@ 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 class AndroidResources( private val context: Context, -) : ResourceHelper { +) : AndroidResourceHelper { override fun getString(@StringRes resourceId: Int): String { return context.getString(resourceId) @@ -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/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/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/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 57% rename from ui/resources/src/main/res/drawable/ic_delete.xml rename to ui/resources/src/androidMain/res/drawable/ic_delete.xml index 282594cdb1..b59d62ff65 100644 --- a/ui/resources/src/main/res/drawable/ic_delete.xml +++ b/ui/resources/src/androidMain/res/drawable/ic_delete.xml @@ -1,5 +1,5 @@ - + 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/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/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..72f1cc0070 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,22 +1,26 @@ 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 - +import org.jetbrains.compose.resources.StringResource + +/** + * 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 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( @@ -29,15 +33,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 { @@ -57,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( @@ -70,15 +68,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/src/main/java/com/getcode/util/resources/icons/SpeakerSlash.kt b/ui/resources/src/commonMain/kotlin/com/getcode/util/resources/icons/SpeakerSlash.kt similarity index 100% rename from ui/resources/src/main/java/com/getcode/util/resources/icons/SpeakerSlash.kt rename to ui/resources/src/commonMain/kotlin/com/getcode/util/resources/icons/SpeakerSlash.kt 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..17df59207e --- /dev/null +++ b/ui/resources/src/jvmMain/kotlin/com/getcode/util/resources/ComposeResourceHelper.kt @@ -0,0 +1,37 @@ +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 + +/** + * 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 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 = + 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..9a15779c2c --- /dev/null +++ b/ui/resources/src/jvmMain/kotlin/com/getcode/util/resources/ComposeResourceIds.kt @@ -0,0 +1,71 @@ +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. + * + * `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 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 } + + 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)) 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 85% 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..ed2adf0fc5 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 @@ -3,12 +3,13 @@ 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 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) @@ -17,6 +18,7 @@ class FakeResourceHelper(vararg rClasses: Class<*>) : ResourceHelper { } private val overrides = mutableMapOf() + private val keyOverrides = mutableMapOf() fun stub(resourceId: Int, value: String): FakeResourceHelper = apply { overrides[resourceId] = value @@ -30,6 +32,19 @@ class FakeResourceHelper(vararg rClasses: Class<*>) : ResourceHelper { 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 { + // 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) + } + 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 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 d3ff32c6b7..bc35d1646c 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, @@ -81,12 +79,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), + ) +}