Changelog¶
Unreleased¶
0.30.0¶
2025-08-01
Behaviour Changes:¶
Rebuilt continuityRetainedStateRegistry as a common lifecycleRetainedStateRegistry and made ViewModel an implementation detail of it.
AnimatedNavDecoration is now using the full back stack to determine the transition animation.
Updates to ViewModelBackStackRecordLocalProvider¶
ViewModelBackStackRecordLocalProvider has moved from the backstack module to the
circuit-foundation module while also changing to use the multiplatform ViewModel implementation.
ViewModelBackStackRecordLocalProvider is now provided as a default through the Circuit instance,
enabling customization of the default BackStackRecordLocalProviders.
Also added backStackHostViewModel() to access a ViewModel located in the ViewModelStoreOwner of NavigableCircuitContent.
Misc:¶
- [gesture-navigation] Fix a crash when using
AndroidPredictiveBackNavDecoratorand having previously calledresetRoot()withrestoreState=false. - [code gen] Added support for
CircuitContextas an assisted param in code gen - Update dagger to
v2.57. - Update Compose Android BOM to
2025.07.00. - Update androidx.lifecycle to
2.9.2.
Special thanks to @CamiloVega and @kvaster for contributing to this release!
0.29.1¶
2025-06-30
- Fix
@AssistedFactorycode gen for Metro to use standard nested class semantics.
0.29.0¶
2025-06-26
- Update to Kotlin
2.2.0. - Update to KSP
2.2.0-2.0.2. - Support
@AssistedFactoryin code gen for Metro. - Add seekable transition support to
AnimatedOverlay. - Add predictive back support to
FullScreenOverlay. - Compile against Android SDK 36.
0.28.1¶
2025-06-09
Behaviour Changes:¶
Replacing rememberContinuityCanRetainChecker() with CanRetainChecker.Always, which changes the
Android rememberRetained behaviour to retain based on the ViewModel lifecycle. This should fix
rememberRetained not functioning as expected when used in a fragment. Previously rememberRetained
would only retain if the Activity was in a configuration change.
Misc:¶
- Update to Kotlin
2.1.21. - Build against KSP
2.1.21-2.0.1. - Fix not being able to provide a custom ViewModel to
continuityRetainedStateRegistry() - Fix
rememberCircuitNavigatorandrememberInterceptingNavigatorreplaying a root pop at the same screen - Update Compose Android BOM to
2025.06.00. - Update Compose Android to
1.8.2. - Update to Compose Multiplatform to
1.8.1. - Update androidx.lifecycle to
2.9.1
0.28.0¶
2025-05-12
New: circuitx-navigation adding navigation interception capabilities:¶
We’ve added a new navigation intercepting system to Circuit that lets you hook into and modify
navigation before it happens. The InterceptingNavigator sits before a regular Circuit Navigator,
giving you a chance to inspect or change navigation events. With the NavigationInterceptor
interface, you can handle goTo, pop, and resetRoot calls and decide if they should proceed,
fail, be skipped, or be rewritten to navigate somewhere else. There’s also aNavigationEventListener
if you just want to know when navigation happens without changing it.
This new system is handy for advanced routing, blocking navigation, or tracking navigation events
for analytics.
dependencies {
implementation("com.slack.circuit:circuitx-navigation:<version>")
}
Docs: https://slackhq.github.io/circuit/circuitx/navigation
Misc:¶
- Fix the provided
Modifiernot being used inNavigatorDefaults.EmptyDecoration - Fix
rememberCircuitNavigator()not being able to propagate the root pop as itsBackHandlerwas still active - Added a common
rememberCircuitNavigator()that uses aBackHandlerto triggerNavigator.popcalls - [docs] Add more alternative state designs.
- Update Compose Android BOM to
2025.05.00. - Update Compose Android to
1.8.1. - Update to Compose Multiplatform to
1.8.0. - Change the published jvmTarget to
11 - Update molecule to
2.1.0
0.27.1¶
2025-04-14
- Fix: Crash caused by calling
resetRootwhile the sameScreenwas still in the composition - New: Added a sample app demonstrating bottom bar navigation
- [gesture-navigation] Update
AndroidPredictiveBackNavDecoratorto behave more like the Android predictive back motion spec - [gesture-navigation] Change the Compose Material dependency to not be exposed as an api
- Update compose-bom to
2025.04.00 - Update dagger to
2.56.1 - Update kotlinInject.anvil to
0.1.3 - Update kotlinx-coroutines to
1.10.2 - Update androidx.core to
1.16.0 - [samples] Update mosaic to
0.17.0
Special thanks to @OSemenovBoyarka and @asapha for contributing to this release!
0.27.0¶
2025-02-28
Screen based animation overrides¶
We have added experimental support for animations based on the source/target screens and the type of navigation event. This can be accomplished with the the new AnimatedScreenTransform interface, allowing customization of the ContentTransform used when transitioning between screens. Having support for screen based animation overrides is especially important for use with shared element transitions, as it provides the ability to replace the transition before the shared elements are loaded.
See this PR for more details and example implementations. Please share feedback in this discussion.
Behaviour Changes:¶
State retention logic was simplified by removing LocalCanRetainChecker, with CanRetainChecker becoming an implementation detail of a RetainedStateRegistry.
This potentially impacts uses of rememberRetained that depended on LocalCanRetainChecker, as rememberRetained would use the composition local before using rememberCanRetainChecker. Also, as rememberCanRetainChecker was only needed for Continuity it has been renamed to rememberContinuityCanRetainChecker.
Misc:¶
- Fix a crash caused by calling
resetRootwhileNavigableCircuitContentwas animating. - Update androidx.activity to
v1.10.1. - [code gen] Make assisted injection detection more robust.
- [code gen] Update to KSP
2.1.10-1.0.31. - [code gen] Update to KotlinPoet
2.1.0. - [samples] Update mosaic to
0.16.0 - [samples] Include shared element tutorial changes.
Special thanks to @vulpeszerda for contributing to this release!
0.26.1¶
2025-02-13
- Fix crash on right side back gesture.
- Update
CupertinoGestureNavigationDecorationto be aAnimatedNavDecorator. - Fix value restoration after
removeStatecall inRetainedStateHolder. - Update Android compose artifacts to
1.7.8. - [docs] Add tutorial for how to use Circuit shared elements.
- [docs] Added basic reference guide on deep-linking using circuit for Android platform.
Special thanks to @vulpeszerda for contributing to this release!
0.26.0¶
2025-02-06
Happy new year!
Shared Elements API!¶
After a lot of iteration and work, this release adds support for Compose’s new shared elements APIs.
These are still experimental and subject to change, both in Circuit and the underlying Compose APIs.
See this PR for full details as well as sample integrations: https://github.com/slackhq/circuit/pull/1550. Please share feedback in this discussion. More formal docs to come as well, we’ll publish updates there!
For now, the easiest way to support shared element transitions is to wrap your content with a SharedElementTransitionLayout.
CircuitCompositionLocals(circuit) {
SharedElementTransitionLayout {
NavigableCircuitContent(
navigator = navigator,
backStack = backStack,
)
}
}
SharedElementTransitionLayout creates and provides a SharedElementTransitionScope to content within it, and in turn exposes a SharedTransitionScope for use with standard compose shared elements/bounds animations. This is supported in NavigableCircuitContent and overlays.
There is also a PreviewSharedElementTransitionLayout for help with Compose previews.
Behaviour Changes: rememberRetained¶
Previously, rememberRetained could sometimes restore values when a composable was re-added, depending on whether its parent RetainedStateRegistry had been saved (#1783).
Now, rememberRetained aligns with remember and rememberSaveable: if a composable is removed and later re-added, its value will not be restored unless it is explicitly saved and then restored via the registry.
Update rememberRetained to allow CanRetainChecker to be updated in place.
Behaviour Change: RetainedStateRegistry¶
saveAllnow returns the saved values.RetainedStateRegistry.Entry.unregisternow returns whether the unsaved valueProvider was actually removed.saveAllandsaveValuenow skip storing child values whenCanRetainCheckerreturnsfalse.
New: RetainedStateHolder¶
Similar to SaveableStateHolder, RetainedStateHolder provides a mechanism to maintain separate RetainedStateRegistry entries for specific keys. This allows saving the state defined with rememberRetained for a subtree before it is disposed, so that the subtree can later be recomposed with its state restored.
val retainedStateHolder = rememberRetainedStateHolder()
var currentTab by remember { mutableStateOf(TabA) }
retainedStateHolder.RetainedStateProvider(key = currentTab.name) {
// rememberRetained values in tab content are preserved across tab switches
when (currentTab) {
TabA -> {
TabAContent()
}
TabB -> {
TabBContent()
}
TabC -> {
TabCContent()
}
}
}
Implementation Changes: NavigableCircuitContent¶
- The approach of managing a separate
RetainedStateRegistryfor each record has been changed to useRetainedStateHolderinstead. - Change
SaveableStateHolderto release saved states of removed records.
Misc¶
- Fixe an issue causing codegen to fail for class @Inject annotations.
- Compile against Android SDK 35.
- Update Compose Android BOM to
2025.01.01. - Update to androidx.annotation
1.9.1. - Update to androidx.activity
1.10.0. - Update to Compose Android
1.7.7. - Update to Compose Multiplatform
1.7.3. - Update to Kotlin
1.9.10. - [code gen] Update to KSP
1.9.10-1.0.29. - [code gen] Update to Dagger
2.55. - [code gen] Update to KotlinPoet
2.0.0. - [code gen] Build against Anvil-KSP
0.4.1. Should still be compatible with square/anvil as well. - [code gen] Build against kotlin-inject-anvil
0.1.2. Should still be compatible with square/anvil as well. - [samples] Update mosaic + modernize mosaic counter sample to fully use effects.
- [docs] Fix variable casing in Navigation documentation example.
Special thanks to @vulpeszerda, @rharter, @alexvanyo, and @easyhooon for contributing to this release!
0.25.0¶
2024-10-23
- New: Pass
tonalElevationtoBottomSheetOverlayso that is reflected inModalBottomSheet. - Enhancement: Add
-dontwarnon Anvil classes from codegen annotations. - Enhancement: Misc small doc fixes and updates.
- Enhancement: Add note about only creating a presenter for supported screen types in tutorial.
- Update kotlinInject.anvil to
0.0.5. - Update androidx.activity to
1.9.3. - Update androidx.lifecycle to
2.8.6. - Update Kotlin to
2.0.21. - Build against KSP to
2.0.21-1.0.25. - Update Turbine to
1.2.0. - Update Compose Android to
1.7.4. - Update Compose Multiplatform to
1.7.0.
Special thanks to @eboudrant, @bidrohi, @hossain-khan, and @dturner for contributing to this release!
0.24.0¶
2024-09-16
- New: Add code gen support for kotlin-inject + kotlin-inject-anvil. See the code gen docs for usage instructions. We’ve also added a sample project.
- New:
presenterTestOf()andPresenter.test()functions now return a newCircuitReceiveTurbineinterface. This interface slightly but importantly modifies the behavior ofawaitItem()by making it only emit changed items rather than every item. If you do want to assert the equivalent state is emitted across recompositions, you can useawaitUnchanged(). - New: Promote
LocalBackStackto public API. - Behavior change: Due to the above-documented change to
awaitItem(), you may need to update tests that previously assumed duplicate emissions. - Update to Kotlin
2.0.20. - Change: Switch to stdlib’s implementation of
Uuid. This release now requires Kotlin2.0.20or later. - Add sample test to demonstrate
rememberAnsweringNavigatorresult handling. - Update to kotlinx.coroutines
1.9.0. - Update to compose-bom
2024.09.01. - Update to kotlinx.collections.immutable
0.3.8. - Update to androidx.activity
1.9.2. - Update to androidx.lifecycle
2.8.5. - Update to kotlin
2.0.20. - Build against KSP
2.0.20-1.0.25.
0.23.1¶
2024-07-30
- New: Promote
NoOpRetainedStateRegistryto public API for use in testing and previews. - New: Add
CircuitPreviewhelper function for composable previews that contain Circuit content. - Enhancement: When running under
LocalInspectionMode, Circuit’s defaultonUnavailableContentnow shows a simpler non-intrusive placeholder UI instead. - Enhancement: Support secondary injected constructors in code gen.
- Fix: Fix non-dismissable
BottomSheetOverlaycrash when invoking back-press. - Update to Kotlin
2.0.10. - Update to androidx.annotation
1.8.2. - Build against KSP
2.0.10-1.0.24.
0.23.0¶
2024-07-30
- New: Add macOS, windows, linux, tvOS, and watchOS targets to Circuit’s runtime and retained artifacts.
- New: Add macOS targets to Circuit’s UI, backstack, overlay, test, circuitx (except gesture nav), and foundation artifacts.
- Slightly optimize
pausableState#1455. - Change:
OverlayHost.showFullScreenOverlaynow returns thePopResult?that was popped by the screen. - Change: Remove
backstackdependency fromcircuit-runtime. It was unnecessary and also accidentally imposed Compose UI on the runtime/presenter artifacts. - Change: Make
Overlayafun interface. - Breaking Change: Change
OverlayEffectto use a newOverlayScopeAPI that implements bothCoroutineScopeandOverlayHost, making both contexts available in the lambda. - Update KSP to
2.0.0-1.0.24. - Update androidx.activity to
1.9.1. - Update androidx.lifecycle to
2.8.4. - Update androidx.annotation to
1.8.1. - Update KotlinPoet
1.18.1. - Update Compose Multiplatform to
1.6.11.
Special thanks to @aschulz90 and @chrisbanes for contributing to this release!
0.22.2¶
2024-06-04
- Fix: Fix
pausableStaterecomposition loops by avoiding backward snapshot writes. - New: Add
Circuit.presentWithLifecycleflag to enable/disable automaticpausableStateuse. This is enabled by default. - Update Compose Multiplatform to
1.6.11. - Update androidx.lifecycle to
2.8.1. - Update androidx.appcompat to
1.7.0.
Special thanks to @chrisbanes, @adamp, and Chuck Jazdzewski for contributing to this release and helping us find a runtime fix for the pausableState issue!
0.22.1¶
2024-05-28
- Fix: Fix
rememberRetainedimplicitly requiringLocalContextwhere it used to no-op. - Update Molecule to
2.0.0.
0.22.0¶
2024-05-28
- Update to Kotlin
2.0.0. - Update to KSP
2.0.0-1.0.21. - Update Compose Multiplatform to
1.6.10. - Switch to the compose compiler shipped with Kotlin.
This release is otherwise identical to 0.21.0, just updated to Kotlin 2.0.
0.21.0¶
2024-05-28
- New: Add WASM targets.
- New: Add
FakeNavigatorfunctions to check for the lack of pop/resetRoot events. - New: Add
FakeNavigatorconstructor param to add additional screens to the backstack. - New: Add support for static UIs. In some cases, a UI may not need a presenter to compute or manage its state. Examples of this include UIs that are stateless or can derive their state from a single static input or an input [Screen]’s properties. In these cases, make your screen implement the
StaticScreeninterface. When aStaticScreenis used, Circuit will internally allow the UI to run on its own and won’t connect it to a presenter if no presenter is provided. - New: Add
RecordLifecycleandLocalRecordLifecyclecomposition local, allowing UIs and presenters to observe when they are ‘active’. Currently, a record is considered ‘active’ when it is the top record on the back stack. - New: Add a
rememberRetainedSaveablevariant that participates in bothRetainedStateRegistryandSaveableStateRegistryrestoration, allowing layered state persistence. - The logic is the following upon
rememberRetainedSaveableentering composition:- consume from both
RetainedStateRegistryandSaveableStateRegistry, if available - if the retained value is available, use that
- otherwise, if the saveable restored value is available, use that
- otherwise, re-initialize the value
- consume from both
- There is also an overload of
rememberRetainedthat explicitly requires aSaverparameter. - Behaviour Change: Presenters are now ‘paused’ when inactive and replay their last emitted
CircuitUiStatewhen they are not active. Presenters can opt-out of this behavior by implementingNonPausablePresenter. - Behaviour Change:
NavigatorImpl.goTono longer navigates if theScreenis equal toNavigator.peek(). - Behaviour Change:
Presenter.presentis now annotated with@ComposableTarget("presenter"). This helps prevent use of Compose UI in the presentation logic as the compiler will emit a warning if you do. Note this does not appear in the IDE, so it’s recommended to useallWarningsAsErrorsto fail the build on this event. - Behaviour Change: Guard against
Navigator.goTo()calls to the same current screen. - Change:
Navigator.goTonow returns a Bool indicating navigation success. - Change: Move iOS
GestureNavigationDecorationimpl tocommonMainand rename toCupertinoGestureNavigationDecoration. - Change: Target jvmTarget
1.8in core libraries. - Fix: Fix saveable state being restored when using reset root navigation events.
- Deprecation:
FakeNavigator.assertIsEmptyandexpectNoEvents(use the specific event type methods instead) - Mark
Presenter.Factoryas@Stable. - Mark
Ui.Factoryas@Stable. - Mark
CircuitContextas@Stable. - Mark
EventListeneras@Stable. - Mark
EventListener.Factoryas@Stable. - [samples] Improve interop sample significantly.
- Update Kotlin to
1.9.24. - Update KSP to
1.9.24-2.0.20. - Update compose-compiler to
1.5.14. - Update KotlinPoet to
1.17.0. - Update androidx.lifecycle to
2.8.0. - Update Molecule to
1.4.3. - Update androidx.annotation to
1.8.0. - Update kotlinx.coroutines to
1.8.1. - Update Compose Multiplatform to
1.6.2. - Update Compose UI to
1.6.7. - Update Compose Runtime to
1.6.7. - Update Compose Animation to
1.6.7. - Update Compose Material to
1.6.7. - Update androidx.core to
1.13.1. - Update androidx.activity to
1.9.0. - Update dagger to
2.51.1. - Update uuid to
0.8.4.
Special thanks to @chrisbanes, @alexvanyo, @eboudrant, @edenman, and @JustinBis for contributing to this release!
0.20.0¶
2024-03-18
- New: Enable
RememberObserverto work withrememberRetained. - New: Add
Navigator.popRoot(). extension (#1274) - Behavior change: Add a key to
CircuitContentto keepUiandPresenterconsistent. We already did this for presenters, this just makes it consistent for both. - [circuitx-android] Implement
ToastEffect. - Fix: Fix
rememberImpressionNavigator()not delegatingPopResult. - Fix: Navigator - Pass
PopResulttoonRootPop(). - Fix: Check
canRetainCheckwhen savingRetainedStateRegistry. - Enhancement: Improve error messaging when using assisted inject.
- Force
com.google.guava:listenablefutureto1.0to avoid conflicts with Guava. - Update compose-compiler to
1.5.10.1. - Update coroutines to
1.8.0. - Update to Compose Multiplatform
1.6.1. - Update Android compose dependencies to
1.6.3. - Update molecule to
1.4.1. - Update dagger to
2.51. - Update turbine to
1.1.0. - Update uuid to
0.8.3. - Update kotlin to
1.9.23. - Update KSP to
1.9.23-1.0.19.
Special thanks to @chrisbanes, @aschulz90, and @alexvanyo for contributing to this release!
0.19.1¶
2024-02-12
This is a small bug fix release focused SaveableBackStack consistency and FakeNavigator API improvements.
- Fix
FakeNavigator.awaitNextScreen()not suspending. - Fix
FakeNavigator.resetRoot()not returning the actual popped screens. - Make
Navigator.peekBackStack()andNavigator.resetRoot()returnImmutableList. - Make
BackStack.popUntil()return theImmutableListof the popped records. - Support
FakeNavigator.peekBackStack()return theImmutableListof the popped records. - Strongly pop events and resetRoot events in
FakeNavigator. This should offer much more information about the events. - Use a real
BackStackinstance inFakeNavigator+ allow for specifying a user-provided instance. - Require an initial root screen to construct
FakeNavigatorunless using a customBackStack. - Note this slightly changes semantics, as now the root screen will not be recorded as the first
goToevent. - Require an initial root screen (or list of screens) for
rememberSaveableBackStack(). - Expose a top-level non-composable
Navigator()factory function.
0.19.0¶
2024-02-09
Navigation with results¶
This release introduces support for inter-screen navigation results. This is useful for scenarios where you want to pass data back to the previous screen after a navigation event, such as when a user selects an item from a list and you want to pass the selected item back to the previous screen.
var photoUrl by remember { mutableStateOf<String?>(null) }
val takePhotoNavigator = rememberAnsweringNavigator<TakePhotoScreen.Result>(navigator) { result ->
photoUrl = result.url
}
// Elsewhere
takePhotoNavigator.goTo(TakePhotoScreen)
// In TakePhotoScreen.kt
data object TakePhotoScreen : Screen {
@Parcelize
data class Result(val url: String) : PopResult
}
class TakePhotoPresenter {
@Composable fun present(): State {
// ...
navigator.pop(result = TakePhotoScreen.Result(newFilters))
}
}
See the new section in the navigation docs for more details, as well as updates to the Overlays docs that help explain when to use an Overlay vs navigating to a Screen with a result.
Support for multiple back stacks¶
This release introduces support for saving/restoring navigation state on root resets (aka multi back stack). This is useful for scenarios where you want to reset the back stack to a new root but still want to retain the previous back stack’s state, such as an app UI that has a persistent bottom navigation bar with different back stacks for each tab.
This works by adding two new optional saveState and restoreState parameters to Navigator.resetRoot().
navigator.resetRoot(HomeNavTab1, saveState = true, restoreState = true)
// User navigates to a details screen
navigator.push(EntityDetails(id = foo))
// Later, user clicks on a bottom navigation item
navigator.resetRoot(HomeNavTab2, saveState = true, restoreState = true)
// Later, user switches back to the first navigation item
navigator.resetRoot(HomeNavTab1, saveState = true, restoreState = true)
// The existing back stack is restored, and EntityDetails(id = foo) will be top of
// the back stack
There are times when saving and restoring the back stack may not be appropriate, so use this feature only when it makes sense. A common example where it probably does not make sense is launching screens which define a UX flow which has a defined completion, such as onboarding.
New Tutorial!¶
On top of Circuit’s existing docs, we’ve added a new tutorial to help you get started with Circuit. It’s a step-by-step guide that walks you through building a simple inbox app using Circuit, intended to serve as a sort of small code lab that one could do in 1-2 hours. Check it out here.
Overlay Improvements¶
- New: Promote
AlertDialogOverlay,BasicAlertDialogOverlay, andBasicDialogOverlaytocircuitx-overlay. - New: Add
OverlayEffecttocircuit-overlay. This offers a simple composable effect to show an overlay and await a result.OverlayEffect(state) { host -> val result = host.show(AlertDialogOverlay(...)) // Do something with the result } - Add
OverlayStateandLocalOverlayStatetocircuit-overlay. This allows you to check the current overlay state (UNAVAILABLE,HIDDEN, orSHOWING). - Mark
OverlayHostas@ReadOnlyOverlayApito indicate that it’s not intended for direct implementation by consumers. - Mark
Overlayas@Stable.
Misc¶
- Make
NavEvent.screenpublic. - Change
Navigator.popUntilto be exclusive. - Add
Navigator.peek()to peek the top screen of the back stack. - Add
Navigator.peekBackStack()to peek the top screen of the back stack. - Align spelling of back stack parameters across all APIs to
backStack. - Refreshed iOS Counter sample using SPM and SKIE.
- Convert STAR sample to KMP. Starting with Android and Desktop.
- Fix baseline profiles packaging. Due to a bug in the baseline profile plugin, we were not packaging the baseline profiles in the artifacts. This is now fixed.
- Mark
BackStack.Recordas@Stable. - Fix an infinite loop in the
onRootPopof the AndroidrememberCircuitNavigator. - Update the default decoration to better match the android 34 transitions.
- Update androidx.lifecycle to
2.7.0. - Update to compose multiplatform to
1.5.12. - Update to compose to
1.6.1. - Update to compose-bom to
2024.02.00. - Update compose-compiler to
1.5.9. - Update AtomicFu to
0.23.2. - Update Anvil to
2.4.9. - Update KotlinPoet to
1.16.0. - Compile against KSP
1.9.22-1.0.17.
Special thanks to @milis92, @ChrisBanes, and @vulpeszerda for contributing to this release!
0.18.2¶
2024-01-05
- Fix: Fix lifetime of
Records’ViewModelStores. This fully fixes #1065. - Update Molecule to
1.3.2. - Update Jetbrains’ compose-compiler to
1.5.7.1.
Special thanks to @dandc87 for contributing to this release!
0.18.1¶
2024-01-01
- Fix: Fix popped Record’s
ProvidedValueslifetime. See #1065 for more details. - Fix: Fix
GestureNavDecorationdropping saveable/retained state on back gestures. See #1089 for more details.
Special thanks to @ChrisBanes and @dandc87 for contributing to this release!
0.18.0¶
2023-12-29
- New: Support animating an overlay out after returning a result with
AnimatedOverlay. - Fix: Fix dropping back stack retained state on Android Activity rotations.
- Enhancement: Add ability to customize
ModalBottomSheetappearance inBottomSheetOverlay. - Update Kotlin to
1.9.22. - Update KSP to
1.9.22-1.0.16. - Update Dagger to
2.50. - Update kotlinx-collections-immutable to
0.3.7. - Update AndroidX Activity to
1.8.2.
Special thanks to @ChrisBanes, @chriswiesner, and @BryanStern for contributing to this release!
0.17.1¶
2023-12-05
- Enhancement: Commonize
SaveableStateRegistryBackStackRecordLocalProviderto be supported across all currently supported platforms. - Fix: Fix
LocalBackStackRecordLocalProvidersalways returning a new composition local. - Update
androidx.compose.compiler:compilerto1.5.5 - Update KotlinPoet to
1.15.3 - Update Dagger to
2.49
Special thanks to @alexvanyo for contributing to this release.
0.17.0¶
2023-11-28
New: circuitx-effects artifact¶
The circuitx-effects artifact provides some effects for use with logging/analytics. These effects
are typically used in Circuit presenters for tracking impressions and will run only once until
forgotten based on the current circuit-retained strategy.
dependencies {
implementation("com.slack.circuit:circuitx-effects:<version>")
}
Docs: https://slackhq.github.io/circuit/circuitx/#effects
New: Add codegen mode to support both Anvil and Hilt¶
Circuit’s code gen artifact now supports generating for Hilt projects. See the docs for usage instructions: https://slackhq.github.io/circuit/code-gen/
Misc¶
- Decompose various
CircuitContentinternals likerememberPresenter(),rememberUi, etc for reuse. - Make
CircuitContent()overload that accepts a pre-constructed presenter/ui parameters public to allow for more control over content. - [samples] Update README to include the interop sample.
- [samples] Various bugfixes to samples.
- [docs] Link sources in kdocs.
- [docs] Nest CircuitX artifacts in kdocs ToC.
- Update uuid to
0.8.2. - Update KotlinPoet to
1.15.1. - Update to Compose Multiplatform
1.5.11. - Update to Kotlin
1.9.21. - Update to KSP
1.9.21-1.0.15. - Update to compose-compiler (multiplatform)
1.5.4. - Update to Molecule
1.3.1.
Special thanks to @jamiesanson, @frett, and @bryanstern for contributing to this release!
0.16.1¶
2023-11-09
- Fix: Fix retained value not recalculating if inputs changed.
- Build against KSP
1.9.20-1.0.14.
0.16.0¶
2023-11-01
- New:
circut-retainedis now enabled automatically inCircuitCompositionLocalsby default, we still allowing overriding it with no-op implementation. - Update to Kotlin
1.9.20. - Update Compose Multiplatform to
1.5.2. - Update
agpto8.1.2. - Update
androidx.activityto1.8.0. - Update
benchmarkto1.2.0. - Update
coilto2.5.0. - Update
compose.material3to1.1.2. - Update
compose.materialto1.5.4. - Update
compose.runtimeto1.5.4. - Update
compose.uito1.5.4. - Update
roborazzito1.6.0.
0.15.0¶
2023-09-20
New: Allow retained state to be retained whilst UIs and Presenters are on the back stack.¶
Originally, circuit-retained was implemented as a solution for preserving arbitrary data across configuration changes on Android. With this change it now also acts as a solution for retaining state across the back stack, meaning that traversing the backstack no longer causes restored contents to re-run through their empty states anymore.
To support this, each back stack entry now has its own RetainedStateRegistry instance.
Note that circuit-retained is still optional for now, but we are considering making it part of CircuitCompositionLocals in the future. Please let us know your thoughts in this issue: https://github.com/slackhq/circuit/issues/891.
Full details + demos can be found in https://github.com/slackhq/circuit/pull/888. Big thank you to @chrisbanes for the implementation!
Other changes¶
- New: Add
collectAsRetainedStateutility function, analogous tocollectAsStatebut will retain the previous value across configuration changes and back stack entries. - Enhancement: Optimize
rememberRetainedwith a port of the analogous optimization inrememberSaveable. See #850. - Enhancement:
PresenterandUiinterfaces are now annotated as@Stable. - Fix: Fix
GestureNavigationDecorationfunction parameter order. - Fix:
BackHandleron iOS now has the proper file name. - Fix: Key the
presenter.present()inCircuitContenton theScreenrather than thepresenteritself, which fixes a severe issue that preventedcurrentCompositeKeyHashfrom working correctly onrememberRetainedandrememberSaveableuses. - Update CM compiler to
1.5.2. - Update CM to
1.5.1. - Update
androidx.compose.animationto1.5.1. - Update
androidx.compose.foundationto1.5.1. - Update
androidx.compose.runtimeto1.5.1. - Update
androidx.compose.materialto1.5.1. - Update
androidx.lifecycleto2.6.2. - Update
androidx.annotationto1.7.0.
0.14.1¶
2023-09-03
- New: Add
GestureNavigationDecorationtoCircuitXcourtesy of @chrisbanes.
This is a new NavDecoration that allows for gesture-based navigation, such as predictive back in Android 14 or drag gestures in iOS. See the docs for more details.
NavigableCircuitContent(
navigator = navigator,
backstack = backstack,
decoration = GestureNavigationDecoration(
// Pop the back stack once the user has gone 'back'
navigator::pop
)
)
- Fix embedded baseline profiles in published artifacts. Unfortunately GMDs used to generate these are quite finicky to run so these are sometimes tricky to regen each release.
Special thanks to @chrisbanes and @alexvanyo for contributing to this release!
0.14.0¶
2023-08-30
- New: Circuit now supports JS targets!
- New: Introduce CircuitX artifacts. CircuitX is a suite of extension artifacts for Circuit. These artifacts are intended to be
batteries-included implementations of common use cases, such as out-of-the-box
Overlaytypes or Android navigation interop. See the docs for more details. - Enhancement: Promote
Screento its own artifact. This is now under thecom.slack.circuit.runtime.screen.Screenname. - Enhancement: Use
Screendirectly in theBackStackin place ofroute. - Enhancement: No longer require
SaveableBackStackinNavigableCircuitContent, now anyBackStackimpl is supported. - Enhancement: Make
CanRetainCheckermore customizable incircuit-retained. - Enhancement: Pass the whole list of active records to
DecoratedContent, allowing more complex handling of back gestures (predictive back in android, drag gestures in iOS, etc). - Enhancement: Refactor out a
buildCircuitContentProviders()inNavigableCircuitContent, which enablesmovableContentOfto work since it’s reusing the same instance for records across changes. - Fix: Fix duplicated
ModifierforDecoratedContent. - Fix: Fix new presenter instances of the same type not being recomposed. See #799 for more details.
- Fix: Export iOS targets for
circuit-testartifact. - Demonstrate back handling for Compose Multiplatform in Counter sample.
- Add
kotlinx.collections.immutableto core APIs. - Update to Compile SDK 34.
- Update to Compose Multiplatform
1.5.0. - Update androidx.compose.compiler to
1.5.3. - Update androidx.compose.ui to
1.5.0. - Update androidx.compose.material to
1.5.0. - Update androidx.compose.runtime to
1.5.0. - Update androidx.compose.foundation to
1.5.0. - Update uuid to
0.8.1. - Update Molecule to
1.2.0. - Update Kotlin to
1.9.10. - Update KSP to
1.9.10-1.0.13.
Thanks to @chrisbanes and @ashdavies for contributing to this release!
0.13.0-beta01¶
2023-08-17
- New: Circuit now supports JS targets!
- New: Introduce CircuitX artifacts. CircuitX is a suite of extension artifacts for Circuit. These artifacts are intended to be
batteries-included implementations of common use cases, such as out-of-the-box
Overlaytypes or Android navigation interop. See the docs for more details. - Fix: Fix new presenter instances of the same type not being recomposed. See #799 for more details.
- Fix: Export iOS targets for
circuit-testartifact. - Update to Compile SDK 34.
- Update to Compose Multiplatform
1.5.0-beta02. - Update androidx.compose.ui to
1.5.0. - Update androidx.compose.material to
1.5.0. - Update androidx.compose.runtime to
1.5.0. - Update androidx.compose.foundation to
1.5.0. - Update Molecule to
1.2.0. - Update KSP to
1.9.0-1.0.13.
Note this release is a beta release due to the dependency on CM 1.5.0-beta02.
0.12.1¶
2023-08-01
- Patch release with baseline profiles bundled in the Android artifacts again.
- Update to Anvil
2.4.7.
0.12.0¶
2023-07-28
- [foundation] Rename
CircuitConfig->Circuit. There is a source-compatible typealias forCircuitConfigleft with a deprecation replacement to ease migration. - [foundation] Rename
CircuitContext.config->CircuitContext.circuit. The previousCircuitContext.configfunction is left with a deprecation replacement to ease migration. - [test] Add new
TestEventSinkhelper for testing event emissions in UI tests. - [overlay] Add missing coroutines implementation dependency.
- Update to Kotlin
1.9.0. - Update to KSP
1.9.0-1.0.12. - Update to Compose Multiplatform
1.4.3. - Update to Coroutines
1.7.3. - Update to Compose compiler to
1.5.1(androidx) and1.5.0(compose-multiplatform). - Update uuid to
0.8.0.
0.11.0¶
2023-07-20
- [runtime] Fix race condition in
EventListener.start()callback. - [code gen] Update to Dagger 2.47.
- [docs] No longer recommend or require extracting intermediate event sink variables. This is no longer an issue 🎉.
- Update Molecule to
1.0.0.
Thanks to @bryanstern for contributing to this release!
0.10.1¶
2023-07-09
- [runtime] Make
CircuitContentoverload withNavigatorpublic. - [runtime] Remember
PresenterandUiinCircuitContent. - [runtime] Fix kdoc typo in
RememberRetained.
Special thanks to @chrisbanes and @bryanstern for contributing to this release!
0.10.0¶
2023-06-30
- [runtime] Fix wrong compose-compiler used in iOS targets. Now we’re using the compose-multiplatform fork.
- [runtime] Allow creation of multiple
RetainedStateRegistryinstances. - [docs] Add clarifying links to Events docs.
- [samples] Add new image detail view in STAR sample.
- Update Molecule to
0.11.0. - Update AndroidX compose-compiler to
1.4.8. - Update compose-multiplatform to
1.4.1. - Update to coroutines
1.7.2. - Update to Turbine
1.0.0. - Update to Kotlin
1.8.22.
Special thanks to @bryanstern, @saket, and @chrisbanes for contributing to this release!
0.9.1¶
2023-06-02
- [runtime] Promote
NavEventsubtypes to public API. - [runtime] Update
com.benasher44:uuidto0.7.1. - [code gen] Update Anvil to
2.4.6.
0.9.0¶
2023-05-26
Preliminary support for iOS targets¶
Following the announcement of Compose for iOS alpha, this release adds ios() and iosSimulatorArm64() targets for the Circuit core artifacts. Note that this support doesn’t come with any extra APIs yet for iOS, just basic target support only. We’re not super sure what direction we want to take with iOS, but encourage others to try it out and let us know what patterns you like. We have updated the Counter sample to include an iOS app target as well, using Circuit for the presentation layer only and SwiftUI for the UI.
Note that circuit-codegen and circuit-codegen-annotations don’t support these yet, as Anvil and Dagger only support JVM targets.
More details can be found in the PR: https://github.com/slackhq/circuit/pull/583
Misc¶
- Use new baseline profile plugin for generating baseline profiles.
- Misc sample app fixes and updates.
- Add window size class example to STAR sample.
- Switch to Roborazzi for screenshot test samples.
- Small documentation updates.
- Add bi-directional Flow/Circuit interop to interop sample.
Note that we unintentionally used an experimental animation API for NavigatorDefaults.DefaultDecotration, which may cause R8 issues if you use a newer, experimental version of Compose animation. To avoid issues, copy the animation code and use your own copy compiled against the newest animation APIs. We’ll fix this after Compose 1.5.0 is released.
Dependency updates¶
androidx.activity -> 1.7.2
compose -> 1.4.3
compose-compiler -> 1.4.7
coroutines -> 1.7.1
kotlin -> 1.8.21
kotlinpoet -> 1.13.2
turbine -> 0.13.0
0.8.0¶
2023-04-06
[Core] Split up core artifacts.¶
circuit-runtime: common runtime components likeScreen,Navigator, etc.circuit-runtime-presenter: thePresenterAPI, depends oncircuit-runtime.circuit-runtime-ui: theUiAPI, depends oncircuit-runtime.circuit-foundation: the circuit foundational APIs likeCircuitConfig,CircuitContent, etc. Depends on the first three.
The goal in this is to allow more granular dependencies and easier building against subsets of the API. For example, this would allow a presenter implementation to easily live in a standalone module that doesn’t depend on any UI dependencies. Vice versa for UI implementations.
Where we think this could really shine is in multiplatform projects where Circuit’s UI APIs may be more or less abstracted away in service of using native UI, like in iOS.
circuit-runtime artifact¶
| Before | After |
|---|---|
| com.slack.circuit.CircuitContext | com.slack.circuit.runtime.CircuitContext |
| com.slack.circuit.CircuitUiState | com.slack.circuit.runtime.CircuitUiState |
| com.slack.circuit.CircuitUiEvent | com.slack.circuit.runtime.CircuitUiEvent |
| com.slack.circuit.Navigator | com.slack.circuit.runtime.Navigator |
| com.slack.circuit.Screen | com.slack.circuit.runtime.Screen |
circuit-runtime-presenter artifact¶
| Before | After |
|---|---|
| com.slack.circuit.Presenter | com.slack.circuit.runtime.presenter.Presenter |
circuit-runtime-ui artifact¶
| Before | After |
|---|---|
| com.slack.circuit.Ui | com.slack.circuit.runtime.presenter.Ui |
circuit-foundation artifact¶
| Before | After |
|---|---|
| com.slack.circuit.CircuitCompositionLocals | com.slack.circuit.foundation.CircuitCompositionLocals |
| com.slack.circuit.CircuitConfig | com.slack.circuit.foundation.CircuitConfig |
| com.slack.circuit.CircuitContent | com.slack.circuit.foundation.CircuitContent |
| com.slack.circuit.EventListener | com.slack.circuit.foundation.EventListener |
| com.slack.circuit.NavEvent | com.slack.circuit.foundation.NavEvent |
| com.slack.circuit.onNavEvent | com.slack.circuit.foundation.onNavEvent |
| com.slack.circuit.NavigableCircuitContent | com.slack.circuit.foundation.NavigableCircuitContent |
| com.slack.circuit.NavigatorDefaults | com.slack.circuit.foundation.NavigatorDefaults |
| com.slack.circuit.rememberCircuitNavigator | com.slack.circuit.foundation.rememberCircuitNavigator |
| com.slack.circuit.push | com.slack.circuit.foundation.push |
| com.slack.circuit.screen | com.slack.circuit.foundation.screen |
More Highlights¶
- [Core] Remove Android-specific
NavigableCircuitContentand just use common one. Back handling still runs throughBackHandler, but is now configured inrememberCircuitNavigator. - [Core] Add
defaultNavDecorationtoCircuitConfigto allow for customizing the defaultNavDecorationused inNavigableCircuitContent. - [Core] Mark
CircuitUiStateas@Stableinstead of@Immutable. - [Code gen] Capitalize generated class names when source is a presenter function.
- [Sample] New
:samples:tacosorder builder sample to demonstrate complex state management. - [Sample]
NavigableCircuitContentexample in the desktop counter. - [Dependencies] Update compose to
1.4.1. - [Dependencies] Update compose-compiler to
1.4.4. - [Dependencies] Update androidx.activity to
1.7.0. - [Dependencies] Update molecule to
0.7.1.
0.7.0¶
2023-02-10
- New: Multiplatform support for
NavigableCircuitContent! Special thanks to @ashdavies for contributions to make this possible. - Fix:
circuit-retainedminSdk is now 21 again. We accidentally bumped it to 28 when merging in its instrumentation tests. - Enhancement: embedded baseline profiles are now embedded per-artifact instead of in the root
circuit-coreartifact. - Enhancement:
circuit-retainedis now covered in embedded baseline profiles. - [Code Gen] Update Dagger to
2.45. - [Code Gen] Update KSP to
1.8.10-1.0.9. - Update to compose-compiler
1.4.2. - Update to Kotlin
1.8.10.
0.6.0¶
2023-02-02
Happy groundhog day!
- Breaking API change:
Ui.Content()now contains aModifierparameter.
This allows you to pass modifiers on to UIs directly.
public interface Ui<UiState : CircuitUiState> {
- @Composable public fun Content(state: UiState)
+ @Composable public fun Content(state: UiState, modifier: Modifier)
}
- New: Add
Navigator.resetRoot(Screen)function to reset the backstack root with a new root screen. There is a correspondingawaitResetRoot()function added toFakeNavigator. - New: Add
EventListener.startcallback function. - New: Add Compose UI dependency to circuit-core (to support
Modifierin the API). - Fix: Fix
CircuitContext.putTaggenerics. - Fix: Fix KSP code gen artifact to just be a pure JVM artifact.
- Fix:
EventListener.onState’s type is nowCircuitUiStateinstead ofAny. - Removed:
ScreenUiis now removed andUi.Factorysimply returnsUiinstances now. -
API Change:
CircuitConfig.onUnavailableContentis now no longer nullable. By default it displays a big ugly error text. If you want the previous behavior of erroring, replace it with a composable function that just throws an exception. -
Dependency updates
Kotlin 1.8.0 Compose-JB 1.3.0 KSP 1.8.0-1.0.9 Compose Runtime 1.3.3 Compose UI 1.3.3 Compose Animation 1.3.3
0.5.0¶
2022-12-22
- Enhancement: Circuit no longer requires manual provisioning of its internal backing
ViewModels. This is now done automatically by the Circuit itself. - Enhancement:
circuit-retainedis now fully optional and not included as a transitive dependency of circuit-core. If you want to use it, see its installation instructions in its README. - Enhancement: Mark
Screenas@Immutable. - Breaking API Change:
LocalCircuitOwneris now justLocalCircuitConfigto be more idiomatic. - Breaking API Change:
LocalRetainedStateRegistryOwneris now justLocalRetainedStateRegistryto be more idiomatic. - Breaking API Change:
Continuityis nowinternaland not publicly exposed since it no longer needs to be manually provided. - Breaking API Change:
ViewModelBackStackRecordLocalProvideris nowinternaland not publicly exposed since it no longer needs to be manually provided. - Fix: Add missing license info to pom.
- Dependency updates
[versions] anvil = "2.4.3" compose-jb = "1.2.2" compose-animation = "1.3.2" compose-compiler = "1.3.2" compose-foundation = "1.3.1" compose-material = "1.3.1" compose-material3 = "1.0.1" compose-runtime = "1.3.2" compose-ui = "1.3.2" kotlin = "1.7.22"
0.4.0¶
2022-12-07
- Breaking API Change:
PresenterandUifactories’create()functions now offer aCircuitContextparameter in place of aCircuitConfigparameter. This class contains aCircuitConfig, a tagging API, and access to parent contexts. This allows for plumbing your own metadata through Circuit’s internals such as tracing tools, logging, etc. - Enhancement: New lifecycle functions added to
EventListener. onBeforeCreatePresenteronAfterCreatePresenteronBeforeCreateUionAfterCreateUionUnavailableContentonStartPresentonDisposePresentonStartContentonDisposeContentdispose- Update Compose to
1.3.1. - Update Compose (JB) to
1.2.1. - Update Molecule to
0.6.1. - Added a demo to the STAR sample that shows how to navigate to standard Android components (#275).
0.3.1¶
2022-11-07
- Enhancement: Add back the
onRootPop()parameter inrememberCircuitNavigator()but useLocalOnBackPressedDispatcherOwnerfor backpress handling by default.
0.3.0¶
2022-11-01
- New: The Overlay API is now extracted to a separate, optional
circuit-overlayartifact. - New: The
circuit-coreartifact now packages in baseline profiles. - Enhancement: Simplify backstack root pop handling. There is no more
onRootPop()option inrememberCircuitNavigator(), instead you should install your ownBackHandler()prior to rendering your circuit content to customize back behavior when the circuitNavigatoris at root. - Fix:
circuit-codegen-annotationsis now a multiplatform project and doesn’t accidentally impose the compose-desktop dependency.
We’ve also updated a number of docs around code gen, overlays, and interop (including a new interop sample).
0.2.2¶
2022-10-27
- Enhancement: Code gen now supports non-assisted constructor-injected types.
- Enhancement: Code gen checks that functions and classes are visible to generated factories.
0.2.1¶
2022-10-27
- Fix: Code gen didn’t properly handle instantiating simple class types.
0.2.0¶
2022-10-26
-
New: Code gen artifact. This targets specifically using Dagger + Anvil and will generate
PresenterandUi.Factoryimplementations for you. SeeCircuitInjectfor more details.ksp("com.slack.circuit:circuit-codegen:x.y.z") implementation("com.slack.circuit:circuit-codegen-annotations:x.y.z") -
New: There is now an
EventListenerAPI for instrumenting state changes for a givenScreen. See its docs for more details. - Fix: Rework
rememberRetainedimplementation and support for multiple variables. Previously it only worked with one variable. - Fix: Clean up some unnecessary transitive dependencies in misc artifacts.
Dependency updates
androidx.activity 1.6.1
androidx.compose 1.3.0
Molecule 0.5.0
0.1.2¶
2022-10-12
- Update to compose-jb
1.2.0. - Update to Turbine
0.12.0. - Fix: Accidentally running molecule twice in
Presenter.test().
0.1.1¶
2022-10-10
- Fix: Accidentally bundling more Compose UI dependencies than necessary.
0.1.0¶
2022-10-10
Initial release, see the docs: https://slackhq.github.io/circuit/.
Note that this library is still under active development and not recommended for production use. We’ll do a more formal announcement when that time comes!