This commit is contained in:
Igor Escodro
2025-03-22 18:26:30 -04:00
parent f1249b8387
commit 05004d9181
45 changed files with 571 additions and 56 deletions

View File

@ -27,7 +27,7 @@ jobs:
distribution: 'adopt'
- name: Build with Gradle
run: ./gradlew clean build test -x shared:testDebugUnitTest -x shared:testReleaseUnitTest --parallel
run: ./gradlew clean build test -x shared:testDebugUnitTest -x shared:testReleaseUnitTest -x shared:desktopTest --parallel
env:
ALKAA_KEY_ALIAS: ${{ secrets.ALKAA_KEY_ALIAS }}
ALKAA_KEY_PASSWORD: ${{ secrets.ALKAA_KEY_PASSWORD }}
@ -49,3 +49,19 @@ jobs:
- name: Build with Xcode
run: xcodebuild -workspace ios-app/alkaa.xcodeproj/project.xcworkspace -configuration Debug -scheme alkaa -sdk iphonesimulator
build-desktop:
runs-on: macos-14
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Java
uses: actions/setup-java@v4
with:
java-version: '19'
distribution: 'temurin'
- name: Build with Gradle
run: ./gradlew desktop-app:createDistributable

View File

@ -90,6 +90,37 @@ jobs:
with:
name: test-results
path: |
/Users/runner/work/alkaa/alkaa/app/build/reports/androidTests/
/Users/runner/work/alkaa/alkaa/app/build/reports/tests/
./logcat.txt
retention-days: 7
desktop-test:
name: "Desktop"
runs-on: macos-latest
timeout-minutes: 80
strategy:
fail-fast: false
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Java
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'zulu'
- name: Run instrumented tests
run: ./gradlew :shared:desktopTest
- name: Save Test Results
uses: actions/upload-artifact@v4
if: ${{ always() }}
with:
name: test-results
path: |
/Users/runner/work/alkaa/alkaa/app/build/reports/tests/
./logcat.txt
retention-days: 7

View File

@ -0,0 +1,11 @@
package com.escodro.datastore
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences
internal class DesktopDataStore {
fun getDataStore(): DataStore<Preferences> = getDataStore(
producePath = { dataStoreFileName },
)
}

View File

@ -0,0 +1,11 @@
package com.escodro.datastore.di
import com.escodro.datastore.DesktopDataStore
import org.koin.dsl.module
/**
* Provides the platform-specific dependencies.
*/
internal actual val platformDataStoreModule = module {
single { DesktopDataStore().getDataStore() }
}

View File

@ -11,6 +11,8 @@ kotlin {
setFrameworkBaseName("local")
sourceSets {
val desktopMain by getting
commonMain.dependencies {
implementation(projects.libraries.coroutines)
implementation(projects.data.repository)
@ -37,6 +39,11 @@ kotlin {
implementation(kotlin("test"))
implementation(libs.kotlinx.coroutines.test)
}
desktopMain.dependencies {
implementation(libs.sqldelight.jvm)
implementation(libs.multiplatform.path)
}
}
}

View File

@ -14,7 +14,4 @@ internal class AndroidDriverFactory(
override fun createDriver(databaseName: String): SqlDriver =
AndroidSqliteDriver(AlkaaDatabase.Schema, context, databaseName)
override fun shouldPrepopulateDatabase(databaseName: String): Boolean =
!context.getDatabasePath(databaseName).exists()
}

View File

@ -47,7 +47,7 @@ internal class DatabaseProvider(
}
private fun prepopulateDatabase(database: AlkaaDatabase) {
if (driverFactory.shouldPrepopulateDatabase(DATABASE_NAME)) {
if (isDatabaseEmpty(database)) {
appCoroutineScope.launch {
for (category in getPrepopulateData()) {
database.categoryQueries.insert(
@ -59,6 +59,17 @@ internal class DatabaseProvider(
}
}
private fun isDatabaseEmpty(database: AlkaaDatabase): Boolean = with(database) {
categoryQueries
.selectAll()
.executeAsList()
.isEmpty() &&
taskQueries
.selectAllTasksWithDueDate()
.executeAsList()
.isEmpty()
}
private suspend fun getPrepopulateData(): List<Category> =
listOf(
Category(

View File

@ -15,13 +15,4 @@ internal interface DriverFactory {
* @return the [SqlDriver] to be used in the database
*/
fun createDriver(databaseName: String): SqlDriver
/**
* Checks if the database is opening for the first time and should be prepopulated.
*
* @param databaseName the database name
*
* @return true if the database should be prepopulated, false otherwise
*/
fun shouldPrepopulateDatabase(databaseName: String): Boolean
}

View File

@ -0,0 +1,14 @@
package com.escodro.local.di
import com.escodro.local.provider.DesktopDriverFactory
import com.escodro.local.provider.DriverFactory
import org.koin.core.module.dsl.singleOf
import org.koin.dsl.bind
import org.koin.dsl.module
/**
* Provides the platform-specific dependencies.
*/
internal actual val platformLocalModule = module {
singleOf(::DesktopDriverFactory) bind DriverFactory::class
}

View File

@ -0,0 +1,21 @@
package com.escodro.local.provider
import app.cash.sqldelight.db.SqlDriver
import app.cash.sqldelight.driver.jdbc.sqlite.JdbcSqliteDriver
import com.escodro.local.AlkaaDatabase
import me.sujanpoudel.utils.paths.appCacheDirectory
internal class DesktopDriverFactory : DriverFactory {
override fun createDriver(databaseName: String): SqlDriver {
val appCacheDirectory = appCacheDirectory(appId = PACKAGE_NAME, createDir = true)
val jdbcUrl = "jdbc:sqlite:$appCacheDirectory$databaseName"
return JdbcSqliteDriver(jdbcUrl).apply {
AlkaaDatabase.Schema.create(this)
}
}
private companion object {
private const val PACKAGE_NAME = "com.escodro.alkaa"
}
}

View File

@ -3,51 +3,11 @@ package com.escodro.local.provider
import app.cash.sqldelight.db.SqlDriver
import app.cash.sqldelight.driver.native.NativeSqliteDriver
import com.escodro.local.AlkaaDatabase
import kotlinx.cinterop.CPointer
import kotlinx.cinterop.DoubleVarOf
import kotlinx.cinterop.ExperimentalForeignApi
import kotlinx.cinterop.get
import platform.CoreGraphics.CGColorGetComponents
import platform.CoreGraphics.CGFloat
import platform.Foundation.NSFileManager
import platform.Foundation.NSLibraryDirectory
import platform.Foundation.NSURL
import platform.Foundation.NSUserDomainMask
import platform.UIKit.UIColor
internal class IosDriverFactory : DriverFactory {
override fun createDriver(databaseName: String): SqlDriver =
NativeSqliteDriver(AlkaaDatabase.Schema, databaseName)
override fun shouldPrepopulateDatabase(databaseName: String): Boolean =
!databaseExists(databaseName)
private fun databaseExists(databaseName: String): Boolean {
val fileManager = NSFileManager.defaultManager
val documentDirectory = NSFileManager
.defaultManager
.URLsForDirectory(
NSLibraryDirectory,
NSUserDomainMask,
).last() as NSURL
val file = documentDirectory
.URLByAppendingPathComponent("$DATABASE_PATH$databaseName")
?.path
return fileManager.fileExistsAtPath(file ?: "")
}
@Suppress("ktlint:standard:chain-method-continuation")
@OptIn(ExperimentalForeignApi::class)
private fun UIColor.toHex(): String {
val components: CPointer<DoubleVarOf<CGFloat>>? = CGColorGetComponents(CGColor)
val r = components?.get(0)?.times(255)?.toInt()?.toString(16)?.padStart(2, '0') ?: "00"
val g = components?.get(1)?.times(255)?.toInt()?.toString(16)?.padStart(2, '0') ?: "00"
val b = components?.get(2)?.times(255)?.toInt()?.toString(16)?.padStart(2, '0') ?: "00"
return "#$r$g$b"
}
private companion object {
private const val DATABASE_PATH = "Application Support/databases/"
}

1
desktop-app/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/build

View File

@ -0,0 +1,61 @@
import extension.setFrameworkBaseName
import org.jetbrains.compose.desktop.application.dsl.TargetFormat
plugins {
id("com.escodro.multiplatform")
alias(libs.plugins.compose)
alias(libs.plugins.compose.compiler)
}
kotlin {
setFrameworkBaseName("desktop-app")
sourceSets {
val desktopMain by getting
commonMain.dependencies {
implementation(projects.shared)
implementation(projects.resources)
implementation(projects.libraries.appstate)
implementation(compose.runtime)
implementation(compose.components.resources)
implementation(libs.kotlinx.coroutines.swing)
}
desktopMain.dependencies {
implementation(compose.desktop.currentOs)
}
}
}
compose.desktop {
application {
mainClass = "com.escodro.desktopapp.MainKt"
nativeDistributions {
targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb)
packageName = "com.escodro.alkaa"
packageVersion = libs.versions.version.name.get()
modules("java.sql")
macOS {
iconFile.set(project.file("src/desktopMain/resources/ic_launcher.icns"))
}
windows {
iconFile.set(project.file("src/desktopMain/resources/ic_launcher.ico"))
}
linux {
iconFile.set(project.file("src/desktopMain/resources/ic_launcher.png"))
}
}
jvmArgs(
"-DpackageVersion=${libs.versions.version.name.get()}"
)
}
}
android {
namespace = "desktop"
}

View File

@ -0,0 +1,22 @@
@file:Suppress("ktlint:standard:filename")
package com.escodro.desktopapp
import androidx.compose.ui.window.Window
import androidx.compose.ui.window.application
import com.escodro.resources.Res
import com.escodro.resources.content_app_name
import com.escodro.shared.AlkaaMultiplatformApp
import com.escodro.shared.di.initKoin
import org.jetbrains.compose.resources.stringResource
fun main() = application {
initKoin()
Window(
onCloseRequest = ::exitApplication,
title = stringResource(Res.string.content_app_name),
) {
AlkaaMultiplatformApp()
}
}

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 164 KiB

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -0,0 +1,17 @@
package com.escodro.alarm.di
import com.escodro.alarm.notification.DesktopNotificationScheduler
import com.escodro.alarm.notification.DesktopTaskNotification
import com.escodro.alarm.notification.NotificationScheduler
import com.escodro.alarm.notification.TaskNotification
import com.escodro.alarm.permission.DesktopAlarmPermission
import com.escodro.alarmapi.AlarmPermission
import org.koin.core.module.dsl.factoryOf
import org.koin.dsl.bind
import org.koin.dsl.module
actual val platformAlarmModule = module {
factoryOf(::DesktopNotificationScheduler) bind NotificationScheduler::class
factoryOf(::DesktopTaskNotification) bind TaskNotification::class
factoryOf(::DesktopAlarmPermission) bind AlarmPermission::class
}

View File

@ -0,0 +1,18 @@
package com.escodro.alarm.notification
import com.escodro.alarm.model.Task
internal class DesktopNotificationScheduler : NotificationScheduler {
override fun scheduleTaskNotification(task: Task, timeInMillis: Long) {
// TODO: Implement scheduleTaskNotification
}
override fun cancelTaskNotification(task: Task) {
// TODO: Implement cancelTaskNotification
}
override fun updateTaskNotification(task: Task) {
// TODO: Implement updateTaskNotification
}
}

View File

@ -0,0 +1,18 @@
package com.escodro.alarm.notification
import com.escodro.alarm.model.Task
internal class DesktopTaskNotification : TaskNotification {
override fun show(task: Task) {
// TODO: Implement show
}
override fun showRepeating(task: Task) {
// TODO: Implement showRepeating
}
override fun dismiss(taskId: Long) {
// TODO: Implement dismiss
}
}

View File

@ -0,0 +1,19 @@
package com.escodro.alarm.permission
import com.escodro.alarmapi.AlarmPermission
internal class DesktopAlarmPermission : AlarmPermission {
override fun hasExactAlarmPermission(): Boolean {
// TODO: Implement hasExactAlarmPermission
return true
}
override fun openExactAlarmPermissionScreen() {
// TODO: Implement openExactAlarmPermissionScreen
}
override fun openAppSettings() {
// TODO: Implement openAppSettings
}
}

View File

@ -10,6 +10,8 @@ kotlin {
setFrameworkBaseName("preference")
sourceSets {
val desktopMain by getting
commonMain.dependencies {
implementation(projects.domain)
implementation(projects.libraries.coroutines)
@ -36,6 +38,10 @@ kotlin {
iosMain.dependencies {
implementation(projects.features.tracker)
}
desktopMain.dependencies{
implementation(projects.features.tracker)
}
}
}
android {

View File

@ -0,0 +1,17 @@
package com.escodro.preference.di
import com.escodro.preference.provider.AppInfoProvider
import com.escodro.preference.provider.DesktopAppInfoProvider
import com.escodro.preference.provider.DesktopTrackerProvider
import com.escodro.preference.provider.TrackerProvider
import org.koin.core.module.dsl.factoryOf
import org.koin.dsl.bind
import org.koin.dsl.module
/**
* Provides the platform-specific dependencies.
*/
internal actual val platformPreferenceModule = module {
factoryOf(::DesktopAppInfoProvider) bind AppInfoProvider::class
factoryOf(::DesktopTrackerProvider) bind TrackerProvider::class
}

View File

@ -0,0 +1,9 @@
package com.escodro.preference.provider
internal class DesktopAppInfoProvider : AppInfoProvider {
override fun getAppVersion(): String {
val version = System.getProperty("packageVersion") ?: "0.0.0"
return "$version-alpha"
}
}

View File

@ -0,0 +1,12 @@
package com.escodro.preference.provider
import androidx.compose.runtime.Composable
import com.escodro.tracker.presentation.TrackerScreen
internal class DesktopTrackerProvider : TrackerProvider {
@Composable
override fun Content(onUpPress: () -> Unit) {
TrackerScreen(onUpPress = onUpPress)
}
}

View File

@ -0,0 +1,14 @@
package com.escodro.task.di
import com.escodro.task.provider.DesktopRelativeDateTimeProvider
import com.escodro.task.provider.RelativeDateTimeProvider
import org.koin.core.module.dsl.factoryOf
import org.koin.dsl.bind
import org.koin.dsl.module
/**
* Provides the platform-specific dependencies.
*/
actual val platformTaskModule = module {
factoryOf(::DesktopRelativeDateTimeProvider) bind RelativeDateTimeProvider::class
}

View File

@ -0,0 +1,23 @@
package com.escodro.task.extension
import kotlinx.datetime.LocalDateTime
import kotlinx.datetime.TimeZone
import kotlinx.datetime.toInstant
import java.text.DateFormat
import java.util.Calendar
import java.util.Locale
/**
* Formats the [LocalDateTime] to a user-friendly string.
*/
actual fun LocalDateTime.format(): String {
val dateFormat = DateFormat.getDateTimeInstance(
DateFormat.LONG,
DateFormat.SHORT,
Locale.getDefault(),
)
val calendar = Calendar.getInstance().apply {
timeInMillis = toInstant(TimeZone.currentSystemDefault()).toEpochMilliseconds()
}
return dateFormat.format(calendar.time)
}

View File

@ -0,0 +1,52 @@
package com.escodro.task.provider
import com.escodro.resources.Res
import com.escodro.resources.relative_date_time_days
import com.escodro.resources.relative_date_time_hours
import com.escodro.resources.relative_date_time_just_now
import com.escodro.resources.relative_date_time_minutes
import com.escodro.resources.relative_date_time_one_hour
import com.escodro.resources.relative_date_time_one_minute
import com.escodro.resources.relative_date_time_yesterday
import kotlinx.coroutines.runBlocking
import kotlinx.datetime.Clock
import kotlinx.datetime.LocalDateTime
import kotlinx.datetime.TimeZone
import kotlinx.datetime.toInstant
import org.jetbrains.compose.resources.getString
internal class DesktopRelativeDateTimeProvider : RelativeDateTimeProvider {
override fun toRelativeDateTimeString(dateTime: LocalDateTime): String {
val currentTime = Clock.System.now()
val targetInstant = dateTime.toInstant(TimeZone.currentSystemDefault())
val duration = currentTime - targetInstant
return runBlocking {
when {
duration.inWholeMinutes < 1 ->
getString(Res.string.relative_date_time_just_now)
duration.inWholeMinutes == 1L ->
getString(Res.string.relative_date_time_one_minute)
duration.inWholeMinutes < 60 ->
getString(Res.string.relative_date_time_minutes, duration.inWholeMinutes)
duration.inWholeHours == 1L ->
getString(Res.string.relative_date_time_one_hour)
duration.inWholeHours < 24 ->
getString(Res.string.relative_date_time_hours, duration.inWholeHours)
duration.inWholeDays == 1L ->
getString(Res.string.relative_date_time_yesterday)
duration.inWholeDays < 7 ->
getString(Res.string.relative_date_time_days, duration.inWholeDays)
else -> dateTime.toString()
}
}
}
}

View File

@ -54,6 +54,9 @@ sqldelight = "2.0.2"
moko = "0.16.1"
moko_permissions = "0.19.1"
# Multiplatform Utils
multiplatform_paths = "0.2.2"
# Test
test_junit = "4.13.2"
test_uiautomator = "2.3.0"
@ -81,6 +84,7 @@ stately = { module = "co.touchlab:stately-common", version.ref = "stately" }
# KotlinX
kotlinx_coroutines_core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx_coroutines" }
kotlinx_coroutines_test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "kotlinx_coroutines" }
kotlinx_coroutines_swing = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-swing", version.ref = "kotlinx_coroutines" }
kotlinx_serialization = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinx_serialization" }
kotlinx_collections_immutable = { module = "org.jetbrains.kotlinx:kotlinx-collections-immutable", version.ref = "kotlinx_collections_immutable" }
kotlinx_datetime = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version.ref = "kotlinx_datetime" }
@ -118,6 +122,7 @@ koin_compose_jb = { module = "io.insert-koin:koin-compose", version.ref = "koin_
# SQLDelight
sqldelight_driver = { module = "app.cash.sqldelight:android-driver", version.ref = "sqldelight" }
sqldelight_native = { module = "app.cash.sqldelight:native-driver", version.ref = "sqldelight" }
sqldelight_jvm = { module = "app.cash.sqldelight:sqlite-driver", version.ref = "sqldelight" }
sqldelight_coroutines = { module = "app.cash.sqldelight:coroutines-extensions", version.ref = "sqldelight" }
# Moko
@ -126,6 +131,9 @@ moko_mvvm_compose = { module = "dev.icerock.moko:mvvm-flow-compose", version.ref
moko_permissions_compose = { module = "dev.icerock.moko:permissions-compose", version.ref = "moko_permissions" }
moko_permissions_notifications = { module = "dev.icerock.moko:permissions-notifications", version.ref = "moko_permissions" }
## Multiplatform Utils
multiplatform_path = { module = "me.sujanpoudel.multiplatform.utils:multiplatform-paths", version.ref = "multiplatform_paths" }
# Test
test_junit = { module = "junit:junit", version.ref = "test_junit" }
test_uiautomator = { module = "androidx.test.uiautomator:uiautomator", version.ref = "test_uiautomator" }

View File

@ -0,0 +1,11 @@
package com.escodro.designsystem.di
import com.escodro.designsystem.provider.DesktopThemeProvider
import com.escodro.designsystem.provider.ThemeProvider
import org.koin.core.module.dsl.factoryOf
import org.koin.dsl.bind
import org.koin.dsl.module
actual val platformDesignSystemModule = module {
factoryOf(::DesktopThemeProvider) bind ThemeProvider::class
}

View File

@ -0,0 +1,14 @@
package com.escodro.designsystem.provider
import androidx.compose.material3.ColorScheme
internal class DesktopThemeProvider : ThemeProvider {
override val isDynamicColorSupported: Boolean
get() = false
override val dynamicDarkColorScheme: ColorScheme
get() = throw UnsupportedOperationException("Dynamic Theme not supported on Desktop")
override val dynamicLightColorScheme: ColorScheme
get() = throw UnsupportedOperationException("Dynamic Theme not supported on Desktop")
}

View File

@ -0,0 +1,15 @@
package com.escodro.di
import dev.icerock.moko.mvvm.viewmodel.ViewModel
import org.koin.core.definition.Definition
import org.koin.core.definition.KoinDefinition
import org.koin.core.module.Module
import org.koin.core.qualifier.Qualifier
/**
* Defines an Desktop [ViewModel] in the Koin module.
*/
actual inline fun <reified T : ViewModel> Module.viewModelDefinition(
qualifier: Qualifier?,
noinline definition: Definition<T>,
): KoinDefinition<T> = factory(qualifier = qualifier, definition = definition)

View File

@ -0,0 +1,3 @@
package com.escodro.parcelable
actual interface CommonParcelable

View File

@ -0,0 +1,10 @@
package com.escodro.permission.api
import androidx.compose.runtime.Composable
@Composable
actual fun BindPermissionEffect(
permissionController: PermissionController,
) {
// Do nothing - not required on Desktop
}

View File

@ -0,0 +1,15 @@
package com.escodro.permission.api
internal class DesktopPermissionController : PermissionController {
override val controller: Any = Any()
override suspend fun requestPermission(permission: Permission) {
// TODO: Implement requestPermission
}
override suspend fun isPermissionGranted(permission: Permission): Boolean {
// TODO: Implement isPermissionGranted
return false
}
}

View File

@ -0,0 +1,11 @@
package com.escodro.permission.di
import com.escodro.permission.api.DesktopPermissionController
import com.escodro.permission.api.PermissionController
import org.koin.core.module.dsl.singleOf
import org.koin.dsl.bind
import org.koin.dsl.module
actual val platformPermissionModule = module {
singleOf(::DesktopPermissionController) bind PermissionController::class
}

View File

@ -8,6 +8,8 @@ kotlin {
setFrameworkBaseName("test")
sourceSets {
val desktopMain by getting
commonMain.dependencies {
implementation(kotlin("test"))
api(libs.kotlinx.coroutines.test)
@ -16,6 +18,11 @@ kotlin {
androidMain.dependencies {
implementation(kotlin("test-junit"))
}
desktopMain.dependencies {
implementation(kotlin("test-junit"))
}
}
tasks.withType<Test> {

View File

@ -1,6 +1,5 @@
package extension
import org.gradle.kotlin.dsl.get
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
/**
@ -18,4 +17,5 @@ fun KotlinMultiplatformExtension.setFrameworkBaseName(name: String) {
baseName = name
}
}
jvm("desktop")
}

View File

@ -119,4 +119,13 @@
<string name="dialog_picker_confirm">Confirmar</string>
<string name="default_ok">OK</string>
<!-- Relative Date -->
<string name="relative_date_time_just_now">agora</string>
<string name="relative_date_time_one_minute">há 1 minuto</string>
<string name="relative_date_time_minutes">há %d minutos</string>
<string name="relative_date_time_one_hour">há 1 hora</string>
<string name="relative_date_time_hours">há %d horas</string>
<string name="relative_date_time_yesterday">ontem</string>
<string name="relative_date_time_days">há %d dias</string>
</resources>

View File

@ -123,4 +123,13 @@
<string name="default_ok">OK</string>
<!-- Relative Date -->
<string name="relative_date_time_just_now">just now</string>
<string name="relative_date_time_one_minute">1 minute ago</string>
<string name="relative_date_time_minutes">%d minutes ago</string>
<string name="relative_date_time_one_hour">1 hour ago</string>
<string name="relative_date_time_hours">%d hours ago</string>
<string name="relative_date_time_yesterday">yesterday</string>
<string name="relative_date_time_days">%d days ago</string>
</resources>

View File

@ -1,4 +1,5 @@
include(":app")
include(":desktop-app")
include(":features:alarm-api")
include(":features:alarm")
include(":features:task")

View File

@ -24,9 +24,12 @@ kotlin {
baseName = "shared"
isStatic = true
}
jvm("desktop")
}
sourceSets {
val desktopTest by getting
commonMain.dependencies {
implementation(projects.data.local)
implementation(projects.data.datastore)
@ -74,6 +77,11 @@ kotlin {
implementation(libs.koin.test)
implementation(libs.kotlinx.datetime)
}
desktopTest.dependencies {
implementation(compose.desktop.currentOs)
implementation(libs.kotlinx.coroutines.swing)
}
}
androidTarget {

View File

@ -0,0 +1,8 @@
package com.escodro.shared.di
import org.koin.core.module.Module
import org.koin.dsl.module
internal actual val platformSharedModule: Module = module {
// No specific modules for Desktop
}

View File

@ -0,0 +1,17 @@
package com.escodro.alkaa.test
actual class PlatformAnimation actual constructor() {
/**
* Disable the animations.
*/
actual fun disable() {
// Do nothing
}
/**
* Enable the animations.
*/
actual fun enable() {
// Do nothing
}
}

View File

@ -0,0 +1,10 @@
package com.escodro.alkaa.test
import org.koin.core.module.Module
import org.koin.dsl.module
/**
* Koin module to provide the platform dependencies.
*/
actual val platformModule: Module
get() = module { }