Skip to content

Releases: futamura/Fluidable

Release list

3.0.0

Choose a tag to compare

@futamura futamura released this 20 Aug 05:27
25770bc

[3.0.0] - 2026-08-20

Fluidable now builds in the Swift 6 language mode. Adopting this release
requires source changes in any project that conforms to Fluidable's delegate
protocols or matches on FluidCoreAnimatorError.

Minimum requirements are unchanged: iOS 15.0 or later, built with Xcode 26.

Breaking Changes

1. Delegate protocols and view-facing types are now @MainActor

FluidDelegate is annotated with @MainActor, so every protocol that inherits
from it is main-actor isolated as well:

  • FluidTransitionConfigurationDelegate
  • FluidTransitionActionDelegate
  • FluidTransitionSourceConfigurationDelegate
  • FluidTransitionDestinationConfigurationDelegate
  • FluidTransitionSourceActionDelegate
  • FluidTransitionDestinationActionDelegate
  • FluidNavigationConfigurationDelegate
  • FluidNavigationActionDelegate
  • FluidNavigationSourceConfigurationDelegate
  • FluidNavigationDestinationConfigurationDelegate
  • FluidNavigationSourceActionDelegate
  • FluidNavigationDestinationActionDelegate

The following declarations are annotated directly:

  • FluidResizableTransitionDelegate
  • FluidNavigationBarCompatible
  • FluidFrameDimensionCompatible
  • FluidInteractiveView
  • FluidBackgroundCompatible
  • FluidAnimatorCompatible
  • FluidCoreAnimatorLayerConvertible
  • AdaptiveElement
  • AdaptiveInterface
  • FluidNavigationControllerDelegate
  • FluidViewControllerTransitioningDelegate
  • FluidLayout

Conforming types must be main-actor isolated. UIViewController and UIView
subclasses already are, so most conformances keep compiling unchanged. A
conformance declared on a type that is not isolated needs an explicit
annotation:

// Before (2.x)
final class TransitionCoordinator: NSObject, FluidTransitionSourceConfigurationDelegate {
    func transitionPresentationStyle(from source: FluidSourceViewController,
                                     to destination: FluidDestinationViewController,
                                     with navigation: FluidNavigationController?) -> FluidTransitionStyle {
        return .fluid(behavior: .all)
    }
}

// After (3.0.0)
@MainActor
final class TransitionCoordinator: NSObject, FluidTransitionSourceConfigurationDelegate {
    func transitionPresentationStyle(from source: FluidSourceViewController,
                                     to destination: FluidDestinationViewController,
                                     with navigation: FluidNavigationController?) -> FluidTransitionStyle {
        return .fluid(behavior: .all)
    }
}

Any access to these types from a non-isolated context now has to hop to the
main actor, for example with await MainActor.run { ... } or by marking the
calling function @MainActor.

2. FluidCoreAnimatorError.invalidArgument carries String instead of Any?

The from and to payloads changed from Any? to String so that the error
is Sendable. The values are formatted with String(describing:) before the
error is thrown, so the rendered text is unchanged.

// Before (2.x)
case .invalidArgument(let id, let key, let from, let to):
    print(id, key, String(describing: from), String(describing: to))

// After (3.0.0)
case .invalidArgument(let id, let key, let from, let to):
    print(id, key, from, to)

3. FluidRoundCornerStyle.all raw value changed from 11 to 15

all was defined as [.top, .right, .left, .left], which omitted .bottom
and duplicated .left. As a result all.contains(.bottom) returned false
and its description dropped bottom. It is now [.top, .right, .bottom, .left].

// Before (2.x)
FluidRoundCornerStyle.all.rawValue          // 11
FluidRoundCornerStyle.all.contains(.bottom) // false

// After (3.0.0)
FluidRoundCornerStyle.all.rawValue          // 15
FluidRoundCornerStyle.all.contains(.bottom) // true

If you persisted the raw value of all, remap 11 to 15 when reading it
back:

let stored: Int = defaults.integer(forKey: "cornerStyle")
let style: FluidRoundCornerStyle = stored == 11 ? .all : .init(rawValue: stored)

4. roundingCorners and maskedCorners now honour arbitrary combinations

Both accessors matched self against the five named constants with a switch.
Because switch on an OptionSet is exact equality, any other combination fell
through to default and produced no rounding. They now union the corner sets of
every flag they contain, so combinations that were silently ignored start taking
effect.

let style: FluidRoundCornerStyle = [.top, .right]

// Before (2.x)
style.roundingCorners  // nil
style.maskedCorners    // []

// After (3.0.0)
style.roundingCorners  // [.topLeft, .topRight, .bottomRight]
style.maskedCorners    // [.layerMinXMinYCorner, .layerMaxXMinYCorner, .layerMaxXMaxYCorner]

roundingCorners still returns UIRectCorner.allCorners when all four corners
are selected, because allCorners has a raw value of ~0 and is not equal to
the union of the four individual corners.

Added

  • Sendable conformance for the public value types: FluidDriverType,
    FluidAnimationType, FluidBackgroundStyle, FluidDriverInteractionType,
    FluidNavigationStyle, FluidPresentationStyle, FluidSlideDirection,
    FluidDrawerPosition, FluidTransitionStyle, FluidGestureDirection,
    PennerEasing, FluidAnimatorEasing, FluidAnimatorState,
    FluidInteractionBehavior, FluidRoundCornerStyle, and FluidGestureAxis.
  • PrivacyInfo.xcprivacy privacy manifest, shipped with both the SwiftPM
    resource bundle and the Xcode framework target. Fluidable collects no data
    and uses no required-reason API, so every key is declared empty.

Changed

  • The library, the test target, the example app, and the UI test target all
    build in the Swift 6 language mode.

Fixed

  • FluidRoundCornerStyle.all now includes .bottom. See breaking change 3.
  • roundingCorners and maskedCorners now round the corners of any flag
    combination instead of only the five named constants. See breaking change 4.

What's Changed

  • chore: remove legacy Jazzy/Carthage-era artifacts by @futamura in #43
  • Migrate Fluidable library to Swift 6 language mode by @futamura in #44
  • Include bottom corner in FluidRoundCornerStyle.all by @futamura in #45
  • Adopt Swift 6 language mode for FluidableTests by @futamura in #46
  • Adopt Swift 6 language mode for Example and UITests by @futamura in #47
  • feat(privacy): add PrivacyInfo.xcprivacy to library target by @futamura in #48
  • build(deps): add Dependabot configuration by @futamura in #49
  • docs: add .spi.yml pointing to the GitHub Pages documentation by @futamura in #50
  • chore(release): prepare 3.0.0 by @futamura in #51
  • Release 3.0.0 by @futamura in #52

Full Changelog: 2.0.0...3.0.0

2.0.0

Choose a tag to compare

@futamura futamura released this 26 May 03:58

What's Changed

  • fix(ci): include UI tests in coverage by @gumob in #21
  • Merge develop into main by @gumob in #22
  • Fix sharded coverage upload by @gumob in #23
  • Fix main coverage upload by @gumob in #25
  • Fix UI coverage shard upload by @gumob in #26
  • Backport UI coverage shard fix to develop by @gumob in #27
  • fix(ui-tests): restore interactive dismiss rotation by @gumob in #28
  • test(ios): align coverage lane with CI shards by @gumob in #29
  • Improve Codecov core coverage by @gumob in #30
  • Sync main into develop for Codecov CI check by @gumob in #32
  • Merge develop into main for Codecov coverage by @gumob in #31
  • test: stabilize coverage UI dismiss flow by @gumob in #33
  • ci: recheck Codecov coverage on main by @gumob in #34
  • #19 Improve Codecov coverage with targeted tests by @gumob in #35
  • Check main Codecov coverage after #19 by @gumob in #36
  • Stabilize DrawerTop UI scroll setup by @gumob in #37
  • Run main Codecov coverage check after DrawerTop stabilization by @gumob in #38
  • Fix modal blur navigation by @gumob in #39
  • Fix modal dismiss table truncation by @gumob in #40
  • fix(example): clean startup warnings by @gumob in #41
  • fix(ios): prewarm modal blur snapshots by @gumob in #42

Full Changelog: 1.0.0...2.0.0