Update circuit to v0.39.0 - #448
Open
renovate[bot] wants to merge 1 commit into
Open
renovate[bot] wants to merge 1 commit into
renovate[bot] wants to merge 1 commit into
Conversation
renovate
Bot
force-pushed
the
renovate/circuit
branch
from
July 16, 2026 05:31
7074d3b to
762ce87
Compare
renovate
Bot
force-pushed
the
renovate/circuit
branch
from
August 5, 2026 06:12
762ce87 to
90d5dcd
Compare
renovate
Bot
force-pushed
the
renovate/circuit
branch
from
August 12, 2026 03:36
90d5dcd to
601ae1d
Compare
renovate
Bot
force-pushed
the
renovate/circuit
branch
from
August 22, 2026 22:45
601ae1d to
df36abb
Compare
renovate
Bot
force-pushed
the
renovate/circuit
branch
from
August 23, 2026 01:08
df36abb to
43579a0
Compare
renovate
Bot
force-pushed
the
renovate/circuit
branch
from
August 26, 2026 20:48
43579a0 to
4986efc
Compare
renovate
Bot
force-pushed
the
renovate/circuit
branch
from
September 16, 2026 01:11
4986efc to
c60d62c
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR contains the following updates:
0.33.1→0.39.00.33.1→0.39.00.33.1→0.39.00.33.1→0.39.00.33.1→0.39.0Release Notes
slackhq/circuit (com.slack.circuit:circuit-test)
v0.39.0Compare Source
2026-09-15
New
RetainedStateRegistry.forgetValue(key), the single-key counterpart toforgetUnclaimedValues(). CustomRetainedStateRegistryimplementations will need to implement it.Changed
2.4.20.1.12.0.1.12.1.9.4.0.2.4.0.Fixed
NavigableCircuitContentnow clears saved and retained state for records truncated out of the navstack while not composed.RetainedStateHolder.removeStatenow retires removed values instead of dropping them silently.v0.38.0Compare Source
2026-08-26
ScreenandPopResultare no longer ParcelableScreenandPopResultno longer extendParcelableon Android. Apps upgrading to this release should choose the persistence strategy that fits each typeAlready using kotlinx-serialization
SerializableCircuitSaverorReflectiveSerializableCircuitSaversetup. Remove@Parcelize, and useScreenorPopResultdirectly instead of the Parcelable marker interfaces.Keep Android Parcelable persistence
@Parcelizeand change the type to implementParcelableScreenorParcelablePopResult. The registry-backed default saver accepts these types on Android.Migrate gradually
Put the serializing saver first and retain the registry-backed saver as a fallback for Parcelable types:
Do not persist navigation state
CircuitSaver.NoOp. Restored stacks start again from their initial value.See Saving navigation state for complete setup and migration examples.
Saving an unsupported value now fails instead of silently dropping it. To intentionally drop values that no earlier saver supports, append
CircuitSaver.Dropping { value -> ... }to the saver chain. UseCircuitSaver.NoOpas the final saver when dropped values do not need to be reported.New
rememberDefaultCircuitSaver()creates a saver backed by the current ComposeSaveableStateRegistry.CircuitCompositionLocals(circuit)uses it automatically when no static or inherited saver is available.CircuitSaverinstances with+. Savers are tried from left to right, and the first saver that supports a value owns the save or restore operation.Circuit.Builder.setCircuitSaver { fallbackSaver -> ... }combines an app saver with the saver inherited from the composition or created from its registry.canSaveandcanRestoreto participate in a composite.Removed
DefaultCircuitSaver.CircuitCompositionLocals(circuit)now creates a registry-backed saver when needed. CallrememberDefaultCircuitSaver()when a saver must be passed explicitly.Saverproperties fromSaveableBackStackandSaveableNavStack. Use theSaver(CircuitSaver)functions.Fixed
@CircuitSerializableor@CircuitInjectwithout Hilt on the runtime classpath.v0.37.1Compare Source
2026-08-22
New
RetainedValuesStoreProviderandRetainedValuesStoreOwnerAPIs for preserving AndroidXretainvalues across composition recreation on non-Android platforms. This is temporary cover until androidx's implementation offers a non-android solution. See the first-partyretaindocumentation.CircuitRetainedSettings.enforceRetainObserverCompatibility, an opt-in check that retained values implementingRememberObserveralso implementRetainObserver.Changed
CircuitRetainedSettings.useFirstParty = falsebefore the first composition to use the previousViewModel-based backing. Other platforms remain opt-in.v0.37.0Compare Source
2026-08-22
Ignore this release, it was accidentally cut with some stale branch changes!
v0.36.1Compare Source
2026-08-11
Fixed
SerializableCircuitSaverround trips for registered types with nestedScreenorPopResultproperties.v0.36.0Compare Source
2026-08-05
New
circuit-codegencan now generate kotlinx-serialization registrations forScreenandPopResulttypes. Annotate each type with@CircuitSerializable(scope). The annotation supplies the default kotlinx serializer, andcircuit-codegencontributes a registration through the selected DI framework. Pass the injectedSet<CircuitSerializerRegistration>toSerializableCircuitSaver.A Metro setup looks like this:
Parcelable. A future release will remove this requirement.See the code generation guide for setup and generated code examples.
rememberAnsweringNavigatorandansweringNavigationAvailableare now part ofcircuit-runtime, so presenters can use them throughcircuit-runtime-presenter.NavigableCircuitContentcontinues to provide result delivery. Without it,rememberAnsweringNavigatorreturns the supplied fallback navigator.AnsweringResultHandlerhas moved tocircuit-runtime.rememberAnsweringResultHandlerremains incircuit-foundationto provide saveable-state persistence without adding Compose runtime-saveable tocircuit-runtime.Fixed
CircuitRetainedSettings.useFirstPartyis enabled,retain {}values removed from conditional UI now retire normally instead of surviving for the navigation record's entire lifetime.Deprecated
answeringNavigationAvailablefunction andrememberAnsweringNavigatoroverloads that take a fallbackNavigatorare deprecated. Use the runtime versions.Tin a reified call. Update the import manually if this occurs (KTIJ-12093).AnsweringResultHandlertype is deprecated in favor of its runtime replacement. ItsSaverAPIs have been removed. UserememberAnsweringResultHandlerfor a saveable handler.Changed
retain(key = ...)andretainSaveable(...)APIs. Non-saveablerememberRetained(key = ...)calls are now deprecated in favor ofretain(key = ...). Unkeyed and saveablerememberRetainedvariants andrememberRetainedSaveableremain supported but will eventually be deprecated.Contributors
Special thanks to the following contributors for contributing to this release!
v0.35.1Compare Source
2026-07-15
New
Pluggable
Screen/PopResultpersistence withCircuitSaverCircuit's saveable back stacks no longer mandate how
Screens andPopResults are persisted. A newCircuitSaverabstraction incircuit-runtime-screenconverts them to and from saveablerepresentations. Everything that saves navigation state (
rememberSaveableBackStack,rememberSaveableNavStack, and answering results) now accepts one.This is the first step toward removing the
Parcelablesupertypes fromScreenandPopResultonAndroid in a future release. In 0.35, both types still need to be Parcelable even when using a
serializing saver or
CircuitSaver.NoOp. The default saver preserves the current Parcelablebehavior. To prepare for the later removal, implement
ParcelableScreenorParcelablePopResulton types that should remain Parcelable, or adopt a serializing saver.
Configure a saver by passing it explicitly, providing
LocalCircuitSaverat your app root viaProvideCircuitSaver, or withCircuit.Builder.setCircuitSaver(reaches only content insideCircuitCompositionLocals).New artifacts:
circuit-serializationandcircuit-serialization-reflectFor kotlinx-serialization users, the new
circuit-serializationartifact persists@Serializablescreens and pop results to
SavedStateviaandroidx.savedstate:SerializableCircuitSaver(configuration): KMP-friendly; register screens and results forpolymorphic serialization against
CircuitSaveablein theSavedStateConfiguration'sserializersModule.ReflectiveSerializableCircuitSaver(configuration)(in the JVM/Android-onlycircuit-serialization-reflectartifact): resolves serializers reflectively with no registrationneeded. It embeds the R8/ProGuard rules it needs, so minified apps need no additional
Circuit-specific rules.
Both savers can restore navigation state saved by Circuit 0.34's default saver. They restore
leniently: records that no longer decode, such as after an app update removed a screen, are dropped
rather than crashing. Pass an
onRestoreErrorcallback to observe drops. The bottom-navigationsample demonstrates the kotlinx setup end to end.
Also new:
ParcelableScreen/ParcelablePopResult: common interfaces that addParcelableon Android.Migrate common-code values to these to keep using the Parcelable strategy once
ScreenandPopResultdrop theirParcelablesupertypes.CircuitSaver.NoOp: disables navigation state persistence entirely.circuit-retained is migrating to upstream
retainedAPIsCompose recently introduced a retain API, which is essentially a first-party solution for what circuit-retained has long offered. While it's not fully ready to replace all the things circuit-retained covered, most of the core functionality is there. As such, we are beginning to wind down circuit-retained in favor of the first-party solution where it makes sense.
This will a multi-phase migration over multiple releases, starting with initial interop in this release to allow making circuit-retained run on top of the first-party
retainAPIs under the hood. This allows for testing use without migrating anything in your codebase.CircuitRetainedSettings.useFirstParty = true(before the first composition) backslifecycleRetainedStateRegistry()with a root-levelretaincall instead of a Circuit-managedViewModel, delegating configuration-change survival to theRetainedValuesStoreinstalled in the composition.rememberRetained/rememberRetainedSaveablesemantics are unchanged.retain {}can be used directly in presenters and UIs alongsiderememberRetained. In navigated content, retained values follow their record's lifetime.See the circuit-retained README for more details.
Deprecated
SaveableBackStack.Record.argsandSaveableBackStack.push(screen, args). Pass data through theScreenitself instead;argswill be removed in a future release. This matches what the newSaveableNavStackalready does.Savervals onSaveableBackStack,SaveableNavStack, andAnsweringResultHandlercompanions. Use theSaver(CircuitSaver)functions instead.Fixed
discard incomplete forward history and fall back to their initial value if the active screen or
its back history cannot be restored.
when one of their records cannot be restored.
awaitResultsuspending indefinitely when a pending pop result cannot be saved or restored.subcircuit-codegenMetro mode (subcircuit.codegen.mode=metro). It previouslyrequired Dagger's
@AssistedFactoryeven in Metro mode, generated@javax.inject.Injectinstead ofMetro's
@Inject, and referenceddev.zacsweers.metro.annotations.ContributesIntoSet(wrong package).Metro mode now accepts
dev.zacsweers.metro.AssistedFactoryand emitsdev.zacsweers.metro.Inject+dev.zacsweers.metro.ContributesIntoSet, so generated factories compile against Metro.Changed
@SubCircuitInjectis now handled by the maincircuit-codegenprocessor.circuitx-subcircuit-codegenis now a relocation pointer tocircuit-codegen, but preferdepending on
circuit-codegendirectly.37.1.11.4.2.60.1.Contributors
Special thanks to the following contributors for contributing to this release!
v0.35.0Compare Source
2026-07-15
Ignore this release, we goofed and it didn't include regenerated baseline profiles! Use 0.35.1.
v0.34.0Compare Source
2026-05-09
New
SubCircuit
SubCircuit is a lightweight version of Circuit for rendering nested presenter/UI pairs that delegate events to an outer component rather than handling navigation themselves. Use it for nested, reusable UI components that don't need direct navigation access, and need to delegate cross-cutting concerns (navigation, dialogs) to a parent. See the SubCircuit docs for more info!
Artifacts
circuitx-subcircuit— core types (SubScreen, SubPresenter, SubUi, SubCircuitContent).circuitx-subcircuit-codegen— KSP @SubCircuitInject to wire presenter and UI factories into the DI graph. Supports Anvil (default) and Metro.circuitx-subcircuit-test— a .test {} extension for SubPresenters, built on Molecule and Turbine.Fixes
SaveableNavStack-isRecordReachable()off-by-one where depth of 0 didn't check the current recordSaveableBackStack— UpdateisRecordReachable()to matchSaveableNavStackbehaviour@CircuitInjectdeclarations to generated factories.Changes
NavDecorationfrombackstacktocircuit-foundationand added aNavigatorparameter toDecoratedContent.AnimatedNavDecoratornow has anupdateNavigatormethod to receive the newNavigatorparameter. This gives decorations direct access to the correct Navigator for handling back gestures.GestureNavigationEventListenerand an optionallistenerparameter toGestureNavigationDecorationFactory, for observing the back gesture lifecycle (e.g. analytics). It's observational only, theNavigatorstill drives the pop.SaveableNavStack&SaveableBackStack- Made theSavers public apis@CircuitInjectdeclarations now treat any non-circuit-provided parameter as an injected dependency across all modes. The generated factory accepts it as a provider (Provider<T>for Dagger/Anvil/Hilt,() -> Tfor kotlin-inject and Metro) and invokes it once atcreate()time, hoisted above the composablepresenterOf { }/ui { }block so it isn't re-invoked on every recomposition. Parameters already declared asProvider<T>orLazy<T>are passed through as-is rather than re-wrapped. In metro and kotlin-inject modes,() -> Tis also passed through; in Dagger/Anvil/Hilt modes it is treated as a regular dependency.@CircuitInject-annotated classes must now be injectable — annotate the class or a constructor with@Inject. Previously, classes without@Injectsilently generated a direct constructor call that could fail to compile.enableFunctionProvidersto be set enabled, which will be the default in Metro 1.0.0.Misc:
2.4.01.11.0Contributors
Special thanks to the following contributors for contributing to this release!
Configuration
📅 Schedule: (UTC)
🚦 Automerge: Enabled.
♻ Rebasing: Whenever PR is behind base branch, or you tick the rebase/retry checkbox.
🔕 Ignore: Close this PR and you won't be reminded about these updates again.
This PR was generated by Mend Renovate. View the repository job log.