diff --git a/buildSrc/src/main/kotlin/multiplatform-compose-setup.gradle.kts b/buildSrc/src/main/kotlin/multiplatform-compose-setup.gradle.kts index ca88a8c5..0d7d02c7 100644 --- a/buildSrc/src/main/kotlin/multiplatform-compose-setup.gradle.kts +++ b/buildSrc/src/main/kotlin/multiplatform-compose-setup.gradle.kts @@ -7,10 +7,6 @@ plugins { kotlin { jvm("desktop") android() - js { - browser() - nodejs() - } sourceSets { named("commonMain") { dependencies { @@ -32,13 +28,6 @@ kotlin { implementation(compose.desktop.common) } } - named("jsMain") { - dependencies { - implementation("org.jetbrains:kotlin-react:17.0.1-pre.148-kotlin-1.4.30") - implementation("org.jetbrains:kotlin-styled:1.0.0-pre.115-kotlin-1.4.10") - implementation("org.jetbrains:kotlin-react-dom:17.0.1-pre.148-kotlin-1.4.30") - } - } } tasks.withType { diff --git a/buildSrc/src/main/kotlin/multiplatform-setup-test.gradle.kts b/buildSrc/src/main/kotlin/multiplatform-setup-test.gradle.kts new file mode 100644 index 00000000..6f128d50 --- /dev/null +++ b/buildSrc/src/main/kotlin/multiplatform-setup-test.gradle.kts @@ -0,0 +1,42 @@ +plugins { + id("com.android.library") + id("kotlin-multiplatform") +} + +kotlin { + jvm("desktop") + android() + //ios() + js { + browser() + nodejs() + } + sourceSets { + named("commonTest") { + dependencies { + implementation(JetBrains.Kotlin.testCommon) + implementation(JetBrains.Kotlin.testAnnotationsCommon) + } + } + + named("androidTest") { + dependencies { + implementation(JetBrains.Kotlin.testJunit) + } + } + named("desktopTest") { + dependencies { + implementation(JetBrains.Kotlin.testJunit) + } + } + named("jsTest") { + dependencies { + + } + } + } + + tasks.withType { + kotlinOptions.jvmTarget = "1.8" + } +} diff --git a/buildSrc/src/main/kotlin/multiplatform-setup.gradle.kts b/buildSrc/src/main/kotlin/multiplatform-setup.gradle.kts index 6f128d50..7d71551c 100644 --- a/buildSrc/src/main/kotlin/multiplatform-setup.gradle.kts +++ b/buildSrc/src/main/kotlin/multiplatform-setup.gradle.kts @@ -1,37 +1,47 @@ +import gradle.kotlin.dsl.accessors._2e23d8fadf0ed92ae13e19db3d83f86d.compose +import gradle.kotlin.dsl.accessors._2e23d8fadf0ed92ae13e19db3d83f86d.kotlin +import gradle.kotlin.dsl.accessors._2e23d8fadf0ed92ae13e19db3d83f86d.sourceSets +import org.gradle.kotlin.dsl.withType + plugins { id("com.android.library") id("kotlin-multiplatform") + id("org.jetbrains.compose") } kotlin { jvm("desktop") android() - //ios() js { browser() nodejs() } sourceSets { - named("commonTest") { + named("commonMain") { dependencies { - implementation(JetBrains.Kotlin.testCommon) - implementation(JetBrains.Kotlin.testAnnotationsCommon) + implementation(compose.runtime) + implementation(compose.foundation) + implementation(compose.material) } } - named("androidTest") { + named("androidMain") { dependencies { - implementation(JetBrains.Kotlin.testJunit) + implementation("androidx.appcompat:appcompat:1.2.0") + implementation(Androidx.core) } } - named("desktopTest") { - dependencies { - implementation(JetBrains.Kotlin.testJunit) - } - } - named("jsTest") { - dependencies { + named("desktopMain") { + dependencies { + implementation(compose.desktop.common) + } + } + named("jsMain") { + dependencies { + implementation("org.jetbrains:kotlin-react:17.0.1-pre.148-kotlin-1.4.30") + implementation("org.jetbrains:kotlin-styled:1.0.0-pre.115-kotlin-1.4.10") + implementation("org.jetbrains:kotlin-react-dom:17.0.1-pre.148-kotlin-1.4.30") } } } diff --git a/common/compose/src/androidMain/kotlin/com/shabinder/common/uikit/AndroidImages.kt b/common/compose/src/androidMain/kotlin/com/shabinder/common/uikit/AndroidImages.kt index 420dcfa9..e1bf1338 100644 --- a/common/compose/src/androidMain/kotlin/com/shabinder/common/uikit/AndroidImages.kt +++ b/common/compose/src/androidMain/kotlin/com/shabinder/common/uikit/AndroidImages.kt @@ -3,16 +3,36 @@ package com.shabinder.common.uikit import androidx.annotation.DrawableRes +import androidx.compose.animation.Crossfade import androidx.compose.foundation.Image -import androidx.compose.runtime.Composable +import androidx.compose.runtime.* import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.ImageBitmap import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.vectorResource import androidx.compose.ui.text.font.Font import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.font.FontWeight import com.shabinder.common.database.R +import com.shabinder.common.di.Picture +import com.shabinder.common.di.dispatcherIO +import kotlinx.coroutines.withContext + +@Composable +actual fun ImageLoad(link:String, loader:suspend (String) -> Picture, desc: String, modifier:Modifier, placeholder: ImageVector) { + var pic by remember(link) { mutableStateOf(null) } + LaunchedEffect(link){ + withContext(dispatcherIO) { + pic = loader(link).image + } + } + + Crossfade(pic){ + if(it == null) Image(placeholder, desc, modifier,contentScale = ContentScale.Crop) else Image(it, desc, modifier,contentScale = ContentScale.Crop) + } +} actual fun montserratFont() = FontFamily( Font(R.font.montserrat_light, FontWeight.Light), diff --git a/common/compose/src/commonMain/kotlin/com/shabinder/common/uikit/ExpectImages.kt b/common/compose/src/commonMain/kotlin/com/shabinder/common/uikit/ExpectImages.kt index 537cbad1..375795be 100644 --- a/common/compose/src/commonMain/kotlin/com/shabinder/common/uikit/ExpectImages.kt +++ b/common/compose/src/commonMain/kotlin/com/shabinder/common/uikit/ExpectImages.kt @@ -1,28 +1,19 @@ @file:Suppress("FunctionName") package com.shabinder.common.uikit -import androidx.compose.animation.Crossfade -import androidx.compose.foundation.Image import androidx.compose.runtime.* import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.ImageBitmap import androidx.compose.ui.graphics.vector.ImageVector -import androidx.compose.ui.layout.ContentScale -import com.shabinder.common.di.dispatcherIO -import kotlinx.coroutines.withContext +import com.shabinder.common.di.Picture @Composable -fun ImageLoad(link:String,loader:suspend (String) ->ImageBitmap?, desc: String = "Album Art", modifier:Modifier = Modifier, placeholder:ImageVector = PlaceHolderImage()) { - var pic by remember(link) { mutableStateOf(null) } - LaunchedEffect(link){ - withContext(dispatcherIO) { - pic = loader(link) - } - } - Crossfade(pic){ - if(it == null) Image(placeholder, desc, modifier,contentScale = ContentScale.Crop) else Image(it, desc, modifier,contentScale = ContentScale.Crop) - } -} +expect fun ImageLoad( + link:String, + loader:suspend (String) ->Picture, + desc: String = "Album Art", + modifier:Modifier = Modifier, + placeholder:ImageVector = PlaceHolderImage() +) @Composable expect fun DownloadImageTick() diff --git a/common/compose/src/desktopMain/kotlin/com/shabinder/common/uikit/DesktopImages.kt b/common/compose/src/desktopMain/kotlin/com/shabinder/common/uikit/DesktopImages.kt index 289499f8..d5867bb6 100644 --- a/common/compose/src/desktopMain/kotlin/com/shabinder/common/uikit/DesktopImages.kt +++ b/common/compose/src/desktopMain/kotlin/com/shabinder/common/uikit/DesktopImages.kt @@ -1,14 +1,35 @@ @file:Suppress("FunctionName") package com.shabinder.common.uikit +import androidx.compose.animation.Crossfade import androidx.compose.foundation.Image -import androidx.compose.runtime.Composable +import androidx.compose.runtime.* import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.ImageBitmap import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.res.vectorXmlResource import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.platform.Font +import com.shabinder.common.di.Picture +import com.shabinder.common.di.dispatcherIO +import kotlinx.coroutines.withContext + + +@Composable +actual fun ImageLoad(link:String, loader:suspend (String) -> Picture, desc: String, modifier:Modifier, placeholder: ImageVector) { + var pic by remember(link) { mutableStateOf(null) } + LaunchedEffect(link){ + withContext(dispatcherIO) { + pic = loader(link).image + } + } + + Crossfade(pic){ + if(it == null) Image(placeholder, desc, modifier,contentScale = ContentScale.Crop) else Image(it, desc, modifier,contentScale = ContentScale.Crop) + } +} @Composable actual fun DownloadImageTick(){ diff --git a/common/database/build.gradle.kts b/common/database/build.gradle.kts index 51e15003..1930d825 100644 --- a/common/database/build.gradle.kts +++ b/common/database/build.gradle.kts @@ -1,5 +1,5 @@ plugins { - id("multiplatform-setup") + id("multiplatform-setup-test") id("android-setup") id("com.squareup.sqldelight") } diff --git a/common/dependency-injection/build.gradle.kts b/common/dependency-injection/build.gradle.kts index 78430ba3..f739c658 100644 --- a/common/dependency-injection/build.gradle.kts +++ b/common/dependency-injection/build.gradle.kts @@ -1,7 +1,7 @@ import org.jetbrains.compose.compose plugins { - id("multiplatform-compose-setup") + id("multiplatform-setup") id("android-setup") kotlin("plugin.serialization") } @@ -11,8 +11,8 @@ kotlin { commonMain { dependencies { implementation(compose.materialIconsExtended) - implementation(project(":common:data-models")) - implementation(project(":common:database")) + api(project(":common:data-models")) + api(project(":common:database")) implementation(project(":fuzzywuzzy:app")) implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.2") implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.1.0") @@ -47,5 +47,10 @@ kotlin { implementation(Ktor.slf4j) } } + jsMain { + dependencies { + implementation(project(":common:data-models")) + } + } } } diff --git a/common/dependency-injection/src/androidMain/kotlin/com/shabinder/common/di/AndroidDir.kt b/common/dependency-injection/src/androidMain/kotlin/com/shabinder/common/di/AndroidDir.kt index 7b8f3f82..4ac04057 100644 --- a/common/dependency-injection/src/androidMain/kotlin/com/shabinder/common/di/AndroidDir.kt +++ b/common/dependency-injection/src/androidMain/kotlin/com/shabinder/common/di/AndroidDir.kt @@ -136,9 +136,9 @@ actual class Dir actual constructor( listOf(path).toTypedArray(), null,null) } - actual suspend fun loadImage(url: String): ImageBitmap? { + actual suspend fun loadImage(url: String): Picture { val cachePath = imageCacheDir() + getNameURL(url) - return (loadCachedImage(cachePath) ?: freshImage(url))?.asImageBitmap() + return Picture(image = (loadCachedImage(cachePath) ?: freshImage(url))?.asImageBitmap()) } private fun loadCachedImage(cachePath: String): Bitmap? { diff --git a/common/dependency-injection/src/androidMain/kotlin/com/shabinder/common/di/AndroidPicture.kt b/common/dependency-injection/src/androidMain/kotlin/com/shabinder/common/di/AndroidPicture.kt new file mode 100644 index 00000000..d2b16f56 --- /dev/null +++ b/common/dependency-injection/src/androidMain/kotlin/com/shabinder/common/di/AndroidPicture.kt @@ -0,0 +1,7 @@ +package com.shabinder.common.di + +import androidx.compose.ui.graphics.ImageBitmap + +actual data class Picture ( + var image: ImageBitmap? +) \ No newline at end of file diff --git a/common/dependency-injection/src/commonMain/kotlin/com/shabinder/common/di/Dir.kt b/common/dependency-injection/src/commonMain/kotlin/com/shabinder/common/di/Dir.kt index 0662146f..c0d8e438 100644 --- a/common/dependency-injection/src/commonMain/kotlin/com/shabinder/common/di/Dir.kt +++ b/common/dependency-injection/src/commonMain/kotlin/com/shabinder/common/di/Dir.kt @@ -1,6 +1,5 @@ package com.shabinder.common.di -import androidx.compose.ui.graphics.ImageBitmap import co.touchlab.kermit.Kermit import com.shabinder.common.models.DownloadResult import com.shabinder.common.models.TrackDetails @@ -20,7 +19,7 @@ expect class Dir( fun imageCacheDir(): String fun createDirectory(dirPath:String) suspend fun cacheImage(image: Any,path: String) // in Android = ImageBitmap, Desktop = BufferedImage - suspend fun loadImage(url:String): ImageBitmap? + suspend fun loadImage(url:String): Picture suspend fun clearCache() suspend fun saveFileWithMetadata(mp3ByteArray: ByteArray, trackDetails: TrackDetails) fun addToLibrary(path:String) diff --git a/common/dependency-injection/src/commonMain/kotlin/com/shabinder/common/di/Picture.kt b/common/dependency-injection/src/commonMain/kotlin/com/shabinder/common/di/Picture.kt new file mode 100644 index 00000000..cee86ad5 --- /dev/null +++ b/common/dependency-injection/src/commonMain/kotlin/com/shabinder/common/di/Picture.kt @@ -0,0 +1,3 @@ +package com.shabinder.common.di + +expect class Picture \ No newline at end of file diff --git a/common/dependency-injection/src/desktopMain/kotlin/com/shabinder/common/di/DesktopDir.kt b/common/dependency-injection/src/desktopMain/kotlin/com/shabinder/common/di/DesktopDir.kt index 8a8fd7f9..5cdb70a2 100644 --- a/common/dependency-injection/src/desktopMain/kotlin/com/shabinder/common/di/DesktopDir.kt +++ b/common/dependency-injection/src/desktopMain/kotlin/com/shabinder/common/di/DesktopDir.kt @@ -18,6 +18,9 @@ import java.net.HttpURLConnection import java.net.URL import javax.imageio.ImageIO + + + actual class Dir actual constructor(private val logger: Kermit) { init { @@ -79,11 +82,12 @@ actual class Dir actual constructor(private val logger: Kermit) { .setId3v2TagsAndSaveFile(trackDetails) } actual fun addToLibrary(path:String){} - actual suspend fun loadImage(url: String): ImageBitmap? { + + actual suspend fun loadImage(url: String): Picture { val cachePath = imageCacheDir() + getNameURL(url) var picture: ImageBitmap? = loadCachedImage(cachePath) if (picture == null) picture = freshImage(url) - return picture + return Picture(image = picture) } private fun loadCachedImage(cachePath: String): ImageBitmap? { diff --git a/common/dependency-injection/src/desktopMain/kotlin/com/shabinder/common/di/DesktopPicture.kt b/common/dependency-injection/src/desktopMain/kotlin/com/shabinder/common/di/DesktopPicture.kt new file mode 100644 index 00000000..4113520c --- /dev/null +++ b/common/dependency-injection/src/desktopMain/kotlin/com/shabinder/common/di/DesktopPicture.kt @@ -0,0 +1,7 @@ +package com.shabinder.common.di + +import androidx.compose.ui.graphics.ImageBitmap + +actual data class Picture( + var image: ImageBitmap? +) \ No newline at end of file diff --git a/common/dependency-injection/src/jsMain/kotlin/com/shabinder/common/di/WebActual.kt b/common/dependency-injection/src/jsMain/kotlin/com/shabinder/common/di/WebActual.kt index 34de4243..cced663e 100644 --- a/common/dependency-injection/src/jsMain/kotlin/com/shabinder/common/di/WebActual.kt +++ b/common/dependency-injection/src/jsMain/kotlin/com/shabinder/common/di/WebActual.kt @@ -46,11 +46,11 @@ actual val isInternetAvailable:Boolean return result } -val DownloadProgressFlow: MutableSharedFlow> = MutableSharedFlow(1) +val DownloadProgressFlow: MutableSharedFlow> = MutableSharedFlow(1) actual suspend fun downloadTracks( list: List, - getYTIDBestMatch:suspend (String,TrackDetails)->String?, + getYTIDBestMatch:suspend (String, TrackDetails)->String?, saveFileWithMetaData:suspend (mp3ByteArray:ByteArray, trackDetails: TrackDetails) -> Unit ){ list.forEach { diff --git a/common/dependency-injection/src/jsMain/kotlin/com/shabinder/common/di/WebDir.kt b/common/dependency-injection/src/jsMain/kotlin/com/shabinder/common/di/WebDir.kt index f59c0f36..b2ea609b 100644 --- a/common/dependency-injection/src/jsMain/kotlin/com/shabinder/common/di/WebDir.kt +++ b/common/dependency-injection/src/jsMain/kotlin/com/shabinder/common/di/WebDir.kt @@ -2,9 +2,6 @@ package com.shabinder.common.di import co.touchlab.kermit.Kermit import com.shabinder.common.models.TrackDetails -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.GlobalScope -import kotlinx.coroutines.launch import org.w3c.dom.ImageBitmap actual class Dir actual constructor(private val logger: Kermit) { @@ -43,8 +40,8 @@ actual class Dir actual constructor(private val logger: Kermit) { actual fun addToLibrary(path:String){} - actual suspend fun loadImage(url: String): ImageBitmap? { - return null + actual suspend fun loadImage(url: String): Picture { + return Picture(url) } private fun loadCachedImage(cachePath: String): ImageBitmap? { diff --git a/common/dependency-injection/src/jsMain/kotlin/com/shabinder/common/di/WebPicture.kt b/common/dependency-injection/src/jsMain/kotlin/com/shabinder/common/di/WebPicture.kt new file mode 100644 index 00000000..a712d3f4 --- /dev/null +++ b/common/dependency-injection/src/jsMain/kotlin/com/shabinder/common/di/WebPicture.kt @@ -0,0 +1,5 @@ +package com.shabinder.common.di + +actual data class Picture( + var imageUrl:String +) \ No newline at end of file diff --git a/common/list/build.gradle.kts b/common/list/build.gradle.kts index f4fd1640..6a190f51 100644 --- a/common/list/build.gradle.kts +++ b/common/list/build.gradle.kts @@ -1,5 +1,5 @@ plugins { - id("multiplatform-compose-setup") + id("multiplatform-setup") id("android-setup") id("kotlin-parcelize") } diff --git a/common/list/src/commonMain/kotlin/com/shabinder/common/list/SpotiFlyerList.kt b/common/list/src/commonMain/kotlin/com/shabinder/common/list/SpotiFlyerList.kt index 37f350be..9e0a15dc 100644 --- a/common/list/src/commonMain/kotlin/com/shabinder/common/list/SpotiFlyerList.kt +++ b/common/list/src/commonMain/kotlin/com/shabinder/common/list/SpotiFlyerList.kt @@ -5,6 +5,7 @@ import com.arkivanov.decompose.ComponentContext import com.arkivanov.mvikotlin.core.store.StoreFactory import com.shabinder.common.di.Dir import com.shabinder.common.di.FetchPlatformQueryResult +import com.shabinder.common.di.Picture import com.shabinder.common.list.integration.SpotiFlyerListImpl import com.shabinder.common.models.Consumer import com.shabinder.common.models.DownloadStatus @@ -35,7 +36,7 @@ interface SpotiFlyerList { /* * Load Image from cache/Internet and cache it * */ - suspend fun loadImage(url:String): ImageBitmap? + suspend fun loadImage(url:String): Picture /* * Sync Tracks Statuses diff --git a/common/list/src/commonMain/kotlin/com/shabinder/common/list/integration/SpotiFlyerListImpl.kt b/common/list/src/commonMain/kotlin/com/shabinder/common/list/integration/SpotiFlyerListImpl.kt index c92a6d32..3acf73e3 100644 --- a/common/list/src/commonMain/kotlin/com/shabinder/common/list/integration/SpotiFlyerListImpl.kt +++ b/common/list/src/commonMain/kotlin/com/shabinder/common/list/integration/SpotiFlyerListImpl.kt @@ -3,6 +3,7 @@ package com.shabinder.common.list.integration import androidx.compose.ui.graphics.ImageBitmap import com.arkivanov.decompose.ComponentContext import com.arkivanov.mvikotlin.extensions.coroutines.states +import com.shabinder.common.di.Picture import com.shabinder.common.list.SpotiFlyerList import com.shabinder.common.list.SpotiFlyerList.Dependencies import com.shabinder.common.list.SpotiFlyerList.State @@ -46,5 +47,5 @@ internal class SpotiFlyerListImpl( store.accept(Intent.RefreshTracksStatuses) } - override suspend fun loadImage(url: String): ImageBitmap? = dir.loadImage(url) + override suspend fun loadImage(url: String): Picture = dir.loadImage(url) } \ No newline at end of file diff --git a/common/main/build.gradle.kts b/common/main/build.gradle.kts index 465077c5..1a4961ad 100644 --- a/common/main/build.gradle.kts +++ b/common/main/build.gradle.kts @@ -1,7 +1,7 @@ import org.jetbrains.compose.compose plugins { - id("multiplatform-compose-setup") + id("multiplatform-setup") id("android-setup") id("kotlin-parcelize") } diff --git a/common/main/src/commonMain/kotlin/com/shabinder/common/main/SpotiFlyerMain.kt b/common/main/src/commonMain/kotlin/com/shabinder/common/main/SpotiFlyerMain.kt index 5e873962..9d72e6ea 100644 --- a/common/main/src/commonMain/kotlin/com/shabinder/common/main/SpotiFlyerMain.kt +++ b/common/main/src/commonMain/kotlin/com/shabinder/common/main/SpotiFlyerMain.kt @@ -4,6 +4,7 @@ import androidx.compose.ui.graphics.ImageBitmap import com.arkivanov.decompose.ComponentContext import com.arkivanov.mvikotlin.core.store.StoreFactory import com.shabinder.common.di.Dir +import com.shabinder.common.di.Picture import com.shabinder.common.main.integration.SpotiFlyerMainImpl import com.shabinder.common.models.Consumer import com.shabinder.common.models.DownloadRecord @@ -33,7 +34,7 @@ interface SpotiFlyerMain { /* * Load Image from cache/Internet and cache it * */ - suspend fun loadImage(url:String): ImageBitmap? + suspend fun loadImage(url:String): Picture interface Dependencies { val mainOutput: Consumer diff --git a/common/main/src/commonMain/kotlin/com/shabinder/common/main/integration/SpotiFlyerMainImpl.kt b/common/main/src/commonMain/kotlin/com/shabinder/common/main/integration/SpotiFlyerMainImpl.kt index e961f1fb..680c0707 100644 --- a/common/main/src/commonMain/kotlin/com/shabinder/common/main/integration/SpotiFlyerMainImpl.kt +++ b/common/main/src/commonMain/kotlin/com/shabinder/common/main/integration/SpotiFlyerMainImpl.kt @@ -3,6 +3,7 @@ package com.shabinder.common.main.integration import androidx.compose.ui.graphics.ImageBitmap import com.arkivanov.decompose.ComponentContext import com.arkivanov.mvikotlin.extensions.coroutines.states +import com.shabinder.common.di.Picture import com.shabinder.common.di.isInternetAvailable import com.shabinder.common.di.showPopUpMessage import com.shabinder.common.main.SpotiFlyerMain @@ -40,5 +41,5 @@ internal class SpotiFlyerMainImpl( store.accept(Intent.SelectCategory(category)) } - override suspend fun loadImage(url: String): ImageBitmap? = dir.loadImage(url) + override suspend fun loadImage(url: String): Picture = dir.loadImage(url) } \ No newline at end of file diff --git a/common/root/build.gradle.kts b/common/root/build.gradle.kts index f67f9492..6539f6b7 100644 --- a/common/root/build.gradle.kts +++ b/common/root/build.gradle.kts @@ -1,7 +1,7 @@ import org.jetbrains.compose.compose plugins { - id("multiplatform-compose-setup") + id("multiplatform-setup") id("android-setup") id("kotlin-parcelize") }