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 support to save non-mutable int in StateSnapshot #1508

Merged
merged 3 commits into from
Sep 26, 2023

Conversation

jingwei99
Copy link

@jingwei99 jingwei99 commented Sep 22, 2023

Tested locally, saving and restoring rememberSaveable of non-mutableState works as expected

@jingwei99
Copy link
Author

jingwei99 commented Sep 22, 2023

The focus of this draft is to support save & restore Int type (that is non-mutableState) across configuration change, that behavior is working as of changes from this PR

After ^, I copied changes from #1494 over to test restoring scroll position, but it's not working, @veyndan can you take a look 🙏?

Comment on lines 50 to 62
public companion object {
/**
* The default [Saver] implementation for [LazyListState].
*/
public val Saver: Saver<LazyListState, *> = Saver(
save = { it.firstVisibleItemIndex },
restore = {
LazyListState(
firstVisibleItemIndex = it,
)
}
)
}
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is copy-paste from #1494, and will be reverted once this PR goes from draft -> ready for review

@veyndan
Copy link
Contributor

veyndan commented Sep 25, 2023

What doesn't work with the PR? Is it that saving a plain Int doesn't work (i.e., ignoring scroll state restoration)? Or is it that this PR does what its supposed to, but when integrating with #1494, scroll state restoration doesn't work?

@jingwei99
Copy link
Author

when integrating with #1494, scroll state restoration doesn't work

this^

@veyndan
Copy link
Contributor

veyndan commented Sep 25, 2023

Cool, so if saving a plain Int works, shall we mark this PR as a non-draft and get it merged? Your PR isn't strictly related to scroll state restoration, as it is useful in its own right. We can tackle any scroll state restoration bugs in #1494.

@jingwei99
Copy link
Author

Cool, so if saving a plain Int works, shall we mark this PR as a non-draft and get it merged? Your PR isn't strictly related to scroll state restoration, as it is useful in its own right. We can tackle any scroll state restoration bugs in #1494.

yep, sounds good to me, will clean up this PR and put it up for review

@jingwei99 jingwei99 force-pushed the jingwei.support_int_in_StateSnapshot branch from 37a15b8 to e3ec6ce Compare September 25, 2023 23:49
@jingwei99 jingwei99 marked this pull request as ready for review September 25, 2023 23:51
@jingwei99 jingwei99 force-pushed the jingwei.support_int_in_StateSnapshot branch from e3ec6ce to c22dd46 Compare September 26, 2023 00:41
import kotlin.test.assertTrue
import kotlinx.serialization.json.JsonPrimitive

class StateSnapshotTest {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tests! Love it 😄

Comment on lines +32 to +41
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"))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could these test cases be simplified with the containsOnly function?

    assertThat(valuesMap).containsOnly(
        "key1" to listOf(mutableStateOf(JsonPrimitive(1)),
        …
    )

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

containsOnly errors out:

expected to contain only:<{"key1"=[MutableState(value=1)@916835004], "key2"=[1.0], "key3"=[MutableState(value="str")@2108297149], "key4"=["str"]}> but was:<{"key1"=[MutableState(value=1)@1112737073], "key2"=[1.0], "key3"=[MutableState(value="str")@1513867245], "key4"=["str"]}> elements not found:<{"key1"=[MutableState(value=1)@916835004], "key3"=[MutableState(value="str")@2108297149]}> extra elements found:<{"key1"=[MutableState(value=1)@1112737073], "key3"=[MutableState(value="str")@1513867245]}>

for the MutableState ones, containsOnly doesn't unwrap and compare the values (it compares the instances)

Comment on lines 48 to 51
assertThat(stateSnapshot.content["key1"]!![0]).isEqualTo(Saveable(true, JsonPrimitive(1)))
assertThat(stateSnapshot.content["key2"]!![0]).isEqualTo(Saveable(false, JsonPrimitive(1)))
assertThat(stateSnapshot.content["key3"]!![0]).isEqualTo(Saveable(true, JsonPrimitive("str")))
assertThat(stateSnapshot.content["key4"]!![0]).isEqualTo(Saveable(false, JsonPrimitive("str")))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same idea with these test cases

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this one works out

Comment on lines +37 to +41
if (it.isMutableState) {
mutableStateOf(it.value)
} else {
it.value.fromJsonElement()
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could remove the need for the Saveable wrapper class if we wrote an adapter to convert between MutableState and JsonElement. Perhaps it isn't worth the effort though, considering we'll change up this mechanism in #1384.

}
return booleanOrNull ?: doubleOrNull ?: error("unexpected type: $this")
// TODO add other primitive types (double, float, long) when needed
if (this.isString) { return content }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks a bit odd having the braces on a single line. Can we revert it, or do if (this.isString) return content?

@jingwei99 jingwei99 enabled auto-merge (squash) September 26, 2023 16:46
@jingwei99 jingwei99 merged commit 52fcbda into trunk Sep 26, 2023
8 checks passed
@jingwei99 jingwei99 deleted the jingwei.support_int_in_StateSnapshot branch September 26, 2023 18:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants