Skip to content

Commit

Permalink
Reimplement core architecture (#106)
Browse files Browse the repository at this point in the history
This PR has breaking changes. See `docs/migration-guide-0.5.x.md` for
more details.

The summary is:
- Moved responsibility for creating SheetExtent to SheetController
- Reimplemented SheetExtent as ValueListenable<SheetMetrics>
- Changed SheetActivity to directly update SheetExtent instead of having
its own `pixels`
- Refactored the core logic of NavigationSheet
- Bumped to 0.5.0
  • Loading branch information
fujidaiti authored May 4, 2024
1 parent 2c5ff53 commit 058b116
Show file tree
Hide file tree
Showing 27 changed files with 1,137 additions and 1,162 deletions.
4 changes: 2 additions & 2 deletions cookbook/lib/showcase/airbnb_mobile_app.dart
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,8 @@ class _MapButton extends StatelessWidget {
final sheetController = DefaultSheetController.of(context);

void onPressed() {
final metrics = sheetController.metrics;
if (metrics != null) {
final metrics = sheetController.value;
if (metrics.hasDimensions) {
// Collapse the sheet to reveal the map behind.
sheetController.animateTo(
Extent.pixels(metrics.minPixels),
Expand Down
2 changes: 1 addition & 1 deletion cookbook/lib/tutorial/bottom_bar_visibility.dart
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ class _ExampleSheet extends StatelessWidget {
// The bottom bar is visible when at least 50% of the sheet is visible.
return metrics.pixels >=
const Extent.proportional(0.5)
.resolve(metrics.contentDimensions);
.resolve(metrics.contentSize);
},
child: bottomBar,
),
Expand Down
5 changes: 2 additions & 3 deletions cookbook/lib/tutorial/sheet_content_scaffold.dart
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,9 @@ class _ExampleSheet extends StatelessWidget {
bottomBar: ConditionalStickyBottomBarVisibility(
// This callback is called whenever the sheet's metrics changes.
getIsVisible: (metrics) {
return metrics.viewportDimensions.insets.bottom == 0 &&
return metrics.viewportInsets.bottom == 0 &&
metrics.pixels >
const Extent.proportional(0.5)
.resolve(metrics.contentDimensions);
const Extent.proportional(0.5).resolve(metrics.contentSize);
},
child: buildBottomBar(),
),
Expand Down
4 changes: 2 additions & 2 deletions cookbook/lib/tutorial/sheet_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,9 @@ class _ExampleHomeState extends State<_ExampleHome> {
// SheetController can be used to observe changes in the sheet extent.
child: ValueListenableBuilder(
valueListenable: controller,
builder: (context, value, child) {
builder: (context, metrics, child) {
return Text(
'Extent: ${value?.toStringAsFixed(1)}',
'Extent: ${metrics.maybePixels?.toStringAsFixed(1)}',
style: Theme.of(context).textTheme.displaySmall,
);
},
Expand Down
96 changes: 96 additions & 0 deletions docs/migration-guide-0.5.x.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# Migration guide to 0.5.x from 0.4.x

The changes in v0.5.0 are summarized in the following list. The breaking changes are marked with :boom:.

## Changes in SheetController

- :boom: Now it implements `ValueListenable<SheetMetrics>` instead of `ValueListenable<double?>`.
- Added `SheetStatus status`.
- Added `createSheetExtent()`.

## Changes in SheetNotification

- Added `SheetStatus status`.

## Changes in SheetMetrics

- Added `double? maybePixels`.
- Added `double? maybeMinPixels`.
- Added `double? maybeMaxPixels`.
- Added `Size? maybeContentSize`.
- Added `Size? maybeViewportSize`.
- Added `EdgeInsets? maybeViewportInsets`.
- :boom:`pixels` is no longer nullable.

- :boom:`minPixels` is no longer nullable.
- :boom:`maxPixels` is no longer nullable.
- :boom:`viewPixels` is no longer nullable.
- :boom:`minViewPixels` is no longer nullable.
- :boom:`maxViewPixels` is no longer nullable.
- :boom: ​Changed `Size? contentDimensions` to `Size contentSize`.
- Added `Size? viewportSize`.
- Added `EdgeInsets? viewportInsets`.
- :boom: ​Removed `ViewportDimensions viewportDimensions`.
- Use `viewportSize` and `viewportInsets` instead.
- Added `double? maybeViewPixels`.
- Added `double? maybeMinViewPixels`.
- Added `double? maybeMaxViewPixels`.
- :boom: ​Changed the signature of `copyWith()`.
- Renamed `contentDimensions` to `contentSize`.
- Removed `viewportDimensions`.
- Added `viewportSize` and `viewportInsets`.

## Changes in SheetExtent

- Now it implements `ValueListenable<SheetMetrics>`.
- :boom:`MaybeSheetMetrics` is no longer mixed in.

- Added `SheetExtentConfig config`.
- Added `SheetExtentDelegate delegate`.
- Added `SheetMetrics metrics`.
- Added `applyNewConfig()`.
- Added `setPixels()`.
- Added `correctPixels()`.
- Added `SheetMetrics value`.
- :boom: ​Removed `SheetMetricsSnapshot snapshot`
- :boom: ​Removed `SheetPhysics physics`.
- Use `config.physics` instead.
- :boom: ​Removed `Extent minExtent`.
- Use `config.minExtent` instead.
- :boom: ​Removed `double? pixels`
- Use `metrics.pixels` instead.
- :boom: ​Removed `double? minPixels`
- Use `metrics.minPixels` instead.
- :boom: ​Removed `double? maxPixels`.
- Use `metrics.maxPixels` instead.
- :boom: ​Renamed `applyNewContentDimensions()` to `applyNewContentSize()`.
- :boom: ​Changed the signature of `applyNewDimensions()`.
- `void (ViewportDimensions)``void (Size, EdgeInsets)`

### Added sub-components

- `SheetExtentConfig`
- `SheetExtentDelegate`

### Removed sub-components

- :boom:`MaybeSheetMetrics`
- Use `SheetMetrics.maybe*` instead to handle cases where values are null.
- :boom:`ViewportDimensions`

## Changes in SheetActivity

- :boom: ​It is no longer a sub-class of `ChangeNotifier`.

- :boom: ​Renamed `delegate` to `owner`.
- :boom: ​Renamed `didChangeContentDimensions()` to `didChangeContentSize()`.

- :boom: ​Removed `double? pixels`.
- :boom: ​Removed `correctPixels()`.
- :boom: ​Removed `setPixels()`.
- :boom: ​Changed the signature of `didChangeViewportDimensions()`.
- `void (ViewportDimensions)``void (Size, EdgeInsets)`

## Others

- Added `kDefaultSheetPhysics`, which is the default `SheetPhysics` used by the sheet widgets.
7 changes: 7 additions & 0 deletions package/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Changelog

## 0.5.0 May 4, 2024

This version contains some breaking changes. See the [migration guide](https://github.com/fujidaiti/smooth_sheets/blob/main/docs/migration-guide-0.5.x.md) for more details.

- Attach default controller to sheet if not explicitly specified (#102)
- Reimplement core architecture (#106)

## 0.4.2 Apr 21, 2024

- Add new SheetNotifications for drag events (#92)
Expand Down
6 changes: 4 additions & 2 deletions package/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ This library is currently in the experimental stage. The API may undergo changes

## Migration guide

- [0.3.x to 0.4.x](https://github.com/fujidaiti/smooth_sheets/blob/main/docs/migration-guide-0.4.x.md) 🆕
- [0.4.x to 0.5.x](https://github.com/fujidaiti/smooth_sheets/blob/main/docs/migration-guide-0.5.x.md) 🆕

- [0.3.x to 0.4.x](https://github.com/fujidaiti/smooth_sheets/blob/main/docs/migration-guide-0.4.x.md)

- [0.2.x to 0.3.x](https://github.com/fujidaiti/smooth_sheets/blob/main/docs/migration-guide-0.3.x.md)

Expand Down Expand Up @@ -313,7 +315,7 @@ A sheet dispatches a [SheetNotification](https://pub.dev/documentation/smooth_sh
```dart
NotificationListener<SheetNotification>(
onNotification: (notification) {
debugPrint('$notification');
debugPrint('${notification.metrics}');
return false;
},
child: DraggableSheet(...),
Expand Down
1 change: 0 additions & 1 deletion package/lib/smooth_sheets.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ export 'src/foundation/sheet_extent.dart';
export 'src/foundation/theme.dart';
export 'src/modal/cupertino.dart';
export 'src/modal/modal_sheet.dart';
export 'src/navigation/navigation_route.dart';
export 'src/navigation/navigation_routes.dart';
export 'src/navigation/navigation_sheet.dart';
export 'src/scrollable/scrollable_sheet.dart'
Expand Down
111 changes: 31 additions & 80 deletions package/lib/src/draggable/draggable_sheet.dart
Original file line number Diff line number Diff line change
Expand Up @@ -42,16 +42,15 @@ class DraggableSheet extends StatelessWidget {
/// The strategy to dismiss the on-screen keyboard when the sheet is dragged.
final SheetKeyboardDismissBehavior? keyboardDismissBehavior;

/// {@macro SizedContentSheetExtent.initialExtent}
final Extent initialExtent;

/// {@macro SheetExtent.minExtent}
/// {@macro SheetExtentConfig.minExtent}
final Extent minExtent;

/// {@macro SheetExtent.maxExtent}
/// {@macro SheetExtentConfig.maxExtent}
final Extent maxExtent;

/// {@macro SheetExtent.physics}
/// {@macro SheetExtentConfig.physics}
final SheetPhysics? physics;

/// An object that can be used to control and observe the sheet height.
Expand All @@ -68,6 +67,7 @@ class DraggableSheet extends StatelessWidget {
@override
Widget build(BuildContext context) {
final theme = SheetTheme.maybeOf(context);
final physics = this.physics ?? theme?.physics ?? kDefaultSheetPhysics;
final keyboardDismissBehavior =
this.keyboardDismissBehavior ?? theme?.keyboardDismissBehavior;

Expand All @@ -76,11 +76,13 @@ class DraggableSheet extends StatelessWidget {
builder: (context, controller) {
return SheetContainer(
controller: controller,
delegate: const DraggableSheetExtentDelegate(),
config: DraggableSheetExtentConfig(
initialExtent: initialExtent,
minExtent: minExtent,
maxExtent: maxExtent,
physics: physics,
debugLabel: 'DraggableSheet',
),
child: SheetDraggable(
behavior: hitTestBehavior,
Expand All @@ -101,99 +103,48 @@ class DraggableSheet extends StatelessWidget {
}
}

/// A configuration of a [DraggableSheetExtent].
class DraggableSheetExtentConfig extends SheetExtentConfig {
const DraggableSheetExtentConfig({
required this.initialExtent,
required this.minExtent,
required this.maxExtent,
required this.physics,
});

/// {@macro DraggableSheetExtent.initialExtent}
final Extent initialExtent;

/// {@macro SheetExtent.minExtent}
final Extent minExtent;

/// {@macro SheetExtent.maxExtent}
final Extent maxExtent;

/// {@macro SheetExtent.physics}
final SheetPhysics? physics;

@override
bool shouldRebuild(BuildContext context, SheetExtent oldExtent) {
return oldExtent is! DraggableSheetExtent ||
oldExtent.minExtent != minExtent ||
oldExtent.maxExtent != maxExtent ||
oldExtent.initialExtent != initialExtent ||
oldExtent.physics != _resolvePhysics(context);
}
class DraggableSheetExtentDelegate with SheetExtentDelegate {
const DraggableSheetExtentDelegate();

@override
SheetExtent build(BuildContext context, SheetContext sheetContext) {
return DraggableSheetExtent(
context: sheetContext,
initialExtent: initialExtent,
minExtent: minExtent,
maxExtent: maxExtent,
physics: _resolvePhysics(context),
);
}

SheetPhysics _resolvePhysics(BuildContext context) {
const fallback = StretchingSheetPhysics(parent: SnappingSheetPhysics());
final theme = SheetTheme.maybeOf(context);
final base = theme?.basePhysics;
if (physics case final physics?) {
return base != null ? physics.applyTo(base) : physics;
} else if (theme?.physics case final inherited?) {
// Do not apply the base physics to the inherited physics.
return inherited;
} else {
return base != null ? fallback.applyTo(base) : fallback;
}
SheetActivity createIdleActivity() {
return _IdleDraggableSheetActivity();
}
}

/// [SheetExtent] for a [DraggableSheet].
class DraggableSheetExtent extends SheetExtent {
DraggableSheetExtent({
required super.context,
required super.physics,
class DraggableSheetExtentConfig extends SheetExtentConfig {
const DraggableSheetExtentConfig({
required this.initialExtent,
required super.minExtent,
required super.maxExtent,
required this.initialExtent,
}) {
goIdle();
}
required super.physics,
super.debugLabel,
});

/// {@template DraggableSheetExtent.initialExtent}
/// The initial extent of the sheet when it is first shown.
/// {@endtemplate}
final Extent initialExtent;

@override
void goIdle() {
beginActivity(_IdleDraggableSheetActivity(
initialExtent: initialExtent,
));
bool operator ==(Object other) {
if (identical(this, other)) return true;
return other is DraggableSheetExtentConfig &&
other.initialExtent == initialExtent &&
super == other;
}

@override
int get hashCode => Object.hash(initialExtent, super.hashCode);
}

class _IdleDraggableSheetActivity extends IdleSheetActivity {
_IdleDraggableSheetActivity({
required this.initialExtent,
});

final Extent initialExtent;
_IdleDraggableSheetActivity();

@override
void didChangeContentDimensions(Size? oldDimensions) {
super.didChangeContentDimensions(oldDimensions);
if (pixels == null) {
setPixels(initialExtent.resolve(delegate.contentDimensions!));
void didChangeContentSize(Size? oldDimensions) {
super.didChangeContentSize(oldDimensions);
final config = owner.config;
final metrics = owner.metrics;
if (metrics.maybePixels == null && config is DraggableSheetExtentConfig) {
owner.setPixels(config.initialExtent.resolve(metrics.contentSize));
}
}
}
Loading

0 comments on commit 058b116

Please sign in to comment.