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

Adding wasm-js target to precompose #297

Closed
wants to merge 4 commits into from
Closed
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
3 changes: 2 additions & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@ android.useAndroidX=true
android.enableJetifier=true
org.gradle.jvmargs=-Xmx4g
org.jetbrains.compose.experimental.jscanvas.enabled=true
org.jetbrains.compose.experimental.wasm.enabled=true
org.jetbrains.compose.experimental.macos.enabled=true
org.jetbrains.compose.experimental.uikit.enabled=true
kotlin.mpp.androidSourceSetLayoutVersion=2
android.defaults.buildfeatures.buildconfig=true
android.nonTransitiveRClass=false
android.nonFinalResIds=false
android.nonFinalResIds=false
4 changes: 2 additions & 2 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ junit = "4.13.2"
junitJupiterEngine = "5.10.1"
junitJupiterApi = "5.10.1"
kotlin = "1.9.21"
kotlinxCoroutinesCore = "1.7.3"
kotlinxCoroutinesCore = "1.8.0"
lifecycleRuntimeKtx = "2.6.2"
material = "1.5.0"
moleculeRuntime = "1.3.2"
savedstateKtx = "1.2.1"
spotless = "6.25.0"
jetbrainsComposePlugin = "1.5.11"
jetbrainsComposePlugin = "1.6.0"
skiko = "0.7.90"
koin = "3.5.0"
koin-compose = "1.1.2"
Expand Down
5 changes: 5 additions & 0 deletions precompose/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import org.jetbrains.kotlin.gradle.targets.js.dsl.ExperimentalWasmDsl
import java.util.Properties

plugins {
Expand All @@ -11,6 +12,7 @@ plugins {
group = "moe.tlaster"
version = rootProject.extra.get("precomposeVersion") as String

@OptIn(ExperimentalWasmDsl::class)
kotlin {
applyDefaultHierarchyTemplate()
macosArm64()
Expand All @@ -32,6 +34,9 @@ kotlin {
js(IR) {
browser()
}
wasmJs {
browser()
}
sourceSets {
val commonMain by getting {
dependencies {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
// TODO Migrate Material's Swipeable to Foundation's AnchoredDraggable APIs.
@file:Suppress("DEPRECATION")

package moe.tlaster.precompose.navigation

import androidx.compose.animation.AnimatedContent
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
@file:OptIn(ExperimentalMaterialApi::class)
// TODO Migrate Material's Swipeable to Foundation's AnchoredDraggable APIs.
@file:Suppress("DEPRECATION")

package moe.tlaster.precompose.navigation

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,31 +3,18 @@
package moe.tlaster.precompose

import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.createSkiaLayer
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.graphics.BlendMode
import androidx.compose.ui.input.pointer.PointerIcon
import androidx.compose.ui.InternalComposeUiApi
import androidx.compose.ui.native.ComposeLayer
import androidx.compose.ui.node.LayoutNode
import androidx.compose.ui.platform.AccessibilityController
import androidx.compose.ui.platform.DefaultInputModeManager
import androidx.compose.ui.platform.EmptyFocusManager
import androidx.compose.ui.platform.MacosTextInputService
import androidx.compose.ui.platform.Platform
import androidx.compose.ui.platform.TextToolbar
import androidx.compose.ui.platform.TextToolbarStatus
import androidx.compose.ui.platform.ViewConfiguration
import androidx.compose.ui.platform.PlatformContext
import androidx.compose.ui.platform.WindowInfoImpl
import androidx.compose.ui.semantics.SemanticsOwner
import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.dp
import kotlinx.cinterop.BetaInteropApi
import kotlinx.cinterop.ExperimentalForeignApi
import kotlinx.cinterop.ObjCAction
import kotlinx.cinterop.useContents
import org.jetbrains.skiko.SkiaLayer
import org.jetbrains.skiko.SkikoInput
import platform.AppKit.NSBackingStoreBuffered
import platform.AppKit.NSWindow
import platform.AppKit.NSWindowDelegateProtocol
Expand Down Expand Up @@ -62,53 +49,22 @@ internal class ComposeWindow(
)
}
private val macosTextInputService = MacosTextInputService()
private val platform: Platform = object : Platform {
override val windowInfo = WindowInfoImpl().apply {
// true is a better default if platform doesn't provide WindowInfo.
// otherwise UI will be rendered always in unfocused mode
// (hidden textfield cursor, gray titlebar, etc)
isWindowFocused = true
}

override var dialogScrimBlendMode by mutableStateOf(BlendMode.SrcOver)

override val inputModeManager = DefaultInputModeManager()
override val focusManager = EmptyFocusManager

override fun requestFocusForOwner() = false

override fun accessibilityController(owner: SemanticsOwner) = object : AccessibilityController {
override fun onSemanticsChange() = Unit
override fun onLayoutChange(layoutNode: LayoutNode) = Unit
override suspend fun syncLoop() = Unit
}
private val _windowInfo = WindowInfoImpl().apply {
isWindowFocused = true
}

override fun setPointerIcon(pointerIcon: PointerIcon) = Unit
override val viewConfiguration = object : ViewConfiguration {
override val longPressTimeoutMillis: Long = 500
override val doubleTapTimeoutMillis: Long = 300
override val doubleTapMinTimeMillis: Long = 40
override val touchSlop: Float get() = with(density) { 18.dp.toPx() }
}
override val textToolbar: TextToolbar = object : TextToolbar {
override fun hide() = Unit
override val status: TextToolbarStatus = TextToolbarStatus.Hidden
override fun showMenu(
rect: Rect,
onCopyRequested: (() -> Unit)?,
onPasteRequested: (() -> Unit)?,
onCutRequested: (() -> Unit)?,
onSelectAllRequested: (() -> Unit)?,
) = Unit
@OptIn(InternalComposeUiApi::class)
private val platformContext: PlatformContext =
object : PlatformContext by PlatformContext.Empty {
override val windowInfo get() = _windowInfo
override val textInputService get() = macosTextInputService
}

override val textInputService = macosTextInputService
}

val layer = ComposeLayer(
layer = createSkiaLayer(),
platform = platform,
input = macosTextInputService.input,
@OptIn(InternalComposeUiApi::class)
private val layer = ComposeLayer(
layer = SkiaLayer(),
platformContext = platformContext,
input = SkikoInput.Empty,
)
val title: String
get() = nsWindow.title()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package moe.tlaster.precompose

import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.remember
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.window.CanvasBasedWindow
import moe.tlaster.precompose.lifecycle.LifecycleOwner
import moe.tlaster.precompose.lifecycle.LifecycleRegistry
import moe.tlaster.precompose.lifecycle.LocalLifecycleOwner
import moe.tlaster.precompose.stateholder.LocalStateHolder
import moe.tlaster.precompose.stateholder.StateHolder
import moe.tlaster.precompose.ui.BackDispatcher
import moe.tlaster.precompose.ui.BackDispatcherOwner
import moe.tlaster.precompose.ui.LocalBackDispatcherOwner

/**
* Creates a new [CanvasBasedWindow] with the given [title] and [content].
*/
@OptIn(ExperimentalComposeUiApi::class)
fun preComposeWindow(
title: String = "Untitled",
canvasElementId: String = "ComposeTarget",
requestResize: (suspend () -> IntSize)? = null,
applyDefaultStyles: Boolean = true,
content: @Composable () -> Unit,
) {
CanvasBasedWindow(
title = title,
canvasElementId = canvasElementId,
requestResize = requestResize,
applyDefaultStyles = applyDefaultStyles,
content = {
PreComposeApp {
content.invoke()
}
},
)
}

@Composable
actual fun PreComposeApp(
content: @Composable () -> Unit,
) {
ProvidePreComposeCompositionLocals {
content.invoke()
}
}

@Composable
fun ProvidePreComposeCompositionLocals(
holder: PreComposeWindowHolder = remember {
PreComposeWindowHolder()
},
content: @Composable () -> Unit,
) {
CompositionLocalProvider(
LocalLifecycleOwner provides holder,
LocalStateHolder provides holder.stateHolder,
LocalBackDispatcherOwner provides holder,
) {
content.invoke()
}
}

class PreComposeWindowHolder : LifecycleOwner, BackDispatcherOwner {
override val lifecycle by lazy {
LifecycleRegistry()
}
val stateHolder by lazy {
StateHolder()
}
override val backDispatcher by lazy {
BackDispatcher()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package moe.tlaster.precompose.reflect

import kotlin.reflect.KClass

actual val <T : Any> KClass<T>.canonicalName: String?
// qualifiedName is unsupported [This reflection API is not supported yet in JavaScript]
get() = this.simpleName