Refactor Ambient.Reference to be CompositionReference
Also removes Ambient.Portal in favor of compositionReference effect
Change-Id: I5f3540bda7d8fe72f76579094ab895d8dd042194
diff --git a/compose/plugins/cli-tests/src/test/java/org/jetbrains/kotlin/r4a/KtxCodegenTests.kt b/compose/plugins/cli-tests/src/test/java/org/jetbrains/kotlin/r4a/KtxCodegenTests.kt
index fa69e1c..3749294 100644
--- a/compose/plugins/cli-tests/src/test/java/org/jetbrains/kotlin/r4a/KtxCodegenTests.kt
+++ b/compose/plugins/cli-tests/src/test/java/org/jetbrains/kotlin/r4a/KtxCodegenTests.kt
@@ -488,25 +488,18 @@
val tvId = 345
var text = "Hello, world!"
- // NOTE(lmr): The fact that "bust" is needed here is actually an issue with the fact that
- // changes to providers don't invalidate consumers from other composers via Ambient.Portal.
- // When that gets fixed, we should update this test to show that.
compose(
"""
val StringAmbient = Ambient.of<String> { "default" }
- fun buildPortal() = effectOf<Ambient.Reference> {
- context.buildReference()
- }
-
@Composable fun App(value: String) {
<StringAmbient.Provider value>
- <Parent bust=Math.random() />
+ <Parent />
</StringAmbient.Provider>
}
- @Composable fun Parent(bust: Double) {
- val ambientRef = +buildPortal()
+ @Composable fun Parent() {
+ val compositionRef = +compositionReference()
val viewRef = +memo { Ref<LinearLayout>() }
<LinearLayout id=$llId ref=viewRef />
@@ -514,14 +507,14 @@
+onCommit {
R4a.composeInto(
container = viewRef.value ?: error("No View Ref!"),
- parent = ambientRef
+ parent = compositionRef
) {
- <Child bust=Math.random() />
+ <Child />
}
}
}
- @Composable fun Child(bust: Double) {
+ @Composable fun Child() {
<StringAmbient.Consumer> value ->
<TextView id=$tvId text=value />
</StringAmbient.Consumer>
@@ -554,37 +547,33 @@
val tvId = 345
var text = "Hello, world!"
- // NOTE(lmr): The fact that "bust" is needed here is actually an issue with the fact that
- // changes to providers don't invalidate consumers from other composers via Ambient.Portal.
- // When that gets fixed, we should update this test to show that.
compose(
"""
val StringAmbient = Ambient.of<String> { "default" }
@Composable fun App(value: String) {
<StringAmbient.Provider value>
- <Parent bust=Math.random() />
+ <Parent />
</StringAmbient.Provider>
}
- @Composable fun Parent(bust: Double) {
- <Ambient.Portal> ambientRef ->
- val viewRef = +memo { Ref<LinearLayout>() }
+ @Composable fun Parent() {
+ val compositionRef = +compositionReference()
+ val viewRef = +memo { Ref<LinearLayout>() }
- <LinearLayout id=$llId ref=viewRef />
+ <LinearLayout id=$llId ref=viewRef />
- +onCommit {
- R4a.composeInto(
- container = viewRef.value ?: error("No View Ref!"),
- parent = ambientRef
- ) {
- <Child bust=Math.random() />
- }
+ +onCommit {
+ R4a.composeInto(
+ container = viewRef.value ?: error("No View Ref!"),
+ parent = compositionRef
+ ) {
+ <Child />
}
- </Ambient.Portal>
+ }
}
- @Composable fun Child(bust: Double) {
+ @Composable fun Child() {
<StringAmbient.Consumer> value ->
<TextView id=$tvId text=value />
</StringAmbient.Consumer>
@@ -681,10 +670,6 @@
compose(
"""
- fun buildPortal() = effectOf<Ambient.Reference> {
- context.buildReference()
- }
-
fun <T> refFor() = memo { Ref<T>() }
val textAmbient = Ambient.of { "default" }
@@ -695,7 +680,7 @@
}
@Composable fun PortalTest() {
- val portal = +buildPortal()
+ val portal = +compositionReference()
val ref = +refFor<LinearLayout>()
<DisplayTest id=$outerId />
diff --git a/compose/r4a-runtime/testData/projects/ExplorerApp/common/src/main/java/com/google/r4a/examples/explorerapp/common/adapters/ComposeFragment.kt b/compose/r4a-runtime/testData/projects/ExplorerApp/common/src/main/java/com/google/r4a/examples/explorerapp/common/adapters/ComposeFragment.kt
index 18b9348..863fc7c 100644
--- a/compose/r4a-runtime/testData/projects/ExplorerApp/common/src/main/java/com/google/r4a/examples/explorerapp/common/adapters/ComposeFragment.kt
+++ b/compose/r4a-runtime/testData/projects/ExplorerApp/common/src/main/java/com/google/r4a/examples/explorerapp/common/adapters/ComposeFragment.kt
@@ -13,7 +13,7 @@
* A fragment that uses a Component as it's UI.
*/
abstract class ComposeFragment : Fragment() {
- var reference: Ambient.Reference? = null
+ var reference: CompositionReference? = null
abstract fun compose()
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
diff --git a/compose/r4a-runtime/testData/projects/ExplorerApp/common/src/main/java/com/google/r4a/examples/explorerapp/common/adapters/ComposePagerAdapter.kt b/compose/r4a-runtime/testData/projects/ExplorerApp/common/src/main/java/com/google/r4a/examples/explorerapp/common/adapters/ComposePagerAdapter.kt
index bf4704c..3e81ef3 100644
--- a/compose/r4a-runtime/testData/projects/ExplorerApp/common/src/main/java/com/google/r4a/examples/explorerapp/common/adapters/ComposePagerAdapter.kt
+++ b/compose/r4a-runtime/testData/projects/ExplorerApp/common/src/main/java/com/google/r4a/examples/explorerapp/common/adapters/ComposePagerAdapter.kt
@@ -31,7 +31,7 @@
private val instantiated = SparseArray<FrameLayout>()
- var reference: Ambient.Reference? = null
+ var reference: CompositionReference? = null
abstract fun composeItem(position: Int)
fun recomposeAll() {
@@ -90,7 +90,7 @@
var children: (Int) -> Unit = {}
var getCount: () -> Int = { 0 }
var getPageTitle: (Int) -> CharSequence? = { null }
- var reference: Ambient.Reference? = null
+ var reference: CompositionReference? = null
var offscreenPageLimit: Int = 1
lateinit var layoutParams: ViewGroup.LayoutParams
@@ -112,14 +112,13 @@
// TODO(lmr): I think we realistically should call myAdapter.notifyDatasetChanged() here or in a
// componentDidUpdate() like lifecycle
with(composer) {
- portal(0) { ref ->
- myAdapter.reference = ref
- emitView(0, ::ViewPager) {
- set(R.id.view_pager_id) { id = it }
- set(myAdapter) { adapter = it }
- set(refToForward) { this.setRef(it) }
- set(offscreenPageLimit) { setOffscreenPageLimit(it) }
- }
+ val ref = +compositionReference()
+ myAdapter.reference = ref
+ emitView(0, ::ViewPager) {
+ set(R.id.view_pager_id) { id = it }
+ set(myAdapter) { adapter = it }
+ set(refToForward) { this.setRef(it) }
+ set(offscreenPageLimit) { setOffscreenPageLimit(it) }
}
}
myAdapter.recomposeAll()
@@ -182,16 +181,15 @@
set(tabRef) { setRef(it) }
}
}, { composeTab ->
- portal(0) { ambients ->
- emitComponent(0, ::ComposeViewPager) { f ->
- set(pagerLayoutParams) { f.layoutParams = it } or
- set(ambients) { f.reference = it } or
- set(composeTab) { f.children = it } or
- set({ titles.size }) { f.getCount = it } or
- set({ position: Int -> titles[position] }) { f.getPageTitle = it } or
- set(pagerRef) { f.ref = it } or
- set(offscreenPageLimit) { offscreenPageLimit = it }
- }
+ val ambients = +compositionReference()
+ emitComponent(0, ::ComposeViewPager) { f ->
+ set(pagerLayoutParams) { f.layoutParams = it } or
+ set(ambients) { f.reference = it } or
+ set(composeTab) { f.children = it } or
+ set({ titles.size }) { f.getCount = it } or
+ set({ position: Int -> titles[position] }) { f.getPageTitle = it } or
+ set(pagerRef) { f.ref = it } or
+ set(offscreenPageLimit) { offscreenPageLimit = it }
}
})
}
diff --git a/compose/r4a-runtime/testData/projects/ExplorerApp/common/src/main/java/com/google/r4a/examples/explorerapp/common/adapters/CompositionContextExtensions.kt b/compose/r4a-runtime/testData/projects/ExplorerApp/common/src/main/java/com/google/r4a/examples/explorerapp/common/adapters/CompositionContextExtensions.kt
index ba7b2b1..361bd89 100644
--- a/compose/r4a-runtime/testData/projects/ExplorerApp/common/src/main/java/com/google/r4a/examples/explorerapp/common/adapters/CompositionContextExtensions.kt
+++ b/compose/r4a-runtime/testData/projects/ExplorerApp/common/src/main/java/com/google/r4a/examples/explorerapp/common/adapters/CompositionContextExtensions.kt
@@ -92,11 +92,4 @@
// set(el, children) { this.children = it }
// compose()
// end()
-//}
-//
-//
-//fun CompositionContext.portal(children: (Ambient.Reference) -> Unit) {
-// emitComponent({ Ambient.Portal() }) {
-// set(it, children) { this.children = it }
-// }
//}
\ No newline at end of file
diff --git a/compose/r4a-runtime/testData/projects/ExplorerApp/common/src/main/java/com/google/r4a/examples/explorerapp/common/adapters/FragmentView.kt b/compose/r4a-runtime/testData/projects/ExplorerApp/common/src/main/java/com/google/r4a/examples/explorerapp/common/adapters/FragmentView.kt
index 2102b4f..678415f 100644
--- a/compose/r4a-runtime/testData/projects/ExplorerApp/common/src/main/java/com/google/r4a/examples/explorerapp/common/adapters/FragmentView.kt
+++ b/compose/r4a-runtime/testData/projects/ExplorerApp/common/src/main/java/com/google/r4a/examples/explorerapp/common/adapters/FragmentView.kt
@@ -13,11 +13,10 @@
with(composer) {
// NOTE(lmr): if we use R4aContext as ambient reference we can probably get rid of this component
// entirely
- portal(0) { ref ->
- emitView(0, { FragmentView(it, construct, id, ref) }) {
- set(layoutParams) { this.layoutParams = it }
- set(id) { this.id = it }
- }
+ val ref = +compositionReference()
+ emitView(0, { FragmentView(it, construct, id, ref) }) {
+ set(layoutParams) { this.layoutParams = it }
+ set(id) { this.id = it }
}
}
}
@@ -26,7 +25,7 @@
context: Context,
construct: () -> Fragment,
thisId: Int,
- reference: Ambient.Reference?
+ reference: CompositionReference?
) : FrameLayout(context) {
private var fragmentManager = CompositionContext.current.getAmbient(Ambients.FragmentManager)
init {
@@ -46,15 +45,15 @@
}
-internal fun View.setAmbientReference(ref: Ambient.Reference) {
+internal fun View.setAmbientReference(ref: CompositionReference) {
setTag(R.id.ambient_reference_tag_key, ref)
}
-internal fun View.findAmbientReference(): Ambient.Reference? {
+internal fun View.findAmbientReference(): CompositionReference? {
var node: View? = this
while (node != null) {
- val value = node.getTag(R.id.ambient_reference_tag_key) as? Ambient.Reference
+ val value = node.getTag(R.id.ambient_reference_tag_key) as? CompositionReference
if (value != null) return value
node = node.parent as? View
}
diff --git a/compose/r4a-runtime/testData/projects/ExplorerApp/common/src/main/java/com/google/r4a/examples/explorerapp/common/adapters/MyNavHostFragment.kt b/compose/r4a-runtime/testData/projects/ExplorerApp/common/src/main/java/com/google/r4a/examples/explorerapp/common/adapters/MyNavHostFragment.kt
index cce5a86..1959622 100644
--- a/compose/r4a-runtime/testData/projects/ExplorerApp/common/src/main/java/com/google/r4a/examples/explorerapp/common/adapters/MyNavHostFragment.kt
+++ b/compose/r4a-runtime/testData/projects/ExplorerApp/common/src/main/java/com/google/r4a/examples/explorerapp/common/adapters/MyNavHostFragment.kt
@@ -44,7 +44,7 @@
class MyNavHostFragment : Fragment(), NavHost {
var controller: NavController? = null
- var reference: Ambient.Reference? = null
+ var reference: CompositionReference? = null
// State that will be saved and restored
private var mDefaultNavHost: Boolean = false
diff --git a/compose/r4a-runtime/testData/projects/ExplorerApp/common/src/main/java/com/google/r4a/examples/explorerapp/common/components/HeaderFooterListAdapter.kt b/compose/r4a-runtime/testData/projects/ExplorerApp/common/src/main/java/com/google/r4a/examples/explorerapp/common/components/HeaderFooterListAdapter.kt
index 43a17b9..45d8218 100644
--- a/compose/r4a-runtime/testData/projects/ExplorerApp/common/src/main/java/com/google/r4a/examples/explorerapp/common/components/HeaderFooterListAdapter.kt
+++ b/compose/r4a-runtime/testData/projects/ExplorerApp/common/src/main/java/com/google/r4a/examples/explorerapp/common/components/HeaderFooterListAdapter.kt
@@ -63,7 +63,7 @@
// TODO(lmr): we end up requiring a reference here, but if we move to an Ambient via Context model, we
// might be able to get rid of it.
- lateinit var reference: Ambient.Reference
+ lateinit var reference: CompositionReference
var headerCount: Int = 0
set(value) {
diff --git a/compose/r4a-runtime/testData/projects/ExplorerApp/common/src/main/java/com/google/r4a/examples/explorerapp/common/components/HeaderFooterPagedListAdapter.kt b/compose/r4a-runtime/testData/projects/ExplorerApp/common/src/main/java/com/google/r4a/examples/explorerapp/common/components/HeaderFooterPagedListAdapter.kt
index 89c15b9..27d87a3 100644
--- a/compose/r4a-runtime/testData/projects/ExplorerApp/common/src/main/java/com/google/r4a/examples/explorerapp/common/components/HeaderFooterPagedListAdapter.kt
+++ b/compose/r4a-runtime/testData/projects/ExplorerApp/common/src/main/java/com/google/r4a/examples/explorerapp/common/components/HeaderFooterPagedListAdapter.kt
@@ -49,7 +49,7 @@
const val TYPE_FOOTER = 3
}
- lateinit var reference: Ambient.Reference
+ lateinit var reference: CompositionReference
var headerCount: Int = 0
set(value) {
diff --git a/compose/r4a-runtime/testData/projects/ExplorerApp/common/src/main/java/com/google/r4a/examples/explorerapp/common/components/HomogeneousList.kt b/compose/r4a-runtime/testData/projects/ExplorerApp/common/src/main/java/com/google/r4a/examples/explorerapp/common/components/HomogeneousList.kt
index ceb1ec9..4aed803 100644
--- a/compose/r4a-runtime/testData/projects/ExplorerApp/common/src/main/java/com/google/r4a/examples/explorerapp/common/components/HomogeneousList.kt
+++ b/compose/r4a-runtime/testData/projects/ExplorerApp/common/src/main/java/com/google/r4a/examples/explorerapp/common/components/HomogeneousList.kt
@@ -83,28 +83,27 @@
@Composable
operator fun invoke() {
with(composer) {
- portal(0) { ref ->
- adapter.reference = ref
- // NOTE(lmr): Realistically, we should call notifyDataSetChanged() on every compose. Otherwise, there
- // may be updates that some of the items of the recycler view. This ideally should be cheap if things
- // are working correctly, as it will essentially call "recompose()" on only the items that are in the
- // window which is what we want.
- adapter.notifyItemRangeChanged(0, adapter.itemCount)
- emitView(0, ::RecyclerView) {
- set(adapter) { adapter = it }
- set(layoutManager) { layoutManager = it }
- set(paddingTop) { setPaddingTop(it) }
- val layoutParams = layoutParams
- if (layoutParams != null) {
- set(layoutParams) { this.layoutParams = it }
- }
- // TODO(lmr): this is problematic with making components composable. I think this
- // goes away if we make this a View instead of a Component, but handling this differently
- // is something to consider.
- val backgroundColor = backgroundColor
- if (backgroundColor != null) {
- set(backgroundColor) { this.setBackgroundColor(it) }
- }
+ val ref = +compositionReference()
+ adapter.reference = ref
+ // NOTE(lmr): Realistically, we should call notifyDataSetChanged() on every compose. Otherwise, there
+ // may be updates that some of the items of the recycler view. This ideally should be cheap if things
+ // are working correctly, as it will essentially call "recompose()" on only the items that are in the
+ // window which is what we want.
+ adapter.notifyItemRangeChanged(0, adapter.itemCount)
+ emitView(0, ::RecyclerView) {
+ set(adapter) { adapter = it }
+ set(layoutManager) { layoutManager = it }
+ set(paddingTop) { setPaddingTop(it) }
+ val layoutParams = layoutParams
+ if (layoutParams != null) {
+ set(layoutParams) { this.layoutParams = it }
+ }
+ // TODO(lmr): this is problematic with making components composable. I think this
+ // goes away if we make this a View instead of a Component, but handling this differently
+ // is something to consider.
+ val backgroundColor = backgroundColor
+ if (backgroundColor != null) {
+ set(backgroundColor) { this.setBackgroundColor(it) }
}
}
}
diff --git a/compose/r4a-runtime/testData/projects/ExplorerApp/common/src/main/java/com/google/r4a/examples/explorerapp/common/components/HomogeneousPagedList.kt b/compose/r4a-runtime/testData/projects/ExplorerApp/common/src/main/java/com/google/r4a/examples/explorerapp/common/components/HomogeneousPagedList.kt
index 9305fca..77c2ee2 100644
--- a/compose/r4a-runtime/testData/projects/ExplorerApp/common/src/main/java/com/google/r4a/examples/explorerapp/common/components/HomogeneousPagedList.kt
+++ b/compose/r4a-runtime/testData/projects/ExplorerApp/common/src/main/java/com/google/r4a/examples/explorerapp/common/components/HomogeneousPagedList.kt
@@ -81,22 +81,21 @@
@Composable
operator fun invoke() {
with(composer) {
- portal(0) { ref ->
- adapter.reference = ref
- emitView(0, ::RecyclerView) {
- set(true) { isNestedScrollingEnabled = it }
- set(adapter) { adapter = it }
- set(layoutManager) { layoutManager = it }
- set(paddingTop) { setPaddingTop(it) }
+ val ref = +compositionReference()
+ adapter.reference = ref
+ emitView(0, ::RecyclerView) {
+ set(true) { isNestedScrollingEnabled = it }
+ set(adapter) { adapter = it }
+ set(layoutManager) { layoutManager = it }
+ set(paddingTop) { setPaddingTop(it) }
// set(it, true) { setHasFixedSize(it) }
- val layoutParams = layoutParams
- if (layoutParams != null) {
- set(layoutParams) { this.layoutParams = it }
- }
- val backgroundColor = backgroundColor
- if (backgroundColor != null) {
- set(backgroundColor) { this.setBackgroundColor(it) }
- }
+ val layoutParams = layoutParams
+ if (layoutParams != null) {
+ set(layoutParams) { this.layoutParams = it }
+ }
+ val backgroundColor = backgroundColor
+ if (backgroundColor != null) {
+ set(backgroundColor) { this.setBackgroundColor(it) }
}
}
}
diff --git a/compose/runtime/src/main/java/com/google/r4a/Ambient.kt b/compose/runtime/src/main/java/com/google/r4a/Ambient.kt
index e32018c..9b2deb0 100644
--- a/compose/runtime/src/main/java/com/google/r4a/Ambient.kt
+++ b/compose/runtime/src/main/java/com/google/r4a/Ambient.kt
@@ -50,21 +50,4 @@
val ambient = this@Ambient
}
-
- interface Reference {
- fun <T> getAmbient(key: Ambient<T>): T
- fun invalidate()
- fun <T> invalidateConsumers(key: Ambient<T>)
- fun <N> registerComposer(composer: Composer<N>)
- }
-
- class Portal(
- @Children
- var children: (ref: Reference) -> Unit
- ) : Component() {
-
- override fun compose() {
- children(composer.composer.buildReference())
- }
- }
}
diff --git a/compose/runtime/src/main/java/com/google/r4a/Composer.kt b/compose/runtime/src/main/java/com/google/r4a/Composer.kt
index f4efacf..b7ea62d 100644
--- a/compose/runtime/src/main/java/com/google/r4a/Composer.kt
+++ b/compose/runtime/src/main/java/com/google/r4a/Composer.kt
@@ -190,7 +190,7 @@
private val insertedParents = Stack<Recomposable>()
private val insertedProviders = Stack<Ambient<*>.Provider>()
private val invalidateStack = Stack<RecomposeScope>()
- internal var ambientReference: Ambient.Reference? = null
+ internal var ambientReference: CompositionReference? = null
// Temporary to allow staged changes. This will move into a sub-object that represents an active
// composition created by startRoot() and recomposeComponentRange()
@@ -454,14 +454,13 @@
}
/**
- * Create or use a memoized `Ambient.Reference` instance at this position in the slot table.
- * Used to implement Ambient.Portal.
+ * Create or use a memoized `CompositionReference` instance at this position in the slot table.
*/
- fun buildReference(): Ambient.Reference {
+ fun buildReference(): CompositionReference {
startGroup(reference)
// NOTE(lmr): VERY important to call nextValue() here instead of nextSlot()
- var ref = nextValue() as? Ambient.Reference
+ var ref = nextValue() as? CompositionReference
if (ref != null && !inserting) {
skipValue()
} else {
@@ -581,7 +580,7 @@
sentinel === reference -> {
val element = slots.get(index + 1)
if (element is CompositionLifecycleObserverHolder) {
- val subElement = element.instance as Ambient.Reference
+ val subElement = element.instance as CompositionReference
subElement.invalidateConsumers(key)
}
}
@@ -1222,7 +1221,7 @@
}
}
- private inner class AmbientReferenceImpl(val scope: RecomposeScope) : Ambient.Reference,
+ private inner class AmbientReferenceImpl(val scope: RecomposeScope) : CompositionReference,
CompositionLifecycleObserver {
val composers = mutableSetOf<Composer<*>>()
diff --git a/compose/runtime/src/main/java/com/google/r4a/ComposerCompositionContext.kt b/compose/runtime/src/main/java/com/google/r4a/ComposerCompositionContext.kt
index d8e8889..1fce9a5 100644
--- a/compose/runtime/src/main/java/com/google/r4a/ComposerCompositionContext.kt
+++ b/compose/runtime/src/main/java/com/google/r4a/ComposerCompositionContext.kt
@@ -8,20 +8,20 @@
private val rootComponent: Component
) : CompositionContext(), Recomposer {
companion object {
- val factory: Function4<Context, Any, Component, Ambient.Reference?, CompositionContext>
+ val factory: Function4<Context, Any, Component, CompositionReference?, CompositionContext>
by lazy {
object : Function4<
Context,
Any,
Component,
- Ambient.Reference?,
+ CompositionReference?,
CompositionContext
> {
override fun invoke(
context: Context,
root: Any,
component: Component,
- ambientReference: Ambient.Reference?
+ ambientReference: CompositionReference?
): CompositionContext {
val result = ComposerCompositionContext(root, component)
result.context = context
diff --git a/compose/runtime/src/main/java/com/google/r4a/CompositionContext.kt b/compose/runtime/src/main/java/com/google/r4a/CompositionContext.kt
index 0a5f1d9..3082475 100644
--- a/compose/runtime/src/main/java/com/google/r4a/CompositionContext.kt
+++ b/compose/runtime/src/main/java/com/google/r4a/CompositionContext.kt
@@ -12,7 +12,7 @@
private val EMITTABLE_ROOT_COMPONENT = WeakHashMap<Emittable, Component>()
private val COMPONENTS_TO_CONTEXT = WeakHashMap<Component, CompositionContext>()
- val factory: Function4<Context, Any, Component, Ambient.Reference?, CompositionContext>
+ val factory: Function4<Context, Any, Component, CompositionReference?, CompositionContext>
get() = ComposerCompositionContext.factory
var current: CompositionContext = EmptyCompositionContext()
@@ -21,7 +21,7 @@
context: Context,
group: Any,
component: Component,
- reference: Ambient.Reference?
+ reference: CompositionReference?
): CompositionContext {
val cc = factory(context, group, component, reference)
when (group) {
@@ -63,14 +63,14 @@
fun disposeComposition(
container: ViewGroup,
- @Suppress("UNUSED_PARAMETER") parent: Ambient.Reference? = null
+ @Suppress("UNUSED_PARAMETER") parent: CompositionReference? = null
) {
container.setTag(TAG_ROOT_COMPONENT, null)
}
fun disposeComposition(
container: Emittable,
- @Suppress("UNUSED_PARAMETER") parent: Ambient.Reference? = null
+ @Suppress("UNUSED_PARAMETER") parent: CompositionReference? = null
) {
// TODO(lmr): clear the ambient reference?
EMITTABLE_ROOT_COMPONENT.remove(container)
@@ -231,13 +231,3 @@
{ key.Consumer(children) },
{ consumer -> update(children) { consumer.children = it } }
)
-
-@Suppress("NOTHING_TO_INLINE")
-inline fun ViewComposition.portal(
- location: Int,
- noinline children: @Composable() (Ambient.Reference) -> Unit
-) = emitComponent(
- location,
- { Ambient.Portal(children) },
- { portal -> update(children) { portal.children = it } }
-)
diff --git a/compose/runtime/src/main/java/com/google/r4a/CompositionReference.kt b/compose/runtime/src/main/java/com/google/r4a/CompositionReference.kt
new file mode 100644
index 0000000..a8b5b84
--- /dev/null
+++ b/compose/runtime/src/main/java/com/google/r4a/CompositionReference.kt
@@ -0,0 +1,24 @@
+/*
+ * 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 com.google.r4a
+
+interface CompositionReference {
+ fun <T> getAmbient(key: Ambient<T>): T
+ fun invalidate()
+ fun <T> invalidateConsumers(key: Ambient<T>)
+ fun <N> registerComposer(composer: Composer<N>)
+}
\ No newline at end of file
diff --git a/compose/runtime/src/main/java/com/google/r4a/Effects.kt b/compose/runtime/src/main/java/com/google/r4a/Effects.kt
index 2f5bbaa..e741978 100644
--- a/compose/runtime/src/main/java/com/google/r4a/Effects.kt
+++ b/compose/runtime/src/main/java/com/google/r4a/Effects.kt
@@ -702,6 +702,15 @@
}
/**
+ * An Effect to construct a CompositionReference at the current point of composition. This can be used
+ * to run a separate composition in the context of the current one, preserving ambients and propagating
+ * invalidations.
+ */
+fun compositionReference() = effectOf<CompositionReference> {
+ context.buildReference()
+}
+
+/**
* IMPORTANT:
* This global operator is TEMPORARY, and should be removed whenever an answer for contextual composers is reached. At that time, the
* unaryPlus operator on the composer itself is the one that should be used.
diff --git a/compose/runtime/src/main/java/com/google/r4a/R4a.kt b/compose/runtime/src/main/java/com/google/r4a/R4a.kt
index f8d284a..bde9291 100644
--- a/compose/runtime/src/main/java/com/google/r4a/R4a.kt
+++ b/compose/runtime/src/main/java/com/google/r4a/R4a.kt
@@ -20,7 +20,7 @@
fun composeInto(
container: ViewGroup,
- parent: Ambient.Reference? = null,
+ parent: CompositionReference? = null,
composable: @Composable() () -> Unit
) {
var root = CompositionContext.getRootComponent(container) as? Root
@@ -36,7 +36,7 @@
}
}
- fun disposeComposition(container: ViewGroup, parent: Ambient.Reference? = null) {
+ fun disposeComposition(container: ViewGroup, parent: CompositionReference? = null) {
// temporary easy way to call correct lifecycles on everything
composeInto(container, parent) { }
CompositionContext.disposeComposition(container, parent)
@@ -45,7 +45,7 @@
fun composeInto(
container: Emittable,
context: Context,
- parent: Ambient.Reference? = null,
+ parent: CompositionReference? = null,
composable: @Composable() () -> Unit
) {
var root = CompositionContext.getRootComponent(container) as? Root
@@ -64,7 +64,7 @@
fun disposeComposition(
container: Emittable,
context: Context,
- parent: Ambient.Reference? = null
+ parent: CompositionReference? = null
) {
// temporary easy way to call correct lifecycles on everything
composeInto(container, context, parent) {}
diff --git a/ui/framework/src/main/java/androidx/ui/core/Layout.kt b/ui/framework/src/main/java/androidx/ui/core/Layout.kt
index 5d85238..f7a7f8d 100644
--- a/ui/framework/src/main/java/androidx/ui/core/Layout.kt
+++ b/ui/framework/src/main/java/androidx/ui/core/Layout.kt
@@ -22,6 +22,7 @@
import com.google.r4a.R4a
import com.google.r4a.ambient
import com.google.r4a.composer
+import com.google.r4a.compositionReference
import com.google.r4a.memo
import com.google.r4a.onCommit
import com.google.r4a.unaryPlus
@@ -413,10 +414,8 @@
*/
@Composable
fun WithConstraints(@Children children: (Constraints) -> Unit) {
- var ambients: Ambient.Reference? = null
- <Ambient.Portal> value ->
- ambients = value
- </Ambient.Portal>
+ val ref = +compositionReference()
+ val context = +ambient(ContextAmbient)
<Layout
layoutBlock = { _, constraints ->
@@ -424,8 +423,8 @@
// Start subcomposition from the current node.
R4a.composeInto(
root,
- ambients!!.getAmbient(ContextAmbient),
- ambients
+ context,
+ ref
) {
<children p1=constraints />
}
diff --git a/ui/framework/src/main/java/androidx/ui/core/Wrapper.kt b/ui/framework/src/main/java/androidx/ui/core/Wrapper.kt
index be8fd68b..1932174f 100644
--- a/ui/framework/src/main/java/androidx/ui/core/Wrapper.kt
+++ b/ui/framework/src/main/java/androidx/ui/core/Wrapper.kt
@@ -23,6 +23,7 @@
import com.google.r4a.R4a
import com.google.r4a.ambient
import com.google.r4a.composer
+import com.google.r4a.compositionReference
import com.google.r4a.effectOf
import com.google.r4a.memo
import com.google.r4a.unaryPlus
@@ -32,17 +33,16 @@
val rootRef = +memo { Ref<AndroidCraneView>() }
<AndroidCraneView ref=rootRef>
- <Ambient.Portal> reference ->
- val rootLayoutNode = rootRef.value?.root ?: error("Failed to create root platform view")
- val context = rootRef.value?.context ?: composer.composer.context
- R4a.composeInto(container = rootLayoutNode, context = context, parent = reference) {
- <ContextAmbient.Provider value=context>
- <DensityAmbient.Provider value=Density(context)>
- <children />
- </DensityAmbient.Provider>
- </ContextAmbient.Provider>
- }
- </Ambient.Portal>
+ val reference = +compositionReference()
+ val rootLayoutNode = rootRef.value?.root ?: error("Failed to create root platform view")
+ val context = rootRef.value?.context ?: composer.composer.context
+ R4a.composeInto(container = rootLayoutNode, context = context, parent = reference) {
+ <ContextAmbient.Provider value=context>
+ <DensityAmbient.Provider value=Density(context)>
+ <children />
+ </DensityAmbient.Provider>
+ </ContextAmbient.Provider>
+ }
</AndroidCraneView>
}