Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Split Treehouse lifecycle out of RedwoodView #2418

Merged
merged 4 commits into from
Oct 31, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
[Unreleased]: https://github.com/cashapp/redwood/compare/0.15.0...HEAD

New:
- Nothing yet!
- Redwood publishes what's happening in bound content through the new `Content.State` type.

Changed:
- Drop support for non-incremental layouts in `Row` and `Column`.
Expand All @@ -17,7 +17,7 @@ Fixed:
- Fix a layout bug where children of `Box` containers were not measured properly.

Breaking:
- Replace `CodeListener` with new functions in `RedwoodView`. This puts the loading/error/ready state with the UI that displays that state.
- Replace `CodeListener` with a new `DynamicContentWidgetFactory` API. Now loading and crashed views work like all other child widgets.


## [0.15.0] - 2024-09-30
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -425,7 +425,7 @@ private class RootProtocolNode<W : Any>(
}

override fun detach() {
children.detach()
// Do nothing because 'children' is owned by the host's TreehouseView.
Copy link
Collaborator

Choose a reason for hiding this comment

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

The Redwood protocol doesn't strictly have to be used by Treehouse, although that is certainly the overwhelmingly common usage. Maybe put a note on the class docs up above, or on close().

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yeah, good point. I should have said RedwoodView here instead.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Oh even better. I thought it was something specific to treehouse.

}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
public class app/cash/redwood/treehouse/composeui/DynamicContent {
public static final field $stable I
public final class app/cash/redwood/treehouse/composeui/ComposableSingletons$EmptyDynamicContentWidgetFactoryKt {
public static final field INSTANCE Lapp/cash/redwood/treehouse/composeui/ComposableSingletons$EmptyDynamicContentWidgetFactoryKt;
public static field lambda-1 Lkotlin/jvm/functions/Function2;
public static field lambda-2 Lkotlin/jvm/functions/Function2;
public fun <init> ()V
public fun Render (Lapp/cash/redwood/widget/compose/ComposeWidgetChildren;Landroidx/compose/runtime/Composer;I)V
public fun contentState (Lkotlinx/coroutines/CoroutineScope;IZLjava/lang/Throwable;)V
public final fun getAttached ()Z
public final fun getLoadCount ()I
public final fun getRestart ()Lkotlin/jvm/functions/Function0;
public final fun getUncaughtException ()Ljava/lang/Throwable;
public final fun restart (Lkotlin/jvm/functions/Function0;)V
public final fun getLambda-1$redwood_treehouse_host_composeui_release ()Lkotlin/jvm/functions/Function2;
public final fun getLambda-2$redwood_treehouse_host_composeui_release ()Lkotlin/jvm/functions/Function2;
}

public final class app/cash/redwood/treehouse/composeui/TreehouseContentKt {
public static final fun TreehouseContent (Lapp/cash/redwood/treehouse/TreehouseApp;Lapp/cash/redwood/treehouse/TreehouseView$WidgetSystem;Lapp/cash/redwood/treehouse/TreehouseContentSource;Landroidx/compose/ui/Modifier;Lapp/cash/redwood/treehouse/composeui/DynamicContent;Landroidx/compose/runtime/Composer;II)V
public static final fun TreehouseContent (Lapp/cash/redwood/treehouse/TreehouseApp;Lapp/cash/redwood/treehouse/TreehouseView$WidgetSystem;Lapp/cash/redwood/treehouse/TreehouseContentSource;Landroidx/compose/ui/Modifier;Lapp/cash/redwood/treehouse/DynamicContentWidgetFactory;Landroidx/compose/runtime/Composer;II)V
}

Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
public class app/cash/redwood/treehouse/composeui/DynamicContent {
public static final field $stable I
public final class app/cash/redwood/treehouse/composeui/ComposableSingletons$EmptyDynamicContentWidgetFactoryKt {
public static final field INSTANCE Lapp/cash/redwood/treehouse/composeui/ComposableSingletons$EmptyDynamicContentWidgetFactoryKt;
public static field lambda-1 Lkotlin/jvm/functions/Function2;
public static field lambda-2 Lkotlin/jvm/functions/Function2;
public fun <init> ()V
public fun Render (Lapp/cash/redwood/widget/compose/ComposeWidgetChildren;Landroidx/compose/runtime/Composer;I)V
public fun contentState (Lkotlinx/coroutines/CoroutineScope;IZLjava/lang/Throwable;)V
public final fun getAttached ()Z
public final fun getLoadCount ()I
public final fun getRestart ()Lkotlin/jvm/functions/Function0;
public final fun getUncaughtException ()Ljava/lang/Throwable;
public final fun restart (Lkotlin/jvm/functions/Function0;)V
public final fun getLambda-1$redwood_treehouse_host_composeui ()Lkotlin/jvm/functions/Function2;
public final fun getLambda-2$redwood_treehouse_host_composeui ()Lkotlin/jvm/functions/Function2;
}

public final class app/cash/redwood/treehouse/composeui/TreehouseContentKt {
public static final fun TreehouseContent (Lapp/cash/redwood/treehouse/TreehouseApp;Lapp/cash/redwood/treehouse/TreehouseView$WidgetSystem;Lapp/cash/redwood/treehouse/TreehouseContentSource;Landroidx/compose/ui/Modifier;Lapp/cash/redwood/treehouse/composeui/DynamicContent;Landroidx/compose/runtime/Composer;II)V
public static final fun TreehouseContent (Lapp/cash/redwood/treehouse/TreehouseApp;Lapp/cash/redwood/treehouse/TreehouseView$WidgetSystem;Lapp/cash/redwood/treehouse/TreehouseContentSource;Landroidx/compose/ui/Modifier;Lapp/cash/redwood/treehouse/DynamicContentWidgetFactory;Landroidx/compose/runtime/Composer;II)V
}

Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,11 @@
// - Show declarations: true

// Library unique name: <app.cash.redwood:redwood-treehouse-host-composeui>
open class app.cash.redwood.treehouse.composeui/DynamicContent { // app.cash.redwood.treehouse.composeui/DynamicContent|null[0]
constructor <init>() // app.cash.redwood.treehouse.composeui/DynamicContent.<init>|<init>(){}[0]
final val app.cash.redwood.treehouse.composeui/app_cash_redwood_treehouse_composeui_EmptyDynamicContentWidgetFactory$stableprop // app.cash.redwood.treehouse.composeui/app_cash_redwood_treehouse_composeui_EmptyDynamicContentWidgetFactory$stableprop|#static{}app_cash_redwood_treehouse_composeui_EmptyDynamicContentWidgetFactory$stableprop[0]
final val app.cash.redwood.treehouse.composeui/app_cash_redwood_treehouse_composeui_EmptyDynamicContentWidgetFactory_EmptyCrashed$stableprop // app.cash.redwood.treehouse.composeui/app_cash_redwood_treehouse_composeui_EmptyDynamicContentWidgetFactory_EmptyCrashed$stableprop|#static{}app_cash_redwood_treehouse_composeui_EmptyDynamicContentWidgetFactory_EmptyCrashed$stableprop[0]
final val app.cash.redwood.treehouse.composeui/app_cash_redwood_treehouse_composeui_EmptyDynamicContentWidgetFactory_EmptyLoading$stableprop // app.cash.redwood.treehouse.composeui/app_cash_redwood_treehouse_composeui_EmptyDynamicContentWidgetFactory_EmptyLoading$stableprop|#static{}app_cash_redwood_treehouse_composeui_EmptyDynamicContentWidgetFactory_EmptyLoading$stableprop[0]

final var attached // app.cash.redwood.treehouse.composeui/DynamicContent.attached|{}attached[0]
final fun <get-attached>(): kotlin/Boolean // app.cash.redwood.treehouse.composeui/DynamicContent.attached.<get-attached>|<get-attached>(){}[0]
final var loadCount // app.cash.redwood.treehouse.composeui/DynamicContent.loadCount|{}loadCount[0]
final fun <get-loadCount>(): kotlin/Int // app.cash.redwood.treehouse.composeui/DynamicContent.loadCount.<get-loadCount>|<get-loadCount>(){}[0]
final var restart // app.cash.redwood.treehouse.composeui/DynamicContent.restart|{}restart[0]
final fun <get-restart>(): kotlin/Function0<kotlin/Unit>? // app.cash.redwood.treehouse.composeui/DynamicContent.restart.<get-restart>|<get-restart>(){}[0]
final var uncaughtException // app.cash.redwood.treehouse.composeui/DynamicContent.uncaughtException|{}uncaughtException[0]
final fun <get-uncaughtException>(): kotlin/Throwable? // app.cash.redwood.treehouse.composeui/DynamicContent.uncaughtException.<get-uncaughtException>|<get-uncaughtException>(){}[0]

final fun restart(kotlin/Function0<kotlin/Unit>?) // app.cash.redwood.treehouse.composeui/DynamicContent.restart|restart(kotlin.Function0<kotlin.Unit>?){}[0]
open fun Render(app.cash.redwood.widget.compose/ComposeWidgetChildren, androidx.compose.runtime/Composer?, kotlin/Int) // app.cash.redwood.treehouse.composeui/DynamicContent.Render|Render(app.cash.redwood.widget.compose.ComposeWidgetChildren;androidx.compose.runtime.Composer?;kotlin.Int){}[0]
open fun contentState(kotlinx.coroutines/CoroutineScope, kotlin/Int, kotlin/Boolean, kotlin/Throwable?) // app.cash.redwood.treehouse.composeui/DynamicContent.contentState|contentState(kotlinx.coroutines.CoroutineScope;kotlin.Int;kotlin.Boolean;kotlin.Throwable?){}[0]
}

final val app.cash.redwood.treehouse.composeui/app_cash_redwood_treehouse_composeui_DynamicContent$stableprop // app.cash.redwood.treehouse.composeui/app_cash_redwood_treehouse_composeui_DynamicContent$stableprop|#static{}app_cash_redwood_treehouse_composeui_DynamicContent$stableprop[0]

final fun <#A: app.cash.redwood.treehouse/AppService> app.cash.redwood.treehouse.composeui/TreehouseContent(app.cash.redwood.treehouse/TreehouseApp<#A>, app.cash.redwood.treehouse/TreehouseView.WidgetSystem<kotlin/Function2<androidx.compose.runtime/Composer, kotlin/Int, kotlin/Unit>>, app.cash.redwood.treehouse/TreehouseContentSource<#A>, androidx.compose.ui/Modifier?, app.cash.redwood.treehouse.composeui/DynamicContent?, androidx.compose.runtime/Composer?, kotlin/Int, kotlin/Int) // app.cash.redwood.treehouse.composeui/TreehouseContent|TreehouseContent(app.cash.redwood.treehouse.TreehouseApp<0:0>;app.cash.redwood.treehouse.TreehouseView.WidgetSystem<kotlin.Function2<androidx.compose.runtime.Composer,kotlin.Int,kotlin.Unit>>;app.cash.redwood.treehouse.TreehouseContentSource<0:0>;androidx.compose.ui.Modifier?;app.cash.redwood.treehouse.composeui.DynamicContent?;androidx.compose.runtime.Composer?;kotlin.Int;kotlin.Int){0§<app.cash.redwood.treehouse.AppService>}[0]
final fun app.cash.redwood.treehouse.composeui/app_cash_redwood_treehouse_composeui_DynamicContent$stableprop_getter(): kotlin/Int // app.cash.redwood.treehouse.composeui/app_cash_redwood_treehouse_composeui_DynamicContent$stableprop_getter|app_cash_redwood_treehouse_composeui_DynamicContent$stableprop_getter(){}[0]
final fun <#A: app.cash.redwood.treehouse/AppService> app.cash.redwood.treehouse.composeui/TreehouseContent(app.cash.redwood.treehouse/TreehouseApp<#A>, app.cash.redwood.treehouse/TreehouseView.WidgetSystem<kotlin/Function2<androidx.compose.runtime/Composer, kotlin/Int, kotlin/Unit>>, app.cash.redwood.treehouse/TreehouseContentSource<#A>, androidx.compose.ui/Modifier?, app.cash.redwood.treehouse/DynamicContentWidgetFactory<kotlin/Function2<androidx.compose.runtime/Composer, kotlin/Int, kotlin/Unit>>?, androidx.compose.runtime/Composer?, kotlin/Int, kotlin/Int) // app.cash.redwood.treehouse.composeui/TreehouseContent|TreehouseContent(app.cash.redwood.treehouse.TreehouseApp<0:0>;app.cash.redwood.treehouse.TreehouseView.WidgetSystem<kotlin.Function2<androidx.compose.runtime.Composer,kotlin.Int,kotlin.Unit>>;app.cash.redwood.treehouse.TreehouseContentSource<0:0>;androidx.compose.ui.Modifier?;app.cash.redwood.treehouse.DynamicContentWidgetFactory<kotlin.Function2<androidx.compose.runtime.Composer,kotlin.Int,kotlin.Unit>>?;androidx.compose.runtime.Composer?;kotlin.Int;kotlin.Int){0§<app.cash.redwood.treehouse.AppService>}[0]
final fun app.cash.redwood.treehouse.composeui/app_cash_redwood_treehouse_composeui_EmptyDynamicContentWidgetFactory$stableprop_getter(): kotlin/Int // app.cash.redwood.treehouse.composeui/app_cash_redwood_treehouse_composeui_EmptyDynamicContentWidgetFactory$stableprop_getter|app_cash_redwood_treehouse_composeui_EmptyDynamicContentWidgetFactory$stableprop_getter(){}[0]
final fun app.cash.redwood.treehouse.composeui/app_cash_redwood_treehouse_composeui_EmptyDynamicContentWidgetFactory_EmptyCrashed$stableprop_getter(): kotlin/Int // app.cash.redwood.treehouse.composeui/app_cash_redwood_treehouse_composeui_EmptyDynamicContentWidgetFactory_EmptyCrashed$stableprop_getter|app_cash_redwood_treehouse_composeui_EmptyDynamicContentWidgetFactory_EmptyCrashed$stableprop_getter(){}[0]
final fun app.cash.redwood.treehouse.composeui/app_cash_redwood_treehouse_composeui_EmptyDynamicContentWidgetFactory_EmptyLoading$stableprop_getter(): kotlin/Int // app.cash.redwood.treehouse.composeui/app_cash_redwood_treehouse_composeui_EmptyDynamicContentWidgetFactory_EmptyLoading$stableprop_getter|app_cash_redwood_treehouse_composeui_EmptyDynamicContentWidgetFactory_EmptyLoading$stableprop_getter(){}[0]

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Copyright (C) 2024 Square, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package app.cash.redwood.treehouse.composeui

import androidx.compose.runtime.Composable
import app.cash.redwood.Modifier
import app.cash.redwood.treehouse.Crashed
import app.cash.redwood.treehouse.DynamicContentWidgetFactory
import app.cash.redwood.treehouse.Loading

/** Don't show anything for loading or error screens. */
internal object EmptyDynamicContentWidgetFactory :
DynamicContentWidgetFactory<@Composable () -> Unit> {
override fun Loading() = EmptyLoading()

override fun Crashed() = EmptyCrashed()

internal class EmptyCrashed : Crashed<@Composable () -> Unit> {
override var modifier: Modifier = Modifier
override val value = @Composable {
}

override fun uncaughtException(uncaughtException: Throwable) {
}

override fun restart(restart: () -> Unit) {
}
}

internal class EmptyLoading : Loading<@Composable () -> Unit> {
override var modifier: Modifier = Modifier
override val value = @Composable {
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.onSizeChanged
Expand All @@ -32,6 +31,7 @@ import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.unit.LayoutDirection
import app.cash.redwood.composeui.safeAreaInsets
import app.cash.redwood.treehouse.AppService
import app.cash.redwood.treehouse.DynamicContentWidgetFactory
import app.cash.redwood.treehouse.StateSnapshot
import app.cash.redwood.treehouse.TreehouseApp
import app.cash.redwood.treehouse.TreehouseContentSource
Expand All @@ -55,10 +55,10 @@ public fun <A : AppService> TreehouseContent(
widgetSystem: WidgetSystem<@Composable () -> Unit>,
contentSource: TreehouseContentSource<A>,
modifier: Modifier = Modifier,
dynamicContent: DynamicContent = DynamicContent(),
dynamicContentWidgetFactory: DynamicContentWidgetFactory<@Composable () -> Unit> =
EmptyDynamicContentWidgetFactory,
) {
val onBackPressedDispatcher = platformOnBackPressedDispatcher()
val scope = rememberCoroutineScope()

var viewportSize: Size? by remember { mutableStateOf(null) }
val density = LocalDensity.current
Expand All @@ -77,17 +77,10 @@ public fun <A : AppService> TreehouseContent(
override val children: ComposeWidgetChildren = ComposeWidgetChildren()

override val value: @Composable () -> Unit = {
dynamicContent.Render(children)
}

override fun contentState(loadCount: Int, attached: Boolean, uncaughtException: Throwable?) {
dynamicContent.contentState(scope, loadCount, attached, uncaughtException)
}

override fun restart(restart: (() -> Unit)?) {
dynamicContent.restart(restart)
children.Render()
}

override val dynamicContentWidgetFactory = dynamicContentWidgetFactory
override val onBackPressedDispatcher = onBackPressedDispatcher
override val uiConfiguration = MutableStateFlow(uiConfiguration)

Expand Down
Loading
Loading