Releases: cashapp/redwood
0.15.0
New:
- Default expressions can now be used directly in the schema rather than using the
@Default
annotation. The annotation has been deprecated, and will be removed in the next release. EventListener.Factory.close()
is called byTreehouseApp.close()
to release any resources held by the factory.- Lambda parameter names defined in the schema are now propagated to the generated composable and widget interface.
ResizableWidget
is an interface thatUIView
widgets must use if their intrinsic sizes may change dynamically. It notifies any enclosing parent views to trigger a new layout.
Changed:
- Removed Wasm JS target. We are not ready to support it yet.
Fixed:
- Breaking the last remaining retain cycle in
UIViewLazyList
. - Don't leak the
DisplayLink
when aTreehouseApp
is stopped on iOS. - Correctly handle dynamic size changes for child widgets of
Box
,Column
, andRow
. - Don't clip elements of
Column
andRow
layouts whose unbounded size exceeds the container size. - Correctly implement margins for
Box
on iOS. - Correctly handle dynamic updates to modifiers on
Column
andRow
.
0.14.0
New:
- Source-based schema parser is now the default. The
useFir
Gradle property has been removed. TreehouseAppFactory
accepts aLeakDetector
which can be used to notify you of reference leaks for native UI nodes, Zipline instances, Redwood's own internal wrappers, and more.- Introduce a
LoadingStrategy
interface to manageLazyList
preloading. - Optimize encoding modifiers in Kotlin/JS.
Changed:
- In Treehouse, events from the UI are now serialized on a background thread. This means that there is both a delay and a thread change between when a UI binding sends an event and when that object is converted to JSON. All arguments to events must not be mutable and support property reads on any thread. Best practice is for all event arguments to be completely immutable.
ProtocolFactory
interface is now sealed as arbitrary subtypes were never supported. Only schema-generated subtypes should be used.UIViewLazyList
doesn't crash with aNullPointerException
if cells are added, removed, and re-added without being reused.- Change
UiConfiguration.viewportSize
to be nullable. A nullviewportSize
indicates the viewport's size has not been resolved yet.
Fixed:
- Breaking
content: UIView
retain cycle inUIViewLazyList
'sLazyListContainerCell
. - Update
ProtocolNode
widget IDs when recycling widgets. This was causing pooled nodes to be leaked.
Breaking:
- The
TreehouseApp.spec
property is removed. Most callers should be able to useTreehouseApp.name
instead. This is necessary to avoid a retain cycle.
Upgraded:
- Kotlin 2.0.20
- Zipline 1.17.0
0.13.0
New:
- Wasm JS added as a target for common Redwood modules. There is no Treehouse support today.
- Add
onScroll
property toRow
andColumn
. This property is invoked whenoverflow = Overflow.Scroll
and the container is scrolled. - Add
Px
class to represent a raw pixel value in the host's coordinate system. - New source-based schema parser can be enabled with
redwood { useFir = true }
in your schema module. Please report and failures to the issue tracker. This parser will become the default in 0.14.0.
Changed:
- The
TreehouseApp
type is now an abstract class. This should make it easier to write unit tests for code that integrates Treehouse. - The
TreehouseApp.Spec.bindServices()
function is now suspending. - The
TreehouseAppFactory
function now accepts a ZiplineLoaderEventListener
parameter.
Fixed:
- Using a
data object
for a widget of modifier no longer causes schema parsing to crash. - Ensuring
LazyList
'sitemsBefore
anditemsAfter
properties are always within[0, itemCount]
, to preventIndexOutOfBoundsException
crashes. - Don't crash in
LazyList
when a scroll and content change occur in the same update. - Updating a flex container's margin now works correctly for Yoga-based layouts.
Breaking:
- The
TreehouseApp.Factory.dispatchers
property is removed, and callers should migrate toTreehouseApp.dispatchers
. With this update eachTreehouseApp
has its own private thread so a shareddispatchers
property no longer fits our implementation.
-TreehouseApp.Spec.bindServices()
now accepts aTreehouseApp
parameter.
Upgraded:
- Zipline 1.16.0
0.12.0
New:
- Upgrade to Kotlin 2.0!
- Added a basic DOM-based
LazyList
implementation. TreehouseApp.close()
stops the app and prevents it from being started again later.- Added
UiConfiguration.layoutDirection
to support reading the host's layout direction. - New
redwood-bom
artifact can be used to ensure all Redwood artifacts use the same version. See Gradle's documentation on how to use the BOM in your build.
Changed:
- The
app.cash.redwood
Gradle plugin has been removed. This plugin did two things: apply the Compose compiler and add a dependency on theredwood-compose
artifact. The Compose compiler can now be added by applying theorg.jetbrains.kotlin.plugin.compose
Gradle plugin. Dependencies on Redwood artifacts can be added manually. - Removed deprecated
typealias
es for generated-WidgetFactories
type which was renamed to-WidgetSystem
in 0.10.0. - Removed deprecated
Modifier.flex
extension function which is now supported natively byRow
andColumn
since 0.8.0. - Removed deprecated
TreehouseWidgetView
andTreehouseUIKitView
type aliases forTreehouseLayout
andTreehouseUIView
which were renamed in 0.7.0. - Removed deprecated
TreehouseAppFactory
functions with the oldFileSystem
andPath
order which were changed in 0.11.0. - Rename the two types named
ProtocolBridge
toProtocolHost
andProtocolGuest
.
Fixed:
- Fix memory leaks caused by reference cycles on iOS. We got into trouble mixing garbage-collected Kotlin objects with reference-counted Swift objects.
Breaking:
TreehouseApp.zipline
is now aStateFlow<Zipline?>
instead of aZipline?
.CodeListener.onCodeDetached()
replacesonUncaughtException()
. The new function is called
whenever code stops driving a view for any reason. The new function accepts aThrowable?
that is
non-null if it's detached due to exception.Content.awaitContent()
now accepts an optionalInt
parameter for the number of updates to
observe before the function returns.- MacOS targets have been (temporarily) removed from all modules.
Upgraded:
- Kotlin 2.0.0
- Zipline 1.13.0
- kotlinx.serialization 1.7.0
Gradle plugin removed
This version of Redwood removes the custom Gradle plugin in favor of the official JetBrains Compose compiler plugin which ships as part of Kotlin itself.
Each module in which you had previously applied the app.cash.redwood
plugin should be changed to apply org.jetbrains.kotlin.plugin.compose
instead.
The Redwood dependencies will no longer be added as a result of the plugin change, and so any module which references Redwoods APIs should add those dependencies explicitly.
For posterity, the Kotlin version compatibility table and compiler version customization for our old Redwood Gradle plugin will be archived here:
Redwood 0.12.0 Gradle plugin Kotlin compatibility table
Since Kotlin compiler plugins are an unstable API, certain versions of Redwood only work with
certain versions of Kotlin.
Kotlin | Redwood |
---|---|
1.9.24 | 0.11.0 |
1.9.23 | 0.10.0 |
1.9.22 | 0.8.0 - 0.9.0 |
1.9.10 | 0.7.0 |
1.9.0 | 0.6.0 |
1.8.22 | 0.5.0 |
1.8.20 | 0.3.0 - 0.4.0 |
1.7.20 | 0.1.0 - 0.2.1 |
Redwood 0.12.0 Gradle plugin Compose compiler customization instructions
Each version of Redwood ships with a specific JetBrains Compose compiler version which works with
a single version of Kotlin (see version table above). Newer versions of
the Compose compiler or alternate Compose compilers can be specified using the Gradle extension.
To use a new version of the JetBrains Compose compiler version:
redwood {
kotlinCompilerPlugin.set("1.4.8")
}
To use an alternate Compose compiler dependency:
redwood {
kotlinCompilerPlugin.set("com.example:custom-compose-compiler:1.0.0")
}
0.11.0
New:
- Added
toDebugString
method forWidgetValue
andList<WidgetValue>
which returns a formatted string of a widget's children and properties, useful for test debugging.
Changed:
- Removed generated
typealias
es for package names which changed in 0.10.0. - In
UIViewLazyList
'sUITableView
, adding special-case handling for programmatic scroll-to-top calls. - APIs accepting a
FileSystem
andPath
now have theFileSystem
coming before thePath
in the parameter list. Compatibility functions are retained for this version, but will be removed in the next version.
Fixed:
- Work around a problem with our memory-leak fix where our old LazyList code would crash when its placeholders were unexpectedly removed.
- Avoid calling into the internal Zipline instance from the UI thread on startup. This would manifest as weird native crashes due to multiple threads mutating shared memory.
- In
UIViewLazyList
, fixUInt
toUIColor
conversion math used forpullRefreshContentColor
. - In
YogaUIView
'ssetScrollEnabled
method, only callsetNeedsLayout
if thescrollEnabled
value is actually changing. - In
YogaUIView
'slayoutNodes
method, return early for nestedYogaUIView
s to prevent redundant frame calculations.
Upgraded:
- Zipline 1.10.1.
This version works with Kotlin 1.9.24 by default.
0.10.0
New:
- Compose UI implementation for
Box
. - Layout modifier support for HTML DOM layouts.
- Unscoped modifiers provide a global hook for side-effecting behavior on native views. For example, create a background color modifier which changes the platform-native UI node through a factory function.
Widget.Children
interface now exposeswidgets: List<Widget<W>>
property. Most subtypes were already exposing this individually.
Changed:
- Disable klib signature clash checks for JS compilations. These occasionally occur as a result of Compose compiler behavior, and are safe to disable (the first-party JetBrains Compose Gradle plugin also disables them).
onModifierChanged
callback inWidget.Children
now receives the index and theWidget
instance affected by the change.- The package of 'redwood-protocol-host' changed to
app.cash.redwood.protocol.host
. This should not affect end-users as its types are mostly for internal use. - The entire
redwood-yoga
artifact's public API has been annotated with an opt-in annotation indicating that it's only for Redwood internal use and is not stable. - Revert: Don't block touch events to non-subviews below a
Row
,Column
, orBox
in the iOSUIView
implementation. This matches the behavior of the Android View and Compose UI implementations. - The generated "widget factories" type (e.g.,
MySchemaWidgetFactories
) is now called a "widget system" (e.g.,MySchemaWidgetSystem
). Sometimes it was also referred to as a "provider" in parameter names. A@Deprecated typealias
is generated for now, but will be removed in the future. - The package names of some generated code has changed. Deprecated
typealias
es are generated in the old locations for public types and functions, but those will be removed in the next release.- Testing code is now under
your.package.testing
. - Protocol guest code is now under
your.package.protocol.guest
. - Protocol host code is now under
your.package.protocol.host
.
- Testing code is now under
- The 'app.cash.redwood.generator.compose.protocol' and 'app.cash.redwood.generator.widget.protocol' Gradle plugins are now deprecated and will be removed in the next release. Use 'app.cash.redwood.generator.protocol.guest' and 'app.cash.redwood.generator.protocol.host', respectively.
- The 'redwood-tooling-codegen' CLI flags for protocol codegen have changed from
--compose-protocol
and--widget-protocol
to--protocol-guest
and--protocol-host
, respectively. - Entrypoints to the protocol on the host-side and guest-side now require supplying the version of Redwood in use on the other side in order to ensure compatibility and work around any bugs in older versions. This uses a new
RedwoodVersion
type, and will be automatically wired if using our Treehouse artifacts.
Fixed:
- Fix failure to release JS resources when calling
CoroutineScope
is being cancelled - JVM targets now correctly link against Java 8 APIs. Previously they produced Java 8 bytecode, but linked against the compile JDK's APIs (21). This allowed linking against newer APIs that might not exist on older runtimes, which is no longer possible. Android targets which also produce Java 8 bytecode were not affected.
- Fix the
View
implementation ofBox
to wrap its width and height by default. This matches the behavior of theUIView
implementation and all other layout widgets. - Fix the
UIView
implementation ofBox
not updating when some of its parameters are changed. - Fix
Modifier.size
not being applied to children inside aBox
. - Fix
Margin
not being applied to theUIView
implementation ofBox
. - The
View
implementation ofBox
now applies start/end margins correctly in RTL, and does not crash if set before the native view was attached. - Fix the backgroundColor for
UIViewLazyList
to be transparent. This matches the behavior of the otherLazyList
platform implementations. - Fix
TreehouseUIView
to size itself according to the size of its subview. - In
UIViewLazyList
, addingbeginUpdates
/endUpdates
calls toinsertRows
/deleteRows
, and wrapping changes inUIView.performWithoutAnimation
blocks. - Fix memory leak in 'protocol-guest' and 'protocol-host' where child nodes beneath a removed node were incorrectly retained in an internal map indefinitely. The guest protocol code has been updated to work around this memory leak when deployed to old hosts by sending individual remove operations for each node in the subtree.
- Ensure that Zipline services are not closed prematurely when disposing a Treehouse UI.
- In
UIViewLazyList
, don't remove subviews from hierarchy duringprepareForReuse
call
0.9.0
Changed:
- Added
Modifier
parameter toRedwoodContent
which is applied to the rootBox
into which content is rendered (https://android.googlesource.com/platform/frameworks/support/+/androidx-main/compose/docs/compose-api-guidelines.md#elements-accept-and-respect-a-modifier-parameter). - The parameter order of
LazyRow
andLazyColumn
have changed to reflect Compose best practices (https://android.googlesource.com/platform/frameworks/support/+/androidx-main/compose/docs/compose-api-guidelines.md#elements-accept-and-respect-a-modifier-parameter). - The parameter order of
TreehouseContent
has changed to reflect Compose best practices (https://android.googlesource.com/platform/frameworks/support/+/androidx-main/compose/docs/compose-api-guidelines.md#elements-accept-and-respect-a-modifier-parameter). - The render function of
ComposeWidgetChildren
has been renamed toRender
to reflect Compose best practices (https://android.googlesource.com/platform/frameworks/support/+/androidx-main/compose/docs/compose-api-guidelines.md#naming-unit-composable-functions-as-entities). - Disable decoy generation for JS target to make compatible with JetBrains Compose 1.6. This is an ABI-breaking change, so all Compose-based libraries targeting JS will also need to have been recompiled.
Fixed:
- Don't block touch events to non-subviews below a
Row
,Column
, orBox
in the iOSUIView
implementation. This matches the behavior of the Android View and Compose UI implementations.
This version works with Kotlin 1.9.22 by default.
0.8.0
New:
flex(double)
modifier for layouts which acts as a weight along the main axis.- Allow reserving widget, modifier, property, and children tags in the schema. This can be used to document old items which no longer exist and prevent their values from accidentally being reused.
- Add
dangerZone { }
DSL to theredwood { }
Gradle extension which allows enabling Compose reports and metrics. Currently these features break build caching as Compose forces the use of absolute paths in the Kotlin compiler arguments when in use (hence why they're marked as dangerous). BackHandler
composable provides a callback for handling hardware back affordances (currently only on Android).- Expose
frameClock
onStandardAppLifecycle
to allow monitoring host frames. CodeListener.onUncaughtException
notifies of any uncaught exceptions which occur in Treehouse guest code.- Preview: Add
Box
widget which stacks children on top of each other. This is currently only implemented for Android views and iOS UIKit. - Support
rememberSaveable
in plain Redwood compositions. - Programmatic scrolls on
LazyListState
can now setanimated=true
for an animated scroll. - Add
ziplineCreated
,manifestReady
, andcodeLoadSkippedNotFresh
event callbacks to TreehouseEventListener
.
Changed:
- The Treehouse Zipline disk cache directory is no longer within the cache directory on Android. This ensures it can't be cleared while the app is running. Zipline automatically constrains the directory to a maximum size so old entires will still be purged automatically.
- Set the Zipline thread's stack size to 8MiB on Android to match iOS.
- Use
margin-inline-start
andmargin-inline-end
for the start and end margin, respectively, for the HTML DOM layout bindings. TestRedwoodComposition
now accepts only the initialUiConfiuration
and exposes aMutableStateFlow
for changing its value over time.TreehouseLayout
now defines a default ID to allow state saving and restoration to work. Note that this will only work when a single instance is present in the hierarchy. If you have multiple, supply your own unique IDs.- Emoji Search sample applications now bundle the latest guest code at compile-time and do not require the server running to work.
- The built-in
RedwoodView
forHTMLElement
now reports density changes to theUiConfiguration
. - Redwood protocol modules have been renamed to 'guest' and 'host' to match Treehouse conventions.
- Suppress deprecation warnings in generated code. This code often refers to user types which may be deprecated, and should not cause additional warnings.
TreehouseAppContent.preload
is now idempotent.LazyList
on iOS has changed fromUICollectionView
toUITableView
, and changes to the backing data are now reported granularly rather than reloading everything.- Allow arbitrary serializable content within
rememberSaveable
inside Treehouse. - Add a
TreehouseApp
argument toCodeListener
. Combined with the new uncaught exception callback, this provides an easy way to restart a Treehouse application on a crash. EventListener.Factory
instances are now supplied as part of aTreehouseApp
instead of aTreehouseAppFactory
. This more closely scopes them with the lifetime of theZipline
instance.
Fixed:
- Ensure changes to modifiers notify their parent widget when using Treehouse.
- Explicitly mark the generated scope objects as
@Stable
to prevent needless recomposition. - Dispose the old composition when the
RedwoodContent
composable recomposes or is removed from the composition. - Ensure
UIViewChildren
indexes children usingtypedArrangedSubviews
when removing views from aUIStackView
. - Correctly parse
data object
modifiers in the schema. - Remember the default
CodeListener
forTreehouseContent
to avoid unneccessary recomposition on creation. - When calling
TreehouseUi.start
, fall back to older API signature when newer one does not match. This is needed because an addiitonal parameter was added in newer versions, but older guest code may have the old signature. - Persist saved values from Treehouse without jumping back to the UI thread which allows proper restoration after a config change.
- Reset the requested widths and heights of a layout in the underlying Yoga engine when the size is invalidated. This ensures that the engine will properly measure changed content the grows and shrinks in either dimension.
This version works with Kotlin 1.9.22 by default.
0.7.0
New:
- Expose viewport size and density in
UiConfiguration
. RedwoodView
and platform-specific subtypes provide a turnkey view into which a
RedwoodComposition
can be rendered.TreehouseView
now extendsRedwoodView
.
Changed:
- Remove support for the Kotlin/JS plugin (
org.jetbrains.kotlin.js
). This plugin is deprecated
and projects should be migrated to Kotlin multiplatform plugin (org.jetbrains.kotlin.multiplatform
). - Some
TreehouseView
subtypes were renamed to better match platform conventions:TreehouseWidgetView
is nowTreehouseLayout
for Android.TreehouseUIKitView
is nowTreehouseUIView
for iOS.
UIViewChildren
now supportsUIStackView
automatically.- Package name of types in 'lazylayout-dom' artifact is now
lazylayout
instead of justlayout
.
This version works with Kotlin 1.9.10 by default.
0.6.0
New:
-
Support for specifying custom Compose compiler versions. This will allow you to use the latest
version of Redwood with newer versions of Kotlin than it explicitly supports.See the README for more information.
-
LazyList
can now be programmatically scrolled through itsScrollItemIndex
parameter. -
Pull-to-refresh indicator color on
LazyList
is now customizable through
pullRefreshContentColor
parameter.
Changes:
- Many public types have been migrated away from
data class
to regular classes with
equals
/hashCode
/toString()
. If you were relying on destructuring orcopy()
for these
types you will need to migrate to doing this manually.
Fix:
- The emoji search browser sample no longer crashes on first load.
- Lots of rendering and performance fixes for UIKit version of
LazyList
- Only measure items which are visible in the active viewport.
- Remove some default item spacing imposed by the backing
UICollectionViewFlowLayout
. - Share most of the internal bookkeeping logic with the Android implementations for consistency
and correctness. - Placeholders are now correctly sized along the main axis.
This version works with Kotlin 1.9.0 by default.