Deprecate @Model
Relnote: “
@Model annotation is now deprecated. Use state and mutableStateOf as alternatives. This deprecation decision was reached after much careful discussion.
Justification
=============
Rationale includes but is not limited to:
- Reduces API surface area and concepts we need to teach
- More closely aligns with other comparable toolkits (Swift UI, React, Flutter)
- Reversible decision. We can always bring @Model back later.
- Removes corner-case usage and difficult to answer questions about configuring @Model as things we need to handle
- @Model data classes, equals, hashcode, etc.
- How do I have some properties “observed” and others not?
- How do I specify structural vs. referential equality to be used in observation?
- Reduces “magic” in the system. Would reduce the likelihood of someone assuming system was smarter than it is (ie, it knowing how to diff a list)
- Makes the granularity of observation more intuitive.
- Improves refactorability from variable -> property on class
- Potentially opens up possibilities to do hand-crafted State-specific optimizations
- More closely aligns with the rest of the ecosystem and reduces ambiguity towards immutable or us “embracing mutable state”
Migration Notes
===============
Almost all existing usages of @Model are fairly trivially transformed in one of two ways. The example below has a @Model class with two properties just for the sake of example, and has it being used in a composable.
```
@Model class Position(
var x: Int,
var y: Int
)
@Composable fun Example() {
var p = remember { Position(0, 0) }
PositionChanger(
position=p,
p.x = it }
p.y = it }
)
}
```
Alternative 1: Use State<OriginalClass> and create copies.
----------------------------------------------------------
This approach is made easier with Kotlin’s data classes. Essentially, make all previously `var` properties into `val` properties of a data class, and then use `state` instead of `remember`, and assign the state value to cloned copies of the original using the data class `copy(...)` convenience method.
It’s important to note that this approach only works when the only mutations to that class were done in the same scope that the `State` instance is created. If the class is internally mutating itself outside of the scope of usage, and you are relying on the observation of that, then the next approach is the one you will want to use.
```
data class Position(
val x: Int,
val y: Int
)
@Composable fun Example() {
var p by state { Position(0, 0) }
PositionChanger(
position=p,
p = p.copy(x=it) }
p = p.copy(y=it) }
)
}
```
Alternative 2: Use mutableStateOf and property delegates
--------------------------------------------------------
This approach is made easier with Kotlin’s property delegates and the `mutableStateOf` API which allows you to create MutableState instances outside of composition. Essentially, replace all `var` properties of the original class with `var` properties with `mutableStateOf` as their property delegate. This has the advantage that the usage of the class will not change at all, only the internal implementation of it. The behavior is not completely identical to the original example though, as each property is now observed/subscribed to individually, so the recompositions you see after this refactor could be more narrow (a good thing).
```
class Position(x: Int, y: Int) {
var x by mutableStateOf(x)
var y by mutableStateOf(y)
}
// source of Example is identical to original
@Composable fun Example() {
var p = remember { Position(0, 0) }
PositionChanger(
position=p,
p.x = it }
p.y = it }
)
}
```
“
Bug: 156546430
Bug: 152993135
Bug: 152050010
Bug: 148866188
Bug: 148422703
Bug: 148394427
Bug: 146362815
Bug: 146342522
Bug: 143413369
Bug: 135715219
Bug: 126418732
Bug: 147088098
Bug: 143263925
Bug: 139653744
Change-Id: I409e8c158841eae1dd548b33f1ec80bb609cba31
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/frames/FrameDiagnosticTests.kt b/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/frames/FrameDiagnosticTests.kt
index 74fb6fd..bd83012 100644
--- a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/frames/FrameDiagnosticTests.kt
+++ b/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/frames/FrameDiagnosticTests.kt
@@ -7,9 +7,9 @@
// Ensure the simple case does not report an error
fun testModel_Accept_Simple() = doTest(
"""
- import androidx.compose.Model
+ import androidx.compose.<!DEPRECATION!>Model<!>
- @Model
+ @<!DEPRECATION!>Model<!>
class MyModel {
var strValue = "default"
}
@@ -19,9 +19,9 @@
// Ensure @Model is not used on an open class
fun testModel_Report_Open() = doTest(
"""
- import androidx.compose.Model
+ import androidx.compose.<!DEPRECATION!>Model<!>
- @Model
+ @<!DEPRECATION!>Model<!>
open class <!OPEN_MODEL!>MyModel<!> {
var strValue = "default"
}
@@ -31,9 +31,9 @@
// Ensure @Model is not used on an abstract class
fun testModel_Report_Abstract() = doTest(
"""
- import androidx.compose.Model
+ import androidx.compose.<!DEPRECATION!>Model<!>
- @Model
+ @<!DEPRECATION!>Model<!>
abstract class <!OPEN_MODEL!>MyModel<!> {
var strValue = "default"
}
@@ -43,11 +43,11 @@
// Ensure @Model supports inheriting from a non-model class
fun testModel_Report_Inheritance() = doTest(
"""
- import androidx.compose.Model
+ import androidx.compose.<!DEPRECATION!>Model<!>
open class NonModel { }
- @Model
+ @<!DEPRECATION!>Model<!>
class MyModel : NonModel() {
var strValue = "default"
}
@@ -57,12 +57,12 @@
// Ensure errors are reported when the class is nested.
fun testModel_Report_Nested_Inheritance() = doTest(
"""
- import androidx.compose.Model
+ import androidx.compose.<!DEPRECATION!>Model<!>
open class NonModel { }
class Tests {
- @Model
+ @<!DEPRECATION!>Model<!>
open class <!OPEN_MODEL!>MyModel<!> : NonModel() {
var strValue = "default"
}
diff --git a/compose/compose-runtime/api/0.1.0-dev12.txt b/compose/compose-runtime/api/0.1.0-dev12.txt
index 4565a1e..f418b7f 100644
--- a/compose/compose-runtime/api/0.1.0-dev12.txt
+++ b/compose/compose-runtime/api/0.1.0-dev12.txt
@@ -227,7 +227,7 @@
method public static String? keySourceInfoOf(Object key);
}
- @androidx.compose.StableMarker @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets=AnnotationTarget.CLASS) public @interface Model {
+ @Deprecated @androidx.compose.StableMarker @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets=AnnotationTarget.CLASS) public @interface Model {
}
@androidx.compose.Stable public interface MutableState<T> extends androidx.compose.State<T> {
diff --git a/compose/compose-runtime/api/current.txt b/compose/compose-runtime/api/current.txt
index 4565a1e..f418b7f 100644
--- a/compose/compose-runtime/api/current.txt
+++ b/compose/compose-runtime/api/current.txt
@@ -227,7 +227,7 @@
method public static String? keySourceInfoOf(Object key);
}
- @androidx.compose.StableMarker @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets=AnnotationTarget.CLASS) public @interface Model {
+ @Deprecated @androidx.compose.StableMarker @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets=AnnotationTarget.CLASS) public @interface Model {
}
@androidx.compose.Stable public interface MutableState<T> extends androidx.compose.State<T> {
diff --git a/compose/compose-runtime/api/public_plus_experimental_0.1.0-dev12.txt b/compose/compose-runtime/api/public_plus_experimental_0.1.0-dev12.txt
index 4565a1e..f418b7f 100644
--- a/compose/compose-runtime/api/public_plus_experimental_0.1.0-dev12.txt
+++ b/compose/compose-runtime/api/public_plus_experimental_0.1.0-dev12.txt
@@ -227,7 +227,7 @@
method public static String? keySourceInfoOf(Object key);
}
- @androidx.compose.StableMarker @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets=AnnotationTarget.CLASS) public @interface Model {
+ @Deprecated @androidx.compose.StableMarker @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets=AnnotationTarget.CLASS) public @interface Model {
}
@androidx.compose.Stable public interface MutableState<T> extends androidx.compose.State<T> {
diff --git a/compose/compose-runtime/api/public_plus_experimental_current.txt b/compose/compose-runtime/api/public_plus_experimental_current.txt
index 4565a1e..f418b7f 100644
--- a/compose/compose-runtime/api/public_plus_experimental_current.txt
+++ b/compose/compose-runtime/api/public_plus_experimental_current.txt
@@ -227,7 +227,7 @@
method public static String? keySourceInfoOf(Object key);
}
- @androidx.compose.StableMarker @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets=AnnotationTarget.CLASS) public @interface Model {
+ @Deprecated @androidx.compose.StableMarker @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets=AnnotationTarget.CLASS) public @interface Model {
}
@androidx.compose.Stable public interface MutableState<T> extends androidx.compose.State<T> {
diff --git a/compose/compose-runtime/api/restricted_0.1.0-dev12.txt b/compose/compose-runtime/api/restricted_0.1.0-dev12.txt
index 4565a1e..f418b7f 100644
--- a/compose/compose-runtime/api/restricted_0.1.0-dev12.txt
+++ b/compose/compose-runtime/api/restricted_0.1.0-dev12.txt
@@ -227,7 +227,7 @@
method public static String? keySourceInfoOf(Object key);
}
- @androidx.compose.StableMarker @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets=AnnotationTarget.CLASS) public @interface Model {
+ @Deprecated @androidx.compose.StableMarker @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets=AnnotationTarget.CLASS) public @interface Model {
}
@androidx.compose.Stable public interface MutableState<T> extends androidx.compose.State<T> {
diff --git a/compose/compose-runtime/api/restricted_current.txt b/compose/compose-runtime/api/restricted_current.txt
index 4565a1e..f418b7f 100644
--- a/compose/compose-runtime/api/restricted_current.txt
+++ b/compose/compose-runtime/api/restricted_current.txt
@@ -227,7 +227,7 @@
method public static String? keySourceInfoOf(Object key);
}
- @androidx.compose.StableMarker @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets=AnnotationTarget.CLASS) public @interface Model {
+ @Deprecated @androidx.compose.StableMarker @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(AnnotationRetention.BINARY) @kotlin.annotation.Target(allowedTargets=AnnotationTarget.CLASS) public @interface Model {
}
@androidx.compose.Stable public interface MutableState<T> extends androidx.compose.State<T> {
diff --git a/compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/benchmark/ComposeBenchmark.kt b/compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/benchmark/ComposeBenchmark.kt
index 983800a9..0e32118 100644
--- a/compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/benchmark/ComposeBenchmark.kt
+++ b/compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/benchmark/ComposeBenchmark.kt
@@ -17,9 +17,11 @@
package androidx.compose.benchmark
import androidx.compose.Composable
-import androidx.compose.Model
import androidx.compose.Observe
import androidx.compose.benchmark.realworld4.RealWorld4_FancyWidget_000
+import androidx.compose.getValue
+import androidx.compose.mutableStateOf
+import androidx.compose.setValue
import androidx.test.annotation.UiThreadTest
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.LargeTest
@@ -163,8 +165,8 @@
private val yellowModifier = Modifier.fillMaxSize() + yellowBackground
private val defaultModifier = yellowModifier
-@Model
-class ColorModel(private var color: Color = Color.Black) {
+class ColorModel(color: Color = Color.Black) {
+ private var color: Color by mutableStateOf(color)
fun toggle() {
color = if (color == Color.Black) Color.Red else Color.Black
}
diff --git a/compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/benchmark/SiblingBenchmark.kt b/compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/benchmark/SiblingBenchmark.kt
index b7e9c71..f269745 100644
--- a/compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/benchmark/SiblingBenchmark.kt
+++ b/compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/benchmark/SiblingBenchmark.kt
@@ -16,12 +16,12 @@
package androidx.compose.benchmark
-import androidx.compose.Model
import androidx.compose.benchmark.siblings.IdentityType
import androidx.compose.benchmark.siblings.Item
import androidx.compose.benchmark.siblings.ReorderType
import androidx.compose.benchmark.siblings.SiblingManagement
import androidx.compose.benchmark.siblings.update
+import androidx.compose.mutableStateOf
import androidx.test.annotation.UiThreadTest
import androidx.test.filters.LargeTest
import androidx.test.rule.ActivityTestRule
@@ -83,7 +83,7 @@
@Test
fun runBenchmark() {
activityRule.runUiRunnable {
- val items = ValueHolder((0..count).map { Item(it) })
+ val items = mutableStateOf((0..count).map { Item(it) })
val random = Random(0)
measureRecompose {
compose {
@@ -105,5 +105,3 @@
}
})
}
-
-@Model private class ValueHolder<T>(var value: T)
\ No newline at end of file
diff --git a/compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/benchmark/dbmonster/DbMonster.kt b/compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/benchmark/dbmonster/DbMonster.kt
index 1f58e03..f9cf4d6 100644
--- a/compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/benchmark/dbmonster/DbMonster.kt
+++ b/compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/benchmark/dbmonster/DbMonster.kt
@@ -17,7 +17,9 @@
package androidx.compose.benchmark.dbmonster
import androidx.compose.Composable
-import androidx.compose.Model
+import androidx.compose.getValue
+import androidx.compose.mutableStateOf
+import androidx.compose.setValue
import androidx.ui.core.Modifier
import androidx.ui.foundation.Text
import androidx.ui.layout.Column
@@ -36,11 +38,13 @@
private const val MAX_ELAPSED = 15.0
-@Model
-class Query(var query: String, var elapsed: Double)
+class Query(query: String, elapsed: Double) {
+ var query by mutableStateOf(query)
+ var elapsed by mutableStateOf(elapsed)
+}
-@Model
-class Database(var name: String, random: Random) {
+class Database(name: String, random: Random) {
+ var name: String by mutableStateOf(name)
private val myRandom = random
var queries: List<Query> = (1..10).map {
Query(randomQuery(random), random.nextDouble() * MAX_ELAPSED)
diff --git a/compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/benchmark/realworld4/RealWorld4_DataModels.kt b/compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/benchmark/realworld4/RealWorld4_DataModels.kt
index ee6f3a5..d00aadb 100644
--- a/compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/benchmark/realworld4/RealWorld4_DataModels.kt
+++ b/compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/benchmark/realworld4/RealWorld4_DataModels.kt
@@ -21,161 +21,168 @@
* large scale (eg. gmail-sized application).
*/
-import androidx.compose.Model
+import androidx.compose.getValue
+import androidx.compose.mutableStateOf
+import androidx.compose.setValue
import androidx.ui.graphics.Color
-@Model
class RealWorld4_DataModel_09() {
- var f0: Color =
+ var f0: Color by mutableStateOf(
Color(red = random.nextInt(255), green = random.nextInt(255), blue = random.nextInt(255))
- var f1: String = smallRange().map { createSomeText() }.joinToString("\n")
- var f2: RealWorld4_DataModel_10 = RealWorld4_DataModel_10()
- var f3: Boolean = random.nextBoolean()
- var f4: Color =
+ )
+ var f1: String by mutableStateOf(smallRange().map { createSomeText() }.joinToString("\n"))
+ var f2: RealWorld4_DataModel_10 by mutableStateOf(RealWorld4_DataModel_10())
+ var f3: Boolean by mutableStateOf(random.nextBoolean())
+ var f4: Color by mutableStateOf(
Color(red = random.nextInt(255), green = random.nextInt(255), blue = random.nextInt(255))
- var f5: RealWorld4_DataModel_10 = RealWorld4_DataModel_10()
+ )
+ var f5: RealWorld4_DataModel_10 by mutableStateOf(RealWorld4_DataModel_10())
}
-@Model
class RealWorld4_DataModel_06() {
- var f0: Boolean = random.nextBoolean()
- var f1: Int = random.nextInt()
- var f2: Boolean = random.nextBoolean()
- var f3: Color =
+ var f0: Boolean by mutableStateOf(random.nextBoolean())
+ var f1: Int by mutableStateOf(random.nextInt())
+ var f2: Boolean by mutableStateOf(random.nextBoolean())
+ var f3: Color by mutableStateOf(
Color(red = random.nextInt(255), green = random.nextInt(255), blue = random.nextInt(255))
- var f4: Color =
+ )
+ var f4: Color by mutableStateOf(
Color(red = random.nextInt(255), green = random.nextInt(255), blue = random.nextInt(255))
- var f5: Int = random.nextInt()
- var f6: Int = random.nextInt()
- var f7: Color =
+ )
+ var f5: Int by mutableStateOf(random.nextInt())
+ var f6: Int by mutableStateOf(random.nextInt())
+ var f7: Color by mutableStateOf(
Color(red = random.nextInt(255), green = random.nextInt(255), blue = random.nextInt(255))
- var f8: Color =
+ )
+ var f8: Color by mutableStateOf(
Color(red = random.nextInt(255), green = random.nextInt(255), blue = random.nextInt(255))
- var f9: Int = random.nextInt()
- var f10: RealWorld4_DataModel_07 = RealWorld4_DataModel_07()
- var f11: RealWorld4_DataModel_07 = RealWorld4_DataModel_07()
+ )
+ var f9: Int by mutableStateOf(random.nextInt())
+ var f10: RealWorld4_DataModel_07 by mutableStateOf(RealWorld4_DataModel_07())
+ var f11: RealWorld4_DataModel_07 by mutableStateOf(RealWorld4_DataModel_07())
}
-@Model
class RealWorld4_DataModel_08() {
- var f0: RealWorld4_DataModel_09 = RealWorld4_DataModel_09()
- var f1: String = smallRange().map { createSomeText() }.joinToString("\n")
- var f2: Color =
+ var f0: RealWorld4_DataModel_09 by mutableStateOf(RealWorld4_DataModel_09())
+ var f1: String by mutableStateOf(smallRange().map { createSomeText() }.joinToString("\n"))
+ var f2: Color by mutableStateOf(
Color(red = random.nextInt(255), green = random.nextInt(255), blue = random.nextInt(255))
- var f3: Int = random.nextInt()
- var f4: RealWorld4_DataModel_09 = RealWorld4_DataModel_09()
- var f5: String = smallRange().map { createSomeText() }.joinToString("\n")
+ )
+ var f3: Int by mutableStateOf(random.nextInt())
+ var f4: RealWorld4_DataModel_09 by mutableStateOf(RealWorld4_DataModel_09())
+ var f5: String by mutableStateOf(smallRange().map { createSomeText() }.joinToString("\n"))
}
-@Model
class RealWorld4_DataModel_10() {
- var f0: Boolean = random.nextBoolean()
- var f1: Int = random.nextInt()
- var f2: Boolean = random.nextBoolean()
- var f3: Boolean = random.nextBoolean()
+ var f0: Boolean by mutableStateOf(random.nextBoolean())
+ var f1: Int by mutableStateOf(random.nextInt())
+ var f2: Boolean by mutableStateOf(random.nextBoolean())
+ var f3: Boolean by mutableStateOf(random.nextBoolean())
}
-@Model
class RealWorld4_DataModel_07() {
- var f0: String = smallRange().map { createSomeText() }.joinToString("\n")
- var f1: String = smallRange().map { createSomeText() }.joinToString("\n")
- var f2: Int = random.nextInt()
- var f3: Int = random.nextInt()
- var f4: String = smallRange().map { createSomeText() }.joinToString("\n")
- var f5: RealWorld4_DataModel_08 = RealWorld4_DataModel_08()
- var f6: String = smallRange().map { createSomeText() }.joinToString("\n")
- var f7: RealWorld4_DataModel_08 = RealWorld4_DataModel_08()
+ var f0: String by mutableStateOf(smallRange().map { createSomeText() }.joinToString("\n"))
+ var f1: String by mutableStateOf(smallRange().map { createSomeText() }.joinToString("\n"))
+ var f2: Int by mutableStateOf(random.nextInt())
+ var f3: Int by mutableStateOf(random.nextInt())
+ var f4: String by mutableStateOf(smallRange().map { createSomeText() }.joinToString("\n"))
+ var f5: RealWorld4_DataModel_08 by mutableStateOf(RealWorld4_DataModel_08())
+ var f6: String by mutableStateOf(smallRange().map { createSomeText() }.joinToString("\n"))
+ var f7: RealWorld4_DataModel_08 by mutableStateOf(RealWorld4_DataModel_08())
}
-@Model
class RealWorld4_DataModel_05() {
- var f0: RealWorld4_DataModel_06 = RealWorld4_DataModel_06()
- var f1: Color =
+ var f0: RealWorld4_DataModel_06 by mutableStateOf(RealWorld4_DataModel_06())
+ var f1: Color by mutableStateOf(
Color(red = random.nextInt(255), green = random.nextInt(255), blue = random.nextInt(255))
- var f2: Color =
+ )
+ var f2: Color by mutableStateOf(
Color(red = random.nextInt(255), green = random.nextInt(255), blue = random.nextInt(255))
- var f3: Color =
+ )
+ var f3: Color by mutableStateOf(
Color(red = random.nextInt(255), green = random.nextInt(255), blue = random.nextInt(255))
- var f4: Boolean = random.nextBoolean()
- var f5: Boolean = random.nextBoolean()
- var f6: RealWorld4_DataModel_06 = RealWorld4_DataModel_06()
- var f7: String = smallRange().map { createSomeText() }.joinToString("\n")
+ )
+ var f4: Boolean by mutableStateOf(random.nextBoolean())
+ var f5: Boolean by mutableStateOf(random.nextBoolean())
+ var f6: RealWorld4_DataModel_06 by mutableStateOf(RealWorld4_DataModel_06())
+ var f7: String by mutableStateOf(smallRange().map { createSomeText() }.joinToString("\n"))
}
-@Model
class RealWorld4_DataModel_00() {
- var f0: String = smallRange().map { createSomeText() }.joinToString("\n")
- var f1: Int = random.nextInt()
- var f2: RealWorld4_DataModel_01 = RealWorld4_DataModel_01()
- var f3: RealWorld4_DataModel_01 = RealWorld4_DataModel_01()
- var f4: Int = random.nextInt()
- var f5: Color =
+ var f0: String by mutableStateOf(smallRange().map { createSomeText() }.joinToString("\n"))
+ var f1: Int by mutableStateOf(random.nextInt())
+ var f2: RealWorld4_DataModel_01 by mutableStateOf(RealWorld4_DataModel_01())
+ var f3: RealWorld4_DataModel_01 by mutableStateOf(RealWorld4_DataModel_01())
+ var f4: Int by mutableStateOf(random.nextInt())
+ var f5: Color by mutableStateOf(
Color(red = random.nextInt(255), green = random.nextInt(255), blue = random.nextInt(255))
- var f6: String = smallRange().map { createSomeText() }.joinToString("\n")
- var f7: Int = random.nextInt()
- var f8: Int = random.nextInt()
+ )
+ var f6: String by mutableStateOf(smallRange().map { createSomeText() }.joinToString("\n"))
+ var f7: Int by mutableStateOf(random.nextInt())
+ var f8: Int by mutableStateOf(random.nextInt())
}
-@Model
class RealWorld4_DataModel_02() {
- var f0: Int = random.nextInt()
- var f1: RealWorld4_DataModel_03 = RealWorld4_DataModel_03()
- var f2: Boolean = random.nextBoolean()
- var f3: Color =
+ var f0: Int by mutableStateOf(random.nextInt())
+ var f1: RealWorld4_DataModel_03 by mutableStateOf(RealWorld4_DataModel_03())
+ var f2: Boolean by mutableStateOf(random.nextBoolean())
+ var f3: Color by mutableStateOf(
Color(red = random.nextInt(255), green = random.nextInt(255), blue = random.nextInt(255))
- var f4: Int = random.nextInt()
- var f5: Int = random.nextInt()
- var f6: RealWorld4_DataModel_03 = RealWorld4_DataModel_03()
- var f7: Int = random.nextInt()
- var f8: Int = random.nextInt()
- var f9: Color =
+ )
+ var f4: Int by mutableStateOf(random.nextInt())
+ var f5: Int by mutableStateOf(random.nextInt())
+ var f6: RealWorld4_DataModel_03 by mutableStateOf(RealWorld4_DataModel_03())
+ var f7: Int by mutableStateOf(random.nextInt())
+ var f8: Int by mutableStateOf(random.nextInt())
+ var f9: Color by mutableStateOf(
Color(red = random.nextInt(255), green = random.nextInt(255), blue = random.nextInt(255))
+ )
}
-@Model
class RealWorld4_DataModel_04() {
- var f0: RealWorld4_DataModel_05 = RealWorld4_DataModel_05()
- var f1_modified: Boolean = random.nextBoolean()
- var f2: RealWorld4_DataModel_05 = RealWorld4_DataModel_05()
- var f3: String = smallRange().map { createSomeText() }.joinToString("\n")
- var f4: Boolean = random.nextBoolean()
- var f5: Boolean = random.nextBoolean()
- var f6: Boolean = random.nextBoolean()
- var f7: Boolean = random.nextBoolean()
- var f8: String = smallRange().map { createSomeText() }.joinToString("\n")
- var f9: String = smallRange().map { createSomeText() }.joinToString("\n")
- var f10: String = smallRange().map { createSomeText() }.joinToString("\n")
+ var f0: RealWorld4_DataModel_05 by mutableStateOf(RealWorld4_DataModel_05())
+ var f1_modified: Boolean by mutableStateOf(random.nextBoolean())
+ var f2: RealWorld4_DataModel_05 by mutableStateOf(RealWorld4_DataModel_05())
+ var f3: String by mutableStateOf(smallRange().map { createSomeText() }.joinToString("\n"))
+ var f4: Boolean by mutableStateOf(random.nextBoolean())
+ var f5: Boolean by mutableStateOf(random.nextBoolean())
+ var f6: Boolean by mutableStateOf(random.nextBoolean())
+ var f7: Boolean by mutableStateOf(random.nextBoolean())
+ var f8: String by mutableStateOf(smallRange().map { createSomeText() }.joinToString("\n"))
+ var f9: String by mutableStateOf(smallRange().map { createSomeText() }.joinToString("\n"))
+ var f10: String by mutableStateOf(smallRange().map { createSomeText() }.joinToString("\n"))
}
-@Model
class RealWorld4_DataModel_01() {
- var f0: RealWorld4_DataModel_02 = RealWorld4_DataModel_02()
- var f1: Int = random.nextInt()
- var f2: Color =
+ var f0: RealWorld4_DataModel_02 by mutableStateOf(RealWorld4_DataModel_02())
+ var f1: Int by mutableStateOf(random.nextInt())
+ var f2: Color by mutableStateOf(
Color(red = random.nextInt(255), green = random.nextInt(255), blue = random.nextInt(255))
- var f3: Boolean = random.nextBoolean()
- var f4: Boolean = random.nextBoolean()
- var f5: Int = random.nextInt()
- var f6: Boolean = random.nextBoolean()
- var f7: String = smallRange().map { createSomeText() }.joinToString("\n")
- var f8: String = smallRange().map { createSomeText() }.joinToString("\n")
- var f9: Boolean = random.nextBoolean()
- var f10: Int = random.nextInt()
- var f11: Int = random.nextInt()
- var f12: Boolean = random.nextBoolean()
- var f13: Boolean = random.nextBoolean()
- var f14: Int = random.nextInt()
- var f15: RealWorld4_DataModel_02 = RealWorld4_DataModel_02()
+ )
+ var f3: Boolean by mutableStateOf(random.nextBoolean())
+ var f4: Boolean by mutableStateOf(random.nextBoolean())
+ var f5: Int by mutableStateOf(random.nextInt())
+ var f6: Boolean by mutableStateOf(random.nextBoolean())
+ var f7: String by mutableStateOf(smallRange().map { createSomeText() }.joinToString("\n"))
+ var f8: String by mutableStateOf(smallRange().map { createSomeText() }.joinToString("\n"))
+ var f9: Boolean by mutableStateOf(random.nextBoolean())
+ var f10: Int by mutableStateOf(random.nextInt())
+ var f11: Int by mutableStateOf(random.nextInt())
+ var f12: Boolean by mutableStateOf(random.nextBoolean())
+ var f13: Boolean by mutableStateOf(random.nextBoolean())
+ var f14: Int by mutableStateOf(random.nextInt())
+ var f15: RealWorld4_DataModel_02 by mutableStateOf(RealWorld4_DataModel_02())
}
-@Model
class RealWorld4_DataModel_03() {
- var f0: Color =
+ var f0: Color by mutableStateOf(
Color(red = random.nextInt(255), green = random.nextInt(255), blue = random.nextInt(255))
- var f1: RealWorld4_DataModel_04 = RealWorld4_DataModel_04()
- var f2: Int = random.nextInt()
- var f3: Color =
+ )
+ var f1: RealWorld4_DataModel_04 by mutableStateOf(RealWorld4_DataModel_04())
+ var f2: Int by mutableStateOf(random.nextInt())
+ var f3: Color by mutableStateOf(
Color(red = random.nextInt(255), green = random.nextInt(255), blue = random.nextInt(255))
- var f4: Boolean = random.nextBoolean()
- var f5: RealWorld4_DataModel_04 = RealWorld4_DataModel_04()
+ )
+ var f4: Boolean by mutableStateOf(random.nextBoolean())
+ var f5: RealWorld4_DataModel_04 by mutableStateOf(RealWorld4_DataModel_04())
}
diff --git a/compose/compose-runtime/samples/src/main/java/androidx/compose/samples/ModelSamples.kt b/compose/compose-runtime/samples/src/main/java/androidx/compose/samples/ModelSamples.kt
index 6f2599f..23fda24 100644
--- a/compose/compose-runtime/samples/src/main/java/androidx/compose/samples/ModelSamples.kt
+++ b/compose/compose-runtime/samples/src/main/java/androidx/compose/samples/ModelSamples.kt
@@ -18,8 +18,9 @@
import androidx.annotation.Sampled
import androidx.compose.Composable
-import androidx.compose.Model
-import androidx.compose.remember
+import androidx.compose.getValue
+import androidx.compose.setValue
+import androidx.compose.state
import androidx.ui.foundation.TextField
import androidx.ui.foundation.Text
import androidx.ui.material.Button
@@ -27,28 +28,23 @@
@Composable
@Sampled
-fun modelSample() {
- @Model
- class LoginState(var username: TextFieldValue, var password: TextFieldValue) {
- fun login() = Api.login(username.text, password.text)
- }
-
+fun stateSample() {
@Composable
fun LoginScreen() {
- val model = remember { LoginState(
- TextFieldValue("user"),
- TextFieldValue("pass")
- ) }
+ var username by state { TextFieldValue("user") }
+ var password by state { TextFieldValue("pass") }
+
+ fun login() = Api.login(username.text, password.text)
TextField(
- value = model.username,
- model.username = it }
+ value = username,
+ username = it }
)
TextField(
- value = model.password,
- model.password = it }
+ value = password,
+ password = it }
)
- Button( model.login() }) {
+ Button( login() }) {
Text("Login")
}
}
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/FrameManager.kt b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/FrameManager.kt
index ffe80b0..34de9e8 100644
--- a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/FrameManager.kt
+++ b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/FrameManager.kt
@@ -153,7 +153,7 @@
* Records that [value], or one of its fields, read while composing and its values were
* used during composition.
*
- * This is the underlying mechanism used by [Model] objects to allow composition to observe
+ * This is the underlying mechanism used by [State] objects to allow composition to observe
* changes made to model objects.
*/
internal fun recordRead(value: Any) = readObserver(value)
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Model.kt b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Model.kt
index 0c167b3..91e2463 100644
--- a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Model.kt
+++ b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Model.kt
@@ -26,19 +26,16 @@
*
* [Model] also adds an MVCC transaction system to ensure data consistency across threads.
*
- * Consider the following example:
- *
- * @sample androidx.compose.samples.modelSample
- *
- * In this example, `LoginScreen` is recomposed every time the username and password of the
- * model updates, keeping the UI synchronized with the model. There is no need to call
- * [androidx.compose.Recompose] manually.
- *
* @see FrameManager
* @see Observe
+ * @see state
+ * @see mutableStateOf
+ * @see State
+ * @see MutableState
*/
@MustBeDocumented
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.BINARY)
@StableMarker
+@Deprecated("Use mutableStateOf and associated State<T> variants")
annotation class Model
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/MutableState.kt b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/MutableState.kt
index bd0cc63..68e41a1 100644
--- a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/MutableState.kt
+++ b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/MutableState.kt
@@ -29,14 +29,19 @@
* A composable used to introduce a state value of type [T] into a composition.
*
* This is useful when you have a value that you would like to locally mutate and use in the context of a composition. Since
- * the returned [MutableState] instance implements [Model], changes to the [MutableState.value] property will be automatically tracked in
- * composition and schedule a recompose.
+ * the returned [MutableState] instance implements [Framed], changes to the [MutableState.value]
+ * property will be automatically tracked in composition and schedule a recompose.
*
* The [MutableState] class can be used several different ways. For example, the most basic way is to store the returned state
* value into a local immutable variable, and then set the [MutableState.value] property on it.
*
* @sample androidx.compose.samples.SimpleStateSample
*
+ * @sample androidx.compose.samples.stateSample
+ *
+ * In this example, `LoginScreen` is recomposed every time the username and password of the
+ * model updates, keeping the UI synchronized with the state.
+ *
* Additionally, you can destructure the [MutableState] object into a value and a "setter" function.
*
* @sample androidx.compose.samples.DestructuredStateSample
@@ -49,7 +54,7 @@
* [MutableState.value] is written to. If this returns true, then no recomposition will be
* scheduled. See [ReferentiallyEqual] and [StructurallyEqual] for simple implementations.
* @param init A factory function to create the initial value of this state
- * @return An [Model] instance of [MutableState] that wraps the value.
+ * @return An instance of [MutableState] that wraps the value.
*
* @see [stateFor]
* @see [remember]
@@ -66,12 +71,13 @@
* This is useful when you have a value that you would like to locally mutate and use in the context of a composition, and its
* value is scoped to another value and you want it to be reset every time the other value changes.
*
- * The returned [MutableState] instance implements [Model] so that changes to the [MutableState.value] property will be automatically tracked in
- * composition and schedule a recompose.
+ * The returned [MutableState] instance implements [Framed] so that changes to the
+ * [MutableState.value] property will be automatically tracked in composition and schedule a
+ * recompose.
*
* @param v1 An input value that, when changed, will cause the state to reset and [init] to be rerun
* @param init A factory function to create the initial value of this state
- * @return An [Model] instance of [MutableState] that wraps the value.
+ * @return An instance of [MutableState] that wraps the value.
*
* @sample androidx.compose.samples.observeUserSample
*
@@ -88,13 +94,14 @@
* This is useful when you have a value that you would like to locally mutate and use in the context of a composition, and its
* value is scoped to another value and you want it to be reset every time the other value changes.
*
- * The returned [MutableState] instance implements [Model] so that changes to the [MutableState.value] property will be automatically tracked in
- * composition and schedule a recompose.
+ * The returned [MutableState] instance implements [Framed] such that changes to the
+ * [MutableState.value] property will be automatically tracked in composition and schedule a
+ * recompose.
*
* @param v1 An input value that, when changed, will cause the state to reset and [init] to be rerun
* @param v2 An input value that, when changed, will cause the state to reset and [init] to be rerun
* @param init A factory function to create the initial value of this state
- * @return An [Model] instance of [MutableState] that wraps the value.
+ * @return An instance of [MutableState] that wraps the value.
*
* @see [state]
* @see [remember]
@@ -112,12 +119,13 @@
* This is useful when you have a value that you would like to locally mutate and use in the context of a composition, and its
* value is scoped to another value and you want it to be reset every time the other value changes.
*
- * The returned [MutableState] instance implements [Model] so that changes to the [MutableState.value] property will be automatically tracked in
- * composition and schedule a recompose.
+ * The returned [MutableState] instance implements [Framed] so that changes to the
+ * [MutableState.value] property will be automatically tracked in composition and schedule a
+ * recompose.
*
* @param inputs A set of inputs such that, when any of them have changed, will cause the state to reset and [init] to be rerun
* @param init A factory function to create the initial value of this state
- * @return An [Model] instance of [MutableState] that wraps the value.
+ * @return An instance of [MutableState] that wraps the value.
*
* @see [state]
* @see [remember]
@@ -129,15 +137,25 @@
/**
* Return a new [MutableState] initialized with the passed in [value]
*
+ * The MutableState class is a single value holder whose reads and writes are observed by
+ * Compose. Additionally, writes to it are transacted as part of the [Framed] transaction system.
+ * During composition, you will likely want to use the `state` and `stateFor` composables instead
+ * of this factory function.
+ *
* @param value the initial value for the [MutableState]
* @param areEquivalent a callback to compare the previous and new instance of [value] when
* it is written to. If this returns true, then no recomposition will be scheduled. See
* [ReferentiallyEqual] and [StructurallyEqual] for simple implementations.
+ *
+ * @see state
+ * @see stateFor
+ * @see State
+ * @see MutableState
*/
fun <T> mutableStateOf(
value: T,
areEquivalent: (old: T, new: T) -> Boolean = ReferentiallyEqual
-): MutableState<T> = ModelMutableState(value, areEquivalent)
+): MutableState<T> = FramedMutableState(value, areEquivalent)
/**
* Simple comparison callback using referential `===` equality
@@ -208,18 +226,20 @@
}
/**
- * The State class is an @Model class meant to wrap around a single value. It is used in the
+ * The ModelMutableState class is a single value holder whose reads and writes are observed by
+ * Compose.
+ * Additionally, writes to it are transacted as part of the [Framed] transaction system.
* `state` and `stateFor` composables.
*
* @property value the wrapped value
* @property areEquivalent function used for comparing old and new [value]s to determine whether
* to trigger a recomposition or not.
*
- * @see [Model]
* @see [state]
* @see [stateFor]
+ * @see [mutableStateOf]
*/
-private class ModelMutableState<T>(
+private class FramedMutableState<T>(
value: T,
val areEquivalent: (old: T, new: T) -> Boolean
) : Framed, MutableState<T> {
@@ -229,9 +249,6 @@
override var value: T
get() = next.readable(this).value
set(value) = next.withCurrent {
- // This intentionally deviates from the typical behavior of @Model. When this is
- // converted to an IR module, this behavior should be preserved with a custom setter
- // on the property in the @Model class.
if (!areEquivalent(it.value, value)) {
next.writable(this).value = value
}
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Observe.kt b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Observe.kt
index 7f90b5d..78284b2 100644
--- a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Observe.kt
+++ b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Observe.kt
@@ -18,14 +18,14 @@
/**
* This component creates a scope which will be the root of recomposition for any reads or writes to
- * [Model] classes that happen inside of it. This can be used to improve performance in situations
- * where you know that a specific [Model] object will need to change at high frequencies, and you
+ * state instances that happen inside of it. This can be used to improve performance in situations
+ * where you know that a specific state object will need to change at high frequencies, and you
* want to reduce the burden of recomposition. It is recommended that you not introduce [Observe]
* into the composition until it is clear that is necessary to improve performance.
*
* @param body The composable content to observe
*
- * @see Model
+ * @see state
* @see invalidate
* @see Recompose
*/
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Recompose.kt b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Recompose.kt
index 3842c9e..185f5d6 100644
--- a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Recompose.kt
+++ b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Recompose.kt
@@ -21,7 +21,7 @@
* invoked, will cause its children to recompose. This is useful if you are updating local state
* and need to cause a recomposition manually.
*
- * In most cases we recommend using [Model] classes or [state] with immutable types in order to
+ * In most cases we recommend using [state] with immutable types in order to
* maintain local state inside of composables. For cases where this is impractical, Recompose can
* help you.
*
@@ -29,9 +29,9 @@
*
* @sample androidx.compose.samples.recomposeSample
*
- * Note: The above example can be done without [Recompose] by annotating `LoginState` with [Model].
+ * Note: The above example can be done without [Recompose] by using [state].
*
- * @see Model
+ * @see state
* @see Observe
* @see invalidate
*/
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/StableMarker.kt b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/StableMarker.kt
index 5bfb4dd..56960ef 100644
--- a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/StableMarker.kt
+++ b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/StableMarker.kt
@@ -28,13 +28,8 @@
* change. The [Immutable] annotation is provided to mark immutable types as stable.
*
* An object whose public properties do not change but is not immutable (for example, it has
- * private mutable state or uses property delegation to a [Model] object, such as a
- * [MutableState] instance, but is otherwise immutable), should use the [Stable] annotation.
- *
- * [Model] types are mutable but obeys the above assumptions because any change to a public
- * property of a [Model] type notifies composition when the change is committed; therefore the
- * [Model] annotation is annotated [StableMarker] and all type annotated with [Model] are assumed
- * to be stable.
+ * private mutable state or uses property delegation to a [MutableState] object, but is otherwise
+ * immutable), should use the [Stable] annotation.
*
* Mutable object that do not notify composition when they changed should not be marked as stable.
*
diff --git a/ui/integration-tests/benchmark/src/androidTest/java/androidx/ui/benchmark/test/ModelObserverBenchmark.kt b/ui/integration-tests/benchmark/src/androidTest/java/androidx/ui/benchmark/test/ModelObserverBenchmark.kt
index ef6b479..d1d3ef2 100644
--- a/ui/integration-tests/benchmark/src/androidTest/java/androidx/ui/benchmark/test/ModelObserverBenchmark.kt
+++ b/ui/integration-tests/benchmark/src/androidTest/java/androidx/ui/benchmark/test/ModelObserverBenchmark.kt
@@ -19,10 +19,10 @@
import android.os.Handler
import android.os.Looper
import androidx.compose.FrameManager
-import androidx.compose.Model
import androidx.compose.frames.commit
import androidx.compose.frames.inFrame
import androidx.compose.frames.open
+import androidx.compose.mutableStateOf
import androidx.test.filters.LargeTest
import androidx.ui.benchmark.ComposeBenchmarkRule
import androidx.ui.core.ModelObserver
@@ -61,7 +61,7 @@
val rule = ComposeBenchmarkRule(enableTransitions = false)
lateinit var modelObserver: ModelObserver
- val models = List(numberOfModels) { SimpleModel() }
+ val models = List(numberOfModels) { mutableStateOf(0) }
val nodes = List(numberOfNodes) { it }
lateinit var random: Random
val numObservations = numberOfModels / 10
@@ -165,6 +165,3 @@
}
}
}
-
-@Model
-class SimpleModel(var value: Int = 0)
diff --git a/ui/integration-tests/benchmark/src/androidTest/java/androidx/ui/benchmark/test/RadioGroupBenchmark.kt b/ui/integration-tests/benchmark/src/androidTest/java/androidx/ui/benchmark/test/RadioGroupBenchmark.kt
index d0e9888..29cd29f 100644
--- a/ui/integration-tests/benchmark/src/androidTest/java/androidx/ui/benchmark/test/RadioGroupBenchmark.kt
+++ b/ui/integration-tests/benchmark/src/androidTest/java/androidx/ui/benchmark/test/RadioGroupBenchmark.kt
@@ -17,7 +17,7 @@
package androidx.ui.benchmark.test
import androidx.compose.Composable
-import androidx.compose.Model
+import androidx.compose.mutableStateOf
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.LargeTest
import androidx.ui.benchmark.ComposeBenchmarkRule
@@ -91,17 +91,14 @@
}
}
-@Model
-internal class RadioGroupSelectedState<T>(var selected: T)
-
internal class RadioGroupTestCase : ComposeTestCase, ToggleableTestCase {
private val radiosCount = 10
private val options = (0 until radiosCount).toList()
- private val select = RadioGroupSelectedState(0)
+ private val select = mutableStateOf(0)
override fun toggleState() {
- select.selected = (select.selected + 1) % radiosCount
+ select.value = (select.value + 1) % radiosCount
}
@Composable
@@ -112,8 +109,8 @@
options.forEach { item ->
RadioGroupTextItem(
text = item.toString(),
- selected = (select.selected == item),
- select.selected = item })
+ selected = (select.value == item),
+ select.value = item })
}
}
}
diff --git a/ui/integration-tests/demos/src/main/java/androidx/ui/demos/DemoColorPalette.kt b/ui/integration-tests/demos/src/main/java/androidx/ui/demos/DemoColorPalette.kt
index 920018e..959d519 100644
--- a/ui/integration-tests/demos/src/main/java/androidx/ui/demos/DemoColorPalette.kt
+++ b/ui/integration-tests/demos/src/main/java/androidx/ui/demos/DemoColorPalette.kt
@@ -18,20 +18,23 @@
import android.content.SharedPreferences
import androidx.compose.Composable
-import androidx.compose.Model
+import androidx.compose.Stable
+import androidx.compose.getValue
+import androidx.compose.mutableStateOf
+import androidx.compose.setValue
import androidx.ui.foundation.isSystemInDarkTheme
import androidx.ui.material.ColorPalette
import androidx.ui.material.darkColorPalette
import androidx.ui.material.lightColorPalette
/**
- * Wrapper [Model] class that contains a light and dark [ColorPalette], to allow saving and
+ * Wrapper class that contains a light and dark [ColorPalette], to allow saving and
* restoring the entire light / dark theme to and from [SharedPreferences].
*/
-@Model
+@Stable
class DemoColorPalette {
- var lightColors: ColorPalette = lightColorPalette()
- var darkColors: ColorPalette = darkColorPalette()
+ var lightColors: ColorPalette by mutableStateOf(lightColorPalette())
+ var darkColors: ColorPalette by mutableStateOf(darkColorPalette())
@Composable
val colors
diff --git a/ui/integration-tests/src/main/java/androidx/ui/integration/test/foundation/RectsInColumnSharedModelTestCase.kt b/ui/integration-tests/src/main/java/androidx/ui/integration/test/foundation/RectsInColumnSharedModelTestCase.kt
index 4d54658..7d34bc3 100644
--- a/ui/integration-tests/src/main/java/androidx/ui/integration/test/foundation/RectsInColumnSharedModelTestCase.kt
+++ b/ui/integration-tests/src/main/java/androidx/ui/integration/test/foundation/RectsInColumnSharedModelTestCase.kt
@@ -17,7 +17,7 @@
package androidx.ui.integration.test.foundation
import androidx.compose.Composable
-import androidx.compose.Model
+import androidx.compose.mutableStateOf
import androidx.ui.core.Modifier
import androidx.ui.foundation.Box
import androidx.ui.unit.dp
@@ -29,9 +29,6 @@
import androidx.ui.integration.test.ToggleableTestCase
import androidx.ui.layout.preferredSize
-@Model
-private class RectanglesInColumnTestCaseColorModel(var color: Color)
-
/**
* Test case that puts the given amount of rectangles into a column layout and makes changes by
* modifying the color used in the model.
@@ -43,7 +40,7 @@
private val amountOfRectangles: Int
) : ComposeTestCase, ToggleableTestCase {
- private val model = RectanglesInColumnTestCaseColorModel(Color.Black)
+ private val color = mutableStateOf(Color.Black)
@Composable
override fun emitContent() {
@@ -51,7 +48,7 @@
Column {
repeat(amountOfRectangles) { i ->
if (i == 0) {
- Box(Modifier.preferredSize(100.dp, 50.dp).drawBackground(model.color))
+ Box(Modifier.preferredSize(100.dp, 50.dp).drawBackground(color.value))
} else {
Box(Modifier.preferredSize(100.dp, 50.dp).drawBackground(Color.Green))
}
@@ -61,10 +58,10 @@
}
override fun toggleState() {
- if (model.color == Color.Magenta) {
- model.color = Color.Blue
+ if (color.value == Color.Magenta) {
+ color.value = Color.Blue
} else {
- model.color = Color.Magenta
+ color.value = Color.Magenta
}
}
}
\ No newline at end of file
diff --git a/ui/ui-android-view/integration-tests/android-view-demos/src/main/java/androidx/ui/androidview/demos/WebComponentActivity.kt b/ui/ui-android-view/integration-tests/android-view-demos/src/main/java/androidx/ui/androidview/demos/WebComponentActivity.kt
index 2374e74..0bededb 100644
--- a/ui/ui-android-view/integration-tests/android-view-demos/src/main/java/androidx/ui/androidview/demos/WebComponentActivity.kt
+++ b/ui/ui-android-view/integration-tests/android-view-demos/src/main/java/androidx/ui/androidview/demos/WebComponentActivity.kt
@@ -39,15 +39,18 @@
import androidx.ui.androidview.adapters.setOnClick
import androidx.ui.androidview.adapters.setOnTextChanged
import androidx.compose.Composable
-import androidx.compose.Model
+import androidx.compose.Stable
+import androidx.compose.getValue
+import androidx.compose.mutableStateOf
+import androidx.compose.setValue
import androidx.compose.state
import androidx.ui.androidview.WebComponent
import androidx.ui.androidview.WebContext
import androidx.ui.core.setViewContent
-@Model
+@Stable
class WebParams {
- var url: String = "https://www.google.com"
+ var url: String by mutableStateOf("https://www.google.com")
}
open class WebComponentActivity : ComponentActivity() {
diff --git a/ui/ui-animation/src/main/java/androidx/ui/animation/AnimatedValueEffects.kt b/ui/ui-animation/src/main/java/androidx/ui/animation/AnimatedValueEffects.kt
index 6e0f9b0..6a47e02 100644
--- a/ui/ui-animation/src/main/java/androidx/ui/animation/AnimatedValueEffects.kt
+++ b/ui/ui-animation/src/main/java/androidx/ui/animation/AnimatedValueEffects.kt
@@ -24,6 +24,7 @@
import androidx.animation.Spring
import androidx.animation.TwoWayConverter
import androidx.compose.Composable
+import androidx.compose.Stable
import androidx.compose.StructurallyEqual
import androidx.compose.getValue
import androidx.compose.mutableStateOf
@@ -101,6 +102,7 @@
* [AnimationVector] type
* @param clock The animation clock that will be used to drive the animation
*/
+@Stable
class AnimatedValueModel<T, V : AnimationVector>(
initialValue: T,
typeConverter: TwoWayConverter<T, V>,
@@ -117,6 +119,7 @@
* @param initialValue The overridden value field that can only be mutated by animation
* @param clock The animation clock that will be used to drive the animation
*/
+@Stable
class AnimatedFloatModel(
initialValue: Float,
clock: AnimationClockObservable,
diff --git a/ui/ui-animation/src/main/java/androidx/ui/animation/Transition.kt b/ui/ui-animation/src/main/java/androidx/ui/animation/Transition.kt
index 7645fde..0af984e 100644
--- a/ui/ui-animation/src/main/java/androidx/ui/animation/Transition.kt
+++ b/ui/ui-animation/src/main/java/androidx/ui/animation/Transition.kt
@@ -24,9 +24,12 @@
import androidx.animation.TransitionState
import androidx.animation.createAnimation
import androidx.compose.Composable
-import androidx.compose.Model
+import androidx.compose.Stable
+import androidx.compose.getValue
+import androidx.compose.mutableStateOf
import androidx.compose.onPreCommit
import androidx.compose.remember
+import androidx.compose.setValue
import androidx.ui.core.AnimationClockAmbient
/**
@@ -101,14 +104,14 @@
var transitionsEnabled = true
// TODO(Doris): Use Clock idea instead of TransitionModel with pulse
-@Model
+@Stable
private class TransitionModel<T>(
transitionDef: TransitionDefinition<T>,
initState: T,
clock: AnimationClockObservable
) : TransitionState {
- private var animationPulse = 0L
+ private var animationPulse by mutableStateOf(0L)
internal val anim: TransitionAnimation<T> =
transitionDef.createAnimation(clock, initState).apply {
>
@@ -117,7 +120,7 @@
}
override fun <T, V : AnimationVector> get(propKey: PropKey<T, V>): T {
- // we need to access the animationPulse so Compose will record this @Model values usage.
+ // we need to access the animationPulse so Compose will record this state values usage.
@Suppress("UNUSED_VARIABLE")
val pulse = animationPulse
return anim[propKey]
diff --git a/ui/ui-core/src/androidTest/java/androidx/ui/core/test/AndroidLayoutDrawTest.kt b/ui/ui-core/src/androidTest/java/androidx/ui/core/test/AndroidLayoutDrawTest.kt
index 49c72ad..156df58 100644
--- a/ui/ui-core/src/androidTest/java/androidx/ui/core/test/AndroidLayoutDrawTest.kt
+++ b/ui/ui-core/src/androidTest/java/androidx/ui/core/test/AndroidLayoutDrawTest.kt
@@ -29,10 +29,13 @@
import androidx.annotation.RequiresApi
import androidx.compose.Composable
import androidx.compose.FrameManager
-import androidx.compose.Model
+import androidx.compose.Stable
+import androidx.compose.State
import androidx.compose.emptyContent
+import androidx.compose.getValue
import androidx.compose.mutableStateOf
import androidx.compose.remember
+import androidx.compose.setValue
import androidx.compose.state
import androidx.test.filters.SdkSuppress
import androidx.test.filters.SmallTest
@@ -212,13 +215,13 @@
val white = Color(0xFFFFFFFF)
val blue = Color(0xFF000080)
val model = SquareModel(outerColor = blue, innerColor = white)
- val offset = OffsetModel(10.ipx)
+ val offset = mutableStateOf(10.ipx)
composeMovingSquaresWithRepaintBoundary(model, offset)
validateSquareColors(outerColor = blue, innerColor = white, size = 10)
positionLatch = CountDownLatch(1)
activityTestRule.runOnUiThreadIR {
- offset.offset = 20.ipx
+ offset.value = 20.ipx
}
assertTrue(positionLatch!!.await(1, TimeUnit.SECONDS))
@@ -233,7 +236,7 @@
val white = Color(0xFFFFFFFF)
val blue = Color(0xFF000080)
val model = SquareModel(outerColor = blue, innerColor = white)
- val offset = OffsetModel(10.ipx)
+ val offset = mutableStateOf(10.ipx)
composeMovingSquares(model, offset)
validateSquareColors(outerColor = blue, innerColor = white, size = 10)
@@ -247,7 +250,7 @@
drawLatch.countDown()
}
})
- offset.offset = 20.ipx
+ offset.value = 20.ipx
}
validateSquareColors(outerColor = blue, innerColor = white, offset = 10, size = 10)
@@ -576,7 +579,7 @@
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
@Test
fun testRelayoutOnNewChild() {
- val drawChild = DoDraw()
+ val drawChild = mutableStateOf(false)
val outerColor = Color(0xFF000080)
val innerColor = Color(0xFFFFFFFF)
@@ -608,7 +611,7 @@
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
@Test
fun moveRootLayoutRedrawsLeafRepaintBoundary() {
- val offset = OffsetModel(0.ipx)
+ val offset = mutableStateOf(0.ipx)
drawLatch = CountDownLatch(2)
activityTestRule.runOnUiThreadIR {
activity.setContent {
@@ -626,7 +629,7 @@
) { measurables, constraints, _ ->
layout(width = 20.ipx, height = 20.ipx) {
measurables.first().measure(constraints)
- .place(offset.offset, offset.offset)
+ .place(offset.value, offset.value)
}
}
}
@@ -639,7 +642,7 @@
}
drawLatch = CountDownLatch(1)
- activityTestRule.runOnUiThreadIR { offset.offset = 10.ipx }
+ activityTestRule.runOnUiThreadIR { offset.value = 10.ipx }
assertTrue(drawLatch.await(1, TimeUnit.SECONDS))
activityTestRule.waitAndScreenShot().apply {
@@ -652,7 +655,7 @@
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
@Test
fun testRedrawOnRemovedChild() {
- val drawChild = DoDraw(true)
+ val drawChild = mutableStateOf(true)
val outerColor = Color(0xFF000080)
val innerColor = Color(0xFFFFFFFF)
@@ -692,7 +695,7 @@
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
@Test
fun testRelayoutOnRemovedChild() {
- val drawChild = DoDraw(true)
+ val drawChild = mutableStateOf(true)
val outerColor = Color(0xFF000080)
val innerColor = Color(0xFFFFFFFF)
@@ -1020,7 +1023,7 @@
fun testAlignmentLines_recomposeCorrectly() {
val TestLine = VerticalAlignmentLine(::min)
var layoutLatch = CountDownLatch(1)
- val model = OffsetModel(10.ipx)
+ val offset = mutableStateOf(10.ipx)
var measure = 0
var layout = 0
var linePosition: IntPx? = null
@@ -1028,7 +1031,7 @@
activity.setContent {
val child = @Composable {
Layout(children = {}) { _, _, _ ->
- layout(0.ipx, 0.ipx, mapOf(TestLine to model.offset)) {}
+ layout(0.ipx, 0.ipx, mapOf(TestLine to offset.value)) {}
}
}
Layout(child) { measurables, constraints, _ ->
@@ -1049,7 +1052,7 @@
layoutLatch = CountDownLatch(1)
activityTestRule.runOnUiThreadIR {
- model.offset = 20.ipx
+ offset.value = 20.ipx
}
assertTrue(layoutLatch.await(1, TimeUnit.SECONDS))
assertEquals(2, measure)
@@ -1061,7 +1064,7 @@
fun testAlignmentLines_recomposeCorrectly_whenQueriedInLayout() {
val TestLine = VerticalAlignmentLine(::min)
var layoutLatch = CountDownLatch(1)
- val model = OffsetModel(10.ipx)
+ val offset = mutableStateOf(10.ipx)
var measure = 0
var layout = 0
var linePosition: IntPx? = null
@@ -1072,7 +1075,7 @@
layout(
0.ipx,
0.ipx,
- mapOf(TestLine to model.offset)
+ mapOf(TestLine to offset.value)
) {}
}
}
@@ -1093,7 +1096,7 @@
assertEquals(10.ipx, linePosition)
layoutLatch = CountDownLatch(1)
- activityTestRule.runOnUiThreadIR { model.offset = 20.ipx }
+ activityTestRule.runOnUiThreadIR { offset.value = 20.ipx }
assertTrue(layoutLatch.await(1, TimeUnit.SECONDS))
assertEquals(2, measure)
assertEquals(2, layout)
@@ -1104,7 +1107,7 @@
fun testAlignmentLines_recomposeCorrectly_whenMeasuredAndQueriedInLayout() {
val TestLine = VerticalAlignmentLine(::min)
var layoutLatch = CountDownLatch(1)
- val model = OffsetModel(10.ipx)
+ val offset = mutableStateOf(10.ipx)
var measure = 0
var layout = 0
var linePosition: IntPx? = null
@@ -1112,7 +1115,7 @@
activity.setContent {
val child = @Composable {
Layout(children = {}) { _, _, _ ->
- layout(0.ipx, 0.ipx, mapOf(TestLine to model.offset)) { }
+ layout(0.ipx, 0.ipx, mapOf(TestLine to offset.value)) { }
}
}
Layout(child) { measurables, constraints, _ ->
@@ -1132,7 +1135,7 @@
assertEquals(10.ipx, linePosition)
layoutLatch = CountDownLatch(1)
- activityTestRule.runOnUiThreadIR { model.offset = 20.ipx }
+ activityTestRule.runOnUiThreadIR { offset.value = 20.ipx }
assertTrue(layoutLatch.await(1, TimeUnit.SECONDS))
assertEquals(1, measure)
assertEquals(2, layout)
@@ -1142,7 +1145,7 @@
@Test
fun testAlignmentLines_onlyComputesAlignmentLinesWhenNeeded() {
var layoutLatch = CountDownLatch(1)
- val model = OffsetModel(10.ipx)
+ val offset = mutableStateOf(10.ipx)
var alignmentLinesCalculations = 0
val TestLine = VerticalAlignmentLine { _, _ ->
++alignmentLinesCalculations
@@ -1151,14 +1154,14 @@
activityTestRule.runOnUiThreadIR {
activity.setContent {
val innerChild = @Composable {
- model.offset // Artificial remeasure.
+ offset.value // Artificial remeasure.
Layout(children = {}) { _, _, _ ->
layout(0.ipx, 0.ipx, mapOf(TestLine to 10.ipx)) { }
}
}
val child = @Composable {
Layout({ innerChild(); innerChild() }) { measurables, constraints, _ ->
- model.offset // Artificial remeasure.
+ offset.value // Artificial remeasure.
val placeable1 = measurables[0].measure(constraints)
val placeable2 = measurables[1].measure(constraints)
layout(0.ipx, 0.ipx) {
@@ -1169,7 +1172,7 @@
}
Layout(child) { measurables, constraints, _ ->
val placeable = measurables.first().measure(constraints)
- if (model.offset < 15.ipx) {
+ if (offset.value < 15.ipx) {
placeable[TestLine]
}
layout(0.ipx, 0.ipx) {
@@ -1183,12 +1186,12 @@
assertEquals(1, alignmentLinesCalculations)
layoutLatch = CountDownLatch(1)
- activityTestRule.runOnUiThreadIR { model.offset = 20.ipx }
+ activityTestRule.runOnUiThreadIR { offset.value = 20.ipx }
assertTrue(layoutLatch.await(1, TimeUnit.SECONDS))
assertEquals(1, alignmentLinesCalculations)
layoutLatch = CountDownLatch(1)
- activityTestRule.runOnUiThreadIR { model.offset = 10.ipx }
+ activityTestRule.runOnUiThreadIR { offset.value = 10.ipx }
assertTrue(layoutLatch.await(1, TimeUnit.SECONDS))
assertEquals(2, alignmentLinesCalculations)
}
@@ -1233,7 +1236,7 @@
var innerChildLayouts = 0
var outerChildMeasures = 0
var outerChildLayouts = 0
- val model = OffsetModel(0.ipx)
+ val offset = mutableStateOf(0.ipx)
activityTestRule.runOnUiThreadIR {
activity.setContent {
val child = @Composable {
@@ -1248,7 +1251,7 @@
val placeable = measurables[0].measure(constraints)
layout(0.ipx, 0.ipx) {
++outerChildLayouts
- placeable.place(model.offset, 0.ipx)
+ placeable.place(offset.value, 0.ipx)
}
}
}
@@ -1257,7 +1260,7 @@
val width = placeable.width.coerceAtLeast(10.ipx)
val height = placeable.height.coerceAtLeast(10.ipx)
layout(width, height) {
- assertEquals(model.offset + 10.ipx, placeable[TestLine])
+ assertEquals(offset.value + 10.ipx, placeable[TestLine])
placeable.place(0.ipx, 0.ipx)
layoutLatch.countDown()
}
@@ -1272,7 +1275,7 @@
layoutLatch = CountDownLatch(1)
activityTestRule.runOnUiThreadIR {
- model.offset = 10.ipx
+ offset.value = 10.ipx
}
assertTrue(layoutLatch.await(1, TimeUnit.SECONDS))
assertEquals(1, innerChildMeasures)
@@ -1325,7 +1328,7 @@
val TestLine = VerticalAlignmentLine(::min)
var layoutLatch = CountDownLatch(1)
var childLayouts = 0
- val model = OffsetModel(10.ipx)
+ val offset = mutableStateOf(10.ipx)
activityTestRule.runOnUiThreadIR {
activity.setContent {
val child = @Composable {
@@ -1335,20 +1338,20 @@
constraints.minHeight,
mapOf(TestLine to 10.ipx)
) {
- model.offset // To ensure relayout.
+ offset.value // To ensure relayout.
++childLayouts
}
}
}
val inner = @Composable {
Layout({
- WrapForceRelayout(model) { child() }
+ WrapForceRelayout(offset) { child() }
}) { measurables, constraints, _ ->
val placeable = measurables[0].measure(constraints)
layout(placeable.width, placeable.height) {
- if (model.offset > 15.ipx) assertEquals(10.ipx, placeable[TestLine])
+ if (offset.value > 15.ipx) assertEquals(10.ipx, placeable[TestLine])
placeable.place(0.ipx, 0.ipx)
- if (model.offset > 5.ipx) assertEquals(10.ipx, placeable[TestLine])
+ if (offset.value > 5.ipx) assertEquals(10.ipx, placeable[TestLine])
}
}
}
@@ -1357,7 +1360,7 @@
val width = placeable.width.coerceAtLeast(10.ipx)
val height = placeable.height.coerceAtLeast(10.ipx)
layout(width, height) {
- model.offset // To ensure relayout.
+ offset.value // To ensure relayout.
placeable.place(0.ipx, 0.ipx)
layoutLatch.countDown()
}
@@ -1369,29 +1372,29 @@
assertEquals(2, childLayouts)
layoutLatch = CountDownLatch(1)
- activityTestRule.runOnUiThreadIR { model.offset = 12.ipx }
+ activityTestRule.runOnUiThreadIR { offset.value = 12.ipx }
assertTrue(layoutLatch.await(5, TimeUnit.SECONDS))
// Just one more layout as the alignment lines were speculatively calculated this time.
assertEquals(3, childLayouts)
layoutLatch = CountDownLatch(1)
- activityTestRule.runOnUiThreadIR { model.offset = 17.ipx }
+ activityTestRule.runOnUiThreadIR { offset.value = 17.ipx }
assertTrue(layoutLatch.await(1, TimeUnit.SECONDS))
// One layout as the alignment lines are queried before.
assertEquals(4, childLayouts)
layoutLatch = CountDownLatch(1)
- activityTestRule.runOnUiThreadIR { model.offset = 12.ipx }
+ activityTestRule.runOnUiThreadIR { offset.value = 12.ipx }
assertTrue(layoutLatch.await(1, TimeUnit.SECONDS))
// One layout as the alignment lines are still calculated speculatively.
assertEquals(5, childLayouts)
layoutLatch = CountDownLatch(1)
- activityTestRule.runOnUiThreadIR { model.offset = 1.ipx }
+ activityTestRule.runOnUiThreadIR { offset.value = 1.ipx }
assertTrue(layoutLatch.await(1, TimeUnit.SECONDS))
assertEquals(6, childLayouts)
layoutLatch = CountDownLatch(1)
- activityTestRule.runOnUiThreadIR { model.offset = 10.ipx }
+ activityTestRule.runOnUiThreadIR { offset.value = 10.ipx }
assertTrue(layoutLatch.await(1, TimeUnit.SECONDS))
// Two layouts again, since alignment lines were not queried during last layout,
// so we did not calculate them speculatively anymore.
@@ -1551,7 +1554,7 @@
@Test
fun testLayoutBeforeDraw_forRecomposingNodesNotAffectingRootSize() {
- val model = OffsetModel(0.ipx)
+ val offset = mutableStateOf(0.ipx)
var latch = CountDownLatch(1)
var laidOut = false
activityTestRule.runOnUiThreadIR {
@@ -1567,7 +1570,7 @@
}
val recomposingChild = @Composable { children: @Composable (IntPx) -> Unit ->
// This simulates a child that recomposes, for example due to a transition.
- children(model.offset)
+ children(offset.value)
}
val assumeLayoutBeforeDraw = @Composable { _: IntPx ->
// This assumes a layout was done before the draw pass.
@@ -1594,7 +1597,7 @@
assertTrue(latch.await(1, TimeUnit.SECONDS))
latch = CountDownLatch(1)
activityTestRule.runOnUiThreadIR {
- model.offset = 10.ipx
+ offset.value = 10.ipx
}
assertTrue(latch.await(1, TimeUnit.SECONDS))
}
@@ -2030,7 +2033,7 @@
fun layoutModifier_redrawsCorrectlyWhenOnlyNonModifiedSizeChanges() {
val blue = Color(0xFF000080)
val green = Color(0xFF00FF00)
- val model = OffsetModel(10.ipx)
+ val offset = mutableStateOf(10.ipx)
activityTestRule.runOnUiThreadIR {
activity.setContent {
@@ -2038,7 +2041,7 @@
drawRect(green)
}) {
FixedSize(
- model.offset,
+ offset.value,
modifier = AlignTopLeft.drawLayer()
.drawBehind {
drawLatch.countDown()
@@ -2053,7 +2056,7 @@
drawLatch = CountDownLatch(1)
activityTestRule.runOnUiThreadIR {
- model.offset = 20.ipx
+ offset.value = 20.ipx
}
validateSquareColors(
outerColor = green,
@@ -2287,7 +2290,7 @@
@Test
fun doubleDraw() {
- val model = OffsetModel(0.ipx)
+ val offset = mutableStateOf(0.ipx)
var outerLatch = CountDownLatch(1)
activityTestRule.runOnUiThread {
activity.setContent {
@@ -2298,8 +2301,8 @@
FixedSize(10.ipx, Modifier.drawBehind {
drawLine(
Color.Blue,
- Offset(model.offset.value.toFloat(), 0f),
- Offset(0f, model.offset.value.toFloat()),
+ Offset(offset.value.value.toFloat(), 0f),
+ Offset(0f, offset.value.value.toFloat()),
stroke = Stroke(width = 0.0f) // 0.0f represents hairline stroke
)
drawLatch.countDown()
@@ -2313,7 +2316,7 @@
activityTestRule.runOnUiThread {
drawLatch = CountDownLatch(1)
outerLatch = CountDownLatch(1)
- model.offset = 10.ipx
+ offset.value = 10.ipx
}
assertTrue(drawLatch.await(1, TimeUnit.SECONDS))
assertFalse(outerLatch.await(200, TimeUnit.MILLISECONDS))
@@ -2389,7 +2392,7 @@
}
}
- private fun composeMovingSquaresWithRepaintBoundary(model: SquareModel, offset: OffsetModel) {
+ private fun composeMovingSquaresWithRepaintBoundary(model: SquareModel, offset: State<IntPx>) {
activityTestRule.runOnUiThreadIR {
activity.setContent {
Position(
@@ -2407,7 +2410,7 @@
}
}
- private fun composeMovingSquares(model: SquareModel, offset: OffsetModel) {
+ private fun composeMovingSquares(model: SquareModel, offset: State<IntPx>) {
activityTestRule.runOnUiThreadIR {
activity.setContent {
Position(
@@ -2487,7 +2490,7 @@
@Composable
fun Position(
size: IntPx,
- offset: OffsetModel,
+ offset: State<IntPx>,
modifier: Modifier = Modifier,
children: @Composable () -> Unit
) {
@@ -2497,7 +2500,7 @@
}
layout(size, size) {
placeables.forEach { child ->
- child.place(offset.offset, offset.offset)
+ child.place(offset.value, offset.value)
}
positionLatch?.countDown()
}
@@ -2737,7 +2740,7 @@
fun Scroller(
modifier: Modifier = Modifier,
onScrollPositionChanged: (position: IntPx, maxPosition: IntPx) -> Unit,
- offset: OffsetModel,
+ offset: State<IntPx>,
child: @Composable () -> Unit
) {
val maxPosition = state { IntPx.Infinity }
@@ -2746,7 +2749,7 @@
maxPosition = maxPosition.value,
>
maxPosition.value = 0.ipx
- onScrollPositionChanged(offset.offset, 0.ipx)
+ onScrollPositionChanged(offset.value, 0.ipx)
},
child = child
)
@@ -2776,7 +2779,7 @@
@Composable
fun WrapForceRelayout(
- model: OffsetModel,
+ model: State<IntPx>,
modifier: Modifier = Modifier,
children: @Composable () -> Unit
) {
@@ -2785,7 +2788,7 @@
val width = placeables.maxBy { it.width.value }?.width ?: 0.ipx
val height = placeables.maxBy { it.height.value }?.height ?: 0.ipx
layout(width, height) {
- model.offset
+ model.value
placeables.forEach { it.place(0.ipx, 0.ipx) }
}
}
@@ -2903,18 +2906,16 @@
}
}
-@Model
+@Stable
class SquareModel(
- var size: IntPx = 10.ipx,
- var outerColor: Color = Color(0xFF000080),
- var innerColor: Color = Color(0xFFFFFFFF)
-)
-
-@Model
-class OffsetModel(var offset: IntPx)
-
-@Model
-class DoDraw(var value: Boolean = false)
+ size: IntPx = 10.ipx,
+ outerColor: Color = Color(0xFF000080),
+ innerColor: Color = Color(0xFFFFFFFF)
+) {
+ var size: IntPx by mutableStateOf(size)
+ var outerColor: Color by mutableStateOf(outerColor)
+ var innerColor: Color by mutableStateOf(innerColor)
+}
// We only need this because IR compiler doesn't like converting lambdas to Runnables
fun ActivityTestRule<*>.runOnUiThreadIR(block: () -> Unit) {
diff --git a/ui/ui-core/src/androidTest/java/androidx/ui/core/test/AndroidViewCompatTest.kt b/ui/ui-core/src/androidTest/java/androidx/ui/core/test/AndroidViewCompatTest.kt
index ca59d04..9906002 100644
--- a/ui/ui-core/src/androidTest/java/androidx/ui/core/test/AndroidViewCompatTest.kt
+++ b/ui/ui-core/src/androidTest/java/androidx/ui/core/test/AndroidViewCompatTest.kt
@@ -29,7 +29,7 @@
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
import androidx.compose.Composable
-import androidx.compose.Model
+import androidx.compose.mutableStateOf
import androidx.test.espresso.Espresso
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers.isDescendantOfA
@@ -79,7 +79,7 @@
@Test
fun simpleLayoutTest() {
val squareRef = Ref<ColoredSquareView>()
- val squareSize = OffsetModel(100.ipx)
+ val squareSize = mutableStateOf(100.ipx)
var expectedSize = 100
composeTestRule.setContent {
TestTag("content") {
@@ -87,7 +87,7 @@
Semantics(container = true) {
Layout(
@Composable {
- ColoredSquareView(size = squareSize.offset.value, ref = squareRef)
+ ColoredSquareView(size = squareSize.value.value, ref = squareRef)
}
) { measurables, constraints, _ ->
assertEquals(1, measurables.size)
@@ -114,7 +114,7 @@
runOnUiThread {
// Change view attribute using recomposition.
- squareSize.offset = 200.ipx
+ squareSize.value = 200.ipx
expectedSize = 200
}
findByTag("content").assertIsDisplayed()
@@ -139,7 +139,7 @@
@Test
fun simpleDrawTest() {
val squareRef = Ref<ColoredSquareView>()
- val colorModel = ColorModel(Color.Blue)
+ val colorModel = mutableStateOf(Color.Blue)
val squareSize = 100
var expectedColor = Color.Blue
composeTestRule.setContent {
@@ -147,7 +147,7 @@
TestTag("content") {
Semantics(container = true) {
Container(Modifier.drawLayer()) {
- ColoredSquareView(color = colorModel.color, ref = squareRef)
+ ColoredSquareView(color = colorModel.value, ref = squareRef)
}
}
}
@@ -173,7 +173,7 @@
runOnUiThread {
// Change view attribute using recomposition.
- colorModel.color = Color.Green
+ colorModel.value = Color.Green
expectedColor = Color.Green
}
Espresso
@@ -187,7 +187,7 @@
runOnUiThread {
// Change view attribute using the View reference.
- colorModel.color = Color.Red
+ colorModel.value = Color.Red
expectedColor = Color.Red
}
Espresso
@@ -333,10 +333,10 @@
val heightMeasureSpecRef = Ref<Int>()
// Unique starting constraints so that new constraints are different and thus recomp is
// guaranteed.
- val constraintsHolder = ConstraintsModel(Constraints.fixed(1234.ipx, 5678.ipx))
+ val constraintsHolder = mutableStateOf(Constraints.fixed(1234.ipx, 5678.ipx))
composeTestRule.setContent {
- Container(LayoutConstraints(constraintsHolder.constraints)) {
+ Container(LayoutConstraints(constraintsHolder.value)) {
MeasureSpecSaverView(
ref = viewRef,
widthMeasureSpecRef = widthMeasureSpecRef,
@@ -346,7 +346,7 @@
}
runOnUiThread {
- constraintsHolder.constraints = constraints
+ constraintsHolder.value = constraints
viewRef.value?.layoutParams = layoutParams
}
@@ -359,14 +359,14 @@
@Test
fun testMeasurement_isDoneWithCorrectMinimumDimensionsSetOnView() {
val viewRef = Ref<MeasureSpecSaverView>()
- val constraintsHolder = ConstraintsModel(Constraints())
+ val constraintsHolder = mutableStateOf(Constraints())
composeTestRule.setContent {
- Container(LayoutConstraints(constraintsHolder.constraints)) {
+ Container(LayoutConstraints(constraintsHolder.value)) {
MeasureSpecSaverView(ref = viewRef)
}
}
runOnUiThread {
- constraintsHolder.constraints = Constraints(minWidth = 20.ipx, minHeight = 30.ipx)
+ constraintsHolder.value = Constraints(minWidth = 20.ipx, minHeight = 30.ipx)
}
runOnIdleCompose {
@@ -455,9 +455,3 @@
}
}
}
-
-@Model
-private data class ColorModel(var color: Color)
-
-@Model
-private data class ConstraintsModel(var constraints: Constraints)
diff --git a/ui/ui-core/src/androidTest/java/androidx/ui/core/test/ClipTest.kt b/ui/ui-core/src/androidTest/java/androidx/ui/core/test/ClipTest.kt
index 87db4c1..30e6f0b 100644
--- a/ui/ui-core/src/androidTest/java/androidx/ui/core/test/ClipTest.kt
+++ b/ui/ui-core/src/androidTest/java/androidx/ui/core/test/ClipTest.kt
@@ -18,6 +18,7 @@
import android.graphics.Bitmap
import android.os.Build
+import androidx.compose.mutableStateOf
import androidx.test.filters.SdkSuppress
import androidx.test.filters.SmallTest
import androidx.test.rule.ActivityTestRule
@@ -276,7 +277,7 @@
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
@Test
fun switchFromRectToRounded() {
- val model = ValueModel<Shape>(rectShape)
+ val model = mutableStateOf<Shape>(rectShape)
rule.runOnUiThreadIR {
activity.setContent {
@@ -311,7 +312,7 @@
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
@Test
fun switchFromRectToPath() {
- val model = ValueModel<Shape>(rectShape)
+ val model = mutableStateOf<Shape>(rectShape)
rule.runOnUiThreadIR {
activity.setContent {
@@ -338,7 +339,7 @@
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
@Test
fun switchFromPathToRect() {
- val model = ValueModel<Shape>(triangleShape)
+ val model = mutableStateOf<Shape>(triangleShape)
rule.runOnUiThreadIR {
activity.setContent {
@@ -365,7 +366,7 @@
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
@Test
fun switchBetweenDifferentPaths() {
- val model = ValueModel<Shape>(triangleShape)
+ val model = mutableStateOf<Shape>(triangleShape)
// to be replaced with a DrawModifier wrapped into remember, so the recomposition
// is not causing invalidation as the DrawModifier didn't change
val drawCallback: DrawScope.() -> Unit = {
@@ -411,7 +412,7 @@
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
@Test
fun emitClipLater() {
- val model = ValueModel(false)
+ val model = mutableStateOf(false)
rule.runOnUiThreadIR {
activity.setContent {
diff --git a/ui/ui-core/src/androidTest/java/androidx/ui/core/test/DrawShadowTest.kt b/ui/ui-core/src/androidTest/java/androidx/ui/core/test/DrawShadowTest.kt
index acb932a..c85a70d 100644
--- a/ui/ui-core/src/androidTest/java/androidx/ui/core/test/DrawShadowTest.kt
+++ b/ui/ui-core/src/androidTest/java/androidx/ui/core/test/DrawShadowTest.kt
@@ -174,7 +174,7 @@
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
@Test
fun emitShadowLater() {
- val model = ValueModel(false)
+ val model = mutableStateOf(false)
rule.runOnUiThreadIR {
activity.setContent {
diff --git a/ui/ui-core/src/androidTest/java/androidx/ui/core/test/ModelReadsTest.kt b/ui/ui-core/src/androidTest/java/androidx/ui/core/test/ModelReadsTest.kt
index 47d4837..95cb933 100644
--- a/ui/ui-core/src/androidTest/java/androidx/ui/core/test/ModelReadsTest.kt
+++ b/ui/ui-core/src/androidTest/java/androidx/ui/core/test/ModelReadsTest.kt
@@ -17,6 +17,7 @@
package androidx.ui.core.test
import androidx.compose.FrameManager
+import androidx.compose.MutableState
import androidx.compose.mutableStateOf
import androidx.test.filters.SmallTest
import androidx.test.rule.ActivityTestRule
@@ -57,19 +58,19 @@
@Test
fun useTheSameModelInDrawAndPosition() {
- val model = OffsetModel(5.ipx)
+ val offset = mutableStateOf(5.ipx)
var drawLatch = CountDownLatch(1)
var positionLatch = CountDownLatch(1)
rule.runOnUiThread {
activity.setContent {
Layout({}, modifier = Modifier.drawBehind {
// read from the model
- model.offset
+ offset.value
drawLatch.countDown()
}) { _, _, _ ->
layout(10.ipx, 10.ipx) {
// read from the model
- model.offset
+ offset.value
positionLatch.countDown()
}
}
@@ -81,7 +82,7 @@
drawLatch = CountDownLatch(1)
positionLatch = CountDownLatch(1)
rule.runOnUiThread {
- model.offset = 7.ipx
+ offset.value = 7.ipx
}
assertTrue(drawLatch.await(1, TimeUnit.SECONDS))
@@ -90,7 +91,7 @@
drawLatch = CountDownLatch(1)
positionLatch = CountDownLatch(1)
rule.runOnUiThread {
- model.offset = 10.ipx
+ offset.value = 10.ipx
}
assertTrue(drawLatch.await(1, TimeUnit.SECONDS))
@@ -99,20 +100,20 @@
@Test
fun useDifferentModelsInDrawAndPosition() {
- val drawModel = OffsetModel(5.ipx)
- val positionModel = OffsetModel(5.ipx)
+ val drawModel = mutableStateOf(5.ipx)
+ val positionModel = mutableStateOf(5.ipx)
var drawLatch = CountDownLatch(1)
var positionLatch = CountDownLatch(1)
rule.runOnUiThread {
activity.setContent {
Layout({}, modifier = Modifier.drawBehind {
// read from the model
- drawModel.offset
+ drawModel.value
drawLatch.countDown()
}) { _, _, _ ->
layout(10.ipx, 10.ipx) {
// read from the model
- positionModel.offset
+ positionModel.value
positionLatch.countDown()
}
}
@@ -124,7 +125,7 @@
drawLatch = CountDownLatch(1)
positionLatch = CountDownLatch(1)
rule.runOnUiThread {
- drawModel.offset = 7.ipx
+ drawModel.value = 7.ipx
}
assertTrue(drawLatch.await(1, TimeUnit.SECONDS))
@@ -133,7 +134,7 @@
drawLatch = CountDownLatch(1)
positionLatch = CountDownLatch(1)
rule.runOnUiThread {
- positionModel.offset = 10.ipx
+ positionModel.value = 10.ipx
}
assertTrue(positionLatch.await(1, TimeUnit.SECONDS))
@@ -142,19 +143,19 @@
@Test
fun useTheSameModelInMeasureAndPosition() {
- val model = OffsetModel(5.ipx)
+ val offset = mutableStateOf(5.ipx)
var measureLatch = CountDownLatch(1)
var drawLatch = CountDownLatch(1)
rule.runOnUiThread {
activity.setContent {
Layout({}, modifier = Modifier.drawBehind {
// read from the model
- model.offset
+ offset.value
drawLatch.countDown()
}) { _, _, _ ->
measureLatch.countDown()
// read from the model
- layout(model.offset, 10.ipx) {}
+ layout(offset.value, 10.ipx) {}
}
}
}
@@ -164,7 +165,7 @@
measureLatch = CountDownLatch(1)
drawLatch = CountDownLatch(1)
rule.runOnUiThread {
- model.offset = 10.ipx
+ offset.value = 10.ipx
}
assertTrue(measureLatch.await(1, TimeUnit.SECONDS))
@@ -173,7 +174,7 @@
measureLatch = CountDownLatch(1)
drawLatch = CountDownLatch(1)
rule.runOnUiThread {
- model.offset = 15.ipx
+ offset.value = 15.ipx
}
assertTrue(measureLatch.await(1, TimeUnit.SECONDS))
@@ -182,8 +183,8 @@
@Test
fun useDifferentModelsInMeasureAndPosition() {
- val measureModel = OffsetModel(5.ipx)
- val positionModel = OffsetModel(5.ipx)
+ val measureModel = mutableStateOf(5.ipx)
+ val positionModel = mutableStateOf(5.ipx)
var measureLatch = CountDownLatch(1)
var positionLatch = CountDownLatch(1)
rule.runOnUiThread {
@@ -191,9 +192,9 @@
Layout({}) { _, _, _ ->
measureLatch.countDown()
// read from the model
- layout(measureModel.offset, 10.ipx) {
+ layout(measureModel.value, 10.ipx) {
// read from the model
- positionModel.offset
+ positionModel.value
positionLatch.countDown()
}
}
@@ -205,7 +206,7 @@
measureLatch = CountDownLatch(1)
positionLatch = CountDownLatch(1)
rule.runOnUiThread {
- measureModel.offset = 10.ipx
+ measureModel.value = 10.ipx
}
assertTrue(measureLatch.await(1, TimeUnit.SECONDS))
@@ -215,7 +216,7 @@
measureLatch = CountDownLatch(1)
positionLatch = CountDownLatch(1)
rule.runOnUiThread {
- positionModel.offset = 15.ipx
+ positionModel.value = 15.ipx
}
assertFalse(measureLatch.await(200, TimeUnit.MILLISECONDS))
@@ -224,8 +225,8 @@
@Test
fun drawReactsOnCorrectModelsChanges() {
- val enabled = ValueModel(true)
- val model = ValueModel(0)
+ val enabled = mutableStateOf(true)
+ val model = mutableStateOf(0)
rule.runOnUiThread {
activity.setContent {
AtLeastSize(10.ipx, modifier = Modifier.drawBehind {
@@ -243,8 +244,8 @@
@Test
fun measureReactsOnCorrectModelsChanges() {
- val enabled = ValueModel(true)
- val model = ValueModel(0)
+ val enabled = mutableStateOf(true)
+ val model = mutableStateOf(0)
rule.runOnUiThread {
activity.setContent {
Layout({}) { _, _, _ ->
@@ -264,8 +265,8 @@
@Test
fun layoutReactsOnCorrectModelsChanges() {
- val enabled = ValueModel(true)
- val model = ValueModel(0)
+ val enabled = mutableStateOf(true)
+ val model = mutableStateOf(0)
rule.runOnUiThread {
activity.setContent {
Layout({}) { _, _, _ ->
@@ -286,8 +287,8 @@
@Test
fun drawStopsReactingOnModelsAfterDetaching() {
- val enabled = ValueModel(true)
- val model = ValueModel(0)
+ val enabled = mutableStateOf(true)
+ val model = mutableStateOf(0)
rule.runOnUiThread {
activity.setContent {
val modifier = if (enabled.value) {
@@ -307,8 +308,8 @@
@Test
fun measureStopsReactingOnModelsAfterDetaching() {
- val enabled = ValueModel(true)
- val model = ValueModel(0)
+ val enabled = mutableStateOf(true)
+ val model = mutableStateOf(0)
rule.runOnUiThread {
activity.setContent {
if (enabled.value) {
@@ -328,8 +329,8 @@
@Test
fun layoutStopsReactingOnModelsAfterDetaching() {
- val enabled = ValueModel(true)
- val model = ValueModel(0)
+ val enabled = mutableStateOf(true)
+ val model = mutableStateOf(0)
rule.runOnUiThread {
activity.setContent {
if (enabled.value) {
@@ -490,8 +491,8 @@
}
fun assertCountDownOnlyWhileEnabled(
- enableModel: ValueModel<Boolean>,
- valueModel: ValueModel<Int>,
+ enableModel: MutableState<Boolean>,
+ valueModel: MutableState<Int>,
triggeredByEnableSwitch: Boolean = true
) {
latch = CountDownLatch(1)
diff --git a/ui/ui-core/src/androidTest/java/androidx/ui/core/test/OpacityTest.kt b/ui/ui-core/src/androidTest/java/androidx/ui/core/test/OpacityTest.kt
index 5a14bf0..7ac8d3b 100644
--- a/ui/ui-core/src/androidTest/java/androidx/ui/core/test/OpacityTest.kt
+++ b/ui/ui-core/src/androidTest/java/androidx/ui/core/test/OpacityTest.kt
@@ -137,14 +137,14 @@
@Test
fun switchFromHalfOpacityToFull() {
val color = Color.Green
- val model = ValueModel(0.5f)
+ val opacity = mutableStateOf(0.5f)
rule.runOnUiThreadIR {
activity.setContent {
AtLeastSize(
size = 10.ipx,
modifier = Modifier.background(Color.White)
- .drawOpacity(model.value)
+ .drawOpacity(opacity.value)
.plus(unlatch)
.background(color)
) {
@@ -154,7 +154,7 @@
assertTrue(drawLatch.await(1, TimeUnit.SECONDS))
rule.runOnUiThreadIR {
- model.value = 1f
+ opacity.value = 1f
}
takeScreenShot(10).apply {
@@ -195,7 +195,7 @@
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
@Test
fun emitDrawWithOpacityLater() {
- val model = ValueModel(false)
+ val model = mutableStateOf(false)
rule.runOnUiThreadIR {
activity.setContent {
diff --git a/ui/ui-core/src/androidTest/java/androidx/ui/core/test/ValueModel.kt b/ui/ui-core/src/androidTest/java/androidx/ui/core/test/ValueModel.kt
deleted file mode 100644
index 27dc87c..0000000
--- a/ui/ui-core/src/androidTest/java/androidx/ui/core/test/ValueModel.kt
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright 2019 The Android Open Source Project
- *
- * 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 androidx.ui.core.test
-
-import androidx.compose.Model
-
-@Model
-data class ValueModel<T>(var value: T)
\ No newline at end of file
diff --git a/ui/ui-core/src/androidTest/java/androidx/ui/core/test/WithConstraintsTest.kt b/ui/ui-core/src/androidTest/java/androidx/ui/core/test/WithConstraintsTest.kt
index f7d19a8..8598aeb 100644
--- a/ui/ui-core/src/androidTest/java/androidx/ui/core/test/WithConstraintsTest.kt
+++ b/ui/ui-core/src/androidTest/java/androidx/ui/core/test/WithConstraintsTest.kt
@@ -199,13 +199,13 @@
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
@Test
fun requestLayoutDuringLayout() {
- val offset = OffsetModel(0.ipx)
+ val offset = mutableStateOf(0.ipx)
rule.runOnUiThreadIR {
activity.setContent {
Scroller(
modifier = countdownLatchBackgroundModifier(Color.Yellow),
position, _ ->
- offset.offset = position
+ offset.value = position
},
offset = offset
) {
@@ -223,7 +223,7 @@
@Test
fun subcomposionInsideWithConstraintsDoesntAffectModelReadsObserving() {
- val model = ValueModel(0)
+ val model = mutableStateOf(0)
var latch = CountDownLatch(1)
rule.runOnUiThreadIR {
@@ -261,7 +261,7 @@
@Test
fun withConstraintCallbackIsNotExecutedWithInnerRecompositions() {
- val model = ValueModel(0)
+ val model = mutableStateOf(0)
var latch = CountDownLatch(1)
var recompositionsCount1 = 0
var recompositionsCount2 = 0
@@ -289,7 +289,7 @@
@Test
fun updateConstraintsRecomposingWithConstraints() {
- val model = ValueModel(50.ipx)
+ val model = mutableStateOf(50.ipx)
var latch = CountDownLatch(1)
var actualConstraints: Constraints? = null
@@ -345,7 +345,7 @@
@Test
fun withConstsraintsBehavesAsWrap() {
- val size = ValueModel(50.ipx)
+ val size = mutableStateOf(50.ipx)
var withConstLatch = CountDownLatch(1)
var childLatch = CountDownLatch(1)
var withConstSize: IntPxSize? = null
@@ -398,7 +398,7 @@
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
@Test
fun withConstraintsIsNotSwallowingInnerRemeasureRequest() {
- val model = ValueModel(100.ipx)
+ val model = mutableStateOf(100.ipx)
rule.runOnUiThreadIR {
activity.setContent {
@@ -468,7 +468,7 @@
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
@Test
fun removeLayoutNodeFromWithConstraintsDuringOnMeasure() {
- val model = ValueModel(100.ipx)
+ val model = mutableStateOf(100.ipx)
drawLatch = CountDownLatch(2)
rule.runOnUiThreadIR {
@@ -884,7 +884,7 @@
}
@Composable
-private fun ChangingConstraintsLayout(size: ValueModel<IntPx>, children: @Composable () -> Unit) {
+private fun ChangingConstraintsLayout(size: State<IntPx>, children: @Composable () -> Unit) {
Layout(children) { measurables, _, _ ->
layout(100.ipx, 100.ipx) {
val constraints = Constraints.fixed(size.value, size.value)
diff --git a/ui/ui-core/src/androidTest/java/androidx/ui/res/ResourcesTest.kt b/ui/ui-core/src/androidTest/java/androidx/ui/res/ResourcesTest.kt
index 87e8e54..39f6ffb 100644
--- a/ui/ui-core/src/androidTest/java/androidx/ui/res/ResourcesTest.kt
+++ b/ui/ui-core/src/androidTest/java/androidx/ui/res/ResourcesTest.kt
@@ -97,7 +97,7 @@
runOnIdleCompose {
pendingExecutor.runNow() // load the resource
assertThat(uiThreadWork).isNotNull()
- // update @Model object so that recompose is expected to be triggered.
+ // update state object so that recompose is expected to be triggered.
uiThreadWork?.invoke()
}
@@ -156,7 +156,7 @@
runOnIdleCompose {
pendingExecutor.runNow() // load the resource
assertThat(uiThreadWork).isNotNull()
- // update @Model object so that recompose is expected to be triggered.
+ // update state object so that recompose is expected to be triggered.
uiThreadWork?.invoke()
}
diff --git a/ui/ui-core/src/androidTest/java/androidx/ui/semantics/SemanticsTests.kt b/ui/ui-core/src/androidTest/java/androidx/ui/semantics/SemanticsTests.kt
index 8a50d6e..2b7c833 100644
--- a/ui/ui-core/src/androidTest/java/androidx/ui/semantics/SemanticsTests.kt
+++ b/ui/ui-core/src/androidTest/java/androidx/ui/semantics/SemanticsTests.kt
@@ -17,10 +17,10 @@
package androidx.ui.semantics
import androidx.compose.Composable
+import androidx.compose.mutableStateOf
import androidx.compose.remember
import androidx.test.filters.MediumTest
import androidx.ui.core.Layout
-import androidx.ui.core.test.ValueModel
import androidx.ui.test.SemanticsNodeInteraction
import androidx.ui.test.SemanticsMatcher
import androidx.ui.test.assertCountEquals
@@ -64,7 +64,7 @@
@Test
fun removingMergedSubtree_updatesSemantics() {
val label = "foo"
- val showSubtree = ValueModel(true)
+ val showSubtree = mutableStateOf(true)
composeTestRule.setContent {
Semantics(container = true, properties = {
testTag = TestTag
@@ -95,7 +95,7 @@
fun addingNewMergedNode_updatesSemantics() {
val label = "foo"
val value = "bar"
- val showNewNode = ValueModel(false)
+ val showNewNode = mutableStateOf(false)
composeTestRule.setContent {
Semantics(container = true, properties = {
testTag = TestTag
@@ -134,7 +134,7 @@
@Test
fun removingSubtreeWithoutSemanticsAsTopNode_updatesSemantics() {
val label = "foo"
- val showSubtree = ValueModel(true)
+ val showSubtree = mutableStateOf(true)
composeTestRule.setContent {
Semantics(container = true, properties = {
testTag = TestTag
@@ -165,7 +165,7 @@
fun changingStackedSemanticsComponent_updatesSemantics() {
val beforeLabel = "before"
val afterLabel = "after"
- val isAfter = ValueModel(false)
+ val isAfter = mutableStateOf(false)
composeTestRule.setContent {
Semantics(container = true, properties = {
testTag = TestTag
@@ -190,7 +190,7 @@
fun changingStackedSemanticsComponent_notTopMost_updatesSemantics() {
val beforeLabel = "before"
val afterLabel = "after"
- val isAfter = ValueModel(false)
+ val isAfter = mutableStateOf(false)
composeTestRule.setContent {
Semantics(container = true, properties = { testTag = "don't care" }) {
@@ -220,7 +220,7 @@
fun changingSemantics_belowStackedLayoutNodes_updatesCorrectly() {
val beforeLabel = "before"
val afterLabel = "after"
- val isAfter = ValueModel(false)
+ val isAfter = mutableStateOf(false)
composeTestRule.setContent {
SimpleTestLayout {
@@ -247,7 +247,7 @@
fun changingSemantics_belowNodeMergedThroughBoundary_updatesCorrectly() {
val beforeLabel = "before"
val afterLabel = "after"
- val isAfter = ValueModel(false)
+ val isAfter = mutableStateOf(false)
composeTestRule.setContent {
Semantics(properties = { testTag = TestTag }) {
@@ -316,7 +316,7 @@
val beforeLabel = "before"
val afterLabel = "after"
- val isAfter = ValueModel(false)
+ val isAfter = mutableStateOf(false)
composeTestRule.setContent {
Semantics(container = true, properties = {
@@ -352,7 +352,7 @@
val beforeAction = { println("this never gets called") }
val afterAction = { println("neither does this") }
- val isAfter = ValueModel(false)
+ val isAfter = mutableStateOf(false)
composeTestRule.setContent {
Semantics(container = true, properties = {
diff --git a/ui/ui-core/src/main/java/androidx/ui/core/ModelObserver.kt b/ui/ui-core/src/main/java/androidx/ui/core/ModelObserver.kt
index 6fbb66c..b946336 100644
--- a/ui/ui-core/src/main/java/androidx/ui/core/ModelObserver.kt
+++ b/ui/ui-core/src/main/java/androidx/ui/core/ModelObserver.kt
@@ -31,7 +31,7 @@
*
* @sample androidx.ui.core.samples.modelObserverExample
*
- * When a `@Model` class change has been committed, the `onCommit` listener will be called
+ * When a state change has been committed, the `onCommit` listener will be called
* with the `targetObject` as the argument. There are no order guarantees for
* `onCommit` listener calls. Commit callbacks are made on the thread that model changes
* are committed, so the [commitExecutor] allows the developer to control the thread on which the
diff --git a/ui/ui-core/src/main/java/androidx/ui/res/Resources.kt b/ui/ui-core/src/main/java/androidx/ui/res/Resources.kt
index 15315fa..f53d035 100644
--- a/ui/ui-core/src/main/java/androidx/ui/res/Resources.kt
+++ b/ui/ui-core/src/main/java/androidx/ui/res/Resources.kt
@@ -21,8 +21,11 @@
import android.util.LruCache
import androidx.annotation.GuardedBy
import androidx.compose.Composable
-import androidx.compose.Model
+import androidx.compose.Stable
+import androidx.compose.getValue
+import androidx.compose.mutableStateOf
import androidx.compose.remember
+import androidx.compose.setValue
import java.util.concurrent.Executor
import java.util.concurrent.Executors
@@ -46,13 +49,15 @@
/**
* A class used for the result of the asynchronous resource loading.
*/
-@Model class DeferredResource<T> internal constructor(
- internal var state: LoadingState = LoadingState.PENDING,
+@Stable
+class DeferredResource<T> internal constructor(
+ state: LoadingState = LoadingState.PENDING,
private val pendingResource: T? = null,
private val failedResource: T? = null
) {
- private var loadedResource: T? = null
- private var failedReason: Throwable? = null
+ internal var state by mutableStateOf(state)
+ private var loadedResource: T? by mutableStateOf<T?>(null)
+ private var failedReason: Throwable? by mutableStateOf<Throwable?>(null)
internal fun loadCompleted(loadedResource: T) {
state = LoadingState.LOADED
diff --git a/ui/ui-core/src/test/java/androidx/ui/core/selection/SelectionManagerDragTest.kt b/ui/ui-core/src/test/java/androidx/ui/core/selection/SelectionManagerDragTest.kt
index b9559d4..9261cb2 100644
--- a/ui/ui-core/src/test/java/androidx/ui/core/selection/SelectionManagerDragTest.kt
+++ b/ui/ui-core/src/test/java/androidx/ui/core/selection/SelectionManagerDragTest.kt
@@ -83,7 +83,7 @@
@Before
fun setup() {
- open(false) // we open a Frame so @Model reads are allowed
+ open(false) // we open a Frame so state reads are allowed
selectionRegistrar.subscribe(selectable)
diff --git a/ui/ui-core/src/test/java/androidx/ui/core/selection/SelectionManagerLongPressDragTest.kt b/ui/ui-core/src/test/java/androidx/ui/core/selection/SelectionManagerLongPressDragTest.kt
index 6d058cb..7079fb1 100644
--- a/ui/ui-core/src/test/java/androidx/ui/core/selection/SelectionManagerLongPressDragTest.kt
+++ b/ui/ui-core/src/test/java/androidx/ui/core/selection/SelectionManagerLongPressDragTest.kt
@@ -80,7 +80,7 @@
@Before
fun setup() {
- open(false) // we open a Frame so @Model reads are allowed
+ open(false) // we open a Frame so state reads are allowed
val containerLayoutCoordinates = mock<LayoutCoordinates> {
on { isAttached } doReturn true
}
diff --git a/ui/ui-core/src/test/java/androidx/ui/core/selection/SelectionManagerTest.kt b/ui/ui-core/src/test/java/androidx/ui/core/selection/SelectionManagerTest.kt
index 7a37b58..8b7bcdf 100644
--- a/ui/ui-core/src/test/java/androidx/ui/core/selection/SelectionManagerTest.kt
+++ b/ui/ui-core/src/test/java/androidx/ui/core/selection/SelectionManagerTest.kt
@@ -84,7 +84,7 @@
@Before
fun setup() {
- open(false) // we open a Frame so @Model reads are allowed
+ open(false) // we open a Frame so state reads are allowed
selectionRegistrar.subscribe(selectable)
selectionManager.containerLayoutCoordinates = containerLayoutCoordinates
selectionManager.hapticFeedBack = hapticFeedback
diff --git a/ui/ui-foundation/src/androidTest/java/androidx/ui/foundation/DeterminateProgressTest.kt b/ui/ui-foundation/src/androidTest/java/androidx/ui/foundation/DeterminateProgressTest.kt
index 59b3a0a..924d435 100644
--- a/ui/ui-foundation/src/androidTest/java/androidx/ui/foundation/DeterminateProgressTest.kt
+++ b/ui/ui-foundation/src/androidTest/java/androidx/ui/foundation/DeterminateProgressTest.kt
@@ -16,7 +16,7 @@
package androidx.ui.foundation
-import androidx.compose.Model
+import androidx.compose.mutableStateOf
import androidx.test.filters.MediumTest
import androidx.ui.core.Modifier
import androidx.ui.core.TestTag
@@ -34,11 +34,6 @@
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
-@Model
-private class State {
- var progress = 0f
-}
-
@MediumTest
@RunWith(JUnit4::class)
class DeterminateProgressTest {
@@ -49,12 +44,12 @@
@Test
fun determinateProgress_testSemantics() {
val tag = "linear"
- val state = State()
+ val progress = mutableStateOf(0f)
composeTestRule
.setContent {
TestTag(tag = tag) {
- DeterminateProgressIndicator(progress = state.progress) {
+ DeterminateProgressIndicator(progress = progress.value) {
Box(Modifier.preferredSize(50.dp).drawBackground(Color.Cyan))
}
}
@@ -65,7 +60,7 @@
.assertRangeInfoEquals(AccessibilityRangeInfo(0f, 0f..1f))
runOnUiThread {
- state.progress = 0.5f
+ progress.value = 0.5f
}
findByTag(tag)
diff --git a/ui/ui-layout/src/androidTest/java/androidx/ui/layout/test/ContainerTest.kt b/ui/ui-layout/src/androidTest/java/androidx/ui/layout/test/ContainerTest.kt
index c17e80a..cc62f65 100644
--- a/ui/ui-layout/src/androidTest/java/androidx/ui/layout/test/ContainerTest.kt
+++ b/ui/ui-layout/src/androidTest/java/androidx/ui/layout/test/ContainerTest.kt
@@ -17,7 +17,7 @@
package androidx.ui.layout.test
import androidx.compose.Composable
-import androidx.compose.Model
+import androidx.compose.mutableStateOf
import androidx.test.filters.SmallTest
import androidx.ui.core.Alignment
import androidx.ui.core.Layout
@@ -357,7 +357,7 @@
@Test
fun testContainer_childAffectsContainerSize() {
var layoutLatch = CountDownLatch(2)
- val model = SizeModel(10.dp)
+ val size = mutableStateOf(10.dp)
var measure = 0
var layout = 0
show {
@@ -365,7 +365,7 @@
Layout(children = {
Container {
EmptyBox(
- width = model.size,
+ width = size.value,
height = 10.dp,
modifier = Modifier.onPositioned { layoutLatch.countDown() }
)
@@ -386,7 +386,7 @@
assertEquals(1, layout)
layoutLatch = CountDownLatch(2)
- activityTestRule.runOnUiThread { model.size = 20.dp }
+ activityTestRule.runOnUiThread { size.value = 20.dp }
assertTrue(layoutLatch.await(1, TimeUnit.SECONDS))
assertEquals(2, measure)
assertEquals(2, layout)
@@ -395,7 +395,7 @@
@Test
fun testContainer_childDoesNotAffectContainerSize_whenSizeIsMax() {
var layoutLatch = CountDownLatch(2)
- val model = SizeModel(10.dp)
+ val size = mutableStateOf(10.dp)
var measure = 0
var layout = 0
show {
@@ -403,7 +403,7 @@
Layout(children = {
Container(expanded = true) {
EmptyBox(
- width = model.size,
+ width = size.value,
height = 10.dp,
modifier = Modifier.onPositioned { layoutLatch.countDown() }
)
@@ -424,7 +424,7 @@
assertEquals(1, layout)
layoutLatch = CountDownLatch(1)
- activityTestRule.runOnUiThread { model.size = 20.dp }
+ activityTestRule.runOnUiThread { size.value = 20.dp }
assertTrue(layoutLatch.await(1, TimeUnit.SECONDS))
assertEquals(1, measure)
assertEquals(1, layout)
@@ -433,7 +433,7 @@
@Test
fun testContainer_childDoesNotAffectContainerSize_whenFixedWidthAndHeight() {
var layoutLatch = CountDownLatch(2)
- val model = SizeModel(10.dp)
+ val size = mutableStateOf(10.dp)
var measure = 0
var layout = 0
show {
@@ -441,7 +441,7 @@
Layout(children = {
Container(width = 20.dp, height = 20.dp) {
EmptyBox(
- width = model.size,
+ width = size.value,
height = 10.dp,
modifier = Modifier.onPositioned { layoutLatch.countDown() }
)
@@ -462,7 +462,7 @@
assertEquals(1, layout)
layoutLatch = CountDownLatch(1)
- activityTestRule.runOnUiThread { model.size = 20.dp }
+ activityTestRule.runOnUiThread { size.value = 20.dp }
assertTrue(layoutLatch.await(1, TimeUnit.SECONDS))
assertEquals(1, measure)
assertEquals(1, layout)
@@ -478,6 +478,3 @@
}
}
}
-
-@Model
-data class SizeModel(var size: Dp)
diff --git a/ui/ui-layout/src/androidTest/java/androidx/ui/layout/test/OnPositionedTest.kt b/ui/ui-layout/src/androidTest/java/androidx/ui/layout/test/OnPositionedTest.kt
index 3bd6d1f..3c5b9ce 100644
--- a/ui/ui-layout/src/androidTest/java/androidx/ui/layout/test/OnPositionedTest.kt
+++ b/ui/ui-layout/src/androidTest/java/androidx/ui/layout/test/OnPositionedTest.kt
@@ -18,9 +18,10 @@
import android.widget.FrameLayout
import androidx.compose.Composable
-import androidx.compose.Model
import androidx.compose.Recomposer
+import androidx.compose.State
import androidx.compose.emptyContent
+import androidx.compose.mutableStateOf
import androidx.test.filters.SmallTest
import androidx.ui.core.Layout
import androidx.ui.core.LayoutCoordinates
@@ -35,6 +36,7 @@
import androidx.ui.layout.Stack
import androidx.ui.layout.fillMaxSize
import androidx.ui.layout.padding
+import androidx.ui.unit.Dp
import androidx.ui.unit.Px
import androidx.ui.unit.PxPosition
import androidx.ui.unit.dp
@@ -215,7 +217,7 @@
@Test
fun justAddedOnPositionedCallbackFiredWithoutLayoutChanges() = with(density) {
- val needCallback = NeedCallback(false)
+ val needCallback = mutableStateOf(false)
val positionedLatch = CountDownLatch(1)
show {
@@ -234,7 +236,7 @@
@Test
fun testRepositionTriggersCallback() {
- val modelLeft = SizeModel(30.dp)
+ val left = mutableStateOf(30.dp)
var realLeft: Px? = null
var positionedLatch = CountDownLatch(1)
@@ -246,7 +248,7 @@
positionedLatch.countDown()
}
.fillMaxSize()
- .padding(start = modelLeft.size),
+ .padding(start = left.value),
children = emptyContent()
)
}
@@ -254,7 +256,7 @@
assertTrue(positionedLatch.await(1, TimeUnit.SECONDS))
positionedLatch = CountDownLatch(1)
- activityTestRule.runOnUiThread { modelLeft.size = 40.dp }
+ activityTestRule.runOnUiThread { left.value = 40.dp }
assertTrue(positionedLatch.await(1, TimeUnit.SECONDS))
with(density) {
@@ -267,12 +269,12 @@
// when we reposition any parent layout is causes the change in global
// position of all the children down the tree(for example during the scrolling).
// children should be able to react on this change.
- val modelLeft = SizeModel(20.dp)
+ val left = mutableStateOf(20.dp)
var realLeft: Px? = null
var positionedLatch = CountDownLatch(1)
show {
Stack {
- Offset(modelLeft) {
+ Offset(left) {
Container(width = 10.dp, height = 10.dp) {
Container(width = 10.dp, height = 10.dp) {
Container(
@@ -292,7 +294,7 @@
assertTrue(positionedLatch.await(1, TimeUnit.SECONDS))
positionedLatch = CountDownLatch(1)
- activityTestRule.runOnUiThread { modelLeft.size = 40.dp }
+ activityTestRule.runOnUiThread { left.value = 40.dp }
assertTrue(positionedLatch.await(1, TimeUnit.SECONDS))
with(density) {
@@ -319,15 +321,12 @@
}
@Composable
- private fun Offset(sizeModel: SizeModel, children: @Composable () -> Unit) {
+ private fun Offset(sizeModel: State<Dp>, children: @Composable () -> Unit) {
// simple copy of Padding which doesn't recompose when the size changes
Layout(children) { measurables, constraints, _ ->
layout(constraints.maxWidth, constraints.maxHeight) {
- measurables.first().measure(constraints).place(sizeModel.size.toPx(), 0.px)
+ measurables.first().measure(constraints).place(sizeModel.value.toPx(), 0.px)
}
}
}
}
-
-@Model
-private data class NeedCallback(var value: Boolean)
diff --git a/ui/ui-material/api/0.1.0-dev12.txt b/ui/ui-material/api/0.1.0-dev12.txt
index 0e65efa..a580938 100644
--- a/ui/ui-material/api/0.1.0-dev12.txt
+++ b/ui/ui-material/api/0.1.0-dev12.txt
@@ -206,6 +206,8 @@
method public boolean isDrawerGesturesEnabled();
method public void setDrawerGesturesEnabled(boolean p);
method public void setDrawerState(androidx.ui.material.DrawerState p);
+ property public final androidx.ui.material.DrawerState drawerState;
+ property public final boolean isDrawerGesturesEnabled;
}
public final class Shapes {
diff --git a/ui/ui-material/api/current.txt b/ui/ui-material/api/current.txt
index 0e65efa..a580938 100644
--- a/ui/ui-material/api/current.txt
+++ b/ui/ui-material/api/current.txt
@@ -206,6 +206,8 @@
method public boolean isDrawerGesturesEnabled();
method public void setDrawerGesturesEnabled(boolean p);
method public void setDrawerState(androidx.ui.material.DrawerState p);
+ property public final androidx.ui.material.DrawerState drawerState;
+ property public final boolean isDrawerGesturesEnabled;
}
public final class Shapes {
diff --git a/ui/ui-material/api/public_plus_experimental_0.1.0-dev12.txt b/ui/ui-material/api/public_plus_experimental_0.1.0-dev12.txt
index 0e65efa..a580938 100644
--- a/ui/ui-material/api/public_plus_experimental_0.1.0-dev12.txt
+++ b/ui/ui-material/api/public_plus_experimental_0.1.0-dev12.txt
@@ -206,6 +206,8 @@
method public boolean isDrawerGesturesEnabled();
method public void setDrawerGesturesEnabled(boolean p);
method public void setDrawerState(androidx.ui.material.DrawerState p);
+ property public final androidx.ui.material.DrawerState drawerState;
+ property public final boolean isDrawerGesturesEnabled;
}
public final class Shapes {
diff --git a/ui/ui-material/api/public_plus_experimental_current.txt b/ui/ui-material/api/public_plus_experimental_current.txt
index 0e65efa..a580938 100644
--- a/ui/ui-material/api/public_plus_experimental_current.txt
+++ b/ui/ui-material/api/public_plus_experimental_current.txt
@@ -206,6 +206,8 @@
method public boolean isDrawerGesturesEnabled();
method public void setDrawerGesturesEnabled(boolean p);
method public void setDrawerState(androidx.ui.material.DrawerState p);
+ property public final androidx.ui.material.DrawerState drawerState;
+ property public final boolean isDrawerGesturesEnabled;
}
public final class Shapes {
diff --git a/ui/ui-material/api/restricted_0.1.0-dev12.txt b/ui/ui-material/api/restricted_0.1.0-dev12.txt
index 0e65efa..a580938 100644
--- a/ui/ui-material/api/restricted_0.1.0-dev12.txt
+++ b/ui/ui-material/api/restricted_0.1.0-dev12.txt
@@ -206,6 +206,8 @@
method public boolean isDrawerGesturesEnabled();
method public void setDrawerGesturesEnabled(boolean p);
method public void setDrawerState(androidx.ui.material.DrawerState p);
+ property public final androidx.ui.material.DrawerState drawerState;
+ property public final boolean isDrawerGesturesEnabled;
}
public final class Shapes {
diff --git a/ui/ui-material/api/restricted_current.txt b/ui/ui-material/api/restricted_current.txt
index 0e65efa..a580938 100644
--- a/ui/ui-material/api/restricted_current.txt
+++ b/ui/ui-material/api/restricted_current.txt
@@ -206,6 +206,8 @@
method public boolean isDrawerGesturesEnabled();
method public void setDrawerGesturesEnabled(boolean p);
method public void setDrawerState(androidx.ui.material.DrawerState p);
+ property public final androidx.ui.material.DrawerState drawerState;
+ property public final boolean isDrawerGesturesEnabled;
}
public final class Shapes {
diff --git a/ui/ui-material/integration-tests/material-demos/src/main/java/androidx/ui/material/demos/DynamicThemeActivity.kt b/ui/ui-material/integration-tests/material-demos/src/main/java/androidx/ui/material/demos/DynamicThemeActivity.kt
index 93ae9fc..414841b 100644
--- a/ui/ui-material/integration-tests/material-demos/src/main/java/androidx/ui/material/demos/DynamicThemeActivity.kt
+++ b/ui/ui-material/integration-tests/material-demos/src/main/java/androidx/ui/material/demos/DynamicThemeActivity.kt
@@ -20,7 +20,8 @@
import androidx.activity.ComponentActivity
import androidx.animation.FastOutSlowInEasing
import androidx.compose.Composable
-import androidx.compose.Model
+import androidx.compose.MutableState
+import androidx.compose.mutableStateOf
import androidx.compose.remember
import androidx.ui.core.Modifier
import androidx.ui.core.setContent
@@ -53,12 +54,12 @@
* as the user scrolls. This has the effect of going from a 'light' theme to a 'dark' theme.
*/
class DynamicThemeActivity : ComponentActivity() {
- private val scrollFraction = ScrollFraction()
+ private val scrollFraction = mutableStateOf(0f)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
- val palette = interpolateTheme(scrollFraction.fraction)
+ val palette = interpolateTheme(scrollFraction.value)
val darkenedPrimary = palette.darkenedPrimary
window.statusBarColor = darkenedPrimary
window.navigationBarColor = darkenedPrimary
@@ -79,8 +80,7 @@
}
}
-@Model
-private class ScrollFraction(var fraction: Float = 0f)
+private typealias ScrollFraction = MutableState<Float>
@Composable
private fun DynamicThemeApp(scrollFraction: ScrollFraction, palette: ColorPalette) {
@@ -88,7 +88,7 @@
val scrollerPosition = ScrollerPosition()
val fraction =
round((scrollerPosition.value / scrollerPosition.maxPosition) * 100) / 100
- remember(fraction) { scrollFraction.fraction = fraction }
+ remember(fraction) { scrollFraction.value = fraction }
Scaffold(
topAppBar = { TopAppBar({ Text("Scroll down!") }) },
bottomAppBar = { BottomAppBar(fabConfiguration = it, cutoutShape = CircleShape) {} },
@@ -109,7 +109,7 @@
@Composable
private fun Fab(scrollFraction: ScrollFraction) {
- val fabText = emojiForScrollFraction(scrollFraction.fraction)
+ val fabText = emojiForScrollFraction(scrollFraction.value)
ExtendedFloatingActionButton(
text = { Text(fabText, style = MaterialTheme.typography.h5) },
>
diff --git a/ui/ui-material/src/androidTest/java/androidx/ui/material/DrawerTest.kt b/ui/ui-material/src/androidTest/java/androidx/ui/material/DrawerTest.kt
index 0219b37..613d4e2 100644
--- a/ui/ui-material/src/androidTest/java/androidx/ui/material/DrawerTest.kt
+++ b/ui/ui-material/src/androidTest/java/androidx/ui/material/DrawerTest.kt
@@ -17,8 +17,8 @@
package androidx.ui.material
import android.os.SystemClock.sleep
-import androidx.compose.Model
import androidx.compose.emptyContent
+import androidx.compose.mutableStateOf
import androidx.test.filters.MediumTest
import androidx.ui.core.LayoutCoordinates
import androidx.ui.core.Modifier
@@ -53,9 +53,6 @@
import java.util.concurrent.TimeUnit
import kotlin.math.roundToInt
-@Model
-data class DrawerStateHolder(var state: DrawerState)
-
@MediumTest
@RunWith(JUnit4::class)
class DrawerTest {
@@ -154,11 +151,11 @@
var contentWidth: IntPx? = null
var openedLatch: CountDownLatch? = null
var closedLatch: CountDownLatch? = CountDownLatch(1)
- val drawerState = DrawerStateHolder(DrawerState.Closed)
+ val drawerState = mutableStateOf(DrawerState.Closed)
composeTestRule.setMaterialContent {
TestTag("Drawer") {
Semantics(container = true) {
- ModalDrawerLayout(drawerState.state, { drawerState.state = it },
+ ModalDrawerLayout(drawerState.value, { drawerState.value = it },
drawerContent = {
Box(
Modifier.fillMaxSize().onPositioned { info: LayoutCoordinates ->
@@ -186,7 +183,7 @@
// When the drawer state is set to Opened
openedLatch = CountDownLatch(1)
runOnIdleCompose {
- drawerState.state = DrawerState.Opened
+ drawerState.value = DrawerState.Opened
}
// Then the drawer should be opened
assertThat(openedLatch.await(5, TimeUnit.SECONDS)).isTrue()
@@ -194,7 +191,7 @@
// When the drawer state is set to Closed
closedLatch = CountDownLatch(1)
runOnIdleCompose {
- drawerState.state = DrawerState.Closed
+ drawerState.value = DrawerState.Closed
}
// Then the drawer should be closed
assertThat(closedLatch.await(5, TimeUnit.SECONDS)).isTrue()
@@ -204,12 +201,12 @@
fun modalDrawer_bodyContent_clickable() {
var drawerClicks = 0
var bodyClicks = 0
- val drawerState = DrawerStateHolder(DrawerState.Closed)
+ val drawerState = mutableStateOf(DrawerState.Closed)
composeTestRule.setMaterialContent {
// emulate click on the screen
TestTag("Drawer") {
Semantics(container = true) {
- ModalDrawerLayout(drawerState.state, { drawerState.state = it },
+ ModalDrawerLayout(drawerState.value, { drawerState.value = it },
drawerContent = {
Clickable( drawerClicks += 1 }) {
Box(Modifier.fillMaxSize(), children = emptyContent())
@@ -231,7 +228,7 @@
assertThat(drawerClicks).isEqualTo(0)
assertThat(bodyClicks).isEqualTo(1)
- drawerState.state = DrawerState.Opened
+ drawerState.value = DrawerState.Opened
}
sleep(100) // TODO(147586311): remove this sleep when opening the drawer triggers a wait
@@ -255,11 +252,11 @@
var openedHeight: IntPx? = null
var openedLatch: CountDownLatch? = null
var closedLatch: CountDownLatch? = CountDownLatch(1)
- val drawerState = DrawerStateHolder(DrawerState.Closed)
+ val drawerState = mutableStateOf(DrawerState.Closed)
composeTestRule.setMaterialContent {
TestTag("Drawer") {
Semantics(container = true) {
- BottomDrawerLayout(drawerState.state, { drawerState.state = it },
+ BottomDrawerLayout(drawerState.value, { drawerState.value = it },
drawerContent = {
Box(Modifier.fillMaxSize().onPositioned { info: LayoutCoordinates ->
val pos = info.localToGlobal(PxPosition.Origin)
@@ -288,7 +285,7 @@
// When the drawer state is set to Opened
openedLatch = CountDownLatch(1)
runOnIdleCompose {
- drawerState.state = DrawerState.Opened
+ drawerState.value = DrawerState.Opened
}
// Then the drawer should be opened
assertThat(openedLatch.await(5, TimeUnit.SECONDS)).isTrue()
@@ -296,7 +293,7 @@
// When the drawer state is set to Closed
closedLatch = CountDownLatch(1)
runOnIdleCompose {
- drawerState.state = DrawerState.Closed
+ drawerState.value = DrawerState.Closed
}
// Then the drawer should be closed
assertThat(closedLatch.await(5, TimeUnit.SECONDS)).isTrue()
@@ -306,12 +303,12 @@
fun bottomDrawer_bodyContent_clickable() {
var drawerClicks = 0
var bodyClicks = 0
- val drawerState = DrawerStateHolder(DrawerState.Closed)
+ val drawerState = mutableStateOf(DrawerState.Closed)
composeTestRule.setMaterialContent {
// emulate click on the screen
TestTag("Drawer") {
Semantics(container = true) {
- BottomDrawerLayout(drawerState.state, { drawerState.state = it },
+ BottomDrawerLayout(drawerState.value, { drawerState.value = it },
drawerContent = {
Clickable( drawerClicks += 1 }) {
Box(Modifier.fillMaxSize(), children = emptyContent())
@@ -335,7 +332,7 @@
}
runOnUiThread {
- drawerState.state = DrawerState.Opened
+ drawerState.value = DrawerState.Opened
}
sleep(100) // TODO(147586311): remove this sleep when opening the drawer triggers a wait
diff --git a/ui/ui-material/src/androidTest/java/androidx/ui/material/ProgressIndicatorTest.kt b/ui/ui-material/src/androidTest/java/androidx/ui/material/ProgressIndicatorTest.kt
index fd9ab03..9df7c78 100644
--- a/ui/ui-material/src/androidTest/java/androidx/ui/material/ProgressIndicatorTest.kt
+++ b/ui/ui-material/src/androidTest/java/androidx/ui/material/ProgressIndicatorTest.kt
@@ -15,7 +15,7 @@
*/
package androidx.ui.material
-import androidx.compose.Model
+import androidx.compose.mutableStateOf
import androidx.test.filters.LargeTest
import androidx.ui.core.TestTag
import androidx.ui.foundation.Strings
@@ -33,11 +33,6 @@
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
-@Model
-private class State {
- var progress = 0f
-}
-
@LargeTest
@RunWith(JUnit4::class)
class ProgressIndicatorTest {
@@ -51,12 +46,12 @@
@Test
fun determinateLinearProgressIndicator_Progress() {
val tag = "linear"
- val state = State()
+ val progress = mutableStateOf(0f)
composeTestRule
.setMaterialContent {
TestTag(tag = tag) {
- LinearProgressIndicator(progress = state.progress)
+ LinearProgressIndicator(progress = progress.value)
}
}
@@ -66,7 +61,7 @@
.assertRangeInfoEquals(AccessibilityRangeInfo(0f, 0f..1f))
runOnUiThread {
- state.progress = 0.5f
+ progress.value = 0.5f
}
findByTag(tag)
@@ -115,12 +110,12 @@
@Test
fun determinateCircularProgressIndicator_Progress() {
val tag = "circular"
- val state = State()
+ val progress = mutableStateOf(0f)
composeTestRule
.setMaterialContent {
TestTag(tag = tag) {
- CircularProgressIndicator(progress = state.progress)
+ CircularProgressIndicator(progress = progress.value)
}
}
@@ -130,7 +125,7 @@
.assertRangeInfoEquals(AccessibilityRangeInfo(0f, 0f..1f))
runOnUiThread {
- state.progress = 0.5f
+ progress.value = 0.5f
}
findByTag(tag)
diff --git a/ui/ui-material/src/androidTest/java/androidx/ui/material/RadioGroupUiTest.kt b/ui/ui-material/src/androidTest/java/androidx/ui/material/RadioGroupUiTest.kt
index 38f0b7d..38a7691 100644
--- a/ui/ui-material/src/androidTest/java/androidx/ui/material/RadioGroupUiTest.kt
+++ b/ui/ui-material/src/androidTest/java/androidx/ui/material/RadioGroupUiTest.kt
@@ -17,7 +17,7 @@
package androidx.ui.material
import androidx.compose.Composable
-import androidx.compose.Model
+import androidx.compose.mutableStateOf
import androidx.test.filters.MediumTest
import androidx.ui.core.TestTag
import androidx.ui.foundation.Strings
@@ -36,9 +36,6 @@
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
-@Model
-internal class RadioGroupSelectedState<T>(var selected: T)
-
@MediumTest
@RunWith(JUnit4::class)
class RadioGroupUiTest {
@@ -73,7 +70,7 @@
@Test
fun radioGroupTest_defaultSemantics() {
- val select = RadioGroupSelectedState(itemOne)
+ val selected = mutableStateOf(itemOne)
composeTestRule.setMaterialContent {
VerticalRadioGroupforTests {
@@ -81,8 +78,8 @@
TestTag(tag = item) {
RadioGroupTextItem(
text = item,
- selected = (select.selected == item),
- select.selected = item })
+ selected = (selected.value == item),
+ selected.value = item })
}
}
}
@@ -95,7 +92,7 @@
@Test
fun radioGroupTest_ensureUnselectable() {
- val select = RadioGroupSelectedState(itemOne)
+ val selected = mutableStateOf(itemOne)
composeTestRule.setMaterialContent {
VerticalRadioGroupforTests {
@@ -103,8 +100,8 @@
TestTag(tag = item) {
RadioGroupTextItem(
text = item,
- selected = (select.selected == item),
- select.selected = item })
+ selected = (selected.value == item),
+ selected.value = item })
}
}
}
@@ -124,15 +121,15 @@
@Test
fun radioGroupTest_clickSelect() {
- val select = RadioGroupSelectedState(itemOne)
+ val selected = mutableStateOf(itemOne)
composeTestRule.setMaterialContent {
VerticalRadioGroupforTests {
options.forEach { item ->
TestTag(tag = item) {
RadioGroupTextItem(
text = item,
- selected = (select.selected == item),
- select.selected = item })
+ selected = (selected.value == item),
+ selected.value = item })
}
}
}
@@ -151,7 +148,7 @@
@Test
fun radioGroupTest_clickSelectTwoDifferentItems() {
- val select = RadioGroupSelectedState(itemOne)
+ val selected = mutableStateOf(itemOne)
composeTestRule.setMaterialContent {
VerticalRadioGroupforTests {
@@ -159,8 +156,8 @@
TestTag(tag = item) {
RadioGroupTextItem(
text = item,
- selected = (select.selected == item),
- select.selected = item })
+ selected = (selected.value == item),
+ selected.value = item })
}
}
}
diff --git a/ui/ui-material/src/main/java/androidx/ui/material/Color.kt b/ui/ui-material/src/main/java/androidx/ui/material/Color.kt
index 7ccf65b..eae3e7c 100644
--- a/ui/ui-material/src/main/java/androidx/ui/material/Color.kt
+++ b/ui/ui-material/src/main/java/androidx/ui/material/Color.kt
@@ -219,7 +219,7 @@
* components that consume the specific color(s) that have been changed - so this default
* implementation is intended to be memoized in the ambient, and then when a new immutable
* [ColorPalette] is provided, we can simply diff and update any values that need to be changed.
- * Because the internal values are provided by an @Model delegate class, components consuming the
+ * Because the internal values are provided by an State delegate class, components consuming the
* specific color will be recomposed, while everything else will remain the same. This allows for
* large performance improvements when the theme is being changed, especially if it is being
* animated.
diff --git a/ui/ui-material/src/main/java/androidx/ui/material/Scaffold.kt b/ui/ui-material/src/main/java/androidx/ui/material/Scaffold.kt
index 1c24800..954f11e 100644
--- a/ui/ui-material/src/main/java/androidx/ui/material/Scaffold.kt
+++ b/ui/ui-material/src/main/java/androidx/ui/material/Scaffold.kt
@@ -17,9 +17,12 @@
package androidx.ui.material
import androidx.compose.Composable
-import androidx.compose.Model
+import androidx.compose.Stable
+import androidx.compose.getValue
+import androidx.compose.mutableStateOf
import androidx.compose.onDispose
import androidx.compose.remember
+import androidx.compose.setValue
import androidx.ui.core.Alignment
import androidx.ui.core.DensityAmbient
import androidx.ui.core.Layout
@@ -48,16 +51,18 @@
* programmatically.
* @param isDrawerGesturesEnabled whether or not drawer can be interacted with via gestures
*/
-@Model
+@Stable
class ScaffoldState(
- var drawerState: DrawerState = DrawerState.Closed,
- var isDrawerGesturesEnabled: Boolean = true
+ drawerState: DrawerState = DrawerState.Closed,
+ isDrawerGesturesEnabled: Boolean = true
) {
+ var drawerState by mutableStateOf(drawerState)
+ var isDrawerGesturesEnabled by mutableStateOf(isDrawerGesturesEnabled)
// TODO: add showSnackbar() method here
- internal var fabConfiguration: FabConfiguration? = null
- internal var bottomBarSize: IntPxSize? = null
+ internal var fabConfiguration: FabConfiguration? by mutableStateOf<FabConfiguration?>(null)
+ internal var bottomBarSize: IntPxSize? by mutableStateOf<IntPxSize?>(null)
}
object Scaffold {
diff --git a/ui/ui-test/src/androidTest/java/androidx/ui/test/AndroidComposeTestCaseRunnerTest.kt b/ui/ui-test/src/androidTest/java/androidx/ui/test/AndroidComposeTestCaseRunnerTest.kt
index f1c2749..e2c813a 100644
--- a/ui/ui-test/src/androidTest/java/androidx/ui/test/AndroidComposeTestCaseRunnerTest.kt
+++ b/ui/ui-test/src/androidTest/java/androidx/ui/test/AndroidComposeTestCaseRunnerTest.kt
@@ -16,7 +16,7 @@
package androidx.ui.test
-import androidx.compose.Model
+import androidx.compose.mutableStateOf
import androidx.compose.onPreCommit
import androidx.compose.state
import androidx.test.filters.SmallTest
@@ -27,11 +27,6 @@
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
-@Model
-private class TestModel {
- var i = 0
-}
-
@SmallTest
@RunWith(JUnit4::class)
class AndroidComposeTestCaseRunnerTest {
@@ -43,10 +38,10 @@
@Test
fun foreverRecomposing_viaModel_shouldFail() {
- val model = TestModel()
+ val count = mutableStateOf(0)
composeTestRule.forGivenContent {
- Text("Hello ${model.i}")
- model.i++
+ Text("Hello ${count.value}")
+ count.value++
}.performTestWithEventsControl {
assertFailsWith<AssertionError>(
"Changes are still pending after '10' frames.") {
@@ -132,11 +127,11 @@
@Test
fun recomposeTwice2() {
- val model = TestModel()
+ val count = mutableStateOf(0)
composeTestRule.forGivenContent {
- Text("Hello ${model.i}")
- if (model.i < 2) {
- model.i++
+ Text("Hello ${count.value}")
+ if (count.value < 2) {
+ count.value++
}
}.performTestWithEventsControl {
doFramesAssertAllHadChangesExceptLastOne(2)
diff --git a/ui/ui-test/src/androidTest/java/androidx/ui/test/MultipleComposeRootsTest.kt b/ui/ui-test/src/androidTest/java/androidx/ui/test/MultipleComposeRootsTest.kt
index b21b853..7c084ca 100644
--- a/ui/ui-test/src/androidTest/java/androidx/ui/test/MultipleComposeRootsTest.kt
+++ b/ui/ui-test/src/androidTest/java/androidx/ui/test/MultipleComposeRootsTest.kt
@@ -20,8 +20,9 @@
import android.widget.LinearLayout
import android.widget.TextView
import androidx.activity.ComponentActivity
-import androidx.compose.Model
+import androidx.compose.MutableState
import androidx.compose.Recomposer
+import androidx.compose.mutableStateOf
import androidx.test.espresso.Espresso
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
@@ -39,17 +40,13 @@
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
-// TODO: Make this inner class once @Model gets fixed.
-@Model
-class CheckboxState(var value: ToggleableState = ToggleableState.Off) {
- fun toggle() {
- value =
- if (value == ToggleableState.On) {
- ToggleableState.Off
- } else {
- ToggleableState.On
- }
- }
+fun MutableState<ToggleableState>.toggle() {
+ value =
+ if (value == ToggleableState.On) {
+ ToggleableState.Off
+ } else {
+ ToggleableState.On
+ }
}
/**
@@ -85,8 +82,8 @@
activity.runOnUiThread(object : Runnable { // Workaround for lambda bug in IR
override fun run() {
- val state1 = CheckboxState(value = ToggleableState.Off)
- val state2 = CheckboxState(value = ToggleableState.On)
+ val state1 = mutableStateOf(value = ToggleableState.Off)
+ val state2 = mutableStateOf(value = ToggleableState.On)
val linearLayout = LinearLayout(activity)
.apply { orientation = LinearLayout.VERTICAL }
diff --git a/ui/ui-text/src/main/java/androidx/ui/text/CoreText.kt b/ui/ui-text/src/main/java/androidx/ui/text/CoreText.kt
index 961c9a2..e16d170f 100644
--- a/ui/ui-text/src/main/java/androidx/ui/text/CoreText.kt
+++ b/ui/ui-text/src/main/java/androidx/ui/text/CoreText.kt
@@ -242,7 +242,7 @@
/**
* The current selection range, used by selection.
* This should be a state as every time we update the value during the selection we
- * need to redraw it. @Model observation during onDraw callback will make it work.
+ * need to redraw it. state observation during onDraw callback will make it work.
*/
var selectionRange by mutableStateOf<TextRange?>(null, StructurallyEqual)
/** The last layout coordinates for the Text's layout, used by selection */
diff --git a/ui/ui-text/src/main/java/androidx/ui/text/CoreTextField.kt b/ui/ui-text/src/main/java/androidx/ui/text/CoreTextField.kt
index c6f613c..1f89449 100644
--- a/ui/ui-text/src/main/java/androidx/ui/text/CoreTextField.kt
+++ b/ui/ui-text/src/main/java/androidx/ui/text/CoreTextField.kt
@@ -251,7 +251,7 @@
var inputSession = NO_SESSION
/**
* This should be a state as every time we update the value we need to redraw it.
- * @Model observation during onDraw callback will make it work.
+ * state observation during onDraw callback will make it work.
*/
var hasFocus by mutableStateOf(false)
/** The last layout coordinates for the Text's layout, used by selection */