Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add wasmJs target [WIP] #724

Draft
wants to merge 1 commit into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ kotlin.mpp.androidSourceSetLayoutVersion=2
org.jetbrains.compose.experimental.jscanvas.enabled=true
org.jetbrains.compose.experimental.uikit.enabled=true
org.jetbrains.compose.experimental.macos.enabled=true
org.jetbrains.compose.experimental.wasm.enabled=true

android.useAndroidX=true

Expand Down
10 changes: 5 additions & 5 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,17 @@ androidGradleVersion = "8.1.4"
androidSdkCommonVersion = "31.1.2"

# kotlinx
kotlinxSerializationVersion = "1.6.1"
kotlinxCoroutinesVersion = "1.6.4"
kotlinxSerializationVersion = "1.6.3"
kotlinxCoroutinesVersion = "1.8.1"

# android
androidAppCompatVersion = "1.6.1"

# android compose
composeUiVersion = "1.5.1"
composeUiVersion = "1.6.7"

# jetbrains compose
composeJetbrainsVersion = "1.6.0"
composeJetbrainsVersion = "1.6.10"

# jvm
apacheCommonsTextVersion = "1.10.0"
Expand All @@ -25,7 +25,7 @@ commonsCodecVersion = "1.15"
batikVersion = "1.17"

# moko
mokoGraphicsVersion = "0.9.0"
mokoGraphicsVersion = "0.10.0-SNAPSHOT"
mokoTestVersion = "0.6.1"
mokoMultiplatformPluginVersion = "0.14.2"

Expand Down
2 changes: 1 addition & 1 deletion gradle/moko.versions.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[versions]
resourcesVersion = "0.24.0-beta-5"
resourcesVersion = "0.24.0-beta-6-SNAPSHOT"

[libraries]
resources = { module = "dev.icerock.moko:resources", version.ref = "resourcesVersion" }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import org.gradle.api.tasks.testing.logging.TestExceptionFormat
import org.gradle.api.tasks.testing.logging.TestLogEvent
import org.jetbrains.kotlin.gradle.targets.js.dsl.ExperimentalWasmDsl

plugins {
id("com.android.library")
Expand All @@ -24,6 +25,11 @@ kotlin {
browser()
useCommonJs()
}
@OptIn(ExperimentalWasmDsl::class)
wasmJs {
browser()
useCommonJs()
}

sourceSets {
val commonMain by getting
Expand Down Expand Up @@ -66,10 +72,13 @@ kotlin {
macosArm64Test.dependsOn(this)
macosX64Test.dependsOn(this)
}

val jsTest by getting {
dependsOn(commonTest)
}
val wasmJsTest by getting {
dependsOn(commonTest)
}
}

jvmToolchain(11)
Expand Down
15 changes: 15 additions & 0 deletions resources-compose/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import org.jetbrains.kotlin.gradle.targets.js.dsl.ExperimentalWasmDsl

/*
* Copyright 2021 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
*/
Expand Down Expand Up @@ -34,6 +36,10 @@ kotlin {
js(IR) {
browser()
}
@OptIn(ExperimentalWasmDsl::class)
wasmJs {
browser()
}

sourceSets {
commonMain {
Expand All @@ -48,5 +54,14 @@ kotlin {
api(libs.composeUi)
}
}
val commonJsMain by creating {
dependsOn(commonMain.get())
}
val wasmJsMain by getting {
dependsOn(commonJsMain)
}
jsMain {
dependsOn(commonJsMain)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,4 @@ actual fun stringResource(resource: PluralsResource, quantity: Int, vararg args:
}

@Composable
private fun localized(stringDesc: StringDesc): String {
return produceState(initialValue = "", stringDesc) {
value = stringDesc.toLocalizedString()
}.value
}
internal expect fun localized(stringDesc: StringDesc): String
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/*
* Copyright 2024 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
*/

package dev.icerock.moko.resources.compose

import androidx.compose.runtime.Composable
import androidx.compose.runtime.produceState
import dev.icerock.moko.resources.desc.StringDesc

@Composable
internal actual fun localized(stringDesc: StringDesc): String {
return produceState(initialValue = "", stringDesc) {
value = stringDesc.toLocalizedString()
}.value
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
* Copyright 2023 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
*/

package dev.icerock.moko.resources.compose

import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.runtime.produceState
import dev.icerock.moko.resources.AssetResource

@Composable
actual fun AssetResource.readTextAsState(): State<String?> {
return produceState<String?>(null, this) {
value = getText()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* Copyright 2023 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
*/

package dev.icerock.moko.resources.compose

import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color
import dev.icerock.moko.resources.ColorResource

@Composable
actual fun colorResource(resource: ColorResource): Color {
// TODO https://github.com/icerockdev/moko-resources/issues/442
// web isSystemInDarkTheme not works now
val mokoColor: dev.icerock.moko.graphics.Color = if (isSystemInDarkTheme()) {
resource.darkColor
} else {
resource.lightColor
}

return Color(mokoColor.argb)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
* Copyright 2023 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
*/

package dev.icerock.moko.resources.compose

import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.runtime.produceState
import dev.icerock.moko.resources.FileResource

@Composable
actual fun FileResource.readTextAsState(): State<String?> {
return produceState<String?>(initialValue = null, this) {
value = getText()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Copyright 2023 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
*/

package dev.icerock.moko.resources.compose

import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.text.font.Font
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.platform.Font
import dev.icerock.moko.resources.FontResource
import dev.icerock.moko.resources.compose.internal.produceByteArray

@Composable
actual fun FontResource.asFont(
weight: FontWeight,
style: FontStyle,
): Font? {
val bytes: ByteArray? by produceByteArray(url = fileUrl)

return remember(fileUrl, bytes?.size ?: 0) {
bytes?.let { b ->
Font(
identity = fontFamily,
data = b,
weight = weight,
style = style,
)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Copyright 2023 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
*/

package dev.icerock.moko.resources.compose

import androidx.compose.runtime.Composable
import androidx.compose.runtime.InternalComposeApi
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.LocalSystemTheme
import androidx.compose.ui.SystemTheme
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.graphics.painter.BitmapPainter
import androidx.compose.ui.graphics.painter.ColorPainter
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.graphics.toComposeImageBitmap
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.Density
import dev.icerock.moko.resources.ImageResource
import dev.icerock.moko.resources.compose.internal.SVGPainter
import dev.icerock.moko.resources.compose.internal.produceByteArray
import org.jetbrains.skia.Data
import org.jetbrains.skia.Image
import org.jetbrains.skia.svg.SVGDOM

@OptIn(InternalComposeApi::class)
@Composable
actual fun painterResource(imageResource: ImageResource): Painter {
val fileUrl: String = if (LocalSystemTheme.current == SystemTheme.Dark) {
imageResource.darkFileUrl ?: imageResource.fileUrl
} else {
imageResource.fileUrl
}

val bytes: ByteArray? by produceByteArray(url = fileUrl)
val localBytes: ByteArray? = bytes
val density: Density = LocalDensity.current

return remember(localBytes, density, fileUrl) {
if (localBytes == null) {
return@remember ColorPainter(color = Color.Transparent)
}

if (fileUrl.endsWith(".svg", ignoreCase = true)) {
SVGPainter(SVGDOM(Data.makeFromBytes(localBytes)), density)
} else {
val skiaImage: Image = Image.makeFromEncoded(bytes = localBytes)
val imageBitmap: ImageBitmap = skiaImage.toComposeImageBitmap()

BitmapPainter(image = imageBitmap)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/*
* Copyright 2023 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
*/

package dev.icerock.moko.resources.compose

import androidx.compose.runtime.Composable
import androidx.compose.runtime.produceState
import dev.icerock.moko.resources.desc.StringDesc

@Composable
actual fun StringDesc.localized(): String {
return produceState("", this) {
value = toLocalizedString()
}.value
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/*
* Copyright 2024 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
*/

package dev.icerock.moko.resources.compose

import androidx.compose.runtime.Composable
import androidx.compose.runtime.produceState
import dev.icerock.moko.resources.desc.StringDesc

@Composable
internal actual fun localized(stringDesc: StringDesc): String {
return produceState(initialValue = "", stringDesc) {
value = stringDesc.toLocalizedString()
}.value
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright 2023 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
*/

@file:Suppress("Filename")

package dev.icerock.moko.resources.compose.internal

import androidx.compose.runtime.Composable
import androidx.compose.runtime.State
import androidx.compose.runtime.produceState
import kotlinx.browser.window
import kotlinx.coroutines.await
import org.khronos.webgl.ArrayBuffer
import org.khronos.webgl.Int8Array
import org.khronos.webgl.get
import org.w3c.fetch.Response

@Composable
internal fun produceByteArray(url: String): State<ByteArray?> {
return produceState<ByteArray?>(null, url) {
val response: Response = window.fetch(url).await()

if (response.ok.not()) {
println("can't load data from $url")
return@produceState
}

val buffer: ArrayBuffer = response.arrayBuffer().await()

value = Int8Array(buffer).toByteArray()
}
}


fun Int8Array.copyInto(inputOffset: Int, output: ByteArray, outputOffset: Int, length: Int) {
repeat(length) { index ->
output[outputOffset + index] = this[inputOffset + index]
}
}

fun Int8Array.toByteArray(): ByteArray = ByteArray(length).also { copyInto(0, it, 0, length) }
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,11 @@ internal class AssetGeneratorFactory(
JsAssetResourceGenerator(
resourcesGenerationDir = outputResourcesDir
)
},
createWasm = {
JsAssetResourceGenerator(
resourcesGenerationDir = outputResourcesDir
)
}
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ internal class ColorGeneratorFactory(
},
createJs = {
JsColorResourceGenerator()
},
createWasm = {
JsColorResourceGenerator()
}
)
}
Expand Down
Loading
Loading