diff --git a/redwood-compose/api/redwood-compose.klib.api b/redwood-compose/api/redwood-compose.klib.api index 4d0dcfd0e5..d4cabe2c36 100644 --- a/redwood-compose/api/redwood-compose.klib.api +++ b/redwood-compose/api/redwood-compose.klib.api @@ -95,8 +95,20 @@ final object app.cash.redwood.compose/WindowAnimationFrameClock : androidx.compo final suspend fun <#A1: kotlin/Any?> withFrameNanos(kotlin/Function1): #A1 // app.cash.redwood.compose/WindowAnimationFrameClock.withFrameNanos|withFrameNanos(kotlin.Function1){0ยง}[0] } +// Targets: [js] +final val app.cash.redwood.compose/app_cash_redwood_compose_JsArray$stableprop // app.cash.redwood.compose/app_cash_redwood_compose_JsArray$stableprop|#static{}app_cash_redwood_compose_JsArray$stableprop[0] + +// Targets: [js] +final val app.cash.redwood.compose/app_cash_redwood_compose_JsSet$stableprop // app.cash.redwood.compose/app_cash_redwood_compose_JsSet$stableprop|#static{}app_cash_redwood_compose_JsSet$stableprop[0] + // Targets: [js] final val app.cash.redwood.compose/app_cash_redwood_compose_WindowAnimationFrameClock$stableprop // app.cash.redwood.compose/app_cash_redwood_compose_WindowAnimationFrameClock$stableprop|#static{}app_cash_redwood_compose_WindowAnimationFrameClock$stableprop[0] +// Targets: [js] +final fun app.cash.redwood.compose/app_cash_redwood_compose_JsArray$stableprop_getter(): kotlin/Int // app.cash.redwood.compose/app_cash_redwood_compose_JsArray$stableprop_getter|app_cash_redwood_compose_JsArray$stableprop_getter(){}[0] + +// Targets: [js] +final fun app.cash.redwood.compose/app_cash_redwood_compose_JsSet$stableprop_getter(): kotlin/Int // app.cash.redwood.compose/app_cash_redwood_compose_JsSet$stableprop_getter|app_cash_redwood_compose_JsSet$stableprop_getter(){}[0] + // Targets: [js] final fun app.cash.redwood.compose/app_cash_redwood_compose_WindowAnimationFrameClock$stableprop_getter(): kotlin/Int // app.cash.redwood.compose/app_cash_redwood_compose_WindowAnimationFrameClock$stableprop_getter|app_cash_redwood_compose_WindowAnimationFrameClock$stableprop_getter(){}[0] diff --git a/redwood-compose/build.gradle b/redwood-compose/build.gradle index e9cb1e4d90..ddcd1641e4 100644 --- a/redwood-compose/build.gradle +++ b/redwood-compose/build.gradle @@ -10,9 +10,18 @@ redwoodBuild { apply plugin: 'org.jetbrains.kotlin.plugin.compose' kotlin { + applyDefaultHierarchyTemplate { + it.group("common") { + it.group("nonJs") { + it.group("ios") {} + it.withAndroidTarget() + it.withJvm() + } + } + } + sourceSets { commonMain { - kotlin.srcDir(redwoodBuild.generateComposeHelpers(tasks, 'app.cash.redwood.compose')) dependencies { api libs.kotlinx.coroutines.core api projects.redwoodRuntime @@ -37,6 +46,12 @@ kotlin { implementation libs.androidx.core } } + nonJsMain { + kotlin.srcDir(redwoodBuild.generateComposeHelpers(tasks, 'app.cash.redwood.compose')) + dependencies { + implementation libs.jetbrains.compose.collection + } + } } } diff --git a/redwood-compose/src/commonMain/kotlin/app/cash/redwood/compose/PlatformList.kt b/redwood-compose/src/commonMain/kotlin/app/cash/redwood/compose/PlatformList.kt new file mode 100644 index 0000000000..abd24e45ca --- /dev/null +++ b/redwood-compose/src/commonMain/kotlin/app/cash/redwood/compose/PlatformList.kt @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2024 Square, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package app.cash.redwood.compose + +internal expect class PlatformList + +internal expect inline fun platformListOf(): PlatformList + +internal expect inline val PlatformList.size: Int + +internal expect inline operator fun PlatformList.get(index: Int): T + +internal expect inline fun PlatformList.add(index: Int, element: T) + +internal expect inline fun PlatformList.remove(index: Int, count: Int) + +internal expect fun PlatformList.move(from: Int, to: Int, count: Int) diff --git a/redwood-compose/src/commonMain/kotlin/app/cash/redwood/compose/PlatformSet.kt b/redwood-compose/src/commonMain/kotlin/app/cash/redwood/compose/PlatformSet.kt new file mode 100644 index 0000000000..dcd1572901 --- /dev/null +++ b/redwood-compose/src/commonMain/kotlin/app/cash/redwood/compose/PlatformSet.kt @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2024 Square, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package app.cash.redwood.compose + +internal expect class PlatformSet + +internal expect inline fun platformSetOf(): PlatformSet + +internal expect inline operator fun PlatformSet.plusAssign(element: T) + +internal expect inline fun PlatformSet.forEach(crossinline block: (T) -> Unit) + +internal expect inline fun PlatformSet.clear() diff --git a/redwood-compose/src/commonMain/kotlin/app/cash/redwood/compose/WidgetApplier.kt b/redwood-compose/src/commonMain/kotlin/app/cash/redwood/compose/WidgetApplier.kt index 493ef0f3a2..e11eed7286 100644 --- a/redwood-compose/src/commonMain/kotlin/app/cash/redwood/compose/WidgetApplier.kt +++ b/redwood-compose/src/commonMain/kotlin/app/cash/redwood/compose/WidgetApplier.kt @@ -58,7 +58,7 @@ internal class NodeApplier( ) : AbstractApplier>(ChildrenNode(root)), RedwoodApplier { private var closed = false - private val changedWidgets = LinkedHashSet() + private val changedWidgets = platformSetOf() override fun recordChanged(widget: Widget) { if (widget is ChangeListener) { @@ -69,10 +69,12 @@ internal class NodeApplier( override fun onEndChanges() { check(!closed) - for (changedWidget in changedWidgets) { - changedWidget.onEndChanges() + changedWidgets.let { changedWidgets -> + changedWidgets.forEach { changedWidget -> + changedWidget.onEndChanges() + } + changedWidgets.clear() } - changedWidgets.clear() onEndChanges.invoke() } @@ -191,7 +193,7 @@ internal class ChildrenNode private constructor( constructor(accessor: (Widget) -> Widget.Children) : this(accessor, null, null) constructor(children: Widget.Children) : this(null, null, children) - private val nodes = mutableListOf, W>>() + private val nodes = platformListOf, W>>() fun insert(index: Int, node: WidgetNode, W>) { nodes.let { nodes -> diff --git a/redwood-compose/src/jsMain/kotlin/app/cash/redwood/compose/PlatformList.kt b/redwood-compose/src/jsMain/kotlin/app/cash/redwood/compose/PlatformList.kt new file mode 100644 index 0000000000..ca70043ee4 --- /dev/null +++ b/redwood-compose/src/jsMain/kotlin/app/cash/redwood/compose/PlatformList.kt @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2024 Square, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +@file:Suppress("NOTHING_TO_INLINE") + +package app.cash.redwood.compose + +@JsName("Array") +internal external class JsArray { + val length: Int + fun splice(start: Int, deleteCount: Int): JsArray + fun splice(start: Int, deleteCount: Int, element: T) +} + +internal actual typealias PlatformList = JsArray + +internal actual inline fun platformListOf(): PlatformList { + return js("[]").unsafeCast>() +} + +internal actual inline val PlatformList.size: Int get() = length + +internal actual inline operator fun PlatformList.get(index: Int): T { + return asDynamic()[index] +} + +internal actual inline fun PlatformList.add(index: Int, element: T) { + splice(index, 0, element) +} + +internal actual inline fun PlatformList.remove(index: Int, count: Int) { + splice(index, count) +} + +internal actual fun PlatformList.move(from: Int, to: Int, count: Int) { + val dest = if (from > to) to else to - count + val removed = splice(from, count) + repeat(count) { offset -> + splice(dest + offset, 0, removed[offset]) + } +} diff --git a/redwood-compose/src/jsMain/kotlin/app/cash/redwood/compose/PlatformSet.kt b/redwood-compose/src/jsMain/kotlin/app/cash/redwood/compose/PlatformSet.kt new file mode 100644 index 0000000000..f841531495 --- /dev/null +++ b/redwood-compose/src/jsMain/kotlin/app/cash/redwood/compose/PlatformSet.kt @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2024 Square, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +@file:Suppress("NOTHING_TO_INLINE") + +package app.cash.redwood.compose + +@JsName("Set") +internal external class JsSet { + fun add(element: T) + fun clear() + fun forEach(block: (T) -> Unit) +} + +internal actual typealias PlatformSet = JsSet + +internal actual inline fun platformSetOf(): PlatformSet { + return JsSet() +} + +internal actual inline operator fun PlatformSet.plusAssign(element: T) { + add(element) +} + +internal actual inline fun PlatformSet.forEach(crossinline block: (T) -> Unit) { + forEach { block(it) } +} + +internal actual inline fun PlatformSet.clear() { + clear() +} diff --git a/redwood-compose/src/nonJsMain/kotlin/app/cash/redwood/compose/PlatformList.kt b/redwood-compose/src/nonJsMain/kotlin/app/cash/redwood/compose/PlatformList.kt new file mode 100644 index 0000000000..ea180cc417 --- /dev/null +++ b/redwood-compose/src/nonJsMain/kotlin/app/cash/redwood/compose/PlatformList.kt @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2024 Square, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +@file:Suppress("NOTHING_TO_INLINE") + +package app.cash.redwood.compose + +@Suppress("ACTUAL_TYPE_ALIAS_NOT_TO_CLASS") // On the JVM it aliases to java.util.ArrayList. +internal actual typealias PlatformList = ArrayList + +internal actual inline fun platformListOf(): PlatformList { + return ArrayList() +} + +internal actual inline val PlatformList.size: Int get() = size + +internal actual inline operator fun PlatformList.get(index: Int): T { + return get(index) +} + +internal actual inline fun PlatformList.add(index: Int, element: T) { + add(index, element) +} + +internal actual inline fun PlatformList.remove(index: Int, count: Int) { + // Force resolution to the generated extension. + (this as MutableList).remove(index, count) +} + +internal actual inline fun PlatformList.move(from: Int, to: Int, count: Int) { + // Force resolution to the generated extension. + (this as MutableList).move(from, to, count) +} diff --git a/redwood-compose/src/nonJsMain/kotlin/app/cash/redwood/compose/PlatformSet.kt b/redwood-compose/src/nonJsMain/kotlin/app/cash/redwood/compose/PlatformSet.kt new file mode 100644 index 0000000000..f87fc19554 --- /dev/null +++ b/redwood-compose/src/nonJsMain/kotlin/app/cash/redwood/compose/PlatformSet.kt @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2024 Square, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +@file:Suppress("NOTHING_TO_INLINE") + +package app.cash.redwood.compose + +import androidx.collection.MutableScatterSet +import androidx.collection.mutableScatterSetOf + +internal actual typealias PlatformSet = MutableScatterSet + +internal actual inline fun platformSetOf(): PlatformSet { + return mutableScatterSetOf() +} + +internal actual inline operator fun PlatformSet.plusAssign(element: T) { + plusAssign(element) +} + +internal actual inline fun PlatformSet.forEach(block: (T) -> Unit) { + forEach(block) +} + +internal actual inline fun PlatformSet.clear() { + clear() +}