-
Notifications
You must be signed in to change notification settings - Fork 74
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
Replace CodeListener with RedwoodView.Root #2374
Conversation
This moves loading/error/ready tracking to live beside the content, rather than as something that side-effects the content. This is not compatible with the old API and there is no shim.
...ost-composeui/src/commonMain/kotlin/app/cash/redwood/treehouse/composeui/TreehouseContent.kt
Outdated
Show resolved
Hide resolved
// Canonicalize "java.lang.Exception(boom!)" to "kotlin.Exception(boom!)". | ||
val exceptionString = uncaughtException?.toString()?.replace("java.lang.", "kotlin.") | ||
|
||
// TODO(jwilson): this is a backwards-compatibility shim. Emit a simpler event. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For follow-up
@@ -37,17 +37,16 @@ import kotlinx.coroutines.flow.StateFlow | |||
@SuppressLint("ViewConstructor") | |||
public open class RedwoodLayout( | |||
context: Context, | |||
public final override val root: RedwoodView.Root<View> = ViewRoot(context), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On Android, this accepts the interface type, RedwoodView.Root
...
@@ -38,17 +38,16 @@ import platform.UIKit.UIUserInterfaceStyle | |||
import platform.UIKit.UIView | |||
|
|||
public open class RedwoodUIView( | |||
public val view: UIView, | |||
final override val root: UIViewRoot, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But on iOS, this accepts our concrete base implementation. This is because I haven’t yet figured out how to add a bounds change listener to a view I didn’t subclass
@@ -6,19 +6,18 @@ class CounterViewController : UIViewController { | |||
private var delegate: CounterViewControllerDelegate! | |||
|
|||
override func viewDidLoad() { | |||
let container = UIStackView() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a behavior change. For a follow-up I need to use a Row
in the Compose-side code for the counter.
} | ||
} | ||
|
||
for (child in viewGroupChildren) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This still isn’t that great . . . I prefer the way this works in Compose
import androidx.appcompat.view.ContextThemeWrapper | ||
|
||
@SuppressLint("ViewConstructor") | ||
internal class LoadingView( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
New: now there’s a spinner when launching emoji search
@JakeWharton this is ready for review. I did an in-place swap from the old type to the new type rather than a graceful migration, which makes the PR larger than I generally like. |
Yeah it's... Big. I started today but had to leave early. Will finish tomorrow morning. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I reviewed as much as I could. Don't want to hold it up any more.
|
||
for (child in viewGroupChildren) { | ||
if (child is ExceptionView || child is LoadingView) { | ||
removeView(child) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is not safe to remove a view like this while iterating. However, the iterator is actually a MutableIterator
that you can call remove()
on: https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:core/core-ktx/src/main/java/androidx/core/view/ViewGroup.kt;l=89-99;drc=1e02caf7787e6fc64ec1913bf6e5cbbab1724a13. Unfortunately that means you can't use a nice for loop anymore.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh hell yes. I was exploiting the fact that this will only contain one child element if its either of those types. But I prefer your fix with an iterator.
if (loadCount == 0) { | ||
addView(LoadingView(context)) | ||
} | ||
if (uncaughtException != null) { | ||
addView(ExceptionView(context, uncaughtException)) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems a bit suspect that the loop will leave both LoadingView
and ExceptionView
instances, but then also possible add new ones as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed. In practice it’s unlikely to transition from loading to loading again, or exception to exception again.
...d-views/src/main/kotlin/com/example/redwood/emojisearch/android/views/EmojiSearchActivity.kt
Outdated
Show resolved
Hide resolved
*/ | ||
public fun reset() | ||
@ObjCName("Root", exact = true) | ||
public interface Root<W : Any> : Widget<W> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems like it exists at the wrong layer of abstraction since Redwood has no concept of loading or errors–just content. Eliminating CodeListener
is a big enough win for now. We can figure out how to move it later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see why this extends Widget
. Do we use that capability anywhere? I haven't seen any usage that relies on it, but perhaps that's just because the diff is pretty big.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We’re using the value
field to get a component to place in the parent container. But that doesn’t need to be polymorphic.
…/redwood/emojisearch/android/views/EmojiSearchActivity.kt Co-authored-by: Jake Wharton <[email protected]>
This moves loading/error/ready tracking to live beside the content, rather than as something that side-effects the content.
This is not compatible with the old API and there is no shim.
Closes: #2174
CHANGELOG.md
's "Unreleased" section has been updated, if applicable.