Skip to content

Commit

Permalink
Merge branch 'trunk' into jw.ui-config-testing.2023-09-26
Browse files Browse the repository at this point in the history
  • Loading branch information
JakeWharton authored Sep 27, 2023
2 parents 586fd28 + 0bc7ce9 commit 128a35a
Show file tree
Hide file tree
Showing 7 changed files with 118 additions and 14 deletions.
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ kotlin = "1.9.10"
kotlinx-coroutines = "1.7.3"
kotlinx-serialization = "1.6.0"
androidx-activity = "1.7.2"
jbCompose = "1.5.1"
jbCompose = "1.5.2"
lint = "31.1.1"
zipline = "1.3.0"
coil = "2.4.0"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,8 @@ private class HTMLFlexContainer(

override fun margin(margin: Margin) {
value.style.apply {
marginLeft = margin.start.toPxString()
marginRight = margin.end.toPxString()
marginInlineStart = margin.start.toPxString()
marginInlineEnd = margin.end.toPxString()
marginTop = margin.top.toPxString()
marginBottom = margin.bottom.toPxString()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import app.cash.redwood.layout.api.Overflow
import app.cash.redwood.ui.Density
import app.cash.redwood.ui.Dp
import kotlin.math.roundToInt
import org.w3c.dom.css.CSSStyleDeclaration

internal fun Dp.toPxString(): String = with(Density(1.0)) {
"${toPx().roundToInt()}px"
Expand Down Expand Up @@ -56,3 +57,15 @@ internal fun Overflow.toCss() = when (this) {
Overflow.Scroll -> "scroll"
else -> throw AssertionError()
}

internal var CSSStyleDeclaration.marginInlineStart: String
get() = this.getPropertyValue("margin-inline-start")
set(value) {
this.setProperty("margin-inline-start", value)
}

internal var CSSStyleDeclaration.marginInlineEnd: String
get() = this.getPropertyValue("margin-inline-end")
set(value) {
this.setProperty("margin-inline-end", value)
}
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ private class RedwoodZiplineTreehouseUi(
)
}

override fun snapshotState(): StateSnapshot? {
override fun snapshotState(): StateSnapshot {
val savedState = saveableStateRegistry.performSave()
return savedState.toStateSnapshot()
}
Expand Down
7 changes: 7 additions & 0 deletions redwood-treehouse/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@ kotlin {
api libs.zipline
}
}

commonTest {
dependencies {
implementation libs.kotlin.test
implementation libs.assertk
}
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,28 @@ package app.cash.redwood.treehouse
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import kotlin.jvm.JvmInline
import kotlinx.serialization.Contextual
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.JsonArray
import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.JsonPrimitive
import kotlinx.serialization.json.booleanOrNull
import kotlinx.serialization.json.doubleOrNull
import kotlinx.serialization.json.intOrNull

@Serializable
public class StateSnapshot(
public val content: Map<String, List<JsonElement?>>,
public val content: Map<String, List<@Contextual Saveable>>,
) {
public fun toValuesMap(): Map<String, List<Any?>>? {
public fun toValuesMap(): Map<String, List<Any?>> {
return content.mapValues { entry ->
entry.value.map { mutableStateOf(it.fromJsonElement()) }
entry.value.map {
if (it.isMutableState) {
mutableStateOf(it.value)
} else {
it.value.fromJsonElement()
}
}
}
}

Expand All @@ -48,8 +56,8 @@ public fun Map<String, List<Any?>>.toStateSnapshot(): StateSnapshot = StateSnaps
mapValues { entry ->
entry.value.map { element ->
when (element) {
is MutableState<*> -> element.value.toJsonElement()
else -> error("unexpected type: $this")
is MutableState<*> -> Saveable(true, element.value.toJsonElement())
else -> Saveable(false, element.toJsonElement())
}
}
},
Expand All @@ -58,6 +66,7 @@ public fun Map<String, List<Any?>>.toStateSnapshot(): StateSnapshot = StateSnaps
private fun Any?.toJsonElement(): JsonElement {
return when (this) {
is String -> JsonPrimitive(this)
is Int -> JsonPrimitive(this)
is List<*> -> JsonArray(map { it.toJsonElement() })
is JsonElement -> this
else -> error("unexpected type: $this")
Expand All @@ -68,11 +77,9 @@ private fun Any?.toJsonElement(): JsonElement {
private fun JsonElement?.fromJsonElement(): Any {
return when (this) {
is JsonPrimitive -> {
if (this.isString) {
return content
}
return booleanOrNull ?: doubleOrNull ?: error("unexpected type: $this")
// TODO add other primitive types (double, float, long) when needed
if (this.isString) return content
return booleanOrNull ?: doubleOrNull ?: intOrNull ?: error("unexpected type: $this")
// TODO add other primitive types (float, long) when needed
}

is JsonArray -> listOf({ this.forEach { it.toJsonElement() } })
Expand All @@ -81,3 +88,8 @@ private fun JsonElement?.fromJsonElement(): Any {
else -> error("unexpected type: $this")
}
}

public data class Saveable(
val isMutableState: Boolean,
val value: JsonElement,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* Copyright (C) 2023 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.treehouse

import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import assertk.assertThat
import assertk.assertions.containsOnly
import assertk.assertions.isEqualTo
import kotlin.test.Test
import kotlin.test.assertTrue
import kotlinx.serialization.json.JsonPrimitive

class StateSnapshotTest {

@Test
fun toValueMapWorksAsExpected() {
val stateSnapshot = stateSnapshot()
val valuesMap = stateSnapshot.toValuesMap()
assertThat(valuesMap.entries.size).isEqualTo(4)
assertTrue(valuesMap["key1"]!![0] is MutableState<*>)
assertThat((valuesMap["key1"]!![0] as MutableState<*>).value).isEqualTo(JsonPrimitive(1))

assertThat(valuesMap["key2"]).isEqualTo(listOf(1.0))

assertThat(valuesMap["key3"]!![0] is MutableState<*>)
assertThat((valuesMap["key3"]!![0] as MutableState<*>).value).isEqualTo(JsonPrimitive("str"))

assertThat(valuesMap["key4"]).isEqualTo(listOf("str"))
}

@Test
fun toStateSnapshotWorksAsExpected() {
val storedStateSnapshot = storedStateSnapshot()
val stateSnapshot = storedStateSnapshot.toStateSnapshot()
assertThat(stateSnapshot.content).containsOnly(
"key1" to listOf(Saveable(true, JsonPrimitive(1))),
"key2" to listOf(Saveable(false, JsonPrimitive(1))),
"key3" to listOf(Saveable(true, JsonPrimitive("str"))),
"key4" to listOf(Saveable(false, JsonPrimitive("str"))),
)
}

private fun stateSnapshot() = StateSnapshot(
mapOf(
"key1" to listOf(Saveable(true, JsonPrimitive(1))),
"key2" to listOf(Saveable(false, JsonPrimitive(1))),
"key3" to listOf(Saveable(true, JsonPrimitive("str"))),
"key4" to listOf(Saveable(false, JsonPrimitive("str"))),
),
)

private fun storedStateSnapshot() = mapOf(
"key1" to listOf(mutableStateOf(1)),
"key2" to listOf(1),
"key3" to listOf(mutableStateOf("str")),
"key4" to listOf("str"),
)
}

0 comments on commit 128a35a

Please sign in to comment.