From 380fdf7db3e164cee808b94b124f3d97030902be Mon Sep 17 00:00:00 2001 From: Matthias Ngeo Date: Mon, 18 Nov 2024 16:03:54 +0800 Subject: [PATCH 01/29] Add shifted sheet --- .../lib/src/widgets/sheet/shifted_sheet.dart | 174 ++++++++++++++++++ 1 file changed, 174 insertions(+) create mode 100644 forui/lib/src/widgets/sheet/shifted_sheet.dart diff --git a/forui/lib/src/widgets/sheet/shifted_sheet.dart b/forui/lib/src/widgets/sheet/shifted_sheet.dart new file mode 100644 index 000000000..fed097c8b --- /dev/null +++ b/forui/lib/src/widgets/sheet/shifted_sheet.dart @@ -0,0 +1,174 @@ +import 'package:flutter/widgets.dart'; +import 'package:flutter/rendering.dart'; +import 'package:forui/src/foundation/rendering.dart'; +import 'package:meta/meta.dart'; + +@internal +class ShiftedSheet extends SingleChildRenderObjectWidget { + final Layout side; + final double value; + final double dimensionRatio; + + const ShiftedSheet({ + required this.side, + required this.value, + required this.dimensionRatio, + required super.child, + super.key, + }); + + @override + RenderBox createRenderObject(BuildContext context) => _ShiftedSheet( + side: side, + value: value, + dimensionRatio: dimensionRatio, + ); + + @override + // ignore: library_private_types_in_public_api + void updateRenderObject(BuildContext context, _ShiftedSheet renderObject) { + renderObject + ..side = side + ..value = value + ..dimensionRatio = dimensionRatio; + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(EnumProperty('side', side)) + ..add(DoubleProperty('value', value)) + ..add(DoubleProperty('dimensionRatio', dimensionRatio)); + } +} + +class _ShiftedSheet extends RenderShiftedBox { + Layout _side; + double _value; + double? _dimensionRatio; + + _ShiftedSheet({ + required Layout side, + required double value, + required double dimensionRatio, + }) : _side = side, + _value = value, + _dimensionRatio = dimensionRatio, + super(null); + + @override + void performLayout() { + size = constraints.biggest; + + if (child case final child?) { + final childConstraints = constrainChild(constraints); + assert(childConstraints.debugAssertIsValid(isAppliedConstraint: true), ''); + + child.layout(childConstraints, parentUsesSize: !childConstraints.isTight); + + final childSize = childConstraints.isTight ? childConstraints.smallest : child.size; + child.data.offset = positionChild(size, childSize); + } + } + + @override + double? computeDryBaseline(covariant BoxConstraints constraints, TextBaseline baseline) { + final child = this.child; + if (child == null) { + return null; + } + + final childConstraints = constrainChild(constraints); + final result = child.getDryBaseline(childConstraints, baseline); + if (result == null) { + return null; + } + + final childSize = childConstraints.isTight ? childConstraints.smallest : child.getDryLayout(childConstraints); + return result + positionChild(constraints.biggest, childSize).dy; + } + + BoxConstraints constrainChild(BoxConstraints constraints) => switch (side) { + Layout.ttb || Layout.btt => BoxConstraints( + minWidth: constraints.maxWidth, + maxWidth: constraints.maxWidth, + maxHeight: _dimensionRatio == null ? constraints.maxHeight : constraints.maxHeight * _dimensionRatio!, + ), + Layout.ltr || Layout.rtl => BoxConstraints( + maxWidth: _dimensionRatio == null ? constraints.maxWidth : constraints.maxWidth * _dimensionRatio!, + minHeight: constraints.maxHeight, + maxHeight: constraints.maxHeight, + ), + }; + + Offset positionChild(Size size, Size childSize) => switch (side) { + Layout.ttb => Offset(0, childSize.height * (_value - 1)), + Layout.btt => Offset(0, size.height - childSize.height * _value), + Layout.ltr => Offset(childSize.width * (_value - 1), 0), + Layout.rtl => Offset(size.width - childSize.width * _value, 0), + }; + + @override + Size computeDryLayout(BoxConstraints constraints) => constraints.biggest; + + @override + double computeMinIntrinsicWidth(double height) { + final width = BoxConstraints.tightForFinite(height: height).biggest.width; + return width.isFinite ? width : 0.0; + } + + @override + double computeMaxIntrinsicWidth(double height) { + final width = BoxConstraints.tightForFinite(height: height).biggest.width; + return width.isFinite ? width : 0.0; + } + + @override + double computeMinIntrinsicHeight(double width) { + final height = BoxConstraints.tightForFinite(width: width).biggest.height; + return height.isFinite ? height : 0.0; + } + + @override + double computeMaxIntrinsicHeight(double width) { + final height = BoxConstraints.tightForFinite(width: width).biggest.height; + return height.isFinite ? height : 0.0; + } + + Layout get side => _side; + + set side(Layout value) { + if (_side != value) { + _side = value; + markNeedsLayout(); + } + } + + double get value => _value; + + set value(double value) { + if (_value != value) { + _value = value; + markNeedsLayout(); + } + } + + double? get dimensionRatio => _dimensionRatio; + + set dimensionRatio(double? value) { + if (_dimensionRatio != value) { + _dimensionRatio = value; + markNeedsLayout(); + } + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(EnumProperty('side', side)) + ..add(DoubleProperty('value', value)) + ..add(DoubleProperty('dimensionRatio', dimensionRatio)); + } +} From e6d63c8ceae474b392994b8dba5b886e54fc2381 Mon Sep 17 00:00:00 2001 From: Matthias Ngeo Date: Mon, 18 Nov 2024 17:08:49 +0800 Subject: [PATCH 02/29] Add _GestureDetector --- forui/example/lib/sheet.dart | 401 ++++++++++++++++++ forui/lib/src/widgets/sheet/sheet.dart | 60 +++ .../lib/src/widgets/sheet/shifted_sheet.dart | 23 +- 3 files changed, 472 insertions(+), 12 deletions(-) create mode 100644 forui/example/lib/sheet.dart create mode 100644 forui/lib/src/widgets/sheet/sheet.dart diff --git a/forui/example/lib/sheet.dart b/forui/example/lib/sheet.dart new file mode 100644 index 000000000..e6e41d846 --- /dev/null +++ b/forui/example/lib/sheet.dart @@ -0,0 +1,401 @@ +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/widgets.dart'; + +const Duration _bottomSheetEnterDuration = Duration(milliseconds: 250); +const Duration _bottomSheetExitDuration = Duration(milliseconds: 200); +const Curve _modalBottomSheetCurve = decelerateEasing; +const double _minFlingVelocity = 700.0; +const double _closeProgressThreshold = 0.5; +const double _defaultScrollControlDisabledMaxHeightRatio = 9.0 / 16.0; + +class BottomSheet extends StatefulWidget { + /// Creates a bottom sheet. + /// + /// Typically, bottom sheets are created implicitly by + /// [ScaffoldState.showBottomSheet], for persistent bottom sheets, or by + /// [showModalBottomSheet], for modal bottom sheets. + const BottomSheet({ + super.key, + this.animationController, + this.enableDrag = true, + this.showDragHandle, + this.dragHandleColor, + this.dragHandleSize, + this.onDragStart, + this.onDragEnd, + this.backgroundColor, + this.shadowColor, + this.elevation, + this.shape, + this.clipBehavior, + this.constraints, + required this.onClosing, + required this.builder, + }) : assert(elevation == null || elevation >= 0.0); + + /// The animation controller that controls the bottom sheet's entrance and + /// exit animations. + /// + /// The BottomSheet widget will manipulate the position of this animation, it + /// is not just a passive observer. + final AnimationController? animationController; + + /// Called when the bottom sheet begins to close. + /// + /// A bottom sheet might be prevented from closing (e.g., by user + /// interaction) even after this callback is called. For this reason, this + /// callback might be call multiple times for a given bottom sheet. + final VoidCallback onClosing; + + /// A builder for the contents of the sheet. + /// + /// The bottom sheet will wrap the widget produced by this builder in a + /// [Material] widget. + final WidgetBuilder builder; + + /// If true, the bottom sheet can be dragged up and down and dismissed by + /// swiping downwards. + /// + /// If [showDragHandle] is true, this only applies to the content below the drag handle, + /// because the drag handle is always draggable. + /// + /// Default is true. + /// + /// If this is true, the [animationController] must not be null. + /// Use [BottomSheet.createAnimationController] to create one, or provide + /// another AnimationController. + final bool enableDrag; + + /// Specifies whether a drag handle is shown. + /// + /// The drag handle appears at the top of the bottom sheet. The default color is + /// [ColorScheme.onSurfaceVariant] with an opacity of 0.4 and can be customized + /// using [dragHandleColor]. The default size is `Size(32,4)` and can be customized + /// with [dragHandleSize]. + /// + /// If null, then the value of [BottomSheetThemeData.showDragHandle] is used. If + /// that is also null, defaults to false. + /// + /// If this is true, the [animationController] must not be null. + /// Use [BottomSheet.createAnimationController] to create one, or provide + /// another AnimationController. + final bool? showDragHandle; + + /// The bottom sheet drag handle's color. + /// + /// Defaults to [BottomSheetThemeData.dragHandleColor]. + /// If that is also null, defaults to [ColorScheme.onSurfaceVariant]. + final Color? dragHandleColor; + + /// Defaults to [BottomSheetThemeData.dragHandleSize]. + /// If that is also null, defaults to Size(32, 4). + final Size? dragHandleSize; + + /// Called when the user begins dragging the bottom sheet vertically, if + /// [enableDrag] is true. + /// + /// Would typically be used to change the bottom sheet animation curve so + /// that it tracks the user's finger accurately. + final BottomSheetDragStartHandler? onDragStart; + + /// Called when the user stops dragging the bottom sheet, if [enableDrag] + /// is true. + /// + /// Would typically be used to reset the bottom sheet animation curve, so + /// that it animates non-linearly. Called before [onClosing] if the bottom + /// sheet is closing. + final BottomSheetDragEndHandler? onDragEnd; + + /// The bottom sheet's background color. + /// + /// Defines the bottom sheet's [Material.color]. + /// + /// Defaults to null and falls back to [Material]'s default. + final Color? backgroundColor; + + /// The color of the shadow below the sheet. + /// + /// If this property is null, then [BottomSheetThemeData.shadowColor] of + /// [ThemeData.bottomSheetTheme] is used. If that is also null, the default value + /// is transparent. + /// + /// See also: + /// + /// * [elevation], which defines the size of the shadow below the sheet. + /// * [shape], which defines the shape of the sheet and its shadow. + final Color? shadowColor; + + /// The z-coordinate at which to place this material relative to its parent. + /// + /// This controls the size of the shadow below the material. + /// + /// Defaults to 0. The value is non-negative. + final double? elevation; + + /// The shape of the bottom sheet. + /// + /// Defines the bottom sheet's [Material.shape]. + /// + /// Defaults to null and falls back to [Material]'s default. + final ShapeBorder? shape; + + /// {@macro flutter.material.Material.clipBehavior} + /// + /// Defines the bottom sheet's [Material.clipBehavior]. + /// + /// Use this property to enable clipping of content when the bottom sheet has + /// a custom [shape] and the content can extend past this shape. For example, + /// a bottom sheet with rounded corners and an edge-to-edge [Image] at the + /// top. + /// + /// If this property is null then [BottomSheetThemeData.clipBehavior] of + /// [ThemeData.bottomSheetTheme] is used. If that's null then the behavior + /// will be [Clip.none]. + final Clip? clipBehavior; + + /// Defines minimum and maximum sizes for a [BottomSheet]. + /// + /// If null, then the ambient [ThemeData.bottomSheetTheme]'s + /// [BottomSheetThemeData.constraints] will be used. If that + /// is null and [ThemeData.useMaterial3] is true, then the bottom sheet + /// will have a max width of 640dp. If [ThemeData.useMaterial3] is false, then + /// the bottom sheet's size will be constrained by its parent + /// (usually a [Scaffold]). In this case, consider limiting the width by + /// setting smaller constraints for large screens. + /// + /// If constraints are specified (either in this property or in the + /// theme), the bottom sheet will be aligned to the bottom-center of + /// the available space. Otherwise, no alignment is applied. + final BoxConstraints? constraints; + + @override + State createState() => _BottomSheetState(); + + /// Creates an [AnimationController] suitable for a + /// [BottomSheet.animationController]. + /// + /// This API is available as a convenience for a Material compliant bottom sheet + /// animation. If alternative animation durations are required, a different + /// animation controller could be provided. + static AnimationController createAnimationController( + TickerProvider vsync, { + AnimationStyle? sheetAnimationStyle, + }) => + AnimationController( + duration: sheetAnimationStyle?.duration ?? _bottomSheetEnterDuration, + reverseDuration: sheetAnimationStyle?.reverseDuration ?? _bottomSheetExitDuration, + debugLabel: 'BottomSheet', + vsync: vsync, + ); +} + +class _BottomSheetState extends State { + final GlobalKey _childKey = GlobalKey(debugLabel: 'BottomSheet child'); + + double get _childHeight { + final RenderBox renderBox = _childKey.currentContext!.findRenderObject()! as RenderBox; + return renderBox.size.height; + } + + bool get _dismissUnderway => widget.animationController!.status == AnimationStatus.reverse; + + Set dragHandleMaterialState = {}; + + void _handleDragStart(DragStartDetails details) { + setState(() { + dragHandleMaterialState.add(MaterialState.dragged); + }); + widget.onDragStart?.call(details); + } + + void _handleDragUpdate(DragUpdateDetails details) { + assert( + (widget.enableDrag || (widget.showDragHandle ?? false)) && widget.animationController != null, + "'BottomSheet.animationController' cannot be null when 'BottomSheet.enableDrag' or 'BottomSheet.showDragHandle' is true. " + "Use 'BottomSheet.createAnimationController' to create one, or provide another AnimationController.", + ); + if (_dismissUnderway) { + return; + } + widget.animationController!.value -= details.primaryDelta! / _childHeight; + print(widget.animationController!.value); + } + + void _handleDragEnd(DragEndDetails details) { + assert( + (widget.enableDrag || (widget.showDragHandle ?? false)) && widget.animationController != null, + "'BottomSheet.animationController' cannot be null when 'BottomSheet.enableDrag' or 'BottomSheet.showDragHandle' is true. " + "Use 'BottomSheet.createAnimationController' to create one, or provide another AnimationController.", + ); + if (_dismissUnderway) { + return; + } + setState(() { + dragHandleMaterialState.remove(MaterialState.dragged); + }); + bool isClosing = false; + if (details.velocity.pixelsPerSecond.dy > _minFlingVelocity) { + final double flingVelocity = -details.velocity.pixelsPerSecond.dy / _childHeight; + if (widget.animationController!.value > 0.0) { + widget.animationController!.fling(velocity: flingVelocity); + } + if (flingVelocity < 0.0) { + isClosing = true; + } + } else if (widget.animationController!.value < _closeProgressThreshold) { + if (widget.animationController!.value > 0.0) { + widget.animationController!.fling(velocity: -1.0); + } + isClosing = true; + } else { + widget.animationController!.forward(); + } + + widget.onDragEnd?.call( + details, + isClosing: isClosing, + ); + + if (isClosing) { + widget.onClosing(); + } + } + + bool extentChanged(DraggableScrollableNotification notification) { + if (notification.extent == notification.minExtent && notification.shouldCloseOnMinExtent) { + widget.onClosing(); + } + return false; + } + + void _handleDragHandleHover(bool hovering) { + if (hovering != dragHandleMaterialState.contains(MaterialState.hovered)) { + setState(() { + if (hovering) { + dragHandleMaterialState.add(MaterialState.hovered); + } else { + dragHandleMaterialState.remove(MaterialState.hovered); + } + }); + } + } + + @override + Widget build(BuildContext context) { + final BottomSheetThemeData bottomSheetTheme = Theme.of(context).bottomSheetTheme; + final bool useMaterial3 = Theme.of(context).useMaterial3; + const BottomSheetThemeData defaults = BottomSheetThemeData(); + final BoxConstraints? constraints = widget.constraints ?? bottomSheetTheme.constraints ?? defaults.constraints; + final Color? color = widget.backgroundColor ?? bottomSheetTheme.backgroundColor ?? defaults.backgroundColor; + final Color? surfaceTintColor = bottomSheetTheme.surfaceTintColor ?? defaults.surfaceTintColor; + final Color? shadowColor = widget.shadowColor ?? bottomSheetTheme.shadowColor ?? defaults.shadowColor; + final double elevation = widget.elevation ?? bottomSheetTheme.elevation ?? defaults.elevation ?? 0; + final ShapeBorder? shape = widget.shape ?? bottomSheetTheme.shape ?? defaults.shape; + final Clip clipBehavior = widget.clipBehavior ?? bottomSheetTheme.clipBehavior ?? Clip.none; + final bool showDragHandle = + widget.showDragHandle ?? (widget.enableDrag && (bottomSheetTheme.showDragHandle ?? false)); + + Widget? dragHandle; + if (showDragHandle) { + // dragHandle = _DragHandle( + // onSemanticsTap: widget.onClosing, + // handleHover: _handleDragHandleHover, + // materialState: dragHandleMaterialState, + // dragHandleColor: widget.dragHandleColor, + // dragHandleSize: widget.dragHandleSize, + // ); + // Only add [_BottomSheetGestureDetector] to the drag handle when the rest of the + // bottom sheet is not draggable. If the whole bottom sheet is draggable, + // no need to add it. + if (!widget.enableDrag) { + // dragHandle = _BottomSheetGestureDetector( + // onVerticalDragStart: _handleDragStart, + // onVerticalDragUpdate: _handleDragUpdate, + // onVerticalDragEnd: _handleDragEnd, + // child: dragHandle, + // ); + } + } + + Widget bottomSheet = Material( + key: _childKey, + color: color, + elevation: elevation, + surfaceTintColor: surfaceTintColor, + shadowColor: shadowColor, + shape: shape, + clipBehavior: clipBehavior, + child: NotificationListener( + onNotification: extentChanged, + child: !showDragHandle + ? widget.builder(context) + : Stack( + alignment: Alignment.topCenter, + children: [ + dragHandle!, + Padding( + padding: const EdgeInsets.only(top: kMinInteractiveDimension), + child: widget.builder(context), + ), + ], + ), + ), + ); + + if (constraints != null) { + bottomSheet = Align( + alignment: Alignment.bottomCenter, + heightFactor: 1.0, + child: ConstrainedBox( + constraints: constraints, + child: bottomSheet, + ), + ); + } + + return !widget.enableDrag + ? bottomSheet + : _BottomSheetGestureDetector( + onVerticalDragStart: _handleDragStart, + onVerticalDragUpdate: _handleDragUpdate, + onVerticalDragEnd: _handleDragEnd, + child: bottomSheet, + ); + } +} + +class _BottomSheetGestureDetector extends StatelessWidget { + const _BottomSheetGestureDetector({ + required this.child, + required this.onVerticalDragStart, + required this.onVerticalDragUpdate, + required this.onVerticalDragEnd, + }); + + final Widget child; + final GestureDragStartCallback onVerticalDragStart; + final GestureDragUpdateCallback onVerticalDragUpdate; + final GestureDragEndCallback onVerticalDragEnd; + + @override + Widget build(BuildContext context) => RawGestureDetector( + excludeFromSemantics: true, + gestures: >{ + VerticalDragGestureRecognizer: GestureRecognizerFactoryWithHandlers( + () => VerticalDragGestureRecognizer(debugOwner: this), + (instance) { + instance + ..onStart = onVerticalDragStart + ..onUpdate = onVerticalDragUpdate + ..onEnd = onVerticalDragEnd + ..onlyAcceptDragOnThreshold = true; + }, + ), + }, + child: child, + ); +} + + diff --git a/forui/lib/src/widgets/sheet/sheet.dart b/forui/lib/src/widgets/sheet/sheet.dart new file mode 100644 index 000000000..4ef52dbb5 --- /dev/null +++ b/forui/lib/src/widgets/sheet/sheet.dart @@ -0,0 +1,60 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/gestures.dart'; +import 'package:flutter/widgets.dart'; +import 'package:forui/forui.dart'; + +/// The sheet's gesture detector. We use a [RawGestureDetector] instead of a [GestureDetector] because the latter +/// doesn't allow `onlyAcceptDragOnThreshold` to be configured. +class _GestureDetector extends StatelessWidget { + final Layout layout; + final GestureDragStartCallback onStart; + final GestureDragUpdateCallback onUpdate; + final GestureDragEndCallback onEnd; + final Widget child; + + const _GestureDetector({ + required this.layout, + required this.onStart, + required this.onUpdate, + required this.onEnd, + required this.child, + }); + + @override + Widget build(BuildContext context) { + void initialize(DragGestureRecognizer recognizer) { + recognizer + ..onStart = onStart + ..onUpdate = onUpdate + ..onEnd = onEnd + ..onlyAcceptDragOnThreshold = true; + } + + return RawGestureDetector( + excludeFromSemantics: true, + gestures: { + if (layout.vertical) + VerticalDragGestureRecognizer: GestureRecognizerFactoryWithHandlers( + () => VerticalDragGestureRecognizer(debugOwner: this), + initialize, + ) + else + HorizontalDragGestureRecognizer: GestureRecognizerFactoryWithHandlers( + () => HorizontalDragGestureRecognizer(debugOwner: this), + initialize, + ) + }, + child: child, + ); + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(EnumProperty('layout', layout)) + ..add(ObjectFlagProperty.has('onStart', onStart)) + ..add(ObjectFlagProperty.has('onUpdate', onUpdate)) + ..add(ObjectFlagProperty.has('onEnd', onEnd)); + } +} diff --git a/forui/lib/src/widgets/sheet/shifted_sheet.dart b/forui/lib/src/widgets/sheet/shifted_sheet.dart index fed097c8b..b9dddcc42 100644 --- a/forui/lib/src/widgets/sheet/shifted_sheet.dart +++ b/forui/lib/src/widgets/sheet/shifted_sheet.dart @@ -89,18 +89,17 @@ class _ShiftedSheet extends RenderShiftedBox { return result + positionChild(constraints.biggest, childSize).dy; } - BoxConstraints constrainChild(BoxConstraints constraints) => switch (side) { - Layout.ttb || Layout.btt => BoxConstraints( - minWidth: constraints.maxWidth, - maxWidth: constraints.maxWidth, - maxHeight: _dimensionRatio == null ? constraints.maxHeight : constraints.maxHeight * _dimensionRatio!, - ), - Layout.ltr || Layout.rtl => BoxConstraints( - maxWidth: _dimensionRatio == null ? constraints.maxWidth : constraints.maxWidth * _dimensionRatio!, - minHeight: constraints.maxHeight, - maxHeight: constraints.maxHeight, - ), - }; + BoxConstraints constrainChild(BoxConstraints constraints) => side.vertical + ? BoxConstraints( + minWidth: constraints.maxWidth, + maxWidth: constraints.maxWidth, + maxHeight: _dimensionRatio == null ? constraints.maxHeight : constraints.maxHeight * _dimensionRatio!, + ) + : BoxConstraints( + maxWidth: _dimensionRatio == null ? constraints.maxWidth : constraints.maxWidth * _dimensionRatio!, + minHeight: constraints.maxHeight, + maxHeight: constraints.maxHeight, + ); Offset positionChild(Size size, Size childSize) => switch (side) { Layout.ttb => Offset(0, childSize.height * (_value - 1)), From a853b006ed572f0b3c3bdd2130cd6eaff64e4ab9 Mon Sep 17 00:00:00 2001 From: Matthias Ngeo Date: Tue, 19 Nov 2024 23:40:56 +0800 Subject: [PATCH 03/29] Initial sheet prototype --- forui/lib/forui.dart | 1 + .../src/widgets/sheet/gesture_detector.dart | 95 ++++ forui/lib/src/widgets/sheet/sheet.dart | 424 ++++++++++++++++-- .../lib/src/widgets/sheet/shifted_sheet.dart | 1 + forui/lib/widgets/sheet.dart | 8 + forui/lib/widgets/tile.dart | 2 +- 6 files changed, 491 insertions(+), 40 deletions(-) create mode 100644 forui/lib/src/widgets/sheet/gesture_detector.dart create mode 100644 forui/lib/widgets/sheet.dart diff --git a/forui/lib/forui.dart b/forui/lib/forui.dart index 321df3e39..ebfc5ef7e 100644 --- a/forui/lib/forui.dart +++ b/forui/lib/forui.dart @@ -29,6 +29,7 @@ export 'widgets/scaffold.dart'; export 'widgets/select_group.dart'; export 'widgets/select_menu_tile.dart'; export 'widgets/select_tile_group.dart'; +export 'widgets/sheet.dart'; export 'widgets/slider.dart'; export 'widgets/switch.dart'; export 'widgets/tabs.dart'; diff --git a/forui/lib/src/widgets/sheet/gesture_detector.dart b/forui/lib/src/widgets/sheet/gesture_detector.dart new file mode 100644 index 000000000..de0ee0f24 --- /dev/null +++ b/forui/lib/src/widgets/sheet/gesture_detector.dart @@ -0,0 +1,95 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/gestures.dart'; +import 'package:flutter/widgets.dart'; +import 'package:forui/forui.dart'; +import 'package:meta/meta.dart'; + +/// This is based on Material's _DragHandle. +@internal +class Handle extends StatelessWidget { + final FSheetStyle style; + + /// Creates a handle. + const Handle({required this.style, super.key}); + + @override + Widget build(BuildContext context) => Padding( + padding: style.handlePadding, + child: MouseRegion( + cursor: SystemMouseCursors.click, + child: DecoratedBox( + decoration: BoxDecoration( + color: style.handleColor, + borderRadius: style.handleBorderRadius, + ), + child: SizedBox.fromSize(size: style.handleSize), + ), + ), + ); + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(DiagnosticsProperty('style', style)); + } +} + +/// The sheet's gesture detector. We use a [RawGestureDetector] instead of a [GestureDetector] because the latter +/// doesn't allow `onlyAcceptDragOnThreshold` to be configured. +/// +/// This is based on Material's _BottomSheetGestureDetector. +@internal +class SheetGestureDetector extends StatelessWidget { + final Layout layout; + final GestureDragStartCallback? onStart; + final GestureDragUpdateCallback? onUpdate; + final GestureDragEndCallback? onEnd; + final Widget child; + + const SheetGestureDetector({ + required this.layout, + required this.onStart, + required this.onUpdate, + required this.onEnd, + required this.child, + super.key, + }); + + @override + Widget build(BuildContext context) { + void initialize(DragGestureRecognizer recognizer) { + recognizer + ..onStart = onStart + ..onUpdate = onUpdate + ..onEnd = onEnd + ..onlyAcceptDragOnThreshold = true; + } + + return RawGestureDetector( + excludeFromSemantics: true, + gestures: { + if (layout.vertical) + VerticalDragGestureRecognizer: GestureRecognizerFactoryWithHandlers( + () => VerticalDragGestureRecognizer(debugOwner: this), + initialize, + ) + else + HorizontalDragGestureRecognizer: GestureRecognizerFactoryWithHandlers( + () => HorizontalDragGestureRecognizer(debugOwner: this), + initialize, + ), + }, + child: child, + ); + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(EnumProperty('layout', layout)) + ..add(ObjectFlagProperty.has('onStart', onStart)) + ..add(ObjectFlagProperty.has('onUpdate', onUpdate)) + ..add(ObjectFlagProperty.has('onEnd', onEnd)); + } +} diff --git a/forui/lib/src/widgets/sheet/sheet.dart b/forui/lib/src/widgets/sheet/sheet.dart index 4ef52dbb5..28c24a17d 100644 --- a/forui/lib/src/widgets/sheet/sheet.dart +++ b/forui/lib/src/widgets/sheet/sheet.dart @@ -1,60 +1,406 @@ import 'package:flutter/foundation.dart'; -import 'package:flutter/gestures.dart'; import 'package:flutter/widgets.dart'; import 'package:forui/forui.dart'; +import 'package:forui/src/widgets/sheet/gesture_detector.dart'; +import 'package:meta/meta.dart'; -/// The sheet's gesture detector. We use a [RawGestureDetector] instead of a [GestureDetector] because the latter -/// doesn't allow `onlyAcceptDragOnThreshold` to be configured. -class _GestureDetector extends StatelessWidget { +@internal +class Sheet extends StatefulWidget { + /// Creates an [AnimationController] suitable for a [Sheet.controller]. + // TODO: move animation to style. + static AnimationController createAnimationController(TickerProvider vsync, {AnimationStyle? sheetAnimationStyle}) => + AnimationController( + duration: sheetAnimationStyle?.duration ?? const Duration(milliseconds: 250), + reverseDuration: sheetAnimationStyle?.reverseDuration ?? const Duration(milliseconds: 200), + debugLabel: 'Sheet', + vsync: vsync, + ); + + static void _onClosing() {} + + /// The animation controller that controls the bottom sheet's entrance and exit animations. + /// + /// This widget will manipulate the position of this animation, it is not just a passive observer. + final AnimationController? controller; + + /// The sheet's layout. final Layout layout; - final GestureDragStartCallback onStart; - final GestureDragUpdateCallback onUpdate; - final GestureDragEndCallback onEnd; - final Widget child; - const _GestureDetector({ + /// The sheet's style. + final FSheetStyle style; + + /// The minimum and maximum size. + final BoxConstraints constraints; + + /// True if the sheet can be dragged up and down/left and right, and dismissed by swiping in the opposite direction. + /// + /// If [handle] is true, this only applies to the content excluding the drag handle, because the drag handle is + /// always draggable. + /// + /// If this is true, the [controller] must not be null. + final bool draggableContents; + + /// True if the sheet can be dragged by the drag handle. Defaults to false. + /// + /// If this is true, the [controller] must not be null. + final bool handle; + + /// A builder for the sheet's contents. + final WidgetBuilder builder; + + /// Called when the user begins dragging the bottom sheet vertically, if [draggableContents] is true. + /// + /// Would typically be used to change the bottom sheet animation curve so that it tracks the user's finger accurately. + final GestureDragStartCallback? onDragStart; + + /// Called when the user stops dragging the sheet, if [draggableContents] is true. + /// + /// Would typically be used to reset the bottom sheet animation curve, so that it animates non-linearly. Called before + /// [onClosing] if the sheet is closing. + final void Function(DragEndDetails details, {required bool closing})? onDragEnd; + + /// Called when the sheet begins to close. + /// + /// A sheet might be prevented from closing (e.g., by user interaction) even after this callback is called. For this + /// reason, this callback might be call multiple times for a given sheet. + final VoidCallback onClosing; + + const Sheet({ + required this.style, required this.layout, - required this.onStart, - required this.onUpdate, - required this.onEnd, - required this.child, - }); + required this.constraints, + required this.builder, + this.controller, + this.onClosing = _onClosing, + super.key, + }) : draggableContents = false, + handle = false, + onDragStart = null, + onDragEnd = null; + + const Sheet.draggable({ + required AnimationController this.controller, + required this.style, + required this.layout, + required this.constraints, + required this.builder, + this.handle = false, + this.draggableContents = true, + this.onDragStart, + this.onDragEnd, + this.onClosing = _onClosing, + super.key, + }) : assert(handle || draggableContents, 'Sheet must be draggable or have a handle.'); @override - Widget build(BuildContext context) { - void initialize(DragGestureRecognizer recognizer) { - recognizer - ..onStart = onStart - ..onUpdate = onUpdate - ..onEnd = onEnd - ..onlyAcceptDragOnThreshold = true; + State createState() => _SheetState(); + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(DiagnosticsProperty('controller', controller)) + ..add(DiagnosticsProperty('style', style)) + ..add(EnumProperty('layout', layout)) + ..add(DiagnosticsProperty('constraints', constraints)) + ..add(FlagProperty('draggableContents', value: draggableContents, ifTrue: 'draggableContents')) + ..add(FlagProperty('handle', value: handle, ifTrue: 'handle')) + ..add(ObjectFlagProperty.has('builder', builder)) + ..add(ObjectFlagProperty.has('onDragStart', onDragStart)) + ..add(ObjectFlagProperty.has('onDragEnd', onDragEnd)) + ..add(ObjectFlagProperty.has('onClosing', onClosing)); + } +} + +class _SheetState extends State with SingleTickerProviderStateMixin { + final GlobalKey _key = GlobalKey(debugLabel: 'Sheet child'); + late AnimationController _controller; + + @override + void initState() { + super.initState(); + _controller = widget.controller ?? Sheet.createAnimationController(this); + } + + @override + void didUpdateWidget(covariant Sheet old) { + super.didUpdateWidget(old); + if (widget.controller != old.controller) { + if (old.controller == null) { + _controller.dispose(); + } + + _controller = widget.controller ?? Sheet.createAnimationController(this); } + } - return RawGestureDetector( - excludeFromSemantics: true, - gestures: { - if (layout.vertical) - VerticalDragGestureRecognizer: GestureRecognizerFactoryWithHandlers( - () => VerticalDragGestureRecognizer(debugOwner: this), - initialize, - ) - else - HorizontalDragGestureRecognizer: GestureRecognizerFactoryWithHandlers( - () => HorizontalDragGestureRecognizer(debugOwner: this), - initialize, - ) + @override + Widget build(BuildContext context) { + final FSheetStyle(:handlePadding, :handleSize) = widget.style; + + // Only add [SheetGestureDetector] to the drag handle when the rest of the bottom sheet is not draggable. If the + // whole sheet is draggable, no need to add it. + final handle = switch (widget.handle) { + true when widget.draggableContents => SheetGestureDetector( + layout: widget.layout, + onStart: widget.onDragStart, + onUpdate: _dragUpdate, + onEnd: _dragEnd, + child: Handle(style: widget.style), + ), + true => Handle(style: widget.style), + false => null, + }; + + final sheet = Align( + alignment: switch (widget.layout) { + Layout.ttb => Alignment.topCenter, + Layout.btt => Alignment.bottomCenter, + Layout.ltr => Alignment.centerLeft, + Layout.rtl => Alignment.centerRight, }, - child: child, + heightFactor: widget.layout.vertical ? 1 : null, + widthFactor: widget.layout.vertical ? null : 1, + child: ConstrainedBox( + constraints: widget.constraints, + child: NotificationListener( + key: _key, + onNotification: (notification) { + if (notification.extent == notification.minExtent && notification.shouldCloseOnMinExtent) { + widget.onClosing(); + } + return false; + }, + child: handle == null + ? widget.builder(context) + : switch (widget.layout) { + Layout.ttb => Stack( + alignment: Alignment.bottomCenter, + children: [ + handle, + Padding( + padding: EdgeInsets.only(bottom: handlePadding.vertical + handleSize.height), + child: widget.builder(context), + ), + ], + ), + Layout.btt => Stack( + alignment: Alignment.topCenter, + children: [ + handle, + Padding( + padding: EdgeInsets.only(top: handlePadding.vertical + handleSize.height), + child: widget.builder(context), + ), + ], + ), + Layout.ltr => Stack( + alignment: Alignment.centerRight, + children: [ + handle, + Padding( + padding: EdgeInsets.only(right: handlePadding.horizontal + handleSize.width), + child: widget.builder(context), + ), + ], + ), + Layout.rtl => Stack( + alignment: Alignment.centerLeft, + children: [ + handle, + Padding( + padding: EdgeInsets.only(left: handlePadding.horizontal + handleSize.width), + child: widget.builder(context), + ), + ], + ), + }, + ), + ), ); + + return widget.draggableContents + ? SheetGestureDetector( + layout: widget.layout, + onStart: widget.onDragStart, + onUpdate: _dragUpdate, + onEnd: _dragEnd, + child: sheet, + ) + : sheet; + } + + GestureDragUpdateCallback get _dragUpdate => switch (widget.layout) { + Layout.ttb => (details) { + if (!_dismissing) { + _controller.value += details.primaryDelta! / _key.currentChildHeight; + } + }, + Layout.btt => (details) { + if (!_dismissing) { + _controller.value -= details.primaryDelta! / _key.currentChildHeight; + } + }, + Layout.ltr => (details) { + if (!_dismissing) { + _controller.value += details.primaryDelta! / _key.currentChildWidth; + } + }, + Layout.rtl => (details) { + if (!_dismissing) { + _controller.value -= details.primaryDelta! / _key.currentChildWidth; + } + }, + }; + + GestureDragEndCallback get _dragEnd { + final double Function(DragEndDetails) velocity = switch (widget.layout) { + Layout.ttb => (details) => details.primaryVelocity! / _key.currentChildHeight, + Layout.btt => (details) => -details.primaryVelocity! / _key.currentChildHeight, + Layout.ltr => (details) => details.primaryVelocity! / _key.currentChildWidth, + Layout.rtl => (details) => -details.primaryVelocity! / _key.currentChildWidth, + }; + + return (details) { + if (_dismissing) { + return; + } + + var closing = false; + if (widget.style.flingVelocity < details.primaryVelocity!) { + final flingVelocity = velocity(details); + if (0 < _controller.value) { + _controller.fling(velocity: flingVelocity); + } + + if (flingVelocity < 0) { + closing = true; + } + } else if (_controller.value < widget.style.closeProgressThreshold) { + if (0 < _controller.value) { + _controller.fling(velocity: -1); + } + closing = true; + } else { + _controller.forward(); + } + + widget.onDragEnd?.call(details, closing: closing); + if (closing) { + widget.onClosing(); + } + }; } + bool get _dismissing => _controller.status == AnimationStatus.reverse; + + @override + void dispose() { + super.dispose(); + if (widget.controller == null) { + _controller.dispose(); + } + } +} + +extension on GlobalKey { + double get currentChildWidth => (currentContext!.findRenderObject()! as RenderBox).size.width; + + double get currentChildHeight => (currentContext!.findRenderObject()! as RenderBox).size.height; +} + +// Handle size: Size(32, 4). +// Minimum accessibility target 44x44. + +// TODO: make abstract + +/// A sheet's style. +class FSheetStyle with Diagnosticable { + /// The sheet's background color. + final Color backgroundColor; + + /// The drag handle's color. + final Color handleColor; + + /// The drag handle's border radius. + final BorderRadius handleBorderRadius; + + /// The drag handle's size. + final Size handleSize; + + /// The padding surrounding the handle. + final EdgeInsets handlePadding; + + /// The minimum velocity to initiate a fling. Defaults to 700. + /// + /// ## Contract + /// Throws an [AssertionError] if the value is not positive. + final double flingVelocity; + + /// The threshold for determining whether the sheet is closing. Defaults to 0.5. + /// + /// ## Contract + /// Throws an [AssertionError] if the value is not in the range [0, 1]. + final double closeProgressThreshold; + + /// Creates a [FSheetStyle]. + const FSheetStyle({ + required this.backgroundColor, + required this.handleColor, + required this.handleBorderRadius, + required this.handleSize, + required this.handlePadding, + this.flingVelocity = 700, + this.closeProgressThreshold = 0.5, + }); + + /// Creates a [FSheetStyle] that inherits its colors from the given [FColorScheme] and [FStyle]. + FSheetStyle.inherit({ + required FColorScheme colorScheme, + required FStyle style, + required Size size, + required EdgeInsets handlePadding, + }) : this( + backgroundColor: colorScheme.background, + handleColor: colorScheme.secondary, + handleBorderRadius: style.borderRadius, + handleSize: size, + handlePadding: handlePadding, + ); + @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); properties - ..add(EnumProperty('layout', layout)) - ..add(ObjectFlagProperty.has('onStart', onStart)) - ..add(ObjectFlagProperty.has('onUpdate', onUpdate)) - ..add(ObjectFlagProperty.has('onEnd', onEnd)); + ..add(ColorProperty('backgroundColor', backgroundColor)) + ..add(ColorProperty('handleColor', handleColor)) + ..add(DiagnosticsProperty('handleBorderRadius', handleBorderRadius)) + ..add(DiagnosticsProperty('handleSize', handleSize)) + ..add(DiagnosticsProperty('handlePadding', handlePadding)) + ..add(DoubleProperty('flingVelocity', flingVelocity)) + ..add(DoubleProperty('closeProgressThreshold', closeProgressThreshold)); } + + @override + bool operator ==(Object other) => + identical(this, other) || + other is FSheetStyle && + runtimeType == other.runtimeType && + backgroundColor == other.backgroundColor && + handleColor == other.handleColor && + handleBorderRadius == other.handleBorderRadius && + handleSize == other.handleSize && + handlePadding == other.handlePadding && + flingVelocity == other.flingVelocity && + closeProgressThreshold == other.closeProgressThreshold; + + @override + int get hashCode => + backgroundColor.hashCode ^ + handleColor.hashCode ^ + handleBorderRadius.hashCode ^ + handleSize.hashCode ^ + handlePadding.hashCode ^ + flingVelocity.hashCode ^ + closeProgressThreshold.hashCode; } diff --git a/forui/lib/src/widgets/sheet/shifted_sheet.dart b/forui/lib/src/widgets/sheet/shifted_sheet.dart index b9dddcc42..5dc15f401 100644 --- a/forui/lib/src/widgets/sheet/shifted_sheet.dart +++ b/forui/lib/src/widgets/sheet/shifted_sheet.dart @@ -3,6 +3,7 @@ import 'package:flutter/rendering.dart'; import 'package:forui/src/foundation/rendering.dart'; import 'package:meta/meta.dart'; +/// This is based on Material's _BottomSheetLayoutWithSizeListener. @internal class ShiftedSheet extends SingleChildRenderObjectWidget { final Layout side; diff --git a/forui/lib/widgets/sheet.dart b/forui/lib/widgets/sheet.dart new file mode 100644 index 000000000..62f2a9055 --- /dev/null +++ b/forui/lib/widgets/sheet.dart @@ -0,0 +1,8 @@ +/// {@category Widgets} +/// +/// A sheet is a panel that slides in from the edge of a screen. +/// +/// See https://forui.dev/docs/sheet/modal-sheet for working examples. +library forui.widgets.sheet; + +export '../src/widgets/sheet/sheet.dart' show FSheetStyle; \ No newline at end of file diff --git a/forui/lib/widgets/tile.dart b/forui/lib/widgets/tile.dart index 641a3c84e..c1475827d 100644 --- a/forui/lib/widgets/tile.dart +++ b/forui/lib/widgets/tile.dart @@ -2,7 +2,7 @@ /// /// A tile is typically used to group related information together. /// -/// See https://forui.dev/tile for working examples. +/// See https://forui.dev/docs/tile/tile for working examples. library forui.widgets.tile; export '../src/widgets/tile/tile.dart' hide extractTile; From 027dc7516d116a00a450d9511516da44ee7820f4 Mon Sep 17 00:00:00 2001 From: Matthias Ngeo Date: Wed, 20 Nov 2024 12:21:53 +0800 Subject: [PATCH 04/29] Fix sheet --- .../src/widgets/sheet/gesture_detector.dart | 30 --- forui/lib/src/widgets/sheet/sheet.dart | 198 +++++------------- .../lib/src/widgets/sheet/shifted_sheet.dart | 30 +-- 3 files changed, 67 insertions(+), 191 deletions(-) diff --git a/forui/lib/src/widgets/sheet/gesture_detector.dart b/forui/lib/src/widgets/sheet/gesture_detector.dart index de0ee0f24..a137e4e58 100644 --- a/forui/lib/src/widgets/sheet/gesture_detector.dart +++ b/forui/lib/src/widgets/sheet/gesture_detector.dart @@ -4,36 +4,6 @@ import 'package:flutter/widgets.dart'; import 'package:forui/forui.dart'; import 'package:meta/meta.dart'; -/// This is based on Material's _DragHandle. -@internal -class Handle extends StatelessWidget { - final FSheetStyle style; - - /// Creates a handle. - const Handle({required this.style, super.key}); - - @override - Widget build(BuildContext context) => Padding( - padding: style.handlePadding, - child: MouseRegion( - cursor: SystemMouseCursors.click, - child: DecoratedBox( - decoration: BoxDecoration( - color: style.handleColor, - borderRadius: style.handleBorderRadius, - ), - child: SizedBox.fromSize(size: style.handleSize), - ), - ), - ); - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties.add(DiagnosticsProperty('style', style)); - } -} - /// The sheet's gesture detector. We use a [RawGestureDetector] instead of a [GestureDetector] because the latter /// doesn't allow `onlyAcceptDragOnThreshold` to be configured. /// diff --git a/forui/lib/src/widgets/sheet/sheet.dart b/forui/lib/src/widgets/sheet/sheet.dart index 28c24a17d..4aeb3fe13 100644 --- a/forui/lib/src/widgets/sheet/sheet.dart +++ b/forui/lib/src/widgets/sheet/sheet.dart @@ -6,16 +6,6 @@ import 'package:meta/meta.dart'; @internal class Sheet extends StatefulWidget { - /// Creates an [AnimationController] suitable for a [Sheet.controller]. - // TODO: move animation to style. - static AnimationController createAnimationController(TickerProvider vsync, {AnimationStyle? sheetAnimationStyle}) => - AnimationController( - duration: sheetAnimationStyle?.duration ?? const Duration(milliseconds: 250), - reverseDuration: sheetAnimationStyle?.reverseDuration ?? const Duration(milliseconds: 200), - debugLabel: 'Sheet', - vsync: vsync, - ); - static void _onClosing() {} /// The animation controller that controls the bottom sheet's entrance and exit animations. @@ -34,26 +24,18 @@ class Sheet extends StatefulWidget { /// True if the sheet can be dragged up and down/left and right, and dismissed by swiping in the opposite direction. /// - /// If [handle] is true, this only applies to the content excluding the drag handle, because the drag handle is - /// always draggable. - /// /// If this is true, the [controller] must not be null. - final bool draggableContents; - - /// True if the sheet can be dragged by the drag handle. Defaults to false. - /// - /// If this is true, the [controller] must not be null. - final bool handle; + final bool draggable; /// A builder for the sheet's contents. final WidgetBuilder builder; - /// Called when the user begins dragging the bottom sheet vertically, if [draggableContents] is true. + /// Called when the user begins dragging the bottom sheet vertically, if [draggable] is true. /// /// Would typically be used to change the bottom sheet animation curve so that it tracks the user's finger accurately. final GestureDragStartCallback? onDragStart; - /// Called when the user stops dragging the sheet, if [draggableContents] is true. + /// Called when the user stops dragging the sheet, if [draggable] is true. /// /// Would typically be used to reset the bottom sheet animation curve, so that it animates non-linearly. Called before /// [onClosing] if the sheet is closing. @@ -68,13 +50,12 @@ class Sheet extends StatefulWidget { const Sheet({ required this.style, required this.layout, - required this.constraints, required this.builder, this.controller, + this.constraints = const BoxConstraints(), this.onClosing = _onClosing, super.key, - }) : draggableContents = false, - handle = false, + }) : draggable = false, onDragStart = null, onDragEnd = null; @@ -82,15 +63,13 @@ class Sheet extends StatefulWidget { required AnimationController this.controller, required this.style, required this.layout, - required this.constraints, required this.builder, - this.handle = false, - this.draggableContents = true, + this.constraints = const BoxConstraints(), this.onDragStart, this.onDragEnd, this.onClosing = _onClosing, super.key, - }) : assert(handle || draggableContents, 'Sheet must be draggable or have a handle.'); + }) : draggable = true; @override State createState() => _SheetState(); @@ -103,8 +82,7 @@ class Sheet extends StatefulWidget { ..add(DiagnosticsProperty('style', style)) ..add(EnumProperty('layout', layout)) ..add(DiagnosticsProperty('constraints', constraints)) - ..add(FlagProperty('draggableContents', value: draggableContents, ifTrue: 'draggableContents')) - ..add(FlagProperty('handle', value: handle, ifTrue: 'handle')) + ..add(FlagProperty('draggable', value: draggable, ifTrue: 'draggable')) ..add(ObjectFlagProperty.has('builder', builder)) ..add(ObjectFlagProperty.has('onDragStart', onDragStart)) ..add(ObjectFlagProperty.has('onDragEnd', onDragEnd)) @@ -119,7 +97,12 @@ class _SheetState extends State with SingleTickerProviderStateMixin { @override void initState() { super.initState(); - _controller = widget.controller ?? Sheet.createAnimationController(this); + _controller = widget.controller ?? + AnimationController( + vsync: this, + duration: widget.style.enterDuration, + reverseDuration: widget.style.exitDuration, + ); } @override @@ -130,29 +113,18 @@ class _SheetState extends State with SingleTickerProviderStateMixin { _controller.dispose(); } - _controller = widget.controller ?? Sheet.createAnimationController(this); + _controller = widget.controller ?? + AnimationController( + vsync: this, + duration: widget.style.enterDuration, + reverseDuration: widget.style.exitDuration, + ); } } @override Widget build(BuildContext context) { - final FSheetStyle(:handlePadding, :handleSize) = widget.style; - - // Only add [SheetGestureDetector] to the drag handle when the rest of the bottom sheet is not draggable. If the - // whole sheet is draggable, no need to add it. - final handle = switch (widget.handle) { - true when widget.draggableContents => SheetGestureDetector( - layout: widget.layout, - onStart: widget.onDragStart, - onUpdate: _dragUpdate, - onEnd: _dragEnd, - child: Handle(style: widget.style), - ), - true => Handle(style: widget.style), - false => null, - }; - - final sheet = Align( + Widget sheet = Align( alignment: switch (widget.layout) { Layout.ttb => Alignment.topCenter, Layout.btt => Alignment.bottomCenter, @@ -164,70 +136,28 @@ class _SheetState extends State with SingleTickerProviderStateMixin { child: ConstrainedBox( constraints: widget.constraints, child: NotificationListener( - key: _key, - onNotification: (notification) { - if (notification.extent == notification.minExtent && notification.shouldCloseOnMinExtent) { - widget.onClosing(); - } - return false; - }, - child: handle == null - ? widget.builder(context) - : switch (widget.layout) { - Layout.ttb => Stack( - alignment: Alignment.bottomCenter, - children: [ - handle, - Padding( - padding: EdgeInsets.only(bottom: handlePadding.vertical + handleSize.height), - child: widget.builder(context), - ), - ], - ), - Layout.btt => Stack( - alignment: Alignment.topCenter, - children: [ - handle, - Padding( - padding: EdgeInsets.only(top: handlePadding.vertical + handleSize.height), - child: widget.builder(context), - ), - ], - ), - Layout.ltr => Stack( - alignment: Alignment.centerRight, - children: [ - handle, - Padding( - padding: EdgeInsets.only(right: handlePadding.horizontal + handleSize.width), - child: widget.builder(context), - ), - ], - ), - Layout.rtl => Stack( - alignment: Alignment.centerLeft, - children: [ - handle, - Padding( - padding: EdgeInsets.only(left: handlePadding.horizontal + handleSize.width), - child: widget.builder(context), - ), - ], - ), - }, - ), + key: _key, + onNotification: (notification) { + if (notification.extent == notification.minExtent && notification.shouldCloseOnMinExtent) { + widget.onClosing(); + } + return false; + }, + child: widget.builder(context)), ), ); - return widget.draggableContents - ? SheetGestureDetector( - layout: widget.layout, - onStart: widget.onDragStart, - onUpdate: _dragUpdate, - onEnd: _dragEnd, - child: sheet, - ) - : sheet; + if (widget.draggable) { + sheet = SheetGestureDetector( + layout: widget.layout, + onStart: widget.onDragStart, + onUpdate: _dragUpdate, + onEnd: _dragEnd, + child: sheet, + ); + } + + return sheet; } GestureDragUpdateCallback get _dragUpdate => switch (widget.layout) { @@ -309,9 +239,6 @@ extension on GlobalKey { double get currentChildHeight => (currentContext!.findRenderObject()! as RenderBox).size.height; } -// Handle size: Size(32, 4). -// Minimum accessibility target 44x44. - // TODO: make abstract /// A sheet's style. @@ -319,17 +246,11 @@ class FSheetStyle with Diagnosticable { /// The sheet's background color. final Color backgroundColor; - /// The drag handle's color. - final Color handleColor; - - /// The drag handle's border radius. - final BorderRadius handleBorderRadius; - - /// The drag handle's size. - final Size handleSize; + /// The entrance duration. Defaults to 200ms. + final Duration enterDuration; - /// The padding surrounding the handle. - final EdgeInsets handlePadding; + /// The exit duration. Defaults to 200ms. + final Duration exitDuration; /// The minimum velocity to initiate a fling. Defaults to 700. /// @@ -346,10 +267,8 @@ class FSheetStyle with Diagnosticable { /// Creates a [FSheetStyle]. const FSheetStyle({ required this.backgroundColor, - required this.handleColor, - required this.handleBorderRadius, - required this.handleSize, - required this.handlePadding, + this.enterDuration = const Duration(milliseconds: 250), + this.exitDuration = const Duration(milliseconds: 200), this.flingVelocity = 700, this.closeProgressThreshold = 0.5, }); @@ -357,15 +276,8 @@ class FSheetStyle with Diagnosticable { /// Creates a [FSheetStyle] that inherits its colors from the given [FColorScheme] and [FStyle]. FSheetStyle.inherit({ required FColorScheme colorScheme, - required FStyle style, - required Size size, - required EdgeInsets handlePadding, }) : this( backgroundColor: colorScheme.background, - handleColor: colorScheme.secondary, - handleBorderRadius: style.borderRadius, - handleSize: size, - handlePadding: handlePadding, ); @override @@ -373,10 +285,8 @@ class FSheetStyle with Diagnosticable { super.debugFillProperties(properties); properties ..add(ColorProperty('backgroundColor', backgroundColor)) - ..add(ColorProperty('handleColor', handleColor)) - ..add(DiagnosticsProperty('handleBorderRadius', handleBorderRadius)) - ..add(DiagnosticsProperty('handleSize', handleSize)) - ..add(DiagnosticsProperty('handlePadding', handlePadding)) + ..add(DiagnosticsProperty('enterDuration', enterDuration)) + ..add(DiagnosticsProperty('exitDuration', exitDuration)) ..add(DoubleProperty('flingVelocity', flingVelocity)) ..add(DoubleProperty('closeProgressThreshold', closeProgressThreshold)); } @@ -387,20 +297,16 @@ class FSheetStyle with Diagnosticable { other is FSheetStyle && runtimeType == other.runtimeType && backgroundColor == other.backgroundColor && - handleColor == other.handleColor && - handleBorderRadius == other.handleBorderRadius && - handleSize == other.handleSize && - handlePadding == other.handlePadding && + enterDuration == other.enterDuration && + exitDuration == other.exitDuration && flingVelocity == other.flingVelocity && closeProgressThreshold == other.closeProgressThreshold; @override int get hashCode => backgroundColor.hashCode ^ - handleColor.hashCode ^ - handleBorderRadius.hashCode ^ - handleSize.hashCode ^ - handlePadding.hashCode ^ + enterDuration.hashCode ^ + exitDuration.hashCode ^ flingVelocity.hashCode ^ closeProgressThreshold.hashCode; } diff --git a/forui/lib/src/widgets/sheet/shifted_sheet.dart b/forui/lib/src/widgets/sheet/shifted_sheet.dart index 5dc15f401..5985b6be2 100644 --- a/forui/lib/src/widgets/sheet/shifted_sheet.dart +++ b/forui/lib/src/widgets/sheet/shifted_sheet.dart @@ -8,12 +8,12 @@ import 'package:meta/meta.dart'; class ShiftedSheet extends SingleChildRenderObjectWidget { final Layout side; final double value; - final double dimensionRatio; + final double mainAxisMaxRatio; const ShiftedSheet({ required this.side, required this.value, - required this.dimensionRatio, + required this.mainAxisMaxRatio, required super.child, super.key, }); @@ -22,7 +22,7 @@ class ShiftedSheet extends SingleChildRenderObjectWidget { RenderBox createRenderObject(BuildContext context) => _ShiftedSheet( side: side, value: value, - dimensionRatio: dimensionRatio, + mainAxisMaxRatio: mainAxisMaxRatio, ); @override @@ -31,7 +31,7 @@ class ShiftedSheet extends SingleChildRenderObjectWidget { renderObject ..side = side ..value = value - ..dimensionRatio = dimensionRatio; + ..mainAxisRatio = mainAxisMaxRatio; } @override @@ -40,22 +40,22 @@ class ShiftedSheet extends SingleChildRenderObjectWidget { properties ..add(EnumProperty('side', side)) ..add(DoubleProperty('value', value)) - ..add(DoubleProperty('dimensionRatio', dimensionRatio)); + ..add(DoubleProperty('dimensionRatio', mainAxisMaxRatio)); } } class _ShiftedSheet extends RenderShiftedBox { Layout _side; double _value; - double? _dimensionRatio; + double? _mainAxisMaxRatio; _ShiftedSheet({ required Layout side, required double value, - required double dimensionRatio, + required double mainAxisMaxRatio, }) : _side = side, _value = value, - _dimensionRatio = dimensionRatio, + _mainAxisMaxRatio = mainAxisMaxRatio, super(null); @override @@ -94,10 +94,10 @@ class _ShiftedSheet extends RenderShiftedBox { ? BoxConstraints( minWidth: constraints.maxWidth, maxWidth: constraints.maxWidth, - maxHeight: _dimensionRatio == null ? constraints.maxHeight : constraints.maxHeight * _dimensionRatio!, + maxHeight: _mainAxisMaxRatio == null ? constraints.maxHeight : constraints.maxHeight * _mainAxisMaxRatio!, ) : BoxConstraints( - maxWidth: _dimensionRatio == null ? constraints.maxWidth : constraints.maxWidth * _dimensionRatio!, + maxWidth: _mainAxisMaxRatio == null ? constraints.maxWidth : constraints.maxWidth * _mainAxisMaxRatio!, minHeight: constraints.maxHeight, maxHeight: constraints.maxHeight, ); @@ -154,11 +154,11 @@ class _ShiftedSheet extends RenderShiftedBox { } } - double? get dimensionRatio => _dimensionRatio; + double? get mainAxisRatio => _mainAxisMaxRatio; - set dimensionRatio(double? value) { - if (_dimensionRatio != value) { - _dimensionRatio = value; + set mainAxisRatio(double? value) { + if (_mainAxisMaxRatio != value) { + _mainAxisMaxRatio = value; markNeedsLayout(); } } @@ -169,6 +169,6 @@ class _ShiftedSheet extends RenderShiftedBox { properties ..add(EnumProperty('side', side)) ..add(DoubleProperty('value', value)) - ..add(DoubleProperty('dimensionRatio', dimensionRatio)); + ..add(DoubleProperty('mainAxisRatio', mainAxisRatio)); } } From 75f81faacf39046aa52d1bee87fede4443c630b5 Mon Sep 17 00:00:00 2001 From: Matthias Ngeo Date: Wed, 20 Nov 2024 19:51:28 +0800 Subject: [PATCH 05/29] Add sheet localizations --- forui/lib/l10n/f_af.arb | 4 +- forui/lib/l10n/f_am.arb | 4 +- forui/lib/l10n/f_ar.arb | 4 +- forui/lib/l10n/f_as.arb | 4 +- forui/lib/l10n/f_az.arb | 4 +- forui/lib/l10n/f_be.arb | 4 +- forui/lib/l10n/f_bg.arb | 4 +- forui/lib/l10n/f_bn.arb | 4 +- forui/lib/l10n/f_bs.arb | 4 +- forui/lib/l10n/f_ca.arb | 4 +- forui/lib/l10n/f_cs.arb | 4 +- forui/lib/l10n/f_cy.arb | 4 +- forui/lib/l10n/f_da.arb | 4 +- forui/lib/l10n/f_de.arb | 4 +- forui/lib/l10n/f_de_CH.arb | 4 +- forui/lib/l10n/f_el.arb | 4 +- forui/lib/l10n/f_en.arb | 10 +- forui/lib/l10n/f_en_AU.arb | 4 +- forui/lib/l10n/f_en_CA.arb | 4 +- forui/lib/l10n/f_en_GB.arb | 4 +- forui/lib/l10n/f_en_IE.arb | 4 +- forui/lib/l10n/f_en_IN.arb | 4 +- forui/lib/l10n/f_en_NZ.arb | 4 +- forui/lib/l10n/f_en_SG.arb | 4 +- forui/lib/l10n/f_en_ZA.arb | 4 +- forui/lib/l10n/f_es.arb | 4 +- forui/lib/l10n/f_es_419.arb | 4 +- forui/lib/l10n/f_es_AR.arb | 4 +- forui/lib/l10n/f_es_BO.arb | 4 +- forui/lib/l10n/f_es_CL.arb | 4 +- forui/lib/l10n/f_es_CO.arb | 4 +- forui/lib/l10n/f_es_CR.arb | 4 +- forui/lib/l10n/f_es_DO.arb | 4 +- forui/lib/l10n/f_es_EC.arb | 4 +- forui/lib/l10n/f_es_GT.arb | 4 +- forui/lib/l10n/f_es_HN.arb | 4 +- forui/lib/l10n/f_es_MX.arb | 4 +- forui/lib/l10n/f_es_NI.arb | 4 +- forui/lib/l10n/f_es_PA.arb | 4 +- forui/lib/l10n/f_es_PE.arb | 4 +- forui/lib/l10n/f_es_PR.arb | 4 +- forui/lib/l10n/f_es_PY.arb | 4 +- forui/lib/l10n/f_es_SV.arb | 4 +- forui/lib/l10n/f_es_US.arb | 4 +- forui/lib/l10n/f_es_UY.arb | 4 +- forui/lib/l10n/f_es_VE.arb | 4 +- forui/lib/l10n/f_et.arb | 4 +- forui/lib/l10n/f_eu.arb | 4 +- forui/lib/l10n/f_fa.arb | 4 +- forui/lib/l10n/f_fi.arb | 4 +- forui/lib/l10n/f_fil.arb | 4 +- forui/lib/l10n/f_fr.arb | 4 +- forui/lib/l10n/f_fr_CA.arb | 4 +- forui/lib/l10n/f_gl.arb | 4 +- forui/lib/l10n/f_gsw.arb | 4 +- forui/lib/l10n/f_gu.arb | 4 +- forui/lib/l10n/f_he.arb | 4 +- forui/lib/l10n/f_hi.arb | 4 +- forui/lib/l10n/f_hr.arb | 4 +- forui/lib/l10n/f_hu.arb | 4 +- forui/lib/l10n/f_hy.arb | 4 +- forui/lib/l10n/f_id.arb | 4 +- forui/lib/l10n/f_is.arb | 4 +- forui/lib/l10n/f_it.arb | 4 +- forui/lib/l10n/f_ja.arb | 4 +- forui/lib/l10n/f_ka.arb | 4 +- forui/lib/l10n/f_kk.arb | 4 +- forui/lib/l10n/f_km.arb | 4 +- forui/lib/l10n/f_kn.arb | 4 +- forui/lib/l10n/f_ko.arb | 4 +- forui/lib/l10n/f_ky.arb | 4 +- forui/lib/l10n/f_lo.arb | 4 +- forui/lib/l10n/f_lt.arb | 4 +- forui/lib/l10n/f_lv.arb | 4 +- forui/lib/l10n/f_mk.arb | 4 +- forui/lib/l10n/f_ml.arb | 4 +- forui/lib/l10n/f_mn.arb | 4 +- forui/lib/l10n/f_mr.arb | 4 +- forui/lib/l10n/f_ms.arb | 4 +- forui/lib/l10n/f_my.arb | 4 +- forui/lib/l10n/f_nb.arb | 4 +- forui/lib/l10n/f_ne.arb | 4 +- forui/lib/l10n/f_nl.arb | 4 +- forui/lib/l10n/f_no.arb | 4 +- forui/lib/l10n/f_or.arb | 4 +- forui/lib/l10n/f_pa.arb | 4 +- forui/lib/l10n/f_pl.arb | 4 +- forui/lib/l10n/f_ps.arb | 4 +- forui/lib/l10n/f_pt.arb | 4 +- forui/lib/l10n/f_pt_PT.arb | 4 +- forui/lib/l10n/f_ro.arb | 4 +- forui/lib/l10n/f_ru.arb | 4 +- forui/lib/l10n/f_si.arb | 4 +- forui/lib/l10n/f_sk.arb | 4 +- forui/lib/l10n/f_sl.arb | 4 +- forui/lib/l10n/f_sq.arb | 4 +- forui/lib/l10n/f_sr.arb | 4 +- forui/lib/l10n/f_sr_Latn.arb | 4 +- forui/lib/l10n/f_sv.arb | 4 +- forui/lib/l10n/f_sw.arb | 4 +- forui/lib/l10n/f_ta.arb | 4 +- forui/lib/l10n/f_te.arb | 4 +- forui/lib/l10n/f_th.arb | 4 +- forui/lib/l10n/f_tl.arb | 4 +- forui/lib/l10n/f_tr.arb | 4 +- forui/lib/l10n/f_uk.arb | 4 +- forui/lib/l10n/f_ur.arb | 4 +- forui/lib/l10n/f_uz.arb | 4 +- forui/lib/l10n/f_vi.arb | 4 +- forui/lib/l10n/f_zh.arb | 4 +- forui/lib/l10n/f_zh_HK.arb | 4 +- forui/lib/l10n/f_zh_TW.arb | 4 +- forui/lib/l10n/f_zu.arb | 4 +- forui/lib/src/localizations/localization.dart | 3 + .../lib/src/localizations/localizations.dart | 515 ++++++------------ .../src/localizations/localizations_af.dart | 3 + .../src/localizations/localizations_am.dart | 3 + .../src/localizations/localizations_ar.dart | 3 + .../src/localizations/localizations_as.dart | 3 + .../src/localizations/localizations_az.dart | 3 + .../src/localizations/localizations_be.dart | 3 + .../src/localizations/localizations_bg.dart | 3 + .../src/localizations/localizations_bn.dart | 3 + .../src/localizations/localizations_bs.dart | 3 + .../src/localizations/localizations_ca.dart | 3 + .../src/localizations/localizations_cs.dart | 3 + .../src/localizations/localizations_cy.dart | 3 + .../src/localizations/localizations_da.dart | 3 + .../src/localizations/localizations_de.dart | 8 +- .../src/localizations/localizations_el.dart | 3 + .../src/localizations/localizations_en.dart | 43 +- .../src/localizations/localizations_es.dart | 103 +++- .../src/localizations/localizations_et.dart | 3 + .../src/localizations/localizations_eu.dart | 3 + .../src/localizations/localizations_fa.dart | 3 + .../src/localizations/localizations_fi.dart | 3 + .../src/localizations/localizations_fil.dart | 3 + .../src/localizations/localizations_fr.dart | 8 +- .../src/localizations/localizations_gl.dart | 3 + .../src/localizations/localizations_gsw.dart | 3 + .../src/localizations/localizations_gu.dart | 3 + .../src/localizations/localizations_he.dart | 3 + .../src/localizations/localizations_hi.dart | 3 + .../src/localizations/localizations_hr.dart | 3 + .../src/localizations/localizations_hu.dart | 3 + .../src/localizations/localizations_hy.dart | 3 + .../src/localizations/localizations_id.dart | 3 + .../src/localizations/localizations_is.dart | 3 + .../src/localizations/localizations_it.dart | 3 + .../src/localizations/localizations_ja.dart | 3 + .../src/localizations/localizations_ka.dart | 3 + .../src/localizations/localizations_kk.dart | 3 + .../src/localizations/localizations_km.dart | 3 + .../src/localizations/localizations_kn.dart | 3 + .../src/localizations/localizations_ko.dart | 3 + .../src/localizations/localizations_ky.dart | 3 + .../src/localizations/localizations_lo.dart | 3 + .../src/localizations/localizations_lt.dart | 3 + .../src/localizations/localizations_lv.dart | 3 + .../src/localizations/localizations_mk.dart | 3 + .../src/localizations/localizations_ml.dart | 3 + .../src/localizations/localizations_mn.dart | 3 + .../src/localizations/localizations_mr.dart | 3 + .../src/localizations/localizations_ms.dart | 3 + .../src/localizations/localizations_my.dart | 3 + .../src/localizations/localizations_nb.dart | 3 + .../src/localizations/localizations_ne.dart | 3 + .../src/localizations/localizations_nl.dart | 3 + .../src/localizations/localizations_no.dart | 3 + .../src/localizations/localizations_or.dart | 3 + .../src/localizations/localizations_pa.dart | 3 + .../src/localizations/localizations_pl.dart | 3 + .../src/localizations/localizations_ps.dart | 3 + .../src/localizations/localizations_pt.dart | 8 +- .../src/localizations/localizations_ro.dart | 3 + .../src/localizations/localizations_ru.dart | 3 + .../src/localizations/localizations_si.dart | 3 + .../src/localizations/localizations_sk.dart | 3 + .../src/localizations/localizations_sl.dart | 3 + .../src/localizations/localizations_sq.dart | 3 + .../src/localizations/localizations_sr.dart | 8 +- .../src/localizations/localizations_sv.dart | 3 + .../src/localizations/localizations_sw.dart | 3 + .../src/localizations/localizations_ta.dart | 3 + .../src/localizations/localizations_te.dart | 3 + .../src/localizations/localizations_th.dart | 3 + .../src/localizations/localizations_tl.dart | 3 + .../src/localizations/localizations_tr.dart | 3 + .../src/localizations/localizations_uk.dart | 3 + .../src/localizations/localizations_ur.dart | 3 + .../src/localizations/localizations_uz.dart | 3 + .../src/localizations/localizations_vi.dart | 3 + .../src/localizations/localizations_zh.dart | 13 +- .../src/localizations/localizations_zu.dart | 3 + forui/lib/src/widgets/sheet/modal_sheet.dart | 94 ++++ forui/lib/src/widgets/sheet/sheet.dart | 19 +- .../lib/src/widgets/sheet/shifted_sheet.dart | 42 +- forui/tool/add_arb_value.dart | 27 + 198 files changed, 1040 insertions(+), 525 deletions(-) create mode 100644 forui/lib/src/widgets/sheet/modal_sheet.dart create mode 100644 forui/tool/add_arb_value.dart diff --git a/forui/lib/l10n/f_af.arb b/forui/lib/l10n/f_af.arb index 9e26dfeeb..3b920a0f7 100644 --- a/forui/lib/l10n/f_af.arb +++ b/forui/lib/l10n/f_af.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Dialoog" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_am.arb b/forui/lib/l10n/f_am.arb index 9e26dfeeb..d26becc70 100644 --- a/forui/lib/l10n/f_am.arb +++ b/forui/lib/l10n/f_am.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "መገናኛ" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_ar.arb b/forui/lib/l10n/f_ar.arb index 9e26dfeeb..8e7e3d86e 100644 --- a/forui/lib/l10n/f_ar.arb +++ b/forui/lib/l10n/f_ar.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "مربع حوار" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_as.arb b/forui/lib/l10n/f_as.arb index 9e26dfeeb..480896f2c 100644 --- a/forui/lib/l10n/f_as.arb +++ b/forui/lib/l10n/f_as.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "ডায়ল'গ" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_az.arb b/forui/lib/l10n/f_az.arb index 9e26dfeeb..c2a80c7be 100644 --- a/forui/lib/l10n/f_az.arb +++ b/forui/lib/l10n/f_az.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Dialoq" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_be.arb b/forui/lib/l10n/f_be.arb index 9e26dfeeb..8dd47f5c5 100644 --- a/forui/lib/l10n/f_be.arb +++ b/forui/lib/l10n/f_be.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Дыялогавае акно" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_bg.arb b/forui/lib/l10n/f_bg.arb index 9e26dfeeb..a79fb7914 100644 --- a/forui/lib/l10n/f_bg.arb +++ b/forui/lib/l10n/f_bg.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Диалогов прозорец" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_bn.arb b/forui/lib/l10n/f_bn.arb index 9e26dfeeb..f116c197e 100644 --- a/forui/lib/l10n/f_bn.arb +++ b/forui/lib/l10n/f_bn.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "ডায়ালগ" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_bs.arb b/forui/lib/l10n/f_bs.arb index 9e26dfeeb..101ec8c57 100644 --- a/forui/lib/l10n/f_bs.arb +++ b/forui/lib/l10n/f_bs.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Dijaloški okvir" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_ca.arb b/forui/lib/l10n/f_ca.arb index 9e26dfeeb..edccf86f6 100644 --- a/forui/lib/l10n/f_ca.arb +++ b/forui/lib/l10n/f_ca.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Diàleg" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_cs.arb b/forui/lib/l10n/f_cs.arb index 9e26dfeeb..dc2daf550 100644 --- a/forui/lib/l10n/f_cs.arb +++ b/forui/lib/l10n/f_cs.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Dialogové okno" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_cy.arb b/forui/lib/l10n/f_cy.arb index 9e26dfeeb..258673f4c 100644 --- a/forui/lib/l10n/f_cy.arb +++ b/forui/lib/l10n/f_cy.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Deialog" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_da.arb b/forui/lib/l10n/f_da.arb index 9e26dfeeb..fff2252c6 100644 --- a/forui/lib/l10n/f_da.arb +++ b/forui/lib/l10n/f_da.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Dialogboks" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_de.arb b/forui/lib/l10n/f_de.arb index 9e26dfeeb..6ee866ee2 100644 --- a/forui/lib/l10n/f_de.arb +++ b/forui/lib/l10n/f_de.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Dialogfeld" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_de_CH.arb b/forui/lib/l10n/f_de_CH.arb index 9e26dfeeb..6ee866ee2 100644 --- a/forui/lib/l10n/f_de_CH.arb +++ b/forui/lib/l10n/f_de_CH.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Dialogfeld" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_el.arb b/forui/lib/l10n/f_el.arb index 9e26dfeeb..0ba9cd3a4 100644 --- a/forui/lib/l10n/f_el.arb +++ b/forui/lib/l10n/f_el.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Παράθυρο διαλόγου" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_en.arb b/forui/lib/l10n/f_en.arb index 8edaba35a..0b1c97fca 100644 --- a/forui/lib/l10n/f_en.arb +++ b/forui/lib/l10n/f_en.arb @@ -9,7 +9,6 @@ } } }, - "year": "{date}", "@year": { "description": "The year.", @@ -20,7 +19,6 @@ } } }, - "yearMonth": "{date}", "@yearMonth": { "description": "The year and month.", @@ -31,7 +29,6 @@ } } }, - "abbreviatedMonth": "{date}", "@abbreviatedMonth": { "description": "The abbreviated month.", @@ -42,7 +39,6 @@ } } }, - "day": "{date}", "@day": { "description": "The day of the month.", @@ -52,5 +48,9 @@ "format": "d" } } - } + }, + "dialogLabel": "Dialog", + "@dialogLabel": { + "description": "The audio announcement made when a Dialog is opened." + }, } \ No newline at end of file diff --git a/forui/lib/l10n/f_en_AU.arb b/forui/lib/l10n/f_en_AU.arb index 9e26dfeeb..1caf7628a 100644 --- a/forui/lib/l10n/f_en_AU.arb +++ b/forui/lib/l10n/f_en_AU.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Dialogue" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_en_CA.arb b/forui/lib/l10n/f_en_CA.arb index 9e26dfeeb..e110b397e 100644 --- a/forui/lib/l10n/f_en_CA.arb +++ b/forui/lib/l10n/f_en_CA.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Dialog" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_en_GB.arb b/forui/lib/l10n/f_en_GB.arb index 9e26dfeeb..1caf7628a 100644 --- a/forui/lib/l10n/f_en_GB.arb +++ b/forui/lib/l10n/f_en_GB.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Dialogue" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_en_IE.arb b/forui/lib/l10n/f_en_IE.arb index 9e26dfeeb..1caf7628a 100644 --- a/forui/lib/l10n/f_en_IE.arb +++ b/forui/lib/l10n/f_en_IE.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Dialogue" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_en_IN.arb b/forui/lib/l10n/f_en_IN.arb index 9e26dfeeb..1caf7628a 100644 --- a/forui/lib/l10n/f_en_IN.arb +++ b/forui/lib/l10n/f_en_IN.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Dialogue" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_en_NZ.arb b/forui/lib/l10n/f_en_NZ.arb index 9e26dfeeb..1caf7628a 100644 --- a/forui/lib/l10n/f_en_NZ.arb +++ b/forui/lib/l10n/f_en_NZ.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Dialogue" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_en_SG.arb b/forui/lib/l10n/f_en_SG.arb index 9e26dfeeb..1caf7628a 100644 --- a/forui/lib/l10n/f_en_SG.arb +++ b/forui/lib/l10n/f_en_SG.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Dialogue" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_en_ZA.arb b/forui/lib/l10n/f_en_ZA.arb index 9e26dfeeb..1caf7628a 100644 --- a/forui/lib/l10n/f_en_ZA.arb +++ b/forui/lib/l10n/f_en_ZA.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Dialogue" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_es.arb b/forui/lib/l10n/f_es.arb index 9e26dfeeb..7df28ef8e 100644 --- a/forui/lib/l10n/f_es.arb +++ b/forui/lib/l10n/f_es.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Cuadro de diálogo" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_es_419.arb b/forui/lib/l10n/f_es_419.arb index 9e26dfeeb..866cdeb96 100644 --- a/forui/lib/l10n/f_es_419.arb +++ b/forui/lib/l10n/f_es_419.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Diálogo" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_es_AR.arb b/forui/lib/l10n/f_es_AR.arb index 9e26dfeeb..866cdeb96 100644 --- a/forui/lib/l10n/f_es_AR.arb +++ b/forui/lib/l10n/f_es_AR.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Diálogo" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_es_BO.arb b/forui/lib/l10n/f_es_BO.arb index 9e26dfeeb..866cdeb96 100644 --- a/forui/lib/l10n/f_es_BO.arb +++ b/forui/lib/l10n/f_es_BO.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Diálogo" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_es_CL.arb b/forui/lib/l10n/f_es_CL.arb index 9e26dfeeb..866cdeb96 100644 --- a/forui/lib/l10n/f_es_CL.arb +++ b/forui/lib/l10n/f_es_CL.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Diálogo" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_es_CO.arb b/forui/lib/l10n/f_es_CO.arb index 9e26dfeeb..866cdeb96 100644 --- a/forui/lib/l10n/f_es_CO.arb +++ b/forui/lib/l10n/f_es_CO.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Diálogo" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_es_CR.arb b/forui/lib/l10n/f_es_CR.arb index 9e26dfeeb..866cdeb96 100644 --- a/forui/lib/l10n/f_es_CR.arb +++ b/forui/lib/l10n/f_es_CR.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Diálogo" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_es_DO.arb b/forui/lib/l10n/f_es_DO.arb index 9e26dfeeb..866cdeb96 100644 --- a/forui/lib/l10n/f_es_DO.arb +++ b/forui/lib/l10n/f_es_DO.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Diálogo" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_es_EC.arb b/forui/lib/l10n/f_es_EC.arb index 9e26dfeeb..866cdeb96 100644 --- a/forui/lib/l10n/f_es_EC.arb +++ b/forui/lib/l10n/f_es_EC.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Diálogo" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_es_GT.arb b/forui/lib/l10n/f_es_GT.arb index 9e26dfeeb..866cdeb96 100644 --- a/forui/lib/l10n/f_es_GT.arb +++ b/forui/lib/l10n/f_es_GT.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Diálogo" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_es_HN.arb b/forui/lib/l10n/f_es_HN.arb index 9e26dfeeb..866cdeb96 100644 --- a/forui/lib/l10n/f_es_HN.arb +++ b/forui/lib/l10n/f_es_HN.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Diálogo" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_es_MX.arb b/forui/lib/l10n/f_es_MX.arb index 9e26dfeeb..866cdeb96 100644 --- a/forui/lib/l10n/f_es_MX.arb +++ b/forui/lib/l10n/f_es_MX.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Diálogo" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_es_NI.arb b/forui/lib/l10n/f_es_NI.arb index 9e26dfeeb..866cdeb96 100644 --- a/forui/lib/l10n/f_es_NI.arb +++ b/forui/lib/l10n/f_es_NI.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Diálogo" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_es_PA.arb b/forui/lib/l10n/f_es_PA.arb index 9e26dfeeb..866cdeb96 100644 --- a/forui/lib/l10n/f_es_PA.arb +++ b/forui/lib/l10n/f_es_PA.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Diálogo" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_es_PE.arb b/forui/lib/l10n/f_es_PE.arb index 9e26dfeeb..866cdeb96 100644 --- a/forui/lib/l10n/f_es_PE.arb +++ b/forui/lib/l10n/f_es_PE.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Diálogo" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_es_PR.arb b/forui/lib/l10n/f_es_PR.arb index 9e26dfeeb..866cdeb96 100644 --- a/forui/lib/l10n/f_es_PR.arb +++ b/forui/lib/l10n/f_es_PR.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Diálogo" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_es_PY.arb b/forui/lib/l10n/f_es_PY.arb index 9e26dfeeb..866cdeb96 100644 --- a/forui/lib/l10n/f_es_PY.arb +++ b/forui/lib/l10n/f_es_PY.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Diálogo" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_es_SV.arb b/forui/lib/l10n/f_es_SV.arb index 9e26dfeeb..866cdeb96 100644 --- a/forui/lib/l10n/f_es_SV.arb +++ b/forui/lib/l10n/f_es_SV.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Diálogo" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_es_US.arb b/forui/lib/l10n/f_es_US.arb index 9e26dfeeb..866cdeb96 100644 --- a/forui/lib/l10n/f_es_US.arb +++ b/forui/lib/l10n/f_es_US.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Diálogo" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_es_UY.arb b/forui/lib/l10n/f_es_UY.arb index 9e26dfeeb..866cdeb96 100644 --- a/forui/lib/l10n/f_es_UY.arb +++ b/forui/lib/l10n/f_es_UY.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Diálogo" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_es_VE.arb b/forui/lib/l10n/f_es_VE.arb index 9e26dfeeb..866cdeb96 100644 --- a/forui/lib/l10n/f_es_VE.arb +++ b/forui/lib/l10n/f_es_VE.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Diálogo" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_et.arb b/forui/lib/l10n/f_et.arb index 9e26dfeeb..3b920a0f7 100644 --- a/forui/lib/l10n/f_et.arb +++ b/forui/lib/l10n/f_et.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Dialoog" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_eu.arb b/forui/lib/l10n/f_eu.arb index 9e26dfeeb..5953845a0 100644 --- a/forui/lib/l10n/f_eu.arb +++ b/forui/lib/l10n/f_eu.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Leihoa" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_fa.arb b/forui/lib/l10n/f_fa.arb index 9e26dfeeb..8a3d2cd5f 100644 --- a/forui/lib/l10n/f_fa.arb +++ b/forui/lib/l10n/f_fa.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "کادر گفتگو" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_fi.arb b/forui/lib/l10n/f_fi.arb index 9e26dfeeb..004008abd 100644 --- a/forui/lib/l10n/f_fi.arb +++ b/forui/lib/l10n/f_fi.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Valintaikkuna" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_fil.arb b/forui/lib/l10n/f_fil.arb index 9e26dfeeb..e110b397e 100644 --- a/forui/lib/l10n/f_fil.arb +++ b/forui/lib/l10n/f_fil.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Dialog" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_fr.arb b/forui/lib/l10n/f_fr.arb index 9e26dfeeb..20c103078 100644 --- a/forui/lib/l10n/f_fr.arb +++ b/forui/lib/l10n/f_fr.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Boîte de dialogue" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_fr_CA.arb b/forui/lib/l10n/f_fr_CA.arb index 9e26dfeeb..20c103078 100644 --- a/forui/lib/l10n/f_fr_CA.arb +++ b/forui/lib/l10n/f_fr_CA.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Boîte de dialogue" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_gl.arb b/forui/lib/l10n/f_gl.arb index 9e26dfeeb..23e825c9d 100644 --- a/forui/lib/l10n/f_gl.arb +++ b/forui/lib/l10n/f_gl.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Cadro de diálogo" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_gsw.arb b/forui/lib/l10n/f_gsw.arb index 9e26dfeeb..6ee866ee2 100644 --- a/forui/lib/l10n/f_gsw.arb +++ b/forui/lib/l10n/f_gsw.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Dialogfeld" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_gu.arb b/forui/lib/l10n/f_gu.arb index 9e26dfeeb..e7bb6b90e 100644 --- a/forui/lib/l10n/f_gu.arb +++ b/forui/lib/l10n/f_gu.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "સંવાદ" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_he.arb b/forui/lib/l10n/f_he.arb index 9e26dfeeb..64cdf294f 100644 --- a/forui/lib/l10n/f_he.arb +++ b/forui/lib/l10n/f_he.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "תיבת דו-שיח" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_hi.arb b/forui/lib/l10n/f_hi.arb index 9e26dfeeb..f1b62e750 100644 --- a/forui/lib/l10n/f_hi.arb +++ b/forui/lib/l10n/f_hi.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "डायलॉग" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_hr.arb b/forui/lib/l10n/f_hr.arb index 9e26dfeeb..82633cdb0 100644 --- a/forui/lib/l10n/f_hr.arb +++ b/forui/lib/l10n/f_hr.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Dijalog" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_hu.arb b/forui/lib/l10n/f_hu.arb index 9e26dfeeb..45d6f60f1 100644 --- a/forui/lib/l10n/f_hu.arb +++ b/forui/lib/l10n/f_hu.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Párbeszédablak" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_hy.arb b/forui/lib/l10n/f_hy.arb index 9e26dfeeb..9b3609509 100644 --- a/forui/lib/l10n/f_hy.arb +++ b/forui/lib/l10n/f_hy.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Երկխոսության պատուհան" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_id.arb b/forui/lib/l10n/f_id.arb index 9e26dfeeb..e110b397e 100644 --- a/forui/lib/l10n/f_id.arb +++ b/forui/lib/l10n/f_id.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Dialog" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_is.arb b/forui/lib/l10n/f_is.arb index 9e26dfeeb..8a10bd807 100644 --- a/forui/lib/l10n/f_is.arb +++ b/forui/lib/l10n/f_is.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Gluggi" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_it.arb b/forui/lib/l10n/f_it.arb index 9e26dfeeb..2e04f7c5a 100644 --- a/forui/lib/l10n/f_it.arb +++ b/forui/lib/l10n/f_it.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Finestra di dialogo" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_ja.arb b/forui/lib/l10n/f_ja.arb index 9e26dfeeb..f105211c1 100644 --- a/forui/lib/l10n/f_ja.arb +++ b/forui/lib/l10n/f_ja.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "ダイアログ" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_ka.arb b/forui/lib/l10n/f_ka.arb index 9e26dfeeb..edb07fc1e 100644 --- a/forui/lib/l10n/f_ka.arb +++ b/forui/lib/l10n/f_ka.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "დიალოგი" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_kk.arb b/forui/lib/l10n/f_kk.arb index 9e26dfeeb..b3680765b 100644 --- a/forui/lib/l10n/f_kk.arb +++ b/forui/lib/l10n/f_kk.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Диалогтық терезе" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_km.arb b/forui/lib/l10n/f_km.arb index 9e26dfeeb..7dc6c43b4 100644 --- a/forui/lib/l10n/f_km.arb +++ b/forui/lib/l10n/f_km.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "ប្រអប់" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_kn.arb b/forui/lib/l10n/f_kn.arb index 9e26dfeeb..40b8e2b08 100644 --- a/forui/lib/l10n/f_kn.arb +++ b/forui/lib/l10n/f_kn.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "ಡೈಲಾಗ್" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_ko.arb b/forui/lib/l10n/f_ko.arb index 9e26dfeeb..90f1cb62b 100644 --- a/forui/lib/l10n/f_ko.arb +++ b/forui/lib/l10n/f_ko.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "대화상자" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_ky.arb b/forui/lib/l10n/f_ky.arb index 9e26dfeeb..26bf7c219 100644 --- a/forui/lib/l10n/f_ky.arb +++ b/forui/lib/l10n/f_ky.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Диалог" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_lo.arb b/forui/lib/l10n/f_lo.arb index 9e26dfeeb..e1d2d413b 100644 --- a/forui/lib/l10n/f_lo.arb +++ b/forui/lib/l10n/f_lo.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "ຂໍ້ຄວາມ" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_lt.arb b/forui/lib/l10n/f_lt.arb index 9e26dfeeb..e846fab7e 100644 --- a/forui/lib/l10n/f_lt.arb +++ b/forui/lib/l10n/f_lt.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Dialogo langas" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_lv.arb b/forui/lib/l10n/f_lv.arb index 9e26dfeeb..5e344124c 100644 --- a/forui/lib/l10n/f_lv.arb +++ b/forui/lib/l10n/f_lv.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Dialoglodziņš" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_mk.arb b/forui/lib/l10n/f_mk.arb index 9e26dfeeb..954f37e72 100644 --- a/forui/lib/l10n/f_mk.arb +++ b/forui/lib/l10n/f_mk.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Дијалог" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_ml.arb b/forui/lib/l10n/f_ml.arb index 9e26dfeeb..2a9e564ca 100644 --- a/forui/lib/l10n/f_ml.arb +++ b/forui/lib/l10n/f_ml.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "ഡയലോഗ്" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_mn.arb b/forui/lib/l10n/f_mn.arb index 9e26dfeeb..8558ab256 100644 --- a/forui/lib/l10n/f_mn.arb +++ b/forui/lib/l10n/f_mn.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Харилцах цонх" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_mr.arb b/forui/lib/l10n/f_mr.arb index 9e26dfeeb..f1b62e750 100644 --- a/forui/lib/l10n/f_mr.arb +++ b/forui/lib/l10n/f_mr.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "डायलॉग" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_ms.arb b/forui/lib/l10n/f_ms.arb index 9e26dfeeb..e110b397e 100644 --- a/forui/lib/l10n/f_ms.arb +++ b/forui/lib/l10n/f_ms.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Dialog" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_my.arb b/forui/lib/l10n/f_my.arb index 9e26dfeeb..2b90405fa 100644 --- a/forui/lib/l10n/f_my.arb +++ b/forui/lib/l10n/f_my.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "ဒိုင်ယာလော့" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_nb.arb b/forui/lib/l10n/f_nb.arb index 9e26dfeeb..fff2252c6 100644 --- a/forui/lib/l10n/f_nb.arb +++ b/forui/lib/l10n/f_nb.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Dialogboks" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_ne.arb b/forui/lib/l10n/f_ne.arb index 9e26dfeeb..7ac3b67db 100644 --- a/forui/lib/l10n/f_ne.arb +++ b/forui/lib/l10n/f_ne.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "संवाद" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_nl.arb b/forui/lib/l10n/f_nl.arb index 9e26dfeeb..09c950b57 100644 --- a/forui/lib/l10n/f_nl.arb +++ b/forui/lib/l10n/f_nl.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Dialoogvenster" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_no.arb b/forui/lib/l10n/f_no.arb index 9e26dfeeb..fff2252c6 100644 --- a/forui/lib/l10n/f_no.arb +++ b/forui/lib/l10n/f_no.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Dialogboks" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_or.arb b/forui/lib/l10n/f_or.arb index 9e26dfeeb..da45257c4 100644 --- a/forui/lib/l10n/f_or.arb +++ b/forui/lib/l10n/f_or.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "ଡାୟଲଗ୍" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_pa.arb b/forui/lib/l10n/f_pa.arb index 9e26dfeeb..507b188be 100644 --- a/forui/lib/l10n/f_pa.arb +++ b/forui/lib/l10n/f_pa.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "ਵਿੰਡੋ" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_pl.arb b/forui/lib/l10n/f_pl.arb index 9e26dfeeb..635e6e66f 100644 --- a/forui/lib/l10n/f_pl.arb +++ b/forui/lib/l10n/f_pl.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Okno dialogowe" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_ps.arb b/forui/lib/l10n/f_ps.arb index 9e26dfeeb..11628794c 100644 --- a/forui/lib/l10n/f_ps.arb +++ b/forui/lib/l10n/f_ps.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "خبرې اترې" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_pt.arb b/forui/lib/l10n/f_pt.arb index 9e26dfeeb..5eaaf3a1b 100644 --- a/forui/lib/l10n/f_pt.arb +++ b/forui/lib/l10n/f_pt.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Caixa de diálogo" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_pt_PT.arb b/forui/lib/l10n/f_pt_PT.arb index 9e26dfeeb..5eaaf3a1b 100644 --- a/forui/lib/l10n/f_pt_PT.arb +++ b/forui/lib/l10n/f_pt_PT.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Caixa de diálogo" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_ro.arb b/forui/lib/l10n/f_ro.arb index 9e26dfeeb..0d92cb0b9 100644 --- a/forui/lib/l10n/f_ro.arb +++ b/forui/lib/l10n/f_ro.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Casetă de dialog" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_ru.arb b/forui/lib/l10n/f_ru.arb index 9e26dfeeb..b5f9f85b2 100644 --- a/forui/lib/l10n/f_ru.arb +++ b/forui/lib/l10n/f_ru.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Диалоговое окно" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_si.arb b/forui/lib/l10n/f_si.arb index 9e26dfeeb..2bf5ee7c0 100644 --- a/forui/lib/l10n/f_si.arb +++ b/forui/lib/l10n/f_si.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "සංවාදය" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_sk.arb b/forui/lib/l10n/f_sk.arb index 9e26dfeeb..9877d3f5b 100644 --- a/forui/lib/l10n/f_sk.arb +++ b/forui/lib/l10n/f_sk.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Dialógové okno" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_sl.arb b/forui/lib/l10n/f_sl.arb index 9e26dfeeb..5fe860836 100644 --- a/forui/lib/l10n/f_sl.arb +++ b/forui/lib/l10n/f_sl.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Pogovorno okno" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_sq.arb b/forui/lib/l10n/f_sq.arb index 9e26dfeeb..9e6271e6b 100644 --- a/forui/lib/l10n/f_sq.arb +++ b/forui/lib/l10n/f_sq.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Dialogu" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_sr.arb b/forui/lib/l10n/f_sr.arb index 9e26dfeeb..954f37e72 100644 --- a/forui/lib/l10n/f_sr.arb +++ b/forui/lib/l10n/f_sr.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Дијалог" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_sr_Latn.arb b/forui/lib/l10n/f_sr_Latn.arb index 9e26dfeeb..82633cdb0 100644 --- a/forui/lib/l10n/f_sr_Latn.arb +++ b/forui/lib/l10n/f_sr_Latn.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Dijalog" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_sv.arb b/forui/lib/l10n/f_sv.arb index 9e26dfeeb..316fb9675 100644 --- a/forui/lib/l10n/f_sv.arb +++ b/forui/lib/l10n/f_sv.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Dialogruta" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_sw.arb b/forui/lib/l10n/f_sw.arb index 9e26dfeeb..2d7c5deab 100644 --- a/forui/lib/l10n/f_sw.arb +++ b/forui/lib/l10n/f_sw.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Kidirisha" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_ta.arb b/forui/lib/l10n/f_ta.arb index 9e26dfeeb..3aa591987 100644 --- a/forui/lib/l10n/f_ta.arb +++ b/forui/lib/l10n/f_ta.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "உரையாடல்" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_te.arb b/forui/lib/l10n/f_te.arb index 9e26dfeeb..c9ff2d584 100644 --- a/forui/lib/l10n/f_te.arb +++ b/forui/lib/l10n/f_te.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "డైలాగ్" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_th.arb b/forui/lib/l10n/f_th.arb index 9e26dfeeb..7fca3841a 100644 --- a/forui/lib/l10n/f_th.arb +++ b/forui/lib/l10n/f_th.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "กล่องโต้ตอบ" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_tl.arb b/forui/lib/l10n/f_tl.arb index 9e26dfeeb..e110b397e 100644 --- a/forui/lib/l10n/f_tl.arb +++ b/forui/lib/l10n/f_tl.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Dialog" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_tr.arb b/forui/lib/l10n/f_tr.arb index 9e26dfeeb..6a6760c1e 100644 --- a/forui/lib/l10n/f_tr.arb +++ b/forui/lib/l10n/f_tr.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "İletişim kutusu" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_uk.arb b/forui/lib/l10n/f_uk.arb index 9e26dfeeb..fa23a2d2f 100644 --- a/forui/lib/l10n/f_uk.arb +++ b/forui/lib/l10n/f_uk.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Вікно" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_ur.arb b/forui/lib/l10n/f_ur.arb index 9e26dfeeb..1838ac93e 100644 --- a/forui/lib/l10n/f_ur.arb +++ b/forui/lib/l10n/f_ur.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "ڈائلاگ" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_uz.arb b/forui/lib/l10n/f_uz.arb index 9e26dfeeb..73343cd96 100644 --- a/forui/lib/l10n/f_uz.arb +++ b/forui/lib/l10n/f_uz.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Muloqot oynasi" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_vi.arb b/forui/lib/l10n/f_vi.arb index 9e26dfeeb..9f872cab0 100644 --- a/forui/lib/l10n/f_vi.arb +++ b/forui/lib/l10n/f_vi.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Hộp thoại" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_zh.arb b/forui/lib/l10n/f_zh.arb index 9e26dfeeb..2ee9f1521 100644 --- a/forui/lib/l10n/f_zh.arb +++ b/forui/lib/l10n/f_zh.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "对话框" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_zh_HK.arb b/forui/lib/l10n/f_zh_HK.arb index 9e26dfeeb..a7594fe97 100644 --- a/forui/lib/l10n/f_zh_HK.arb +++ b/forui/lib/l10n/f_zh_HK.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "對話方塊" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_zh_TW.arb b/forui/lib/l10n/f_zh_TW.arb index 9e26dfeeb..a7594fe97 100644 --- a/forui/lib/l10n/f_zh_TW.arb +++ b/forui/lib/l10n/f_zh_TW.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "對話方塊" +} \ No newline at end of file diff --git a/forui/lib/l10n/f_zu.arb b/forui/lib/l10n/f_zu.arb index 9e26dfeeb..5fa3095d6 100644 --- a/forui/lib/l10n/f_zu.arb +++ b/forui/lib/l10n/f_zu.arb @@ -1 +1,3 @@ -{} \ No newline at end of file +{ + "dialogLabel": "Ingxoxo" +} \ No newline at end of file diff --git a/forui/lib/src/localizations/localization.dart b/forui/lib/src/localizations/localization.dart index 649c3245d..2ff69eae6 100644 --- a/forui/lib/src/localizations/localization.dart +++ b/forui/lib/src/localizations/localization.dart @@ -32,4 +32,7 @@ class DefaultLocalizations extends FLocalizations { @override String day(DateTime date) => DateFormat.d().format(date); + + @override + String get dialogLabel => 'Dialog'; } diff --git a/forui/lib/src/localizations/localizations.dart b/forui/lib/src/localizations/localizations.dart index 94b86ccb2..ce4ecb408 100644 --- a/forui/lib/src/localizations/localizations.dart +++ b/forui/lib/src/localizations/localizations.dart @@ -314,6 +314,12 @@ abstract class FLocalizations { /// In en, this message translates to: /// **'{date}'** String day(DateTime date); + + /// No description provided for @dialogLabel. + /// + /// In en, this message translates to: + /// **'Dialog'** + String get dialogLabel; } class _FLocalizationsDelegate extends LocalizationsDelegate { @@ -325,375 +331,178 @@ class _FLocalizationsDelegate extends LocalizationsDelegate { } @override - bool isSupported(Locale locale) => [ - 'af', - 'am', - 'ar', - 'as', - 'az', - 'be', - 'bg', - 'bn', - 'bs', - 'ca', - 'cs', - 'cy', - 'da', - 'de', - 'el', - 'en', - 'es', - 'et', - 'eu', - 'fa', - 'fi', - 'fil', - 'fr', - 'gl', - 'gsw', - 'gu', - 'he', - 'hi', - 'hr', - 'hu', - 'hy', - 'id', - 'is', - 'it', - 'ja', - 'ka', - 'kk', - 'km', - 'kn', - 'ko', - 'ky', - 'lo', - 'lt', - 'lv', - 'mk', - 'ml', - 'mn', - 'mr', - 'ms', - 'my', - 'nb', - 'ne', - 'nl', - 'no', - 'or', - 'pa', - 'pl', - 'ps', - 'pt', - 'ro', - 'ru', - 'si', - 'sk', - 'sl', - 'sq', - 'sr', - 'sv', - 'sw', - 'ta', - 'te', - 'th', - 'tl', - 'tr', - 'uk', - 'ur', - 'uz', - 'vi', - 'zh', - 'zu' - ].contains(locale.languageCode); + bool isSupported(Locale locale) => ['af', 'am', 'ar', 'as', 'az', 'be', 'bg', 'bn', 'bs', 'ca', 'cs', 'cy', 'da', 'de', 'el', 'en', 'es', 'et', 'eu', 'fa', 'fi', 'fil', 'fr', 'gl', 'gsw', 'gu', 'he', 'hi', 'hr', 'hu', 'hy', 'id', 'is', 'it', 'ja', 'ka', 'kk', 'km', 'kn', 'ko', 'ky', 'lo', 'lt', 'lv', 'mk', 'ml', 'mn', 'mr', 'ms', 'my', 'nb', 'ne', 'nl', 'no', 'or', 'pa', 'pl', 'ps', 'pt', 'ro', 'ru', 'si', 'sk', 'sl', 'sq', 'sr', 'sv', 'sw', 'ta', 'te', 'th', 'tl', 'tr', 'uk', 'ur', 'uz', 'vi', 'zh', 'zu'].contains(locale.languageCode); @override bool shouldReload(_FLocalizationsDelegate old) => false; } FLocalizations lookupFLocalizations(Locale locale) { + // Lookup logic when language+script codes are specified. switch (locale.languageCode) { - case 'sr': - { - switch (locale.scriptCode) { - case 'Latn': - return FLocalizationsSrLatn(); - } - break; - } + case 'sr': { + switch (locale.scriptCode) { + case 'Latn': return FLocalizationsSrLatn(); + } + break; + } } // Lookup logic when language+country codes are specified. switch (locale.languageCode) { - case 'de': - { - switch (locale.countryCode) { - case 'CH': - return FLocalizationsDeCh(); - } - break; - } - case 'en': - { - switch (locale.countryCode) { - case 'AU': - return FLocalizationsEnAu(); - case 'CA': - return FLocalizationsEnCa(); - case 'GB': - return FLocalizationsEnGb(); - case 'IE': - return FLocalizationsEnIe(); - case 'IN': - return FLocalizationsEnIn(); - case 'NZ': - return FLocalizationsEnNz(); - case 'SG': - return FLocalizationsEnSg(); - case 'ZA': - return FLocalizationsEnZa(); - } - break; - } - case 'es': - { - switch (locale.countryCode) { - case '419': - return FLocalizationsEs419(); - case 'AR': - return FLocalizationsEsAr(); - case 'BO': - return FLocalizationsEsBo(); - case 'CL': - return FLocalizationsEsCl(); - case 'CO': - return FLocalizationsEsCo(); - case 'CR': - return FLocalizationsEsCr(); - case 'DO': - return FLocalizationsEsDo(); - case 'EC': - return FLocalizationsEsEc(); - case 'GT': - return FLocalizationsEsGt(); - case 'HN': - return FLocalizationsEsHn(); - case 'MX': - return FLocalizationsEsMx(); - case 'NI': - return FLocalizationsEsNi(); - case 'PA': - return FLocalizationsEsPa(); - case 'PE': - return FLocalizationsEsPe(); - case 'PR': - return FLocalizationsEsPr(); - case 'PY': - return FLocalizationsEsPy(); - case 'SV': - return FLocalizationsEsSv(); - case 'US': - return FLocalizationsEsUs(); - case 'UY': - return FLocalizationsEsUy(); - case 'VE': - return FLocalizationsEsVe(); - } - break; - } - case 'fr': - { - switch (locale.countryCode) { - case 'CA': - return FLocalizationsFrCa(); - } - break; - } - case 'pt': - { - switch (locale.countryCode) { - case 'PT': - return FLocalizationsPtPt(); - } - break; - } - case 'zh': - { - switch (locale.countryCode) { - case 'HK': - return FLocalizationsZhHk(); - case 'TW': - return FLocalizationsZhTw(); - } - break; - } + case 'de': { + switch (locale.countryCode) { + case 'CH': return FLocalizationsDeCh(); + } + break; + } + case 'en': { + switch (locale.countryCode) { + case 'AU': return FLocalizationsEnAu(); +case 'CA': return FLocalizationsEnCa(); +case 'GB': return FLocalizationsEnGb(); +case 'IE': return FLocalizationsEnIe(); +case 'IN': return FLocalizationsEnIn(); +case 'NZ': return FLocalizationsEnNz(); +case 'SG': return FLocalizationsEnSg(); +case 'ZA': return FLocalizationsEnZa(); + } + break; + } + case 'es': { + switch (locale.countryCode) { + case '419': return FLocalizationsEs419(); +case 'AR': return FLocalizationsEsAr(); +case 'BO': return FLocalizationsEsBo(); +case 'CL': return FLocalizationsEsCl(); +case 'CO': return FLocalizationsEsCo(); +case 'CR': return FLocalizationsEsCr(); +case 'DO': return FLocalizationsEsDo(); +case 'EC': return FLocalizationsEsEc(); +case 'GT': return FLocalizationsEsGt(); +case 'HN': return FLocalizationsEsHn(); +case 'MX': return FLocalizationsEsMx(); +case 'NI': return FLocalizationsEsNi(); +case 'PA': return FLocalizationsEsPa(); +case 'PE': return FLocalizationsEsPe(); +case 'PR': return FLocalizationsEsPr(); +case 'PY': return FLocalizationsEsPy(); +case 'SV': return FLocalizationsEsSv(); +case 'US': return FLocalizationsEsUs(); +case 'UY': return FLocalizationsEsUy(); +case 'VE': return FLocalizationsEsVe(); + } + break; + } + case 'fr': { + switch (locale.countryCode) { + case 'CA': return FLocalizationsFrCa(); + } + break; + } + case 'pt': { + switch (locale.countryCode) { + case 'PT': return FLocalizationsPtPt(); + } + break; + } + case 'zh': { + switch (locale.countryCode) { + case 'HK': return FLocalizationsZhHk(); +case 'TW': return FLocalizationsZhTw(); + } + break; + } } // Lookup logic when only language code is specified. switch (locale.languageCode) { - case 'af': - return FLocalizationsAf(); - case 'am': - return FLocalizationsAm(); - case 'ar': - return FLocalizationsAr(); - case 'as': - return FLocalizationsAs(); - case 'az': - return FLocalizationsAz(); - case 'be': - return FLocalizationsBe(); - case 'bg': - return FLocalizationsBg(); - case 'bn': - return FLocalizationsBn(); - case 'bs': - return FLocalizationsBs(); - case 'ca': - return FLocalizationsCa(); - case 'cs': - return FLocalizationsCs(); - case 'cy': - return FLocalizationsCy(); - case 'da': - return FLocalizationsDa(); - case 'de': - return FLocalizationsDe(); - case 'el': - return FLocalizationsEl(); - case 'en': - return FLocalizationsEn(); - case 'es': - return FLocalizationsEs(); - case 'et': - return FLocalizationsEt(); - case 'eu': - return FLocalizationsEu(); - case 'fa': - return FLocalizationsFa(); - case 'fi': - return FLocalizationsFi(); - case 'fil': - return FLocalizationsFil(); - case 'fr': - return FLocalizationsFr(); - case 'gl': - return FLocalizationsGl(); - case 'gsw': - return FLocalizationsGsw(); - case 'gu': - return FLocalizationsGu(); - case 'he': - return FLocalizationsHe(); - case 'hi': - return FLocalizationsHi(); - case 'hr': - return FLocalizationsHr(); - case 'hu': - return FLocalizationsHu(); - case 'hy': - return FLocalizationsHy(); - case 'id': - return FLocalizationsId(); - case 'is': - return FLocalizationsIs(); - case 'it': - return FLocalizationsIt(); - case 'ja': - return FLocalizationsJa(); - case 'ka': - return FLocalizationsKa(); - case 'kk': - return FLocalizationsKk(); - case 'km': - return FLocalizationsKm(); - case 'kn': - return FLocalizationsKn(); - case 'ko': - return FLocalizationsKo(); - case 'ky': - return FLocalizationsKy(); - case 'lo': - return FLocalizationsLo(); - case 'lt': - return FLocalizationsLt(); - case 'lv': - return FLocalizationsLv(); - case 'mk': - return FLocalizationsMk(); - case 'ml': - return FLocalizationsMl(); - case 'mn': - return FLocalizationsMn(); - case 'mr': - return FLocalizationsMr(); - case 'ms': - return FLocalizationsMs(); - case 'my': - return FLocalizationsMy(); - case 'nb': - return FLocalizationsNb(); - case 'ne': - return FLocalizationsNe(); - case 'nl': - return FLocalizationsNl(); - case 'no': - return FLocalizationsNo(); - case 'or': - return FLocalizationsOr(); - case 'pa': - return FLocalizationsPa(); - case 'pl': - return FLocalizationsPl(); - case 'ps': - return FLocalizationsPs(); - case 'pt': - return FLocalizationsPt(); - case 'ro': - return FLocalizationsRo(); - case 'ru': - return FLocalizationsRu(); - case 'si': - return FLocalizationsSi(); - case 'sk': - return FLocalizationsSk(); - case 'sl': - return FLocalizationsSl(); - case 'sq': - return FLocalizationsSq(); - case 'sr': - return FLocalizationsSr(); - case 'sv': - return FLocalizationsSv(); - case 'sw': - return FLocalizationsSw(); - case 'ta': - return FLocalizationsTa(); - case 'te': - return FLocalizationsTe(); - case 'th': - return FLocalizationsTh(); - case 'tl': - return FLocalizationsTl(); - case 'tr': - return FLocalizationsTr(); - case 'uk': - return FLocalizationsUk(); - case 'ur': - return FLocalizationsUr(); - case 'uz': - return FLocalizationsUz(); - case 'vi': - return FLocalizationsVi(); - case 'zh': - return FLocalizationsZh(); - case 'zu': - return FLocalizationsZu(); + case 'af': return FLocalizationsAf(); + case 'am': return FLocalizationsAm(); + case 'ar': return FLocalizationsAr(); + case 'as': return FLocalizationsAs(); + case 'az': return FLocalizationsAz(); + case 'be': return FLocalizationsBe(); + case 'bg': return FLocalizationsBg(); + case 'bn': return FLocalizationsBn(); + case 'bs': return FLocalizationsBs(); + case 'ca': return FLocalizationsCa(); + case 'cs': return FLocalizationsCs(); + case 'cy': return FLocalizationsCy(); + case 'da': return FLocalizationsDa(); + case 'de': return FLocalizationsDe(); + case 'el': return FLocalizationsEl(); + case 'en': return FLocalizationsEn(); + case 'es': return FLocalizationsEs(); + case 'et': return FLocalizationsEt(); + case 'eu': return FLocalizationsEu(); + case 'fa': return FLocalizationsFa(); + case 'fi': return FLocalizationsFi(); + case 'fil': return FLocalizationsFil(); + case 'fr': return FLocalizationsFr(); + case 'gl': return FLocalizationsGl(); + case 'gsw': return FLocalizationsGsw(); + case 'gu': return FLocalizationsGu(); + case 'he': return FLocalizationsHe(); + case 'hi': return FLocalizationsHi(); + case 'hr': return FLocalizationsHr(); + case 'hu': return FLocalizationsHu(); + case 'hy': return FLocalizationsHy(); + case 'id': return FLocalizationsId(); + case 'is': return FLocalizationsIs(); + case 'it': return FLocalizationsIt(); + case 'ja': return FLocalizationsJa(); + case 'ka': return FLocalizationsKa(); + case 'kk': return FLocalizationsKk(); + case 'km': return FLocalizationsKm(); + case 'kn': return FLocalizationsKn(); + case 'ko': return FLocalizationsKo(); + case 'ky': return FLocalizationsKy(); + case 'lo': return FLocalizationsLo(); + case 'lt': return FLocalizationsLt(); + case 'lv': return FLocalizationsLv(); + case 'mk': return FLocalizationsMk(); + case 'ml': return FLocalizationsMl(); + case 'mn': return FLocalizationsMn(); + case 'mr': return FLocalizationsMr(); + case 'ms': return FLocalizationsMs(); + case 'my': return FLocalizationsMy(); + case 'nb': return FLocalizationsNb(); + case 'ne': return FLocalizationsNe(); + case 'nl': return FLocalizationsNl(); + case 'no': return FLocalizationsNo(); + case 'or': return FLocalizationsOr(); + case 'pa': return FLocalizationsPa(); + case 'pl': return FLocalizationsPl(); + case 'ps': return FLocalizationsPs(); + case 'pt': return FLocalizationsPt(); + case 'ro': return FLocalizationsRo(); + case 'ru': return FLocalizationsRu(); + case 'si': return FLocalizationsSi(); + case 'sk': return FLocalizationsSk(); + case 'sl': return FLocalizationsSl(); + case 'sq': return FLocalizationsSq(); + case 'sr': return FLocalizationsSr(); + case 'sv': return FLocalizationsSv(); + case 'sw': return FLocalizationsSw(); + case 'ta': return FLocalizationsTa(); + case 'te': return FLocalizationsTe(); + case 'th': return FLocalizationsTh(); + case 'tl': return FLocalizationsTl(); + case 'tr': return FLocalizationsTr(); + case 'uk': return FLocalizationsUk(); + case 'ur': return FLocalizationsUr(); + case 'uz': return FLocalizationsUz(); + case 'vi': return FLocalizationsVi(); + case 'zh': return FLocalizationsZh(); + case 'zu': return FLocalizationsZu(); } - throw FlutterError('FLocalizations.delegate failed to load unsupported locale "$locale". This is likely ' - 'an issue with the localizations generation tool. Please file an issue ' - 'on GitHub with a reproducible sample app and the gen-l10n configuration ' - 'that was used.'); + throw FlutterError( + 'FLocalizations.delegate failed to load unsupported locale "$locale". This is likely ' + 'an issue with the localizations generation tool. Please file an issue ' + 'on GitHub with a reproducible sample app and the gen-l10n configuration ' + 'that was used.' + ); } diff --git a/forui/lib/src/localizations/localizations_af.dart b/forui/lib/src/localizations/localizations_af.dart index 792153a62..e3d6f6bec 100644 --- a/forui/lib/src/localizations/localizations_af.dart +++ b/forui/lib/src/localizations/localizations_af.dart @@ -47,4 +47,7 @@ class FLocalizationsAf extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'Dialoog'; } diff --git a/forui/lib/src/localizations/localizations_am.dart b/forui/lib/src/localizations/localizations_am.dart index 02c279749..b5af5f546 100644 --- a/forui/lib/src/localizations/localizations_am.dart +++ b/forui/lib/src/localizations/localizations_am.dart @@ -47,4 +47,7 @@ class FLocalizationsAm extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'መገናኛ'; } diff --git a/forui/lib/src/localizations/localizations_ar.dart b/forui/lib/src/localizations/localizations_ar.dart index a182772b7..d566fb58e 100644 --- a/forui/lib/src/localizations/localizations_ar.dart +++ b/forui/lib/src/localizations/localizations_ar.dart @@ -47,4 +47,7 @@ class FLocalizationsAr extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'مربع حوار'; } diff --git a/forui/lib/src/localizations/localizations_as.dart b/forui/lib/src/localizations/localizations_as.dart index 661d02c36..4a5c99e58 100644 --- a/forui/lib/src/localizations/localizations_as.dart +++ b/forui/lib/src/localizations/localizations_as.dart @@ -47,4 +47,7 @@ class FLocalizationsAs extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'ডায়ল\'গ'; } diff --git a/forui/lib/src/localizations/localizations_az.dart b/forui/lib/src/localizations/localizations_az.dart index 1d80c6d11..91f8fd491 100644 --- a/forui/lib/src/localizations/localizations_az.dart +++ b/forui/lib/src/localizations/localizations_az.dart @@ -47,4 +47,7 @@ class FLocalizationsAz extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'Dialoq'; } diff --git a/forui/lib/src/localizations/localizations_be.dart b/forui/lib/src/localizations/localizations_be.dart index e93e18d49..907f9cfef 100644 --- a/forui/lib/src/localizations/localizations_be.dart +++ b/forui/lib/src/localizations/localizations_be.dart @@ -47,4 +47,7 @@ class FLocalizationsBe extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'Дыялогавае акно'; } diff --git a/forui/lib/src/localizations/localizations_bg.dart b/forui/lib/src/localizations/localizations_bg.dart index ba949c8d2..c80aef1fc 100644 --- a/forui/lib/src/localizations/localizations_bg.dart +++ b/forui/lib/src/localizations/localizations_bg.dart @@ -47,4 +47,7 @@ class FLocalizationsBg extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'Диалогов прозорец'; } diff --git a/forui/lib/src/localizations/localizations_bn.dart b/forui/lib/src/localizations/localizations_bn.dart index d11399a6d..7d80739a4 100644 --- a/forui/lib/src/localizations/localizations_bn.dart +++ b/forui/lib/src/localizations/localizations_bn.dart @@ -47,4 +47,7 @@ class FLocalizationsBn extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'ডায়ালগ'; } diff --git a/forui/lib/src/localizations/localizations_bs.dart b/forui/lib/src/localizations/localizations_bs.dart index 4bcb20546..c03f2c57d 100644 --- a/forui/lib/src/localizations/localizations_bs.dart +++ b/forui/lib/src/localizations/localizations_bs.dart @@ -47,4 +47,7 @@ class FLocalizationsBs extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'Dijaloški okvir'; } diff --git a/forui/lib/src/localizations/localizations_ca.dart b/forui/lib/src/localizations/localizations_ca.dart index 56d887b76..4798563da 100644 --- a/forui/lib/src/localizations/localizations_ca.dart +++ b/forui/lib/src/localizations/localizations_ca.dart @@ -47,4 +47,7 @@ class FLocalizationsCa extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'Diàleg'; } diff --git a/forui/lib/src/localizations/localizations_cs.dart b/forui/lib/src/localizations/localizations_cs.dart index 1623849af..0f790c71a 100644 --- a/forui/lib/src/localizations/localizations_cs.dart +++ b/forui/lib/src/localizations/localizations_cs.dart @@ -47,4 +47,7 @@ class FLocalizationsCs extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'Dialogové okno'; } diff --git a/forui/lib/src/localizations/localizations_cy.dart b/forui/lib/src/localizations/localizations_cy.dart index 04ecbce74..64e488749 100644 --- a/forui/lib/src/localizations/localizations_cy.dart +++ b/forui/lib/src/localizations/localizations_cy.dart @@ -47,4 +47,7 @@ class FLocalizationsCy extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'Deialog'; } diff --git a/forui/lib/src/localizations/localizations_da.dart b/forui/lib/src/localizations/localizations_da.dart index 37e143504..0f8df543c 100644 --- a/forui/lib/src/localizations/localizations_da.dart +++ b/forui/lib/src/localizations/localizations_da.dart @@ -47,4 +47,7 @@ class FLocalizationsDa extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'Dialogboks'; } diff --git a/forui/lib/src/localizations/localizations_de.dart b/forui/lib/src/localizations/localizations_de.dart index c79a02895..bf0043c7f 100644 --- a/forui/lib/src/localizations/localizations_de.dart +++ b/forui/lib/src/localizations/localizations_de.dart @@ -47,9 +47,15 @@ class FLocalizationsDe extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'Dialogfeld'; } /// The translations for German, as used in Switzerland (`de_CH`). class FLocalizationsDeCh extends FLocalizationsDe { - FLocalizationsDeCh() : super('de_CH'); + FLocalizationsDeCh(): super('de_CH'); + + @override + String get dialogLabel => 'Dialogfeld'; } diff --git a/forui/lib/src/localizations/localizations_el.dart b/forui/lib/src/localizations/localizations_el.dart index fb54e1b11..0dcaf679c 100644 --- a/forui/lib/src/localizations/localizations_el.dart +++ b/forui/lib/src/localizations/localizations_el.dart @@ -47,4 +47,7 @@ class FLocalizationsEl extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'Παράθυρο διαλόγου'; } diff --git a/forui/lib/src/localizations/localizations_en.dart b/forui/lib/src/localizations/localizations_en.dart index 9c8ca4eb4..a96f68353 100644 --- a/forui/lib/src/localizations/localizations_en.dart +++ b/forui/lib/src/localizations/localizations_en.dart @@ -47,44 +47,71 @@ class FLocalizationsEn extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'Dialog'; } /// The translations for English, as used in Australia (`en_AU`). class FLocalizationsEnAu extends FLocalizationsEn { - FLocalizationsEnAu() : super('en_AU'); + FLocalizationsEnAu(): super('en_AU'); + + @override + String get dialogLabel => 'Dialogue'; } /// The translations for English, as used in Canada (`en_CA`). class FLocalizationsEnCa extends FLocalizationsEn { - FLocalizationsEnCa() : super('en_CA'); + FLocalizationsEnCa(): super('en_CA'); + + @override + String get dialogLabel => 'Dialog'; } /// The translations for English, as used in the United Kingdom (`en_GB`). class FLocalizationsEnGb extends FLocalizationsEn { - FLocalizationsEnGb() : super('en_GB'); + FLocalizationsEnGb(): super('en_GB'); + + @override + String get dialogLabel => 'Dialogue'; } /// The translations for English, as used in Ireland (`en_IE`). class FLocalizationsEnIe extends FLocalizationsEn { - FLocalizationsEnIe() : super('en_IE'); + FLocalizationsEnIe(): super('en_IE'); + + @override + String get dialogLabel => 'Dialogue'; } /// The translations for English, as used in India (`en_IN`). class FLocalizationsEnIn extends FLocalizationsEn { - FLocalizationsEnIn() : super('en_IN'); + FLocalizationsEnIn(): super('en_IN'); + + @override + String get dialogLabel => 'Dialogue'; } /// The translations for English, as used in New Zealand (`en_NZ`). class FLocalizationsEnNz extends FLocalizationsEn { - FLocalizationsEnNz() : super('en_NZ'); + FLocalizationsEnNz(): super('en_NZ'); + + @override + String get dialogLabel => 'Dialogue'; } /// The translations for English, as used in Singapore (`en_SG`). class FLocalizationsEnSg extends FLocalizationsEn { - FLocalizationsEnSg() : super('en_SG'); + FLocalizationsEnSg(): super('en_SG'); + + @override + String get dialogLabel => 'Dialogue'; } /// The translations for English, as used in South Africa (`en_ZA`). class FLocalizationsEnZa extends FLocalizationsEn { - FLocalizationsEnZa() : super('en_ZA'); + FLocalizationsEnZa(): super('en_ZA'); + + @override + String get dialogLabel => 'Dialogue'; } diff --git a/forui/lib/src/localizations/localizations_es.dart b/forui/lib/src/localizations/localizations_es.dart index a46eefe40..2782220f3 100644 --- a/forui/lib/src/localizations/localizations_es.dart +++ b/forui/lib/src/localizations/localizations_es.dart @@ -47,104 +47,167 @@ class FLocalizationsEs extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'Cuadro de diálogo'; } /// The translations for Spanish Castilian, as used in Latin America and the Caribbean (`es_419`). class FLocalizationsEs419 extends FLocalizationsEs { - FLocalizationsEs419() : super('es_419'); + FLocalizationsEs419(): super('es_419'); + + @override + String get dialogLabel => 'Diálogo'; } /// The translations for Spanish Castilian, as used in Argentina (`es_AR`). class FLocalizationsEsAr extends FLocalizationsEs { - FLocalizationsEsAr() : super('es_AR'); + FLocalizationsEsAr(): super('es_AR'); + + @override + String get dialogLabel => 'Diálogo'; } /// The translations for Spanish Castilian, as used in Bolivia (`es_BO`). class FLocalizationsEsBo extends FLocalizationsEs { - FLocalizationsEsBo() : super('es_BO'); + FLocalizationsEsBo(): super('es_BO'); + + @override + String get dialogLabel => 'Diálogo'; } /// The translations for Spanish Castilian, as used in Chile (`es_CL`). class FLocalizationsEsCl extends FLocalizationsEs { - FLocalizationsEsCl() : super('es_CL'); + FLocalizationsEsCl(): super('es_CL'); + + @override + String get dialogLabel => 'Diálogo'; } /// The translations for Spanish Castilian, as used in Colombia (`es_CO`). class FLocalizationsEsCo extends FLocalizationsEs { - FLocalizationsEsCo() : super('es_CO'); + FLocalizationsEsCo(): super('es_CO'); + + @override + String get dialogLabel => 'Diálogo'; } /// The translations for Spanish Castilian, as used in Costa Rica (`es_CR`). class FLocalizationsEsCr extends FLocalizationsEs { - FLocalizationsEsCr() : super('es_CR'); + FLocalizationsEsCr(): super('es_CR'); + + @override + String get dialogLabel => 'Diálogo'; } /// The translations for Spanish Castilian, as used in the Dominican Republic (`es_DO`). class FLocalizationsEsDo extends FLocalizationsEs { - FLocalizationsEsDo() : super('es_DO'); + FLocalizationsEsDo(): super('es_DO'); + + @override + String get dialogLabel => 'Diálogo'; } /// The translations for Spanish Castilian, as used in Ecuador (`es_EC`). class FLocalizationsEsEc extends FLocalizationsEs { - FLocalizationsEsEc() : super('es_EC'); + FLocalizationsEsEc(): super('es_EC'); + + @override + String get dialogLabel => 'Diálogo'; } /// The translations for Spanish Castilian, as used in Guatemala (`es_GT`). class FLocalizationsEsGt extends FLocalizationsEs { - FLocalizationsEsGt() : super('es_GT'); + FLocalizationsEsGt(): super('es_GT'); + + @override + String get dialogLabel => 'Diálogo'; } /// The translations for Spanish Castilian, as used in Honduras (`es_HN`). class FLocalizationsEsHn extends FLocalizationsEs { - FLocalizationsEsHn() : super('es_HN'); + FLocalizationsEsHn(): super('es_HN'); + + @override + String get dialogLabel => 'Diálogo'; } /// The translations for Spanish Castilian, as used in Mexico (`es_MX`). class FLocalizationsEsMx extends FLocalizationsEs { - FLocalizationsEsMx() : super('es_MX'); + FLocalizationsEsMx(): super('es_MX'); + + @override + String get dialogLabel => 'Diálogo'; } /// The translations for Spanish Castilian, as used in Nicaragua (`es_NI`). class FLocalizationsEsNi extends FLocalizationsEs { - FLocalizationsEsNi() : super('es_NI'); + FLocalizationsEsNi(): super('es_NI'); + + @override + String get dialogLabel => 'Diálogo'; } /// The translations for Spanish Castilian, as used in Panama (`es_PA`). class FLocalizationsEsPa extends FLocalizationsEs { - FLocalizationsEsPa() : super('es_PA'); + FLocalizationsEsPa(): super('es_PA'); + + @override + String get dialogLabel => 'Diálogo'; } /// The translations for Spanish Castilian, as used in Peru (`es_PE`). class FLocalizationsEsPe extends FLocalizationsEs { - FLocalizationsEsPe() : super('es_PE'); + FLocalizationsEsPe(): super('es_PE'); + + @override + String get dialogLabel => 'Diálogo'; } /// The translations for Spanish Castilian, as used in Puerto Rico (`es_PR`). class FLocalizationsEsPr extends FLocalizationsEs { - FLocalizationsEsPr() : super('es_PR'); + FLocalizationsEsPr(): super('es_PR'); + + @override + String get dialogLabel => 'Diálogo'; } /// The translations for Spanish Castilian, as used in Paraguay (`es_PY`). class FLocalizationsEsPy extends FLocalizationsEs { - FLocalizationsEsPy() : super('es_PY'); + FLocalizationsEsPy(): super('es_PY'); + + @override + String get dialogLabel => 'Diálogo'; } /// The translations for Spanish Castilian, as used in El Salvador (`es_SV`). class FLocalizationsEsSv extends FLocalizationsEs { - FLocalizationsEsSv() : super('es_SV'); + FLocalizationsEsSv(): super('es_SV'); + + @override + String get dialogLabel => 'Diálogo'; } /// The translations for Spanish Castilian, as used in the United States (`es_US`). class FLocalizationsEsUs extends FLocalizationsEs { - FLocalizationsEsUs() : super('es_US'); + FLocalizationsEsUs(): super('es_US'); + + @override + String get dialogLabel => 'Diálogo'; } /// The translations for Spanish Castilian, as used in Uruguay (`es_UY`). class FLocalizationsEsUy extends FLocalizationsEs { - FLocalizationsEsUy() : super('es_UY'); + FLocalizationsEsUy(): super('es_UY'); + + @override + String get dialogLabel => 'Diálogo'; } /// The translations for Spanish Castilian, as used in Venezuela (`es_VE`). class FLocalizationsEsVe extends FLocalizationsEs { - FLocalizationsEsVe() : super('es_VE'); + FLocalizationsEsVe(): super('es_VE'); + + @override + String get dialogLabel => 'Diálogo'; } diff --git a/forui/lib/src/localizations/localizations_et.dart b/forui/lib/src/localizations/localizations_et.dart index 18ddb790e..a11b8f356 100644 --- a/forui/lib/src/localizations/localizations_et.dart +++ b/forui/lib/src/localizations/localizations_et.dart @@ -47,4 +47,7 @@ class FLocalizationsEt extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'Dialoog'; } diff --git a/forui/lib/src/localizations/localizations_eu.dart b/forui/lib/src/localizations/localizations_eu.dart index 3fac395db..6a9878501 100644 --- a/forui/lib/src/localizations/localizations_eu.dart +++ b/forui/lib/src/localizations/localizations_eu.dart @@ -47,4 +47,7 @@ class FLocalizationsEu extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'Leihoa'; } diff --git a/forui/lib/src/localizations/localizations_fa.dart b/forui/lib/src/localizations/localizations_fa.dart index 5c6a42bfd..bace9f316 100644 --- a/forui/lib/src/localizations/localizations_fa.dart +++ b/forui/lib/src/localizations/localizations_fa.dart @@ -47,4 +47,7 @@ class FLocalizationsFa extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'کادر گفتگو'; } diff --git a/forui/lib/src/localizations/localizations_fi.dart b/forui/lib/src/localizations/localizations_fi.dart index 57fd14919..fb758c63a 100644 --- a/forui/lib/src/localizations/localizations_fi.dart +++ b/forui/lib/src/localizations/localizations_fi.dart @@ -47,4 +47,7 @@ class FLocalizationsFi extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'Valintaikkuna'; } diff --git a/forui/lib/src/localizations/localizations_fil.dart b/forui/lib/src/localizations/localizations_fil.dart index c835ce3fc..967b8612b 100644 --- a/forui/lib/src/localizations/localizations_fil.dart +++ b/forui/lib/src/localizations/localizations_fil.dart @@ -47,4 +47,7 @@ class FLocalizationsFil extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'Dialog'; } diff --git a/forui/lib/src/localizations/localizations_fr.dart b/forui/lib/src/localizations/localizations_fr.dart index 7f9dea2b7..1860d97df 100644 --- a/forui/lib/src/localizations/localizations_fr.dart +++ b/forui/lib/src/localizations/localizations_fr.dart @@ -47,9 +47,15 @@ class FLocalizationsFr extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'Boîte de dialogue'; } /// The translations for French, as used in Canada (`fr_CA`). class FLocalizationsFrCa extends FLocalizationsFr { - FLocalizationsFrCa() : super('fr_CA'); + FLocalizationsFrCa(): super('fr_CA'); + + @override + String get dialogLabel => 'Boîte de dialogue'; } diff --git a/forui/lib/src/localizations/localizations_gl.dart b/forui/lib/src/localizations/localizations_gl.dart index 02f88a4fe..8b1e9df55 100644 --- a/forui/lib/src/localizations/localizations_gl.dart +++ b/forui/lib/src/localizations/localizations_gl.dart @@ -47,4 +47,7 @@ class FLocalizationsGl extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'Cadro de diálogo'; } diff --git a/forui/lib/src/localizations/localizations_gsw.dart b/forui/lib/src/localizations/localizations_gsw.dart index c0239a469..65c7cb7da 100644 --- a/forui/lib/src/localizations/localizations_gsw.dart +++ b/forui/lib/src/localizations/localizations_gsw.dart @@ -47,4 +47,7 @@ class FLocalizationsGsw extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'Dialogfeld'; } diff --git a/forui/lib/src/localizations/localizations_gu.dart b/forui/lib/src/localizations/localizations_gu.dart index f6a87decb..83d0259f9 100644 --- a/forui/lib/src/localizations/localizations_gu.dart +++ b/forui/lib/src/localizations/localizations_gu.dart @@ -47,4 +47,7 @@ class FLocalizationsGu extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'સંવાદ'; } diff --git a/forui/lib/src/localizations/localizations_he.dart b/forui/lib/src/localizations/localizations_he.dart index 23d69689f..e16fdcdc5 100644 --- a/forui/lib/src/localizations/localizations_he.dart +++ b/forui/lib/src/localizations/localizations_he.dart @@ -47,4 +47,7 @@ class FLocalizationsHe extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'תיבת דו-שיח'; } diff --git a/forui/lib/src/localizations/localizations_hi.dart b/forui/lib/src/localizations/localizations_hi.dart index f31f1bdca..752bd4eef 100644 --- a/forui/lib/src/localizations/localizations_hi.dart +++ b/forui/lib/src/localizations/localizations_hi.dart @@ -47,4 +47,7 @@ class FLocalizationsHi extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'डायलॉग'; } diff --git a/forui/lib/src/localizations/localizations_hr.dart b/forui/lib/src/localizations/localizations_hr.dart index fed86b8ad..fe0d82253 100644 --- a/forui/lib/src/localizations/localizations_hr.dart +++ b/forui/lib/src/localizations/localizations_hr.dart @@ -47,4 +47,7 @@ class FLocalizationsHr extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'Dijalog'; } diff --git a/forui/lib/src/localizations/localizations_hu.dart b/forui/lib/src/localizations/localizations_hu.dart index 806833eb2..58af6960f 100644 --- a/forui/lib/src/localizations/localizations_hu.dart +++ b/forui/lib/src/localizations/localizations_hu.dart @@ -47,4 +47,7 @@ class FLocalizationsHu extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'Párbeszédablak'; } diff --git a/forui/lib/src/localizations/localizations_hy.dart b/forui/lib/src/localizations/localizations_hy.dart index 263340036..40d8beb6f 100644 --- a/forui/lib/src/localizations/localizations_hy.dart +++ b/forui/lib/src/localizations/localizations_hy.dart @@ -47,4 +47,7 @@ class FLocalizationsHy extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'Երկխոսության պատուհան'; } diff --git a/forui/lib/src/localizations/localizations_id.dart b/forui/lib/src/localizations/localizations_id.dart index 97e84d1e2..7fa8e079a 100644 --- a/forui/lib/src/localizations/localizations_id.dart +++ b/forui/lib/src/localizations/localizations_id.dart @@ -47,4 +47,7 @@ class FLocalizationsId extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'Dialog'; } diff --git a/forui/lib/src/localizations/localizations_is.dart b/forui/lib/src/localizations/localizations_is.dart index 9c9ac735b..62614947e 100644 --- a/forui/lib/src/localizations/localizations_is.dart +++ b/forui/lib/src/localizations/localizations_is.dart @@ -47,4 +47,7 @@ class FLocalizationsIs extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'Gluggi'; } diff --git a/forui/lib/src/localizations/localizations_it.dart b/forui/lib/src/localizations/localizations_it.dart index fc93e1047..99b51163a 100644 --- a/forui/lib/src/localizations/localizations_it.dart +++ b/forui/lib/src/localizations/localizations_it.dart @@ -47,4 +47,7 @@ class FLocalizationsIt extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'Finestra di dialogo'; } diff --git a/forui/lib/src/localizations/localizations_ja.dart b/forui/lib/src/localizations/localizations_ja.dart index 617b1bdaa..03c3ae453 100644 --- a/forui/lib/src/localizations/localizations_ja.dart +++ b/forui/lib/src/localizations/localizations_ja.dart @@ -47,4 +47,7 @@ class FLocalizationsJa extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'ダイアログ'; } diff --git a/forui/lib/src/localizations/localizations_ka.dart b/forui/lib/src/localizations/localizations_ka.dart index 3eea4f4a0..044ffcd23 100644 --- a/forui/lib/src/localizations/localizations_ka.dart +++ b/forui/lib/src/localizations/localizations_ka.dart @@ -47,4 +47,7 @@ class FLocalizationsKa extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'დიალოგი'; } diff --git a/forui/lib/src/localizations/localizations_kk.dart b/forui/lib/src/localizations/localizations_kk.dart index a9632d68d..b086439a5 100644 --- a/forui/lib/src/localizations/localizations_kk.dart +++ b/forui/lib/src/localizations/localizations_kk.dart @@ -47,4 +47,7 @@ class FLocalizationsKk extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'Диалогтық терезе'; } diff --git a/forui/lib/src/localizations/localizations_km.dart b/forui/lib/src/localizations/localizations_km.dart index 5f5e504f2..12d84310d 100644 --- a/forui/lib/src/localizations/localizations_km.dart +++ b/forui/lib/src/localizations/localizations_km.dart @@ -47,4 +47,7 @@ class FLocalizationsKm extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'ប្រអប់'; } diff --git a/forui/lib/src/localizations/localizations_kn.dart b/forui/lib/src/localizations/localizations_kn.dart index d7f9ff50b..986c68ffd 100644 --- a/forui/lib/src/localizations/localizations_kn.dart +++ b/forui/lib/src/localizations/localizations_kn.dart @@ -47,4 +47,7 @@ class FLocalizationsKn extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'ಡೈಲಾಗ್'; } diff --git a/forui/lib/src/localizations/localizations_ko.dart b/forui/lib/src/localizations/localizations_ko.dart index 1c2bf8b8e..17189f89b 100644 --- a/forui/lib/src/localizations/localizations_ko.dart +++ b/forui/lib/src/localizations/localizations_ko.dart @@ -47,4 +47,7 @@ class FLocalizationsKo extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => '대화상자'; } diff --git a/forui/lib/src/localizations/localizations_ky.dart b/forui/lib/src/localizations/localizations_ky.dart index a53a8d6d1..7626f7c70 100644 --- a/forui/lib/src/localizations/localizations_ky.dart +++ b/forui/lib/src/localizations/localizations_ky.dart @@ -47,4 +47,7 @@ class FLocalizationsKy extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'Диалог'; } diff --git a/forui/lib/src/localizations/localizations_lo.dart b/forui/lib/src/localizations/localizations_lo.dart index 348cdb957..bb22d2b92 100644 --- a/forui/lib/src/localizations/localizations_lo.dart +++ b/forui/lib/src/localizations/localizations_lo.dart @@ -47,4 +47,7 @@ class FLocalizationsLo extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'ຂໍ້ຄວາມ'; } diff --git a/forui/lib/src/localizations/localizations_lt.dart b/forui/lib/src/localizations/localizations_lt.dart index 7a201741c..47aa8b68e 100644 --- a/forui/lib/src/localizations/localizations_lt.dart +++ b/forui/lib/src/localizations/localizations_lt.dart @@ -47,4 +47,7 @@ class FLocalizationsLt extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'Dialogo langas'; } diff --git a/forui/lib/src/localizations/localizations_lv.dart b/forui/lib/src/localizations/localizations_lv.dart index 32a60f261..ac757bc50 100644 --- a/forui/lib/src/localizations/localizations_lv.dart +++ b/forui/lib/src/localizations/localizations_lv.dart @@ -47,4 +47,7 @@ class FLocalizationsLv extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'Dialoglodziņš'; } diff --git a/forui/lib/src/localizations/localizations_mk.dart b/forui/lib/src/localizations/localizations_mk.dart index 362d9153c..8fc8cc6ed 100644 --- a/forui/lib/src/localizations/localizations_mk.dart +++ b/forui/lib/src/localizations/localizations_mk.dart @@ -47,4 +47,7 @@ class FLocalizationsMk extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'Дијалог'; } diff --git a/forui/lib/src/localizations/localizations_ml.dart b/forui/lib/src/localizations/localizations_ml.dart index a4820dd87..bc788a6e3 100644 --- a/forui/lib/src/localizations/localizations_ml.dart +++ b/forui/lib/src/localizations/localizations_ml.dart @@ -47,4 +47,7 @@ class FLocalizationsMl extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'ഡയലോഗ്'; } diff --git a/forui/lib/src/localizations/localizations_mn.dart b/forui/lib/src/localizations/localizations_mn.dart index 1a4076adc..4e59419a8 100644 --- a/forui/lib/src/localizations/localizations_mn.dart +++ b/forui/lib/src/localizations/localizations_mn.dart @@ -47,4 +47,7 @@ class FLocalizationsMn extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'Харилцах цонх'; } diff --git a/forui/lib/src/localizations/localizations_mr.dart b/forui/lib/src/localizations/localizations_mr.dart index 5ff8ad851..07d3709d9 100644 --- a/forui/lib/src/localizations/localizations_mr.dart +++ b/forui/lib/src/localizations/localizations_mr.dart @@ -47,4 +47,7 @@ class FLocalizationsMr extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'डायलॉग'; } diff --git a/forui/lib/src/localizations/localizations_ms.dart b/forui/lib/src/localizations/localizations_ms.dart index 1a7b92728..b8004dc82 100644 --- a/forui/lib/src/localizations/localizations_ms.dart +++ b/forui/lib/src/localizations/localizations_ms.dart @@ -47,4 +47,7 @@ class FLocalizationsMs extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'Dialog'; } diff --git a/forui/lib/src/localizations/localizations_my.dart b/forui/lib/src/localizations/localizations_my.dart index 14788ecae..c152bf823 100644 --- a/forui/lib/src/localizations/localizations_my.dart +++ b/forui/lib/src/localizations/localizations_my.dart @@ -47,4 +47,7 @@ class FLocalizationsMy extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'ဒိုင်ယာလော့'; } diff --git a/forui/lib/src/localizations/localizations_nb.dart b/forui/lib/src/localizations/localizations_nb.dart index 0f362c869..22b721deb 100644 --- a/forui/lib/src/localizations/localizations_nb.dart +++ b/forui/lib/src/localizations/localizations_nb.dart @@ -47,4 +47,7 @@ class FLocalizationsNb extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'Dialogboks'; } diff --git a/forui/lib/src/localizations/localizations_ne.dart b/forui/lib/src/localizations/localizations_ne.dart index 45496ac7c..3112d7312 100644 --- a/forui/lib/src/localizations/localizations_ne.dart +++ b/forui/lib/src/localizations/localizations_ne.dart @@ -47,4 +47,7 @@ class FLocalizationsNe extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'संवाद'; } diff --git a/forui/lib/src/localizations/localizations_nl.dart b/forui/lib/src/localizations/localizations_nl.dart index 7d370088a..0df6bddba 100644 --- a/forui/lib/src/localizations/localizations_nl.dart +++ b/forui/lib/src/localizations/localizations_nl.dart @@ -47,4 +47,7 @@ class FLocalizationsNl extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'Dialoogvenster'; } diff --git a/forui/lib/src/localizations/localizations_no.dart b/forui/lib/src/localizations/localizations_no.dart index 7fe2a4920..266f6acc7 100644 --- a/forui/lib/src/localizations/localizations_no.dart +++ b/forui/lib/src/localizations/localizations_no.dart @@ -47,4 +47,7 @@ class FLocalizationsNo extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'Dialogboks'; } diff --git a/forui/lib/src/localizations/localizations_or.dart b/forui/lib/src/localizations/localizations_or.dart index 8af75fe39..cf703b6e2 100644 --- a/forui/lib/src/localizations/localizations_or.dart +++ b/forui/lib/src/localizations/localizations_or.dart @@ -47,4 +47,7 @@ class FLocalizationsOr extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'ଡାୟଲଗ୍'; } diff --git a/forui/lib/src/localizations/localizations_pa.dart b/forui/lib/src/localizations/localizations_pa.dart index 09ff361ce..bdc0d7e5c 100644 --- a/forui/lib/src/localizations/localizations_pa.dart +++ b/forui/lib/src/localizations/localizations_pa.dart @@ -47,4 +47,7 @@ class FLocalizationsPa extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'ਵਿੰਡੋ'; } diff --git a/forui/lib/src/localizations/localizations_pl.dart b/forui/lib/src/localizations/localizations_pl.dart index 4ada2665a..c387ab7cd 100644 --- a/forui/lib/src/localizations/localizations_pl.dart +++ b/forui/lib/src/localizations/localizations_pl.dart @@ -47,4 +47,7 @@ class FLocalizationsPl extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'Okno dialogowe'; } diff --git a/forui/lib/src/localizations/localizations_ps.dart b/forui/lib/src/localizations/localizations_ps.dart index b96a01939..f4456edd4 100644 --- a/forui/lib/src/localizations/localizations_ps.dart +++ b/forui/lib/src/localizations/localizations_ps.dart @@ -47,4 +47,7 @@ class FLocalizationsPs extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'خبرې اترې'; } diff --git a/forui/lib/src/localizations/localizations_pt.dart b/forui/lib/src/localizations/localizations_pt.dart index 0c5100358..e61975d3d 100644 --- a/forui/lib/src/localizations/localizations_pt.dart +++ b/forui/lib/src/localizations/localizations_pt.dart @@ -47,9 +47,15 @@ class FLocalizationsPt extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'Caixa de diálogo'; } /// The translations for Portuguese, as used in Portugal (`pt_PT`). class FLocalizationsPtPt extends FLocalizationsPt { - FLocalizationsPtPt() : super('pt_PT'); + FLocalizationsPtPt(): super('pt_PT'); + + @override + String get dialogLabel => 'Caixa de diálogo'; } diff --git a/forui/lib/src/localizations/localizations_ro.dart b/forui/lib/src/localizations/localizations_ro.dart index ed9bac50b..0c751722c 100644 --- a/forui/lib/src/localizations/localizations_ro.dart +++ b/forui/lib/src/localizations/localizations_ro.dart @@ -47,4 +47,7 @@ class FLocalizationsRo extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'Casetă de dialog'; } diff --git a/forui/lib/src/localizations/localizations_ru.dart b/forui/lib/src/localizations/localizations_ru.dart index 1a3cf4a04..cf65500e8 100644 --- a/forui/lib/src/localizations/localizations_ru.dart +++ b/forui/lib/src/localizations/localizations_ru.dart @@ -47,4 +47,7 @@ class FLocalizationsRu extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'Диалоговое окно'; } diff --git a/forui/lib/src/localizations/localizations_si.dart b/forui/lib/src/localizations/localizations_si.dart index 7b76b9d32..ed705d34a 100644 --- a/forui/lib/src/localizations/localizations_si.dart +++ b/forui/lib/src/localizations/localizations_si.dart @@ -47,4 +47,7 @@ class FLocalizationsSi extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'සංවාදය'; } diff --git a/forui/lib/src/localizations/localizations_sk.dart b/forui/lib/src/localizations/localizations_sk.dart index f2f1f06cc..de66737bf 100644 --- a/forui/lib/src/localizations/localizations_sk.dart +++ b/forui/lib/src/localizations/localizations_sk.dart @@ -47,4 +47,7 @@ class FLocalizationsSk extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'Dialógové okno'; } diff --git a/forui/lib/src/localizations/localizations_sl.dart b/forui/lib/src/localizations/localizations_sl.dart index d2289fea8..f1ff399a0 100644 --- a/forui/lib/src/localizations/localizations_sl.dart +++ b/forui/lib/src/localizations/localizations_sl.dart @@ -47,4 +47,7 @@ class FLocalizationsSl extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'Pogovorno okno'; } diff --git a/forui/lib/src/localizations/localizations_sq.dart b/forui/lib/src/localizations/localizations_sq.dart index d3cc35084..986b49ecf 100644 --- a/forui/lib/src/localizations/localizations_sq.dart +++ b/forui/lib/src/localizations/localizations_sq.dart @@ -47,4 +47,7 @@ class FLocalizationsSq extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'Dialogu'; } diff --git a/forui/lib/src/localizations/localizations_sr.dart b/forui/lib/src/localizations/localizations_sr.dart index 0e7c6947f..9a32890ec 100644 --- a/forui/lib/src/localizations/localizations_sr.dart +++ b/forui/lib/src/localizations/localizations_sr.dart @@ -47,9 +47,15 @@ class FLocalizationsSr extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'Дијалог'; } /// The translations for Serbian, using the Latin script (`sr_Latn`). class FLocalizationsSrLatn extends FLocalizationsSr { - FLocalizationsSrLatn() : super('sr_Latn'); + FLocalizationsSrLatn(): super('sr_Latn'); + + @override + String get dialogLabel => 'Dijalog'; } diff --git a/forui/lib/src/localizations/localizations_sv.dart b/forui/lib/src/localizations/localizations_sv.dart index b3b2b8b20..1598e424b 100644 --- a/forui/lib/src/localizations/localizations_sv.dart +++ b/forui/lib/src/localizations/localizations_sv.dart @@ -47,4 +47,7 @@ class FLocalizationsSv extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'Dialogruta'; } diff --git a/forui/lib/src/localizations/localizations_sw.dart b/forui/lib/src/localizations/localizations_sw.dart index 55c2c3fe3..7954e8a91 100644 --- a/forui/lib/src/localizations/localizations_sw.dart +++ b/forui/lib/src/localizations/localizations_sw.dart @@ -47,4 +47,7 @@ class FLocalizationsSw extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'Kidirisha'; } diff --git a/forui/lib/src/localizations/localizations_ta.dart b/forui/lib/src/localizations/localizations_ta.dart index 015838537..8bbf465b5 100644 --- a/forui/lib/src/localizations/localizations_ta.dart +++ b/forui/lib/src/localizations/localizations_ta.dart @@ -47,4 +47,7 @@ class FLocalizationsTa extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'உரையாடல்'; } diff --git a/forui/lib/src/localizations/localizations_te.dart b/forui/lib/src/localizations/localizations_te.dart index 0ea2691a3..130312c52 100644 --- a/forui/lib/src/localizations/localizations_te.dart +++ b/forui/lib/src/localizations/localizations_te.dart @@ -47,4 +47,7 @@ class FLocalizationsTe extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'డైలాగ్'; } diff --git a/forui/lib/src/localizations/localizations_th.dart b/forui/lib/src/localizations/localizations_th.dart index b96cb97c1..2a29b194b 100644 --- a/forui/lib/src/localizations/localizations_th.dart +++ b/forui/lib/src/localizations/localizations_th.dart @@ -47,4 +47,7 @@ class FLocalizationsTh extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'กล่องโต้ตอบ'; } diff --git a/forui/lib/src/localizations/localizations_tl.dart b/forui/lib/src/localizations/localizations_tl.dart index 5be76e858..fc4b811ba 100644 --- a/forui/lib/src/localizations/localizations_tl.dart +++ b/forui/lib/src/localizations/localizations_tl.dart @@ -47,4 +47,7 @@ class FLocalizationsTl extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'Dialog'; } diff --git a/forui/lib/src/localizations/localizations_tr.dart b/forui/lib/src/localizations/localizations_tr.dart index 2851243cb..cdb6c6095 100644 --- a/forui/lib/src/localizations/localizations_tr.dart +++ b/forui/lib/src/localizations/localizations_tr.dart @@ -47,4 +47,7 @@ class FLocalizationsTr extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'İletişim kutusu'; } diff --git a/forui/lib/src/localizations/localizations_uk.dart b/forui/lib/src/localizations/localizations_uk.dart index 037e2faf0..65525a65f 100644 --- a/forui/lib/src/localizations/localizations_uk.dart +++ b/forui/lib/src/localizations/localizations_uk.dart @@ -47,4 +47,7 @@ class FLocalizationsUk extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'Вікно'; } diff --git a/forui/lib/src/localizations/localizations_ur.dart b/forui/lib/src/localizations/localizations_ur.dart index 2f20c5dee..1b2460f10 100644 --- a/forui/lib/src/localizations/localizations_ur.dart +++ b/forui/lib/src/localizations/localizations_ur.dart @@ -47,4 +47,7 @@ class FLocalizationsUr extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'ڈائلاگ'; } diff --git a/forui/lib/src/localizations/localizations_uz.dart b/forui/lib/src/localizations/localizations_uz.dart index 5c3a253d4..4c411f57b 100644 --- a/forui/lib/src/localizations/localizations_uz.dart +++ b/forui/lib/src/localizations/localizations_uz.dart @@ -47,4 +47,7 @@ class FLocalizationsUz extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'Muloqot oynasi'; } diff --git a/forui/lib/src/localizations/localizations_vi.dart b/forui/lib/src/localizations/localizations_vi.dart index 7666cf668..58d001f8d 100644 --- a/forui/lib/src/localizations/localizations_vi.dart +++ b/forui/lib/src/localizations/localizations_vi.dart @@ -47,4 +47,7 @@ class FLocalizationsVi extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'Hộp thoại'; } diff --git a/forui/lib/src/localizations/localizations_zh.dart b/forui/lib/src/localizations/localizations_zh.dart index 28a1fead5..35186c86d 100644 --- a/forui/lib/src/localizations/localizations_zh.dart +++ b/forui/lib/src/localizations/localizations_zh.dart @@ -47,14 +47,23 @@ class FLocalizationsZh extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => '对话框'; } /// The translations for Chinese, as used in Hong Kong (`zh_HK`). class FLocalizationsZhHk extends FLocalizationsZh { - FLocalizationsZhHk() : super('zh_HK'); + FLocalizationsZhHk(): super('zh_HK'); + + @override + String get dialogLabel => '對話方塊'; } /// The translations for Chinese, as used in Taiwan (`zh_TW`). class FLocalizationsZhTw extends FLocalizationsZh { - FLocalizationsZhTw() : super('zh_TW'); + FLocalizationsZhTw(): super('zh_TW'); + + @override + String get dialogLabel => '對話方塊'; } diff --git a/forui/lib/src/localizations/localizations_zu.dart b/forui/lib/src/localizations/localizations_zu.dart index 9cbeec7a6..9c89b6627 100644 --- a/forui/lib/src/localizations/localizations_zu.dart +++ b/forui/lib/src/localizations/localizations_zu.dart @@ -47,4 +47,7 @@ class FLocalizationsZu extends FLocalizations { return '$dateString'; } + + @override + String get dialogLabel => 'Ingxoxo'; } diff --git a/forui/lib/src/widgets/sheet/modal_sheet.dart b/forui/lib/src/widgets/sheet/modal_sheet.dart new file mode 100644 index 000000000..6bc8eadee --- /dev/null +++ b/forui/lib/src/widgets/sheet/modal_sheet.dart @@ -0,0 +1,94 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; +import 'package:forui/forui.dart'; +import 'package:forui/src/widgets/sheet/sheet.dart'; +import 'package:forui/src/widgets/sheet/shifted_sheet.dart'; + +const double _defaultScrollControlDisabledMaxHeightRatio = 9.0 / 16.0; + +class _ModalSheet extends StatefulWidget { + final PopupRoute route; // TODO: Change route to more specific. + final Layout side; + final FSheetStyle style; + final double? mainAxisMaxRatio; + final BoxConstraints constraints; + final bool draggable; + + const _ModalSheet({ + required this.route, + required this.side, + required this.style, + required this.mainAxisMaxRatio, + required this.constraints, + required this.draggable, + super.key, + }); + + @override + _ModalSheetState createState() => _ModalSheetState(); + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(DiagnosticsProperty('route', route)) + ..add(EnumProperty('side', side)) + ..add(DiagnosticsProperty('style', style)) + ..add(DoubleProperty('mainAxisMaxRatio', mainAxisMaxRatio)) + ..add(DiagnosticsProperty('constraints', constraints)) + ..add(FlagProperty('draggable', value: draggable, ifTrue: 'draggable')); + } +} + +class _ModalSheetState extends State<_ModalSheet> { + static const _cubic = Cubic(0.0, 0.0, 0.2, 1.0); + + ParametricCurve _curve = _cubic; + + EdgeInsets _getNewClipDetails(Size topLayerSize) => EdgeInsets.fromLTRB(0, 0, 0, topLayerSize.height); + + @override + Widget build(BuildContext context) { + assert(debugCheckHasMediaQuery(context), ''); + + return AnimatedBuilder( + animation: widget.route.animation!, + builder: (context, child) => Semantics( + scopesRoute: true, + namesRoute: true, + label: switch (defaultTargetPlatform) { + TargetPlatform.iOS || TargetPlatform.macOS => null, + _ => FLocalizations.of(context).dialogLabel, + }, + explicitChildNodes: true, + child: ClipRect( + child: ShiftedSheet( + side: widget.side, + onChange: (size) => widget.route._didChangeBarrierSemanticsClip(_getNewClipDetails(size)), + value: _curve.transform(widget.route.animation!.value), + mainAxisMaxRatio: widget.mainAxisMaxRatio, + child: child, + ), + ), + ), + child: Sheet( + controller: widget.route._animationController, + layout: widget.side, + style: widget.style, + constraints: widget.constraints, + draggable: widget.draggable, + builder: widget.route.builder, + // Allow the bottom sheet to track the user's finger accurately. + onDragStart: (details) => _curve = Curves.linear, + // Allow the sheet to animate smoothly from its current position. + onDragEnd: (details, {required closing}) => _curve = Split(widget.route.animation!.value, endCurve: _cubic), + onClosing: () { + if (widget.route.isCurrent) { + Navigator.pop(context); + } + }, + ), + ); + } +} diff --git a/forui/lib/src/widgets/sheet/sheet.dart b/forui/lib/src/widgets/sheet/sheet.dart index 4aeb3fe13..e362832c3 100644 --- a/forui/lib/src/widgets/sheet/sheet.dart +++ b/forui/lib/src/widgets/sheet/sheet.dart @@ -24,6 +24,8 @@ class Sheet extends StatefulWidget { /// True if the sheet can be dragged up and down/left and right, and dismissed by swiping in the opposite direction. /// + /// Defaults to true. + /// /// If this is true, the [controller] must not be null. final bool draggable; @@ -48,28 +50,17 @@ class Sheet extends StatefulWidget { final VoidCallback onClosing; const Sheet({ - required this.style, - required this.layout, - required this.builder, - this.controller, - this.constraints = const BoxConstraints(), - this.onClosing = _onClosing, - super.key, - }) : draggable = false, - onDragStart = null, - onDragEnd = null; - - const Sheet.draggable({ - required AnimationController this.controller, + required this.controller, required this.style, required this.layout, required this.builder, this.constraints = const BoxConstraints(), + this.draggable = true, this.onDragStart, this.onDragEnd, this.onClosing = _onClosing, super.key, - }) : draggable = true; + }): assert(!draggable || controller != null, 'Draggable sheets must have a controller.'); @override State createState() => _SheetState(); diff --git a/forui/lib/src/widgets/sheet/shifted_sheet.dart b/forui/lib/src/widgets/sheet/shifted_sheet.dart index 5985b6be2..628e8551c 100644 --- a/forui/lib/src/widgets/sheet/shifted_sheet.dart +++ b/forui/lib/src/widgets/sheet/shifted_sheet.dart @@ -1,19 +1,25 @@ +import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter/rendering.dart'; import 'package:forui/src/foundation/rendering.dart'; import 'package:meta/meta.dart'; +@internal +typedef SizeChangeCallback = void Function(Size size); + /// This is based on Material's _BottomSheetLayoutWithSizeListener. @internal class ShiftedSheet extends SingleChildRenderObjectWidget { final Layout side; final double value; - final double mainAxisMaxRatio; + final double? mainAxisMaxRatio; + final SizeChangeCallback onChange; const ShiftedSheet({ required this.side, required this.value, required this.mainAxisMaxRatio, + required this.onChange, required super.child, super.key, }); @@ -23,6 +29,7 @@ class ShiftedSheet extends SingleChildRenderObjectWidget { side: side, value: value, mainAxisMaxRatio: mainAxisMaxRatio, + onChange: onChange, ); @override @@ -31,7 +38,8 @@ class ShiftedSheet extends SingleChildRenderObjectWidget { renderObject ..side = side ..value = value - ..mainAxisRatio = mainAxisMaxRatio; + ..mainAxisMaxRatio = mainAxisMaxRatio + ..onChange = onChange; } @override @@ -40,7 +48,8 @@ class ShiftedSheet extends SingleChildRenderObjectWidget { properties ..add(EnumProperty('side', side)) ..add(DoubleProperty('value', value)) - ..add(DoubleProperty('dimensionRatio', mainAxisMaxRatio)); + ..add(DoubleProperty('mainAxisMaxRatio', mainAxisMaxRatio)) + ..add(ObjectFlagProperty.has('onChange', onChange)); } } @@ -48,14 +57,18 @@ class _ShiftedSheet extends RenderShiftedBox { Layout _side; double _value; double? _mainAxisMaxRatio; + SizeChangeCallback _onChange; + Size _previous = Size.zero; _ShiftedSheet({ required Layout side, required double value, - required double mainAxisMaxRatio, + required double? mainAxisMaxRatio, + required SizeChangeCallback onChange, }) : _side = side, _value = value, _mainAxisMaxRatio = mainAxisMaxRatio, + _onChange = onChange, super(null); @override @@ -70,6 +83,11 @@ class _ShiftedSheet extends RenderShiftedBox { final childSize = childConstraints.isTight ? childConstraints.smallest : child.size; child.data.offset = positionChild(size, childSize); + + if (_previous != childSize) { + _previous = childSize; + _onChange.call(_previous); + } } } @@ -154,21 +172,31 @@ class _ShiftedSheet extends RenderShiftedBox { } } - double? get mainAxisRatio => _mainAxisMaxRatio; + double? get mainAxisMaxRatio => _mainAxisMaxRatio; - set mainAxisRatio(double? value) { + set mainAxisMaxRatio(double? value) { if (_mainAxisMaxRatio != value) { _mainAxisMaxRatio = value; markNeedsLayout(); } } + SizeChangeCallback get onChange => _onChange; + + set onChange(SizeChangeCallback value) { + if (_onChange != value) { + _onChange = value; + markNeedsLayout(); + } + } + @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); properties ..add(EnumProperty('side', side)) ..add(DoubleProperty('value', value)) - ..add(DoubleProperty('mainAxisRatio', mainAxisRatio)); + ..add(DoubleProperty('mainAxisRatio', mainAxisMaxRatio)) + ..add(ObjectFlagProperty.has('onChange', onChange)); } } diff --git a/forui/tool/add_arb_value.dart b/forui/tool/add_arb_value.dart new file mode 100644 index 000000000..41456e8e0 --- /dev/null +++ b/forui/tool/add_arb_value.dart @@ -0,0 +1,27 @@ +// ignore_for_file: avoid_dynamic_calls + +import 'dart:convert'; +import 'dart:io'; + +final pattern = RegExp(r'material_([\w_]+)\.arb'); + +// Change this to add other keys. +const key = 'dialogLabel'; + +void main() { + // I usually just download all Material localization files into the .temp folder. + for (final source in Directory('.temp').listSync().whereType()) { + final material = json.decode(source.readAsStringSync()); + if (!material.containsKey(key)) { + continue; + } + + final locale = pattern.firstMatch(source.path)?.group(1); + final target = File('lib/l10n/f_$locale.arb'); + + final forui = json.decode(target.readAsStringSync()); + forui[key] = material[key]; + + target.writeAsStringSync(const JsonEncoder.withIndent(' ').convert(forui)); + } +} \ No newline at end of file From 3698044acccc23999afd175943b4616e37d374ea Mon Sep 17 00:00:00 2001 From: Matthias Ngeo Date: Wed, 20 Nov 2024 23:21:48 +0800 Subject: [PATCH 06/29] Almost there --- forui/example/lib/sheet.dart | 401 ------------------ forui/lib/l10n/f_af.arb | 5 +- forui/lib/l10n/f_am.arb | 5 +- forui/lib/l10n/f_ar.arb | 5 +- forui/lib/l10n/f_as.arb | 5 +- forui/lib/l10n/f_az.arb | 5 +- forui/lib/l10n/f_be.arb | 5 +- forui/lib/l10n/f_bg.arb | 5 +- forui/lib/l10n/f_bn.arb | 5 +- forui/lib/l10n/f_bs.arb | 5 +- forui/lib/l10n/f_ca.arb | 5 +- forui/lib/l10n/f_cs.arb | 5 +- forui/lib/l10n/f_cy.arb | 5 +- forui/lib/l10n/f_da.arb | 5 +- forui/lib/l10n/f_de.arb | 5 +- forui/lib/l10n/f_el.arb | 5 +- forui/lib/l10n/f_en.arb | 25 +- forui/lib/l10n/f_en_AU.arb | 5 +- forui/lib/l10n/f_en_CA.arb | 5 +- forui/lib/l10n/f_en_GB.arb | 5 +- forui/lib/l10n/f_en_IE.arb | 5 +- forui/lib/l10n/f_en_IN.arb | 5 +- forui/lib/l10n/f_en_NZ.arb | 5 +- forui/lib/l10n/f_en_SG.arb | 5 +- forui/lib/l10n/f_en_ZA.arb | 5 +- forui/lib/l10n/f_es.arb | 5 +- forui/lib/l10n/f_es_419.arb | 5 +- forui/lib/l10n/f_es_AR.arb | 5 +- forui/lib/l10n/f_es_BO.arb | 5 +- forui/lib/l10n/f_es_CL.arb | 5 +- forui/lib/l10n/f_es_CO.arb | 5 +- forui/lib/l10n/f_es_CR.arb | 5 +- forui/lib/l10n/f_es_DO.arb | 5 +- forui/lib/l10n/f_es_EC.arb | 5 +- forui/lib/l10n/f_es_GT.arb | 5 +- forui/lib/l10n/f_es_HN.arb | 5 +- forui/lib/l10n/f_es_MX.arb | 5 +- forui/lib/l10n/f_es_NI.arb | 5 +- forui/lib/l10n/f_es_PA.arb | 5 +- forui/lib/l10n/f_es_PE.arb | 5 +- forui/lib/l10n/f_es_PR.arb | 5 +- forui/lib/l10n/f_es_PY.arb | 5 +- forui/lib/l10n/f_es_SV.arb | 5 +- forui/lib/l10n/f_es_US.arb | 5 +- forui/lib/l10n/f_es_UY.arb | 5 +- forui/lib/l10n/f_es_VE.arb | 5 +- forui/lib/l10n/f_et.arb | 5 +- forui/lib/l10n/f_eu.arb | 5 +- forui/lib/l10n/f_fa.arb | 5 +- forui/lib/l10n/f_fi.arb | 5 +- forui/lib/l10n/f_fil.arb | 5 +- forui/lib/l10n/f_fr.arb | 5 +- forui/lib/l10n/f_fr_CA.arb | 5 +- forui/lib/l10n/f_gl.arb | 5 +- forui/lib/l10n/f_gsw.arb | 5 +- forui/lib/l10n/f_gu.arb | 5 +- forui/lib/l10n/f_he.arb | 5 +- forui/lib/l10n/f_hi.arb | 5 +- forui/lib/l10n/f_hr.arb | 5 +- forui/lib/l10n/f_hu.arb | 5 +- forui/lib/l10n/f_hy.arb | 5 +- forui/lib/l10n/f_id.arb | 5 +- forui/lib/l10n/f_is.arb | 5 +- forui/lib/l10n/f_it.arb | 5 +- forui/lib/l10n/f_ja.arb | 5 +- forui/lib/l10n/f_ka.arb | 5 +- forui/lib/l10n/f_kk.arb | 5 +- forui/lib/l10n/f_km.arb | 5 +- forui/lib/l10n/f_kn.arb | 5 +- forui/lib/l10n/f_ko.arb | 5 +- forui/lib/l10n/f_ky.arb | 5 +- forui/lib/l10n/f_lo.arb | 5 +- forui/lib/l10n/f_lt.arb | 5 +- forui/lib/l10n/f_lv.arb | 5 +- forui/lib/l10n/f_mk.arb | 5 +- forui/lib/l10n/f_ml.arb | 5 +- forui/lib/l10n/f_mn.arb | 5 +- forui/lib/l10n/f_mr.arb | 5 +- forui/lib/l10n/f_ms.arb | 5 +- forui/lib/l10n/f_my.arb | 5 +- forui/lib/l10n/f_nb.arb | 5 +- forui/lib/l10n/f_ne.arb | 5 +- forui/lib/l10n/f_nl.arb | 5 +- forui/lib/l10n/f_no.arb | 5 +- forui/lib/l10n/f_or.arb | 5 +- forui/lib/l10n/f_pa.arb | 5 +- forui/lib/l10n/f_pl.arb | 5 +- forui/lib/l10n/f_ps.arb | 5 +- forui/lib/l10n/f_pt.arb | 5 +- forui/lib/l10n/f_pt_PT.arb | 5 +- forui/lib/l10n/f_ro.arb | 5 +- forui/lib/l10n/f_ru.arb | 5 +- forui/lib/l10n/f_si.arb | 5 +- forui/lib/l10n/f_sk.arb | 5 +- forui/lib/l10n/f_sl.arb | 5 +- forui/lib/l10n/f_sq.arb | 5 +- forui/lib/l10n/f_sr.arb | 5 +- forui/lib/l10n/f_sr_Latn.arb | 5 +- forui/lib/l10n/f_sv.arb | 5 +- forui/lib/l10n/f_sw.arb | 5 +- forui/lib/l10n/f_ta.arb | 5 +- forui/lib/l10n/f_te.arb | 5 +- forui/lib/l10n/f_th.arb | 5 +- forui/lib/l10n/f_tl.arb | 5 +- forui/lib/l10n/f_tr.arb | 5 +- forui/lib/l10n/f_uk.arb | 5 +- forui/lib/l10n/f_ur.arb | 5 +- forui/lib/l10n/f_uz.arb | 5 +- forui/lib/l10n/f_vi.arb | 5 +- forui/lib/l10n/f_zh.arb | 5 +- forui/lib/l10n/f_zh_HK.arb | 5 +- forui/lib/l10n/f_zh_TW.arb | 5 +- forui/lib/l10n/f_zu.arb | 5 +- forui/lib/src/localizations/localization.dart | 9 + .../lib/src/localizations/localizations.dart | 21 +- .../src/localizations/localizations_af.dart | 11 + .../src/localizations/localizations_am.dart | 11 + .../src/localizations/localizations_ar.dart | 11 + .../src/localizations/localizations_as.dart | 11 + .../src/localizations/localizations_az.dart | 11 + .../src/localizations/localizations_be.dart | 11 + .../src/localizations/localizations_bg.dart | 11 + .../src/localizations/localizations_bn.dart | 11 + .../src/localizations/localizations_bs.dart | 11 + .../src/localizations/localizations_ca.dart | 11 + .../src/localizations/localizations_cs.dart | 11 + .../src/localizations/localizations_cy.dart | 11 + .../src/localizations/localizations_da.dart | 11 + .../src/localizations/localizations_de.dart | 11 + .../src/localizations/localizations_el.dart | 11 + .../src/localizations/localizations_en.dart | 99 +++++ .../src/localizations/localizations_es.dart | 231 ++++++++++ .../src/localizations/localizations_et.dart | 11 + .../src/localizations/localizations_eu.dart | 11 + .../src/localizations/localizations_fa.dart | 11 + .../src/localizations/localizations_fi.dart | 11 + .../src/localizations/localizations_fil.dart | 11 + .../src/localizations/localizations_fr.dart | 22 + .../src/localizations/localizations_gl.dart | 11 + .../src/localizations/localizations_gsw.dart | 11 + .../src/localizations/localizations_gu.dart | 11 + .../src/localizations/localizations_he.dart | 11 + .../src/localizations/localizations_hi.dart | 11 + .../src/localizations/localizations_hr.dart | 11 + .../src/localizations/localizations_hu.dart | 11 + .../src/localizations/localizations_hy.dart | 11 + .../src/localizations/localizations_id.dart | 11 + .../src/localizations/localizations_is.dart | 11 + .../src/localizations/localizations_it.dart | 11 + .../src/localizations/localizations_ja.dart | 11 + .../src/localizations/localizations_ka.dart | 11 + .../src/localizations/localizations_kk.dart | 11 + .../src/localizations/localizations_km.dart | 11 + .../src/localizations/localizations_kn.dart | 11 + .../src/localizations/localizations_ko.dart | 11 + .../src/localizations/localizations_ky.dart | 11 + .../src/localizations/localizations_lo.dart | 11 + .../src/localizations/localizations_lt.dart | 11 + .../src/localizations/localizations_lv.dart | 11 + .../src/localizations/localizations_mk.dart | 11 + .../src/localizations/localizations_ml.dart | 11 + .../src/localizations/localizations_mn.dart | 11 + .../src/localizations/localizations_mr.dart | 11 + .../src/localizations/localizations_ms.dart | 11 + .../src/localizations/localizations_my.dart | 11 + .../src/localizations/localizations_nb.dart | 11 + .../src/localizations/localizations_ne.dart | 11 + .../src/localizations/localizations_nl.dart | 11 + .../src/localizations/localizations_no.dart | 11 + .../src/localizations/localizations_or.dart | 11 + .../src/localizations/localizations_pa.dart | 11 + .../src/localizations/localizations_pl.dart | 11 + .../src/localizations/localizations_ps.dart | 11 + .../src/localizations/localizations_pt.dart | 22 + .../src/localizations/localizations_ro.dart | 11 + .../src/localizations/localizations_ru.dart | 11 + .../src/localizations/localizations_si.dart | 11 + .../src/localizations/localizations_sk.dart | 11 + .../src/localizations/localizations_sl.dart | 11 + .../src/localizations/localizations_sq.dart | 11 + .../src/localizations/localizations_sr.dart | 22 + .../src/localizations/localizations_sv.dart | 11 + .../src/localizations/localizations_sw.dart | 11 + .../src/localizations/localizations_ta.dart | 11 + .../src/localizations/localizations_te.dart | 11 + .../src/localizations/localizations_th.dart | 11 + .../src/localizations/localizations_tl.dart | 11 + .../src/localizations/localizations_tr.dart | 11 + .../src/localizations/localizations_uk.dart | 11 + .../src/localizations/localizations_ur.dart | 11 + .../src/localizations/localizations_uz.dart | 11 + .../src/localizations/localizations_vi.dart | 11 + .../src/localizations/localizations_zh.dart | 33 ++ .../src/localizations/localizations_zu.dart | 11 + forui/lib/src/theme/theme_data.dart | 10 + forui/lib/src/widgets/sheet/modal_sheet.dart | 282 +++++++++++- forui/lib/src/widgets/sheet/sheet.dart | 49 +-- .../lib/src/widgets/sheet/shifted_sheet.dart | 2 + forui/lib/widgets/sheet.dart | 6 +- forui/tool/add_arb_value.dart | 6 +- 200 files changed, 2044 insertions(+), 554 deletions(-) delete mode 100644 forui/example/lib/sheet.dart diff --git a/forui/example/lib/sheet.dart b/forui/example/lib/sheet.dart deleted file mode 100644 index e6e41d846..000000000 --- a/forui/example/lib/sheet.dart +++ /dev/null @@ -1,401 +0,0 @@ -import 'package:flutter/gestures.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; -import 'package:flutter/widgets.dart'; - -const Duration _bottomSheetEnterDuration = Duration(milliseconds: 250); -const Duration _bottomSheetExitDuration = Duration(milliseconds: 200); -const Curve _modalBottomSheetCurve = decelerateEasing; -const double _minFlingVelocity = 700.0; -const double _closeProgressThreshold = 0.5; -const double _defaultScrollControlDisabledMaxHeightRatio = 9.0 / 16.0; - -class BottomSheet extends StatefulWidget { - /// Creates a bottom sheet. - /// - /// Typically, bottom sheets are created implicitly by - /// [ScaffoldState.showBottomSheet], for persistent bottom sheets, or by - /// [showModalBottomSheet], for modal bottom sheets. - const BottomSheet({ - super.key, - this.animationController, - this.enableDrag = true, - this.showDragHandle, - this.dragHandleColor, - this.dragHandleSize, - this.onDragStart, - this.onDragEnd, - this.backgroundColor, - this.shadowColor, - this.elevation, - this.shape, - this.clipBehavior, - this.constraints, - required this.onClosing, - required this.builder, - }) : assert(elevation == null || elevation >= 0.0); - - /// The animation controller that controls the bottom sheet's entrance and - /// exit animations. - /// - /// The BottomSheet widget will manipulate the position of this animation, it - /// is not just a passive observer. - final AnimationController? animationController; - - /// Called when the bottom sheet begins to close. - /// - /// A bottom sheet might be prevented from closing (e.g., by user - /// interaction) even after this callback is called. For this reason, this - /// callback might be call multiple times for a given bottom sheet. - final VoidCallback onClosing; - - /// A builder for the contents of the sheet. - /// - /// The bottom sheet will wrap the widget produced by this builder in a - /// [Material] widget. - final WidgetBuilder builder; - - /// If true, the bottom sheet can be dragged up and down and dismissed by - /// swiping downwards. - /// - /// If [showDragHandle] is true, this only applies to the content below the drag handle, - /// because the drag handle is always draggable. - /// - /// Default is true. - /// - /// If this is true, the [animationController] must not be null. - /// Use [BottomSheet.createAnimationController] to create one, or provide - /// another AnimationController. - final bool enableDrag; - - /// Specifies whether a drag handle is shown. - /// - /// The drag handle appears at the top of the bottom sheet. The default color is - /// [ColorScheme.onSurfaceVariant] with an opacity of 0.4 and can be customized - /// using [dragHandleColor]. The default size is `Size(32,4)` and can be customized - /// with [dragHandleSize]. - /// - /// If null, then the value of [BottomSheetThemeData.showDragHandle] is used. If - /// that is also null, defaults to false. - /// - /// If this is true, the [animationController] must not be null. - /// Use [BottomSheet.createAnimationController] to create one, or provide - /// another AnimationController. - final bool? showDragHandle; - - /// The bottom sheet drag handle's color. - /// - /// Defaults to [BottomSheetThemeData.dragHandleColor]. - /// If that is also null, defaults to [ColorScheme.onSurfaceVariant]. - final Color? dragHandleColor; - - /// Defaults to [BottomSheetThemeData.dragHandleSize]. - /// If that is also null, defaults to Size(32, 4). - final Size? dragHandleSize; - - /// Called when the user begins dragging the bottom sheet vertically, if - /// [enableDrag] is true. - /// - /// Would typically be used to change the bottom sheet animation curve so - /// that it tracks the user's finger accurately. - final BottomSheetDragStartHandler? onDragStart; - - /// Called when the user stops dragging the bottom sheet, if [enableDrag] - /// is true. - /// - /// Would typically be used to reset the bottom sheet animation curve, so - /// that it animates non-linearly. Called before [onClosing] if the bottom - /// sheet is closing. - final BottomSheetDragEndHandler? onDragEnd; - - /// The bottom sheet's background color. - /// - /// Defines the bottom sheet's [Material.color]. - /// - /// Defaults to null and falls back to [Material]'s default. - final Color? backgroundColor; - - /// The color of the shadow below the sheet. - /// - /// If this property is null, then [BottomSheetThemeData.shadowColor] of - /// [ThemeData.bottomSheetTheme] is used. If that is also null, the default value - /// is transparent. - /// - /// See also: - /// - /// * [elevation], which defines the size of the shadow below the sheet. - /// * [shape], which defines the shape of the sheet and its shadow. - final Color? shadowColor; - - /// The z-coordinate at which to place this material relative to its parent. - /// - /// This controls the size of the shadow below the material. - /// - /// Defaults to 0. The value is non-negative. - final double? elevation; - - /// The shape of the bottom sheet. - /// - /// Defines the bottom sheet's [Material.shape]. - /// - /// Defaults to null and falls back to [Material]'s default. - final ShapeBorder? shape; - - /// {@macro flutter.material.Material.clipBehavior} - /// - /// Defines the bottom sheet's [Material.clipBehavior]. - /// - /// Use this property to enable clipping of content when the bottom sheet has - /// a custom [shape] and the content can extend past this shape. For example, - /// a bottom sheet with rounded corners and an edge-to-edge [Image] at the - /// top. - /// - /// If this property is null then [BottomSheetThemeData.clipBehavior] of - /// [ThemeData.bottomSheetTheme] is used. If that's null then the behavior - /// will be [Clip.none]. - final Clip? clipBehavior; - - /// Defines minimum and maximum sizes for a [BottomSheet]. - /// - /// If null, then the ambient [ThemeData.bottomSheetTheme]'s - /// [BottomSheetThemeData.constraints] will be used. If that - /// is null and [ThemeData.useMaterial3] is true, then the bottom sheet - /// will have a max width of 640dp. If [ThemeData.useMaterial3] is false, then - /// the bottom sheet's size will be constrained by its parent - /// (usually a [Scaffold]). In this case, consider limiting the width by - /// setting smaller constraints for large screens. - /// - /// If constraints are specified (either in this property or in the - /// theme), the bottom sheet will be aligned to the bottom-center of - /// the available space. Otherwise, no alignment is applied. - final BoxConstraints? constraints; - - @override - State createState() => _BottomSheetState(); - - /// Creates an [AnimationController] suitable for a - /// [BottomSheet.animationController]. - /// - /// This API is available as a convenience for a Material compliant bottom sheet - /// animation. If alternative animation durations are required, a different - /// animation controller could be provided. - static AnimationController createAnimationController( - TickerProvider vsync, { - AnimationStyle? sheetAnimationStyle, - }) => - AnimationController( - duration: sheetAnimationStyle?.duration ?? _bottomSheetEnterDuration, - reverseDuration: sheetAnimationStyle?.reverseDuration ?? _bottomSheetExitDuration, - debugLabel: 'BottomSheet', - vsync: vsync, - ); -} - -class _BottomSheetState extends State { - final GlobalKey _childKey = GlobalKey(debugLabel: 'BottomSheet child'); - - double get _childHeight { - final RenderBox renderBox = _childKey.currentContext!.findRenderObject()! as RenderBox; - return renderBox.size.height; - } - - bool get _dismissUnderway => widget.animationController!.status == AnimationStatus.reverse; - - Set dragHandleMaterialState = {}; - - void _handleDragStart(DragStartDetails details) { - setState(() { - dragHandleMaterialState.add(MaterialState.dragged); - }); - widget.onDragStart?.call(details); - } - - void _handleDragUpdate(DragUpdateDetails details) { - assert( - (widget.enableDrag || (widget.showDragHandle ?? false)) && widget.animationController != null, - "'BottomSheet.animationController' cannot be null when 'BottomSheet.enableDrag' or 'BottomSheet.showDragHandle' is true. " - "Use 'BottomSheet.createAnimationController' to create one, or provide another AnimationController.", - ); - if (_dismissUnderway) { - return; - } - widget.animationController!.value -= details.primaryDelta! / _childHeight; - print(widget.animationController!.value); - } - - void _handleDragEnd(DragEndDetails details) { - assert( - (widget.enableDrag || (widget.showDragHandle ?? false)) && widget.animationController != null, - "'BottomSheet.animationController' cannot be null when 'BottomSheet.enableDrag' or 'BottomSheet.showDragHandle' is true. " - "Use 'BottomSheet.createAnimationController' to create one, or provide another AnimationController.", - ); - if (_dismissUnderway) { - return; - } - setState(() { - dragHandleMaterialState.remove(MaterialState.dragged); - }); - bool isClosing = false; - if (details.velocity.pixelsPerSecond.dy > _minFlingVelocity) { - final double flingVelocity = -details.velocity.pixelsPerSecond.dy / _childHeight; - if (widget.animationController!.value > 0.0) { - widget.animationController!.fling(velocity: flingVelocity); - } - if (flingVelocity < 0.0) { - isClosing = true; - } - } else if (widget.animationController!.value < _closeProgressThreshold) { - if (widget.animationController!.value > 0.0) { - widget.animationController!.fling(velocity: -1.0); - } - isClosing = true; - } else { - widget.animationController!.forward(); - } - - widget.onDragEnd?.call( - details, - isClosing: isClosing, - ); - - if (isClosing) { - widget.onClosing(); - } - } - - bool extentChanged(DraggableScrollableNotification notification) { - if (notification.extent == notification.minExtent && notification.shouldCloseOnMinExtent) { - widget.onClosing(); - } - return false; - } - - void _handleDragHandleHover(bool hovering) { - if (hovering != dragHandleMaterialState.contains(MaterialState.hovered)) { - setState(() { - if (hovering) { - dragHandleMaterialState.add(MaterialState.hovered); - } else { - dragHandleMaterialState.remove(MaterialState.hovered); - } - }); - } - } - - @override - Widget build(BuildContext context) { - final BottomSheetThemeData bottomSheetTheme = Theme.of(context).bottomSheetTheme; - final bool useMaterial3 = Theme.of(context).useMaterial3; - const BottomSheetThemeData defaults = BottomSheetThemeData(); - final BoxConstraints? constraints = widget.constraints ?? bottomSheetTheme.constraints ?? defaults.constraints; - final Color? color = widget.backgroundColor ?? bottomSheetTheme.backgroundColor ?? defaults.backgroundColor; - final Color? surfaceTintColor = bottomSheetTheme.surfaceTintColor ?? defaults.surfaceTintColor; - final Color? shadowColor = widget.shadowColor ?? bottomSheetTheme.shadowColor ?? defaults.shadowColor; - final double elevation = widget.elevation ?? bottomSheetTheme.elevation ?? defaults.elevation ?? 0; - final ShapeBorder? shape = widget.shape ?? bottomSheetTheme.shape ?? defaults.shape; - final Clip clipBehavior = widget.clipBehavior ?? bottomSheetTheme.clipBehavior ?? Clip.none; - final bool showDragHandle = - widget.showDragHandle ?? (widget.enableDrag && (bottomSheetTheme.showDragHandle ?? false)); - - Widget? dragHandle; - if (showDragHandle) { - // dragHandle = _DragHandle( - // onSemanticsTap: widget.onClosing, - // handleHover: _handleDragHandleHover, - // materialState: dragHandleMaterialState, - // dragHandleColor: widget.dragHandleColor, - // dragHandleSize: widget.dragHandleSize, - // ); - // Only add [_BottomSheetGestureDetector] to the drag handle when the rest of the - // bottom sheet is not draggable. If the whole bottom sheet is draggable, - // no need to add it. - if (!widget.enableDrag) { - // dragHandle = _BottomSheetGestureDetector( - // onVerticalDragStart: _handleDragStart, - // onVerticalDragUpdate: _handleDragUpdate, - // onVerticalDragEnd: _handleDragEnd, - // child: dragHandle, - // ); - } - } - - Widget bottomSheet = Material( - key: _childKey, - color: color, - elevation: elevation, - surfaceTintColor: surfaceTintColor, - shadowColor: shadowColor, - shape: shape, - clipBehavior: clipBehavior, - child: NotificationListener( - onNotification: extentChanged, - child: !showDragHandle - ? widget.builder(context) - : Stack( - alignment: Alignment.topCenter, - children: [ - dragHandle!, - Padding( - padding: const EdgeInsets.only(top: kMinInteractiveDimension), - child: widget.builder(context), - ), - ], - ), - ), - ); - - if (constraints != null) { - bottomSheet = Align( - alignment: Alignment.bottomCenter, - heightFactor: 1.0, - child: ConstrainedBox( - constraints: constraints, - child: bottomSheet, - ), - ); - } - - return !widget.enableDrag - ? bottomSheet - : _BottomSheetGestureDetector( - onVerticalDragStart: _handleDragStart, - onVerticalDragUpdate: _handleDragUpdate, - onVerticalDragEnd: _handleDragEnd, - child: bottomSheet, - ); - } -} - -class _BottomSheetGestureDetector extends StatelessWidget { - const _BottomSheetGestureDetector({ - required this.child, - required this.onVerticalDragStart, - required this.onVerticalDragUpdate, - required this.onVerticalDragEnd, - }); - - final Widget child; - final GestureDragStartCallback onVerticalDragStart; - final GestureDragUpdateCallback onVerticalDragUpdate; - final GestureDragEndCallback onVerticalDragEnd; - - @override - Widget build(BuildContext context) => RawGestureDetector( - excludeFromSemantics: true, - gestures: >{ - VerticalDragGestureRecognizer: GestureRecognizerFactoryWithHandlers( - () => VerticalDragGestureRecognizer(debugOwner: this), - (instance) { - instance - ..onStart = onVerticalDragStart - ..onUpdate = onVerticalDragUpdate - ..onEnd = onVerticalDragEnd - ..onlyAcceptDragOnThreshold = true; - }, - ), - }, - child: child, - ); -} - - diff --git a/forui/lib/l10n/f_af.arb b/forui/lib/l10n/f_af.arb index 3b920a0f7..f4f7030e8 100644 --- a/forui/lib/l10n/f_af.arb +++ b/forui/lib/l10n/f_af.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Dialoog" + "dialogLabel": "Dialoog", + "sheetLabel": "blad", + "barrierOnTapHint": "Maak $modalRouteContentName toe", + "barrierLabel": "Skerm" } \ No newline at end of file diff --git a/forui/lib/l10n/f_am.arb b/forui/lib/l10n/f_am.arb index d26becc70..447edd405 100644 --- a/forui/lib/l10n/f_am.arb +++ b/forui/lib/l10n/f_am.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "መገናኛ" + "dialogLabel": "መገናኛ", + "sheetLabel": "ሉህ", + "barrierOnTapHint": "$modalRouteContentNameን ዝጋ", + "barrierLabel": "ገዳቢ" } \ No newline at end of file diff --git a/forui/lib/l10n/f_ar.arb b/forui/lib/l10n/f_ar.arb index 8e7e3d86e..f76ebe7b4 100644 --- a/forui/lib/l10n/f_ar.arb +++ b/forui/lib/l10n/f_ar.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "مربع حوار" + "dialogLabel": "مربع حوار", + "sheetLabel": "بطاق ", + "barrierOnTapHint": "إغلاق \"$modalRouteContentName\"", + "barrierLabel": "تمويه" } \ No newline at end of file diff --git a/forui/lib/l10n/f_as.arb b/forui/lib/l10n/f_as.arb index 480896f2c..fe9b69537 100644 --- a/forui/lib/l10n/f_as.arb +++ b/forui/lib/l10n/f_as.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "ডায়ল'গ" + "dialogLabel": "ডায়ল'গ", + "sheetLabel": "শ্বীট", + "barrierOnTapHint": "$modalRouteContentName বন্ধ কৰক", + "barrierLabel": "স্ক্ৰিম" } \ No newline at end of file diff --git a/forui/lib/l10n/f_az.arb b/forui/lib/l10n/f_az.arb index c2a80c7be..2b5aa8052 100644 --- a/forui/lib/l10n/f_az.arb +++ b/forui/lib/l10n/f_az.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Dialoq" + "dialogLabel": "Dialoq", + "sheetLabel": "Vərəq", + "barrierOnTapHint": "Bağlayın: $modalRouteContentName", + "barrierLabel": "Kətan" } \ No newline at end of file diff --git a/forui/lib/l10n/f_be.arb b/forui/lib/l10n/f_be.arb index 8dd47f5c5..12477e0af 100644 --- a/forui/lib/l10n/f_be.arb +++ b/forui/lib/l10n/f_be.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Дыялогавае акно" + "dialogLabel": "Дыялогавае акно", + "sheetLabel": "аркуш", + "barrierOnTapHint": "Закрыць: $modalRouteContentName", + "barrierLabel": "Палатно" } \ No newline at end of file diff --git a/forui/lib/l10n/f_bg.arb b/forui/lib/l10n/f_bg.arb index a79fb7914..cacd38976 100644 --- a/forui/lib/l10n/f_bg.arb +++ b/forui/lib/l10n/f_bg.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Диалогов прозорец" + "dialogLabel": "Диалогов прозорец", + "sheetLabel": "лист", + "barrierOnTapHint": "Затваряне на $modalRouteContentName", + "barrierLabel": "Скрим" } \ No newline at end of file diff --git a/forui/lib/l10n/f_bn.arb b/forui/lib/l10n/f_bn.arb index f116c197e..89f4a4767 100644 --- a/forui/lib/l10n/f_bn.arb +++ b/forui/lib/l10n/f_bn.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "ডায়ালগ" + "dialogLabel": "ডায়ালগ", + "sheetLabel": "শীট", + "barrierOnTapHint": "$modalRouteContentName বন্ধ করুন", + "barrierLabel": "স্ক্রিম" } \ No newline at end of file diff --git a/forui/lib/l10n/f_bs.arb b/forui/lib/l10n/f_bs.arb index 101ec8c57..180c95998 100644 --- a/forui/lib/l10n/f_bs.arb +++ b/forui/lib/l10n/f_bs.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Dijaloški okvir" + "dialogLabel": "Dijaloški okvir", + "sheetLabel": "tabela", + "barrierOnTapHint": "Zatvori: $modalRouteContentName", + "barrierLabel": "Rubno" } \ No newline at end of file diff --git a/forui/lib/l10n/f_ca.arb b/forui/lib/l10n/f_ca.arb index edccf86f6..546f23d07 100644 --- a/forui/lib/l10n/f_ca.arb +++ b/forui/lib/l10n/f_ca.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Diàleg" + "dialogLabel": "Diàleg", + "sheetLabel": "Full", + "barrierOnTapHint": "Tanca $modalRouteContentName", + "barrierLabel": "Fons atenuat" } \ No newline at end of file diff --git a/forui/lib/l10n/f_cs.arb b/forui/lib/l10n/f_cs.arb index dc2daf550..bac81491f 100644 --- a/forui/lib/l10n/f_cs.arb +++ b/forui/lib/l10n/f_cs.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Dialogové okno" + "dialogLabel": "Dialogové okno", + "sheetLabel": "tabulka", + "barrierOnTapHint": "Zavřít $modalRouteContentName", + "barrierLabel": "Scrim" } \ No newline at end of file diff --git a/forui/lib/l10n/f_cy.arb b/forui/lib/l10n/f_cy.arb index 258673f4c..edc096f91 100644 --- a/forui/lib/l10n/f_cy.arb +++ b/forui/lib/l10n/f_cy.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Deialog" + "dialogLabel": "Deialog", + "sheetLabel": "Taflen", + "barrierOnTapHint": "Cau $modalRouteContentName", + "barrierLabel": "Scrim" } \ No newline at end of file diff --git a/forui/lib/l10n/f_da.arb b/forui/lib/l10n/f_da.arb index fff2252c6..40481e134 100644 --- a/forui/lib/l10n/f_da.arb +++ b/forui/lib/l10n/f_da.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Dialogboks" + "dialogLabel": "Dialogboks", + "sheetLabel": "Felt", + "barrierOnTapHint": "Luk $modalRouteContentName", + "barrierLabel": "Dæmpeskærm" } \ No newline at end of file diff --git a/forui/lib/l10n/f_de.arb b/forui/lib/l10n/f_de.arb index 6ee866ee2..f78b171c3 100644 --- a/forui/lib/l10n/f_de.arb +++ b/forui/lib/l10n/f_de.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Dialogfeld" + "dialogLabel": "Dialogfeld", + "sheetLabel": "Ansicht", + "barrierOnTapHint": "$modalRouteContentName schließen", + "barrierLabel": "Gitter" } \ No newline at end of file diff --git a/forui/lib/l10n/f_el.arb b/forui/lib/l10n/f_el.arb index 0ba9cd3a4..fca6c59be 100644 --- a/forui/lib/l10n/f_el.arb +++ b/forui/lib/l10n/f_el.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Παράθυρο διαλόγου" + "dialogLabel": "Παράθυρο διαλόγου", + "sheetLabel": "Φύλλο", + "barrierOnTapHint": "Κλείσιμο $modalRouteContentName", + "barrierLabel": "Επικάλυψη" } \ No newline at end of file diff --git a/forui/lib/l10n/f_en.arb b/forui/lib/l10n/f_en.arb index 0b1c97fca..3e3c7adb5 100644 --- a/forui/lib/l10n/f_en.arb +++ b/forui/lib/l10n/f_en.arb @@ -49,8 +49,29 @@ } } }, + "dialogLabel": "Dialog", "@dialogLabel": { - "description": "The audio announcement made when a Dialog is opened." - }, + "description": "The audio announcement made when a dialog is opened." + }, + + "sheetLabel": "Sheet", + "@dialogLabel": { + "description": "The sheet's label." + }, + + "barrierLabel": "Barrier", + "@barrierLabel": { + "description": "The label for the barrier rendered underneath the content of a bottom sheet (used as the 'modalRouteContentName' of the 'barrierOnTapHint' message)." + }, + + "barrierOnTapHint": "Close {modalRouteContentName}", + "@barrierOnTapHint": { + "description": "The onTapHint for the barrier rendered underneath the content of a modal route (especially a sheet) which users can tap to dismiss the content.", + "placeholders": { + "modalRouteContentName": { + "type": "String" + } + } + } } \ No newline at end of file diff --git a/forui/lib/l10n/f_en_AU.arb b/forui/lib/l10n/f_en_AU.arb index 1caf7628a..391db18ab 100644 --- a/forui/lib/l10n/f_en_AU.arb +++ b/forui/lib/l10n/f_en_AU.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Dialogue" + "dialogLabel": "Dialogue", + "sheetLabel": "Sheet", + "barrierOnTapHint": "Close $modalRouteContentName", + "barrierLabel": "Scrim" } \ No newline at end of file diff --git a/forui/lib/l10n/f_en_CA.arb b/forui/lib/l10n/f_en_CA.arb index e110b397e..f7b78b655 100644 --- a/forui/lib/l10n/f_en_CA.arb +++ b/forui/lib/l10n/f_en_CA.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Dialog" + "dialogLabel": "Dialog", + "sheetLabel": "Sheet", + "barrierOnTapHint": "Close $modalRouteContentName", + "barrierLabel": "Scrim" } \ No newline at end of file diff --git a/forui/lib/l10n/f_en_GB.arb b/forui/lib/l10n/f_en_GB.arb index 1caf7628a..86e2346a5 100644 --- a/forui/lib/l10n/f_en_GB.arb +++ b/forui/lib/l10n/f_en_GB.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Dialogue" + "dialogLabel": "Dialogue", + "sheetLabel": "sheet", + "barrierOnTapHint": "Close $modalRouteContentName", + "barrierLabel": "Scrim" } \ No newline at end of file diff --git a/forui/lib/l10n/f_en_IE.arb b/forui/lib/l10n/f_en_IE.arb index 1caf7628a..86e2346a5 100644 --- a/forui/lib/l10n/f_en_IE.arb +++ b/forui/lib/l10n/f_en_IE.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Dialogue" + "dialogLabel": "Dialogue", + "sheetLabel": "sheet", + "barrierOnTapHint": "Close $modalRouteContentName", + "barrierLabel": "Scrim" } \ No newline at end of file diff --git a/forui/lib/l10n/f_en_IN.arb b/forui/lib/l10n/f_en_IN.arb index 1caf7628a..86e2346a5 100644 --- a/forui/lib/l10n/f_en_IN.arb +++ b/forui/lib/l10n/f_en_IN.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Dialogue" + "dialogLabel": "Dialogue", + "sheetLabel": "sheet", + "barrierOnTapHint": "Close $modalRouteContentName", + "barrierLabel": "Scrim" } \ No newline at end of file diff --git a/forui/lib/l10n/f_en_NZ.arb b/forui/lib/l10n/f_en_NZ.arb index 1caf7628a..391db18ab 100644 --- a/forui/lib/l10n/f_en_NZ.arb +++ b/forui/lib/l10n/f_en_NZ.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Dialogue" + "dialogLabel": "Dialogue", + "sheetLabel": "Sheet", + "barrierOnTapHint": "Close $modalRouteContentName", + "barrierLabel": "Scrim" } \ No newline at end of file diff --git a/forui/lib/l10n/f_en_SG.arb b/forui/lib/l10n/f_en_SG.arb index 1caf7628a..86e2346a5 100644 --- a/forui/lib/l10n/f_en_SG.arb +++ b/forui/lib/l10n/f_en_SG.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Dialogue" + "dialogLabel": "Dialogue", + "sheetLabel": "sheet", + "barrierOnTapHint": "Close $modalRouteContentName", + "barrierLabel": "Scrim" } \ No newline at end of file diff --git a/forui/lib/l10n/f_en_ZA.arb b/forui/lib/l10n/f_en_ZA.arb index 1caf7628a..86e2346a5 100644 --- a/forui/lib/l10n/f_en_ZA.arb +++ b/forui/lib/l10n/f_en_ZA.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Dialogue" + "dialogLabel": "Dialogue", + "sheetLabel": "sheet", + "barrierOnTapHint": "Close $modalRouteContentName", + "barrierLabel": "Scrim" } \ No newline at end of file diff --git a/forui/lib/l10n/f_es.arb b/forui/lib/l10n/f_es.arb index 7df28ef8e..ceed48ba3 100644 --- a/forui/lib/l10n/f_es.arb +++ b/forui/lib/l10n/f_es.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Cuadro de diálogo" + "dialogLabel": "Cuadro de diálogo", + "sheetLabel": "Hoja", + "barrierOnTapHint": "Cerrar $modalRouteContentName", + "barrierLabel": "Sombreado" } \ No newline at end of file diff --git a/forui/lib/l10n/f_es_419.arb b/forui/lib/l10n/f_es_419.arb index 866cdeb96..e1a646c6b 100644 --- a/forui/lib/l10n/f_es_419.arb +++ b/forui/lib/l10n/f_es_419.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Diálogo" + "dialogLabel": "Diálogo", + "sheetLabel": "Hoja", + "barrierOnTapHint": "Cerrar $modalRouteContentName", + "barrierLabel": "Lámina" } \ No newline at end of file diff --git a/forui/lib/l10n/f_es_AR.arb b/forui/lib/l10n/f_es_AR.arb index 866cdeb96..e1a646c6b 100644 --- a/forui/lib/l10n/f_es_AR.arb +++ b/forui/lib/l10n/f_es_AR.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Diálogo" + "dialogLabel": "Diálogo", + "sheetLabel": "Hoja", + "barrierOnTapHint": "Cerrar $modalRouteContentName", + "barrierLabel": "Lámina" } \ No newline at end of file diff --git a/forui/lib/l10n/f_es_BO.arb b/forui/lib/l10n/f_es_BO.arb index 866cdeb96..e1a646c6b 100644 --- a/forui/lib/l10n/f_es_BO.arb +++ b/forui/lib/l10n/f_es_BO.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Diálogo" + "dialogLabel": "Diálogo", + "sheetLabel": "Hoja", + "barrierOnTapHint": "Cerrar $modalRouteContentName", + "barrierLabel": "Lámina" } \ No newline at end of file diff --git a/forui/lib/l10n/f_es_CL.arb b/forui/lib/l10n/f_es_CL.arb index 866cdeb96..e1a646c6b 100644 --- a/forui/lib/l10n/f_es_CL.arb +++ b/forui/lib/l10n/f_es_CL.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Diálogo" + "dialogLabel": "Diálogo", + "sheetLabel": "Hoja", + "barrierOnTapHint": "Cerrar $modalRouteContentName", + "barrierLabel": "Lámina" } \ No newline at end of file diff --git a/forui/lib/l10n/f_es_CO.arb b/forui/lib/l10n/f_es_CO.arb index 866cdeb96..e1a646c6b 100644 --- a/forui/lib/l10n/f_es_CO.arb +++ b/forui/lib/l10n/f_es_CO.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Diálogo" + "dialogLabel": "Diálogo", + "sheetLabel": "Hoja", + "barrierOnTapHint": "Cerrar $modalRouteContentName", + "barrierLabel": "Lámina" } \ No newline at end of file diff --git a/forui/lib/l10n/f_es_CR.arb b/forui/lib/l10n/f_es_CR.arb index 866cdeb96..e1a646c6b 100644 --- a/forui/lib/l10n/f_es_CR.arb +++ b/forui/lib/l10n/f_es_CR.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Diálogo" + "dialogLabel": "Diálogo", + "sheetLabel": "Hoja", + "barrierOnTapHint": "Cerrar $modalRouteContentName", + "barrierLabel": "Lámina" } \ No newline at end of file diff --git a/forui/lib/l10n/f_es_DO.arb b/forui/lib/l10n/f_es_DO.arb index 866cdeb96..e1a646c6b 100644 --- a/forui/lib/l10n/f_es_DO.arb +++ b/forui/lib/l10n/f_es_DO.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Diálogo" + "dialogLabel": "Diálogo", + "sheetLabel": "Hoja", + "barrierOnTapHint": "Cerrar $modalRouteContentName", + "barrierLabel": "Lámina" } \ No newline at end of file diff --git a/forui/lib/l10n/f_es_EC.arb b/forui/lib/l10n/f_es_EC.arb index 866cdeb96..e1a646c6b 100644 --- a/forui/lib/l10n/f_es_EC.arb +++ b/forui/lib/l10n/f_es_EC.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Diálogo" + "dialogLabel": "Diálogo", + "sheetLabel": "Hoja", + "barrierOnTapHint": "Cerrar $modalRouteContentName", + "barrierLabel": "Lámina" } \ No newline at end of file diff --git a/forui/lib/l10n/f_es_GT.arb b/forui/lib/l10n/f_es_GT.arb index 866cdeb96..e1a646c6b 100644 --- a/forui/lib/l10n/f_es_GT.arb +++ b/forui/lib/l10n/f_es_GT.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Diálogo" + "dialogLabel": "Diálogo", + "sheetLabel": "Hoja", + "barrierOnTapHint": "Cerrar $modalRouteContentName", + "barrierLabel": "Lámina" } \ No newline at end of file diff --git a/forui/lib/l10n/f_es_HN.arb b/forui/lib/l10n/f_es_HN.arb index 866cdeb96..e1a646c6b 100644 --- a/forui/lib/l10n/f_es_HN.arb +++ b/forui/lib/l10n/f_es_HN.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Diálogo" + "dialogLabel": "Diálogo", + "sheetLabel": "Hoja", + "barrierOnTapHint": "Cerrar $modalRouteContentName", + "barrierLabel": "Lámina" } \ No newline at end of file diff --git a/forui/lib/l10n/f_es_MX.arb b/forui/lib/l10n/f_es_MX.arb index 866cdeb96..e1a646c6b 100644 --- a/forui/lib/l10n/f_es_MX.arb +++ b/forui/lib/l10n/f_es_MX.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Diálogo" + "dialogLabel": "Diálogo", + "sheetLabel": "Hoja", + "barrierOnTapHint": "Cerrar $modalRouteContentName", + "barrierLabel": "Lámina" } \ No newline at end of file diff --git a/forui/lib/l10n/f_es_NI.arb b/forui/lib/l10n/f_es_NI.arb index 866cdeb96..e1a646c6b 100644 --- a/forui/lib/l10n/f_es_NI.arb +++ b/forui/lib/l10n/f_es_NI.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Diálogo" + "dialogLabel": "Diálogo", + "sheetLabel": "Hoja", + "barrierOnTapHint": "Cerrar $modalRouteContentName", + "barrierLabel": "Lámina" } \ No newline at end of file diff --git a/forui/lib/l10n/f_es_PA.arb b/forui/lib/l10n/f_es_PA.arb index 866cdeb96..e1a646c6b 100644 --- a/forui/lib/l10n/f_es_PA.arb +++ b/forui/lib/l10n/f_es_PA.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Diálogo" + "dialogLabel": "Diálogo", + "sheetLabel": "Hoja", + "barrierOnTapHint": "Cerrar $modalRouteContentName", + "barrierLabel": "Lámina" } \ No newline at end of file diff --git a/forui/lib/l10n/f_es_PE.arb b/forui/lib/l10n/f_es_PE.arb index 866cdeb96..e1a646c6b 100644 --- a/forui/lib/l10n/f_es_PE.arb +++ b/forui/lib/l10n/f_es_PE.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Diálogo" + "dialogLabel": "Diálogo", + "sheetLabel": "Hoja", + "barrierOnTapHint": "Cerrar $modalRouteContentName", + "barrierLabel": "Lámina" } \ No newline at end of file diff --git a/forui/lib/l10n/f_es_PR.arb b/forui/lib/l10n/f_es_PR.arb index 866cdeb96..e1a646c6b 100644 --- a/forui/lib/l10n/f_es_PR.arb +++ b/forui/lib/l10n/f_es_PR.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Diálogo" + "dialogLabel": "Diálogo", + "sheetLabel": "Hoja", + "barrierOnTapHint": "Cerrar $modalRouteContentName", + "barrierLabel": "Lámina" } \ No newline at end of file diff --git a/forui/lib/l10n/f_es_PY.arb b/forui/lib/l10n/f_es_PY.arb index 866cdeb96..62ae3b26a 100644 --- a/forui/lib/l10n/f_es_PY.arb +++ b/forui/lib/l10n/f_es_PY.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Diálogo" + "dialogLabel": "Diálogo", + "sheetLabel": "inferior", + "barrierOnTapHint": "Cerrar $modalRouteContentName", + "barrierLabel": "Lámina" } \ No newline at end of file diff --git a/forui/lib/l10n/f_es_SV.arb b/forui/lib/l10n/f_es_SV.arb index 866cdeb96..e1a646c6b 100644 --- a/forui/lib/l10n/f_es_SV.arb +++ b/forui/lib/l10n/f_es_SV.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Diálogo" + "dialogLabel": "Diálogo", + "sheetLabel": "Hoja", + "barrierOnTapHint": "Cerrar $modalRouteContentName", + "barrierLabel": "Lámina" } \ No newline at end of file diff --git a/forui/lib/l10n/f_es_US.arb b/forui/lib/l10n/f_es_US.arb index 866cdeb96..e1a646c6b 100644 --- a/forui/lib/l10n/f_es_US.arb +++ b/forui/lib/l10n/f_es_US.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Diálogo" + "dialogLabel": "Diálogo", + "sheetLabel": "Hoja", + "barrierOnTapHint": "Cerrar $modalRouteContentName", + "barrierLabel": "Lámina" } \ No newline at end of file diff --git a/forui/lib/l10n/f_es_UY.arb b/forui/lib/l10n/f_es_UY.arb index 866cdeb96..e1a646c6b 100644 --- a/forui/lib/l10n/f_es_UY.arb +++ b/forui/lib/l10n/f_es_UY.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Diálogo" + "dialogLabel": "Diálogo", + "sheetLabel": "Hoja", + "barrierOnTapHint": "Cerrar $modalRouteContentName", + "barrierLabel": "Lámina" } \ No newline at end of file diff --git a/forui/lib/l10n/f_es_VE.arb b/forui/lib/l10n/f_es_VE.arb index 866cdeb96..e1a646c6b 100644 --- a/forui/lib/l10n/f_es_VE.arb +++ b/forui/lib/l10n/f_es_VE.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Diálogo" + "dialogLabel": "Diálogo", + "sheetLabel": "Hoja", + "barrierOnTapHint": "Cerrar $modalRouteContentName", + "barrierLabel": "Lámina" } \ No newline at end of file diff --git a/forui/lib/l10n/f_et.arb b/forui/lib/l10n/f_et.arb index 3b920a0f7..e3230789a 100644 --- a/forui/lib/l10n/f_et.arb +++ b/forui/lib/l10n/f_et.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Dialoog" + "dialogLabel": "Dialoog", + "sheetLabel": "leht", + "barrierOnTapHint": "Sule $modalRouteContentName", + "barrierLabel": "Sirm" } \ No newline at end of file diff --git a/forui/lib/l10n/f_eu.arb b/forui/lib/l10n/f_eu.arb index 5953845a0..289e77f0a 100644 --- a/forui/lib/l10n/f_eu.arb +++ b/forui/lib/l10n/f_eu.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Leihoa" + "dialogLabel": "Leihoa", + "sheetLabel": "orria", + "barrierOnTapHint": "Itxi $modalRouteContentName", + "barrierLabel": "Barrera" } \ No newline at end of file diff --git a/forui/lib/l10n/f_fa.arb b/forui/lib/l10n/f_fa.arb index 8a3d2cd5f..1bba83e29 100644 --- a/forui/lib/l10n/f_fa.arb +++ b/forui/lib/l10n/f_fa.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "کادر گفتگو" + "dialogLabel": "کادر گفتگو", + "sheetLabel": "برگ", + "barrierOnTapHint": "بستن $modalRouteContentName", + "barrierLabel": "رویه" } \ No newline at end of file diff --git a/forui/lib/l10n/f_fi.arb b/forui/lib/l10n/f_fi.arb index 004008abd..3b8597aa3 100644 --- a/forui/lib/l10n/f_fi.arb +++ b/forui/lib/l10n/f_fi.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Valintaikkuna" + "dialogLabel": "Valintaikkuna", + "sheetLabel": "arkki", + "barrierOnTapHint": "Sulje $modalRouteContentName", + "barrierLabel": "Sermi" } \ No newline at end of file diff --git a/forui/lib/l10n/f_fil.arb b/forui/lib/l10n/f_fil.arb index e110b397e..18d5664e0 100644 --- a/forui/lib/l10n/f_fil.arb +++ b/forui/lib/l10n/f_fil.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Dialog" + "dialogLabel": "Dialog", + "sheetLabel": "sheet", + "barrierOnTapHint": "Isara ang $modalRouteContentName", + "barrierLabel": "Scrim" } \ No newline at end of file diff --git a/forui/lib/l10n/f_fr.arb b/forui/lib/l10n/f_fr.arb index 20c103078..70827c266 100644 --- a/forui/lib/l10n/f_fr.arb +++ b/forui/lib/l10n/f_fr.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Boîte de dialogue" + "dialogLabel": "Boîte de dialogue", + "sheetLabel": "sheet", + "barrierOnTapHint": "Fermer $modalRouteContentName", + "barrierLabel": "Fond" } \ No newline at end of file diff --git a/forui/lib/l10n/f_fr_CA.arb b/forui/lib/l10n/f_fr_CA.arb index 20c103078..42d5aebe2 100644 --- a/forui/lib/l10n/f_fr_CA.arb +++ b/forui/lib/l10n/f_fr_CA.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Boîte de dialogue" + "dialogLabel": "Boîte de dialogue", + "sheetLabel": "Zone de contenu", + "barrierOnTapHint": "Fermer $modalRouteContentName", + "barrierLabel": "Grille" } \ No newline at end of file diff --git a/forui/lib/l10n/f_gl.arb b/forui/lib/l10n/f_gl.arb index 23e825c9d..614934b89 100644 --- a/forui/lib/l10n/f_gl.arb +++ b/forui/lib/l10n/f_gl.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Cadro de diálogo" + "dialogLabel": "Cadro de diálogo", + "sheetLabel": "Panel", + "barrierOnTapHint": "Pechar $modalRouteContentName", + "barrierLabel": "Sombreado" } \ No newline at end of file diff --git a/forui/lib/l10n/f_gsw.arb b/forui/lib/l10n/f_gsw.arb index 6ee866ee2..f78b171c3 100644 --- a/forui/lib/l10n/f_gsw.arb +++ b/forui/lib/l10n/f_gsw.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Dialogfeld" + "dialogLabel": "Dialogfeld", + "sheetLabel": "Ansicht", + "barrierOnTapHint": "$modalRouteContentName schließen", + "barrierLabel": "Gitter" } \ No newline at end of file diff --git a/forui/lib/l10n/f_gu.arb b/forui/lib/l10n/f_gu.arb index e7bb6b90e..48341219a 100644 --- a/forui/lib/l10n/f_gu.arb +++ b/forui/lib/l10n/f_gu.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "સંવાદ" + "dialogLabel": "સંવાદ", + "sheetLabel": "શીટ", + "barrierOnTapHint": "$modalRouteContentNameને બંધ કરો", + "barrierLabel": "સ્ક્રિમ" } \ No newline at end of file diff --git a/forui/lib/l10n/f_he.arb b/forui/lib/l10n/f_he.arb index 64cdf294f..43500e149 100644 --- a/forui/lib/l10n/f_he.arb +++ b/forui/lib/l10n/f_he.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "תיבת דו-שיח" + "dialogLabel": "תיבת דו-שיח", + "sheetLabel": "גיליו ", + "barrierOnTapHint": "סגירת $modalRouteContentName", + "barrierLabel": "מיסוך" } \ No newline at end of file diff --git a/forui/lib/l10n/f_hi.arb b/forui/lib/l10n/f_hi.arb index f1b62e750..ea74f8926 100644 --- a/forui/lib/l10n/f_hi.arb +++ b/forui/lib/l10n/f_hi.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "डायलॉग" + "dialogLabel": "डायलॉग", + "sheetLabel": "शीट", + "barrierOnTapHint": "$modalRouteContentName को बंद करें", + "barrierLabel": "स्क्रिम" } \ No newline at end of file diff --git a/forui/lib/l10n/f_hr.arb b/forui/lib/l10n/f_hr.arb index 82633cdb0..9c053acf8 100644 --- a/forui/lib/l10n/f_hr.arb +++ b/forui/lib/l10n/f_hr.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Dijalog" + "dialogLabel": "Dijalog", + "sheetLabel": "tablica", + "barrierOnTapHint": "Zatvori $modalRouteContentName", + "barrierLabel": "Rubno" } \ No newline at end of file diff --git a/forui/lib/l10n/f_hu.arb b/forui/lib/l10n/f_hu.arb index 45d6f60f1..6eebb19b8 100644 --- a/forui/lib/l10n/f_hu.arb +++ b/forui/lib/l10n/f_hu.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Párbeszédablak" + "dialogLabel": "Párbeszédablak", + "sheetLabel": "lap", + "barrierOnTapHint": "$modalRouteContentName bezárása", + "barrierLabel": "Borítás" } \ No newline at end of file diff --git a/forui/lib/l10n/f_hy.arb b/forui/lib/l10n/f_hy.arb index 9b3609509..3863ac709 100644 --- a/forui/lib/l10n/f_hy.arb +++ b/forui/lib/l10n/f_hy.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Երկխոսության պատուհան" + "dialogLabel": "Երկխոսության պատուհան", + "sheetLabel": "էկրան", + "barrierOnTapHint": "Փակել՝ $modalRouteContentName", + "barrierLabel": "Դիմակ" } \ No newline at end of file diff --git a/forui/lib/l10n/f_id.arb b/forui/lib/l10n/f_id.arb index e110b397e..2003ad0bb 100644 --- a/forui/lib/l10n/f_id.arb +++ b/forui/lib/l10n/f_id.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Dialog" + "dialogLabel": "Dialog", + "sheetLabel": "Sheet", + "barrierOnTapHint": "Tutup $modalRouteContentName", + "barrierLabel": "Scrim" } \ No newline at end of file diff --git a/forui/lib/l10n/f_is.arb b/forui/lib/l10n/f_is.arb index 8a10bd807..41bcc1d5d 100644 --- a/forui/lib/l10n/f_is.arb +++ b/forui/lib/l10n/f_is.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Gluggi" + "dialogLabel": "Gluggi", + "sheetLabel": "Blað", + "barrierOnTapHint": "Loka $modalRouteContentName", + "barrierLabel": "Möskvi" } \ No newline at end of file diff --git a/forui/lib/l10n/f_it.arb b/forui/lib/l10n/f_it.arb index 2e04f7c5a..ecdea25c3 100644 --- a/forui/lib/l10n/f_it.arb +++ b/forui/lib/l10n/f_it.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Finestra di dialogo" + "dialogLabel": "Finestra di dialogo", + "sheetLabel": "Riquadro", + "barrierOnTapHint": "Chiudi $modalRouteContentName", + "barrierLabel": "Rete" } \ No newline at end of file diff --git a/forui/lib/l10n/f_ja.arb b/forui/lib/l10n/f_ja.arb index f105211c1..387394461 100644 --- a/forui/lib/l10n/f_ja.arb +++ b/forui/lib/l10n/f_ja.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "ダイアログ" + "dialogLabel": "ダイアログ", + "sheetLabel": "シート", + "barrierOnTapHint": "$modalRouteContentName を閉じる", + "barrierLabel": "スクリム" } \ No newline at end of file diff --git a/forui/lib/l10n/f_ka.arb b/forui/lib/l10n/f_ka.arb index edb07fc1e..6c43bf503 100644 --- a/forui/lib/l10n/f_ka.arb +++ b/forui/lib/l10n/f_ka.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "დიალოგი" + "dialogLabel": "დიალოგი", + "sheetLabel": "ფურცელი", + "barrierOnTapHint": "$modalRouteContentName-ის დახურვა", + "barrierLabel": "სკრიმი" } \ No newline at end of file diff --git a/forui/lib/l10n/f_kk.arb b/forui/lib/l10n/f_kk.arb index b3680765b..39f2705c3 100644 --- a/forui/lib/l10n/f_kk.arb +++ b/forui/lib/l10n/f_kk.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Диалогтық терезе" + "dialogLabel": "Диалогтық терезе", + "sheetLabel": "парақша", + "barrierOnTapHint": "$modalRouteContentName жабу", + "barrierLabel": "Кенеп" } \ No newline at end of file diff --git a/forui/lib/l10n/f_km.arb b/forui/lib/l10n/f_km.arb index 7dc6c43b4..a05eaaa5c 100644 --- a/forui/lib/l10n/f_km.arb +++ b/forui/lib/l10n/f_km.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "ប្រអប់" + "dialogLabel": "ប្រអប់", + "sheetLabel": "សន្លឹក", + "barrierOnTapHint": "បិទ $modalRouteContentName", + "barrierLabel": "ផ្ទាំងស្រអាប់" } \ No newline at end of file diff --git a/forui/lib/l10n/f_kn.arb b/forui/lib/l10n/f_kn.arb index 40b8e2b08..aa6bb7374 100644 --- a/forui/lib/l10n/f_kn.arb +++ b/forui/lib/l10n/f_kn.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "ಡೈಲಾಗ್" + "dialogLabel": "ಡೈಲಾಗ್", + "sheetLabel": "ಶೀಟ್", + "barrierOnTapHint": "$modalRouteContentName ಅನ್ನು ಮುಚ್ಚಿರಿ", + "barrierLabel": "ಸ್ಕ್ರಿಮ್" } \ No newline at end of file diff --git a/forui/lib/l10n/f_ko.arb b/forui/lib/l10n/f_ko.arb index 90f1cb62b..02f00e4b5 100644 --- a/forui/lib/l10n/f_ko.arb +++ b/forui/lib/l10n/f_ko.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "대화상자" + "dialogLabel": "대화상자", + "sheetLabel": "시트", + "barrierOnTapHint": "$modalRouteContentName 닫기", + "barrierLabel": "스크림" } \ No newline at end of file diff --git a/forui/lib/l10n/f_ky.arb b/forui/lib/l10n/f_ky.arb index 26bf7c219..199d0e5a6 100644 --- a/forui/lib/l10n/f_ky.arb +++ b/forui/lib/l10n/f_ky.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Диалог" + "dialogLabel": "Диалог", + "sheetLabel": "экран", + "barrierOnTapHint": "$modalRouteContentName жабуу", + "barrierLabel": "Кенеп" } \ No newline at end of file diff --git a/forui/lib/l10n/f_lo.arb b/forui/lib/l10n/f_lo.arb index e1d2d413b..6354ddd82 100644 --- a/forui/lib/l10n/f_lo.arb +++ b/forui/lib/l10n/f_lo.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "ຂໍ້ຄວາມ" + "dialogLabel": "ຂໍ້ຄວາມ", + "sheetLabel": "ແຜ່ນ", + "barrierOnTapHint": "ປິດ $modalRouteContentName", + "barrierLabel": "Scrim" } \ No newline at end of file diff --git a/forui/lib/l10n/f_lt.arb b/forui/lib/l10n/f_lt.arb index e846fab7e..f1ed32860 100644 --- a/forui/lib/l10n/f_lt.arb +++ b/forui/lib/l10n/f_lt.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Dialogo langas" + "dialogLabel": "Dialogo langas", + "sheetLabel": "lapas", + "barrierOnTapHint": "Uždaryti „$modalRouteContentName“", + "barrierLabel": "Užsklanda" } \ No newline at end of file diff --git a/forui/lib/l10n/f_lv.arb b/forui/lib/l10n/f_lv.arb index 5e344124c..315b722cc 100644 --- a/forui/lib/l10n/f_lv.arb +++ b/forui/lib/l10n/f_lv.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Dialoglodziņš" + "dialogLabel": "Dialoglodziņš", + "sheetLabel": "lapa", + "barrierOnTapHint": "Aizvērt $modalRouteContentName", + "barrierLabel": "Pārklājums" } \ No newline at end of file diff --git a/forui/lib/l10n/f_mk.arb b/forui/lib/l10n/f_mk.arb index 954f37e72..1801cb075 100644 --- a/forui/lib/l10n/f_mk.arb +++ b/forui/lib/l10n/f_mk.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Дијалог" + "dialogLabel": "Дијалог", + "sheetLabel": "лист", + "barrierOnTapHint": "Затворете ја $modalRouteContentName", + "barrierLabel": "Скрим" } \ No newline at end of file diff --git a/forui/lib/l10n/f_ml.arb b/forui/lib/l10n/f_ml.arb index 2a9e564ca..a22548c84 100644 --- a/forui/lib/l10n/f_ml.arb +++ b/forui/lib/l10n/f_ml.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "ഡയലോഗ്" + "dialogLabel": "ഡയലോഗ്", + "sheetLabel": "ഷീറ്റ്", + "barrierOnTapHint": "$modalRouteContentName അടയ്ക്കുക", + "barrierLabel": "സ്ക്രിം" } \ No newline at end of file diff --git a/forui/lib/l10n/f_mn.arb b/forui/lib/l10n/f_mn.arb index 8558ab256..822e5e603 100644 --- a/forui/lib/l10n/f_mn.arb +++ b/forui/lib/l10n/f_mn.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Харилцах цонх" + "dialogLabel": "Харилцах цонх", + "sheetLabel": "хүснэгт", + "barrierOnTapHint": "$modalRouteContentName-г хаах", + "barrierLabel": "Скрим" } \ No newline at end of file diff --git a/forui/lib/l10n/f_mr.arb b/forui/lib/l10n/f_mr.arb index f1b62e750..b27d0c1a7 100644 --- a/forui/lib/l10n/f_mr.arb +++ b/forui/lib/l10n/f_mr.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "डायलॉग" + "dialogLabel": "डायलॉग", + "sheetLabel": "शीट", + "barrierOnTapHint": "$modalRouteContentName बंद करा", + "barrierLabel": "स्क्रिम" } \ No newline at end of file diff --git a/forui/lib/l10n/f_ms.arb b/forui/lib/l10n/f_ms.arb index e110b397e..f0d27ddf2 100644 --- a/forui/lib/l10n/f_ms.arb +++ b/forui/lib/l10n/f_ms.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Dialog" + "dialogLabel": "Dialog", + "sheetLabel": "Helaian", + "barrierOnTapHint": "Tutup $modalRouteContentName", + "barrierLabel": "Scrim" } \ No newline at end of file diff --git a/forui/lib/l10n/f_my.arb b/forui/lib/l10n/f_my.arb index 2b90405fa..1e7217d20 100644 --- a/forui/lib/l10n/f_my.arb +++ b/forui/lib/l10n/f_my.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "ဒိုင်ယာလော့" + "dialogLabel": "ဒိုင်ယာလော့", + "sheetLabel": "ပိုဆောင်း စာမျက်နှာ", + "barrierOnTapHint": "$modalRouteContentName ပိတ်ရန်", + "barrierLabel": "Scrim" } \ No newline at end of file diff --git a/forui/lib/l10n/f_nb.arb b/forui/lib/l10n/f_nb.arb index fff2252c6..35e841252 100644 --- a/forui/lib/l10n/f_nb.arb +++ b/forui/lib/l10n/f_nb.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Dialogboks" + "dialogLabel": "Dialogboks", + "sheetLabel": "Felt", + "barrierOnTapHint": "Lukk $modalRouteContentName", + "barrierLabel": "Vev" } \ No newline at end of file diff --git a/forui/lib/l10n/f_ne.arb b/forui/lib/l10n/f_ne.arb index 7ac3b67db..b1d54e267 100644 --- a/forui/lib/l10n/f_ne.arb +++ b/forui/lib/l10n/f_ne.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "संवाद" + "dialogLabel": "संवाद", + "sheetLabel": "पाना", + "barrierOnTapHint": "$modalRouteContentName बन्द गर्नुहोस्", + "barrierLabel": "स्क्रिम" } \ No newline at end of file diff --git a/forui/lib/l10n/f_nl.arb b/forui/lib/l10n/f_nl.arb index 09c950b57..89786aef0 100644 --- a/forui/lib/l10n/f_nl.arb +++ b/forui/lib/l10n/f_nl.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Dialoogvenster" + "dialogLabel": "Dialoogvenster", + "sheetLabel": "Blad", + "barrierOnTapHint": "$modalRouteContentName sluiten", + "barrierLabel": "Scrim" } \ No newline at end of file diff --git a/forui/lib/l10n/f_no.arb b/forui/lib/l10n/f_no.arb index fff2252c6..35e841252 100644 --- a/forui/lib/l10n/f_no.arb +++ b/forui/lib/l10n/f_no.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Dialogboks" + "dialogLabel": "Dialogboks", + "sheetLabel": "Felt", + "barrierOnTapHint": "Lukk $modalRouteContentName", + "barrierLabel": "Vev" } \ No newline at end of file diff --git a/forui/lib/l10n/f_or.arb b/forui/lib/l10n/f_or.arb index da45257c4..7fb28c6e6 100644 --- a/forui/lib/l10n/f_or.arb +++ b/forui/lib/l10n/f_or.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "ଡାୟଲଗ୍" + "dialogLabel": "ଡାୟଲଗ୍", + "sheetLabel": "ସିଟ", + "barrierOnTapHint": "$modalRouteContentNameକୁ ବନ୍ଦ କରନ୍ତୁ", + "barrierLabel": "ସ୍କ୍ରିମ" } \ No newline at end of file diff --git a/forui/lib/l10n/f_pa.arb b/forui/lib/l10n/f_pa.arb index 507b188be..44b499384 100644 --- a/forui/lib/l10n/f_pa.arb +++ b/forui/lib/l10n/f_pa.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "ਵਿੰਡੋ" + "dialogLabel": "ਵਿੰਡੋ", + "sheetLabel": "ਸ਼ੀਟ", + "barrierOnTapHint": "$modalRouteContentName ਨੂੰ ਬੰਦ ਕਰੋ", + "barrierLabel": "ਸਕ੍ਰਿਮ" } \ No newline at end of file diff --git a/forui/lib/l10n/f_pl.arb b/forui/lib/l10n/f_pl.arb index 635e6e66f..b52db54d1 100644 --- a/forui/lib/l10n/f_pl.arb +++ b/forui/lib/l10n/f_pl.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Okno dialogowe" + "dialogLabel": "Okno dialogowe", + "sheetLabel": "Plansza", + "barrierOnTapHint": "Zamknij: $modalRouteContentName", + "barrierLabel": "Siatka" } \ No newline at end of file diff --git a/forui/lib/l10n/f_ps.arb b/forui/lib/l10n/f_ps.arb index 11628794c..a7a9d5b72 100644 --- a/forui/lib/l10n/f_ps.arb +++ b/forui/lib/l10n/f_ps.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "خبرې اترې" + "dialogLabel": "خبرې اترې", + "sheetLabel": "Sheet", + "barrierOnTapHint": "Close $modalRouteName", + "barrierLabel": "Scrim" } \ No newline at end of file diff --git a/forui/lib/l10n/f_pt.arb b/forui/lib/l10n/f_pt.arb index 5eaaf3a1b..42cde9097 100644 --- a/forui/lib/l10n/f_pt.arb +++ b/forui/lib/l10n/f_pt.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Caixa de diálogo" + "dialogLabel": "Caixa de diálogo", + "sheetLabel": "inferior", + "barrierOnTapHint": "Fechar $modalRouteContentName", + "barrierLabel": "Scrim" } \ No newline at end of file diff --git a/forui/lib/l10n/f_pt_PT.arb b/forui/lib/l10n/f_pt_PT.arb index 5eaaf3a1b..b60f09c7a 100644 --- a/forui/lib/l10n/f_pt_PT.arb +++ b/forui/lib/l10n/f_pt_PT.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Caixa de diálogo" + "dialogLabel": "Caixa de diálogo", + "sheetLabel": "Secção", + "barrierOnTapHint": "Fechar $modalRouteContentName", + "barrierLabel": "Scrim" } \ No newline at end of file diff --git a/forui/lib/l10n/f_ro.arb b/forui/lib/l10n/f_ro.arb index 0d92cb0b9..bc8e163ad 100644 --- a/forui/lib/l10n/f_ro.arb +++ b/forui/lib/l10n/f_ro.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Casetă de dialog" + "dialogLabel": "Casetă de dialog", + "sheetLabel": "Foaie", + "barrierOnTapHint": "Închideți $modalRouteContentName", + "barrierLabel": "Material" } \ No newline at end of file diff --git a/forui/lib/l10n/f_ru.arb b/forui/lib/l10n/f_ru.arb index b5f9f85b2..cd6f012a6 100644 --- a/forui/lib/l10n/f_ru.arb +++ b/forui/lib/l10n/f_ru.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Диалоговое окно" + "dialogLabel": "Диалоговое окно", + "sheetLabel": "экран", + "barrierOnTapHint": "Закрыть $modalRouteContentName", + "barrierLabel": "Маска" } \ No newline at end of file diff --git a/forui/lib/l10n/f_si.arb b/forui/lib/l10n/f_si.arb index 2bf5ee7c0..92545ba46 100644 --- a/forui/lib/l10n/f_si.arb +++ b/forui/lib/l10n/f_si.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "සංවාදය" + "dialogLabel": "සංවාදය", + "sheetLabel": "පත්‍රය", + "barrierOnTapHint": "$modalRouteContentName වසන්න", + "barrierLabel": "ස්ක්‍රිම්" } \ No newline at end of file diff --git a/forui/lib/l10n/f_sk.arb b/forui/lib/l10n/f_sk.arb index 9877d3f5b..ef4937d14 100644 --- a/forui/lib/l10n/f_sk.arb +++ b/forui/lib/l10n/f_sk.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Dialógové okno" + "dialogLabel": "Dialógové okno", + "sheetLabel": "hárok", + "barrierOnTapHint": "Zavrieť $modalRouteContentName", + "barrierLabel": "Scrim" } \ No newline at end of file diff --git a/forui/lib/l10n/f_sl.arb b/forui/lib/l10n/f_sl.arb index 5fe860836..337be873b 100644 --- a/forui/lib/l10n/f_sl.arb +++ b/forui/lib/l10n/f_sl.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Pogovorno okno" + "dialogLabel": "Pogovorno okno", + "sheetLabel": "Razdelek", + "barrierOnTapHint": "Zapiranje »$modalRouteContentName«", + "barrierLabel": "Scrim" } \ No newline at end of file diff --git a/forui/lib/l10n/f_sq.arb b/forui/lib/l10n/f_sq.arb index 9e6271e6b..ffbd1a92e 100644 --- a/forui/lib/l10n/f_sq.arb +++ b/forui/lib/l10n/f_sq.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Dialogu" + "dialogLabel": "Dialogu", + "sheetLabel": "Fleta", + "barrierOnTapHint": "Mbyll $modalRouteContentName", + "barrierLabel": "Kanavacë" } \ No newline at end of file diff --git a/forui/lib/l10n/f_sr.arb b/forui/lib/l10n/f_sr.arb index 954f37e72..6e4089262 100644 --- a/forui/lib/l10n/f_sr.arb +++ b/forui/lib/l10n/f_sr.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Дијалог" + "dialogLabel": "Дијалог", + "sheetLabel": "табела", + "barrierOnTapHint": "Затвори: $modalRouteContentName", + "barrierLabel": "Скрим" } \ No newline at end of file diff --git a/forui/lib/l10n/f_sr_Latn.arb b/forui/lib/l10n/f_sr_Latn.arb index 82633cdb0..909cc39e2 100644 --- a/forui/lib/l10n/f_sr_Latn.arb +++ b/forui/lib/l10n/f_sr_Latn.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Dijalog" + "dialogLabel": "Dijalog", + "sheetLabel": "tabela", + "barrierOnTapHint": "Zatvori: $modalRouteContentName", + "barrierLabel": "Skrim" } \ No newline at end of file diff --git a/forui/lib/l10n/f_sv.arb b/forui/lib/l10n/f_sv.arb index 316fb9675..9e0176c87 100644 --- a/forui/lib/l10n/f_sv.arb +++ b/forui/lib/l10n/f_sv.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Dialogruta" + "dialogLabel": "Dialogruta", + "sheetLabel": "Ark", + "barrierOnTapHint": "Stäng $modalRouteContentName", + "barrierLabel": "Scrim" } \ No newline at end of file diff --git a/forui/lib/l10n/f_sw.arb b/forui/lib/l10n/f_sw.arb index 2d7c5deab..6b21d2579 100644 --- a/forui/lib/l10n/f_sw.arb +++ b/forui/lib/l10n/f_sw.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Kidirisha" + "dialogLabel": "Kidirisha", + "sheetLabel": "Safu", + "barrierOnTapHint": "Funga $modalRouteContentName", + "barrierLabel": "Scrim" } \ No newline at end of file diff --git a/forui/lib/l10n/f_ta.arb b/forui/lib/l10n/f_ta.arb index 3aa591987..16ef7db5b 100644 --- a/forui/lib/l10n/f_ta.arb +++ b/forui/lib/l10n/f_ta.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "உரையாடல்" + "dialogLabel": "உரையாடல்", + "sheetLabel": "திரை", + "barrierOnTapHint": "$modalRouteContentName ஐ மூடுக", + "barrierLabel": "ஸ்க்ரிம்" } \ No newline at end of file diff --git a/forui/lib/l10n/f_te.arb b/forui/lib/l10n/f_te.arb index c9ff2d584..6e615ca09 100644 --- a/forui/lib/l10n/f_te.arb +++ b/forui/lib/l10n/f_te.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "డైలాగ్" + "dialogLabel": "డైలాగ్", + "sheetLabel": "షీట్", + "barrierOnTapHint": "$modalRouteContentName‌ను మూసివేయండి", + "barrierLabel": "స్క్రిమ్" } \ No newline at end of file diff --git a/forui/lib/l10n/f_th.arb b/forui/lib/l10n/f_th.arb index 7fca3841a..f60302c4d 100644 --- a/forui/lib/l10n/f_th.arb +++ b/forui/lib/l10n/f_th.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "กล่องโต้ตอบ" + "dialogLabel": "กล่องโต้ตอบ", + "sheetLabel": "Sheet", + "barrierOnTapHint": "ปิด $modalRouteContentName", + "barrierLabel": "Scrim" } \ No newline at end of file diff --git a/forui/lib/l10n/f_tl.arb b/forui/lib/l10n/f_tl.arb index e110b397e..18d5664e0 100644 --- a/forui/lib/l10n/f_tl.arb +++ b/forui/lib/l10n/f_tl.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Dialog" + "dialogLabel": "Dialog", + "sheetLabel": "sheet", + "barrierOnTapHint": "Isara ang $modalRouteContentName", + "barrierLabel": "Scrim" } \ No newline at end of file diff --git a/forui/lib/l10n/f_tr.arb b/forui/lib/l10n/f_tr.arb index 6a6760c1e..6c764a5d1 100644 --- a/forui/lib/l10n/f_tr.arb +++ b/forui/lib/l10n/f_tr.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "İletişim kutusu" + "dialogLabel": "İletişim kutusu", + "sheetLabel": "sayfa", + "barrierOnTapHint": "$modalRouteContentName içeriğini kapat", + "barrierLabel": "opaklık katmanı" } \ No newline at end of file diff --git a/forui/lib/l10n/f_uk.arb b/forui/lib/l10n/f_uk.arb index fa23a2d2f..a24a0a352 100644 --- a/forui/lib/l10n/f_uk.arb +++ b/forui/lib/l10n/f_uk.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Вікно" + "dialogLabel": "Вікно", + "sheetLabel": "екран", + "barrierOnTapHint": "Закрити: $modalRouteContentName", + "barrierLabel": "Маскувальний фон" } \ No newline at end of file diff --git a/forui/lib/l10n/f_ur.arb b/forui/lib/l10n/f_ur.arb index 1838ac93e..a3b312b08 100644 --- a/forui/lib/l10n/f_ur.arb +++ b/forui/lib/l10n/f_ur.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "ڈائلاگ" + "dialogLabel": "ڈائلاگ", + "sheetLabel": "شیٹ", + "barrierOnTapHint": "$modalRouteContentName بند کریں", + "barrierLabel": "اسکریم" } \ No newline at end of file diff --git a/forui/lib/l10n/f_uz.arb b/forui/lib/l10n/f_uz.arb index 73343cd96..682f1f04f 100644 --- a/forui/lib/l10n/f_uz.arb +++ b/forui/lib/l10n/f_uz.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Muloqot oynasi" + "dialogLabel": "Muloqot oynasi", + "sheetLabel": "ekran", + "barrierOnTapHint": "Yopish: $modalRouteContentName", + "barrierLabel": "Kanop" } \ No newline at end of file diff --git a/forui/lib/l10n/f_vi.arb b/forui/lib/l10n/f_vi.arb index 9f872cab0..4400aa794 100644 --- a/forui/lib/l10n/f_vi.arb +++ b/forui/lib/l10n/f_vi.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Hộp thoại" + "dialogLabel": "Hộp thoại", + "sheetLabel": "Bảng", + "barrierOnTapHint": "Đóng $modalRouteContentName", + "barrierLabel": "Scrim" } \ No newline at end of file diff --git a/forui/lib/l10n/f_zh.arb b/forui/lib/l10n/f_zh.arb index 2ee9f1521..03215ae06 100644 --- a/forui/lib/l10n/f_zh.arb +++ b/forui/lib/l10n/f_zh.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "对话框" + "dialogLabel": "对话框", + "sheetLabel": "动作条", + "barrierOnTapHint": "关闭 $modalRouteContentName", + "barrierLabel": "纱罩" } \ No newline at end of file diff --git a/forui/lib/l10n/f_zh_HK.arb b/forui/lib/l10n/f_zh_HK.arb index a7594fe97..214a53ddf 100644 --- a/forui/lib/l10n/f_zh_HK.arb +++ b/forui/lib/l10n/f_zh_HK.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "對話方塊" + "dialogLabel": "對話方塊", + "sheetLabel": "面板", + "barrierOnTapHint": "關閉 $modalRouteContentName", + "barrierLabel": "Scrim" } \ No newline at end of file diff --git a/forui/lib/l10n/f_zh_TW.arb b/forui/lib/l10n/f_zh_TW.arb index a7594fe97..6ed0d4fcd 100644 --- a/forui/lib/l10n/f_zh_TW.arb +++ b/forui/lib/l10n/f_zh_TW.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "對話方塊" + "dialogLabel": "對話方塊", + "sheetLabel": "功能表", + "barrierOnTapHint": "關閉「$modalRouteContentName」", + "barrierLabel": "紗罩" } \ No newline at end of file diff --git a/forui/lib/l10n/f_zu.arb b/forui/lib/l10n/f_zu.arb index 5fa3095d6..ca858bf0b 100644 --- a/forui/lib/l10n/f_zu.arb +++ b/forui/lib/l10n/f_zu.arb @@ -1,3 +1,6 @@ { - "dialogLabel": "Ingxoxo" + "dialogLabel": "Ingxoxo", + "sheetLabel": "Ishidi", + "barrierOnTapHint": "Vala i-$modalRouteContentName", + "barrierLabel": "I-Scrim" } \ No newline at end of file diff --git a/forui/lib/src/localizations/localization.dart b/forui/lib/src/localizations/localization.dart index 2ff69eae6..8df67c08a 100644 --- a/forui/lib/src/localizations/localization.dart +++ b/forui/lib/src/localizations/localization.dart @@ -35,4 +35,13 @@ class DefaultLocalizations extends FLocalizations { @override String get dialogLabel => 'Dialog'; + + @override + String get sheetLabel => 'Sheet'; + + @override + String get barrierLabel => 'Barrier'; + + @override + String barrierOnTapHint(String modalRouteContentName) => 'Close $modalRouteContentName'; } diff --git a/forui/lib/src/localizations/localizations.dart b/forui/lib/src/localizations/localizations.dart index ce4ecb408..f683803ca 100644 --- a/forui/lib/src/localizations/localizations.dart +++ b/forui/lib/src/localizations/localizations.dart @@ -2,7 +2,6 @@ import 'dart:async'; import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; - import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:intl/intl.dart' as intl; @@ -315,11 +314,29 @@ abstract class FLocalizations { /// **'{date}'** String day(DateTime date); - /// No description provided for @dialogLabel. + /// The sheet's label. /// /// In en, this message translates to: /// **'Dialog'** String get dialogLabel; + + /// No description provided for @sheetLabel. + /// + /// In en, this message translates to: + /// **'Sheet'** + String get sheetLabel; + + /// The label for the barrier rendered underneath the content of a bottom sheet (used as the 'modalRouteContentName' of the 'barrierOnTapHint' message). + /// + /// In en, this message translates to: + /// **'Barrier'** + String get barrierLabel; + + /// The onTapHint for the barrier rendered underneath the content of a modal route (especially a sheet) which users can tap to dismiss the content. + /// + /// In en, this message translates to: + /// **'Close {modalRouteContentName}'** + String barrierOnTapHint(String modalRouteContentName); } class _FLocalizationsDelegate extends LocalizationsDelegate { diff --git a/forui/lib/src/localizations/localizations_af.dart b/forui/lib/src/localizations/localizations_af.dart index e3d6f6bec..d4ead4422 100644 --- a/forui/lib/src/localizations/localizations_af.dart +++ b/forui/lib/src/localizations/localizations_af.dart @@ -50,4 +50,15 @@ class FLocalizationsAf extends FLocalizations { @override String get dialogLabel => 'Dialoog'; + + @override + String get sheetLabel => 'blad'; + + @override + String get barrierLabel => 'Skerm'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Maak \$modalRouteContentName toe'; + } } diff --git a/forui/lib/src/localizations/localizations_am.dart b/forui/lib/src/localizations/localizations_am.dart index b5af5f546..f2758aa7a 100644 --- a/forui/lib/src/localizations/localizations_am.dart +++ b/forui/lib/src/localizations/localizations_am.dart @@ -50,4 +50,15 @@ class FLocalizationsAm extends FLocalizations { @override String get dialogLabel => 'መገናኛ'; + + @override + String get sheetLabel => 'ሉህ'; + + @override + String get barrierLabel => 'ገዳቢ'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return '\$modalRouteContentNameን ዝጋ'; + } } diff --git a/forui/lib/src/localizations/localizations_ar.dart b/forui/lib/src/localizations/localizations_ar.dart index d566fb58e..507b8adfc 100644 --- a/forui/lib/src/localizations/localizations_ar.dart +++ b/forui/lib/src/localizations/localizations_ar.dart @@ -50,4 +50,15 @@ class FLocalizationsAr extends FLocalizations { @override String get dialogLabel => 'مربع حوار'; + + @override + String get sheetLabel => 'بطاق '; + + @override + String get barrierLabel => 'تمويه'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'إغلاق \"\$modalRouteContentName\"'; + } } diff --git a/forui/lib/src/localizations/localizations_as.dart b/forui/lib/src/localizations/localizations_as.dart index 4a5c99e58..ba735940c 100644 --- a/forui/lib/src/localizations/localizations_as.dart +++ b/forui/lib/src/localizations/localizations_as.dart @@ -50,4 +50,15 @@ class FLocalizationsAs extends FLocalizations { @override String get dialogLabel => 'ডায়ল\'গ'; + + @override + String get sheetLabel => 'শ্বীট'; + + @override + String get barrierLabel => 'স্ক্ৰিম'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return '\$modalRouteContentName বন্ধ কৰক'; + } } diff --git a/forui/lib/src/localizations/localizations_az.dart b/forui/lib/src/localizations/localizations_az.dart index 91f8fd491..adc404ecf 100644 --- a/forui/lib/src/localizations/localizations_az.dart +++ b/forui/lib/src/localizations/localizations_az.dart @@ -50,4 +50,15 @@ class FLocalizationsAz extends FLocalizations { @override String get dialogLabel => 'Dialoq'; + + @override + String get sheetLabel => 'Vərəq'; + + @override + String get barrierLabel => 'Kətan'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Bağlayın: \$modalRouteContentName'; + } } diff --git a/forui/lib/src/localizations/localizations_be.dart b/forui/lib/src/localizations/localizations_be.dart index 907f9cfef..d837ecb28 100644 --- a/forui/lib/src/localizations/localizations_be.dart +++ b/forui/lib/src/localizations/localizations_be.dart @@ -50,4 +50,15 @@ class FLocalizationsBe extends FLocalizations { @override String get dialogLabel => 'Дыялогавае акно'; + + @override + String get sheetLabel => 'аркуш'; + + @override + String get barrierLabel => 'Палатно'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Закрыць: \$modalRouteContentName'; + } } diff --git a/forui/lib/src/localizations/localizations_bg.dart b/forui/lib/src/localizations/localizations_bg.dart index c80aef1fc..e0ac1dd62 100644 --- a/forui/lib/src/localizations/localizations_bg.dart +++ b/forui/lib/src/localizations/localizations_bg.dart @@ -50,4 +50,15 @@ class FLocalizationsBg extends FLocalizations { @override String get dialogLabel => 'Диалогов прозорец'; + + @override + String get sheetLabel => 'лист'; + + @override + String get barrierLabel => 'Скрим'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Затваряне на \$modalRouteContentName'; + } } diff --git a/forui/lib/src/localizations/localizations_bn.dart b/forui/lib/src/localizations/localizations_bn.dart index 7d80739a4..bc6112cc7 100644 --- a/forui/lib/src/localizations/localizations_bn.dart +++ b/forui/lib/src/localizations/localizations_bn.dart @@ -50,4 +50,15 @@ class FLocalizationsBn extends FLocalizations { @override String get dialogLabel => 'ডায়ালগ'; + + @override + String get sheetLabel => 'শীট'; + + @override + String get barrierLabel => 'স্ক্রিম'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return '\$modalRouteContentName বন্ধ করুন'; + } } diff --git a/forui/lib/src/localizations/localizations_bs.dart b/forui/lib/src/localizations/localizations_bs.dart index c03f2c57d..5466ad763 100644 --- a/forui/lib/src/localizations/localizations_bs.dart +++ b/forui/lib/src/localizations/localizations_bs.dart @@ -50,4 +50,15 @@ class FLocalizationsBs extends FLocalizations { @override String get dialogLabel => 'Dijaloški okvir'; + + @override + String get sheetLabel => 'tabela'; + + @override + String get barrierLabel => 'Rubno'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Zatvori: \$modalRouteContentName'; + } } diff --git a/forui/lib/src/localizations/localizations_ca.dart b/forui/lib/src/localizations/localizations_ca.dart index 4798563da..9ff52da99 100644 --- a/forui/lib/src/localizations/localizations_ca.dart +++ b/forui/lib/src/localizations/localizations_ca.dart @@ -50,4 +50,15 @@ class FLocalizationsCa extends FLocalizations { @override String get dialogLabel => 'Diàleg'; + + @override + String get sheetLabel => 'Full'; + + @override + String get barrierLabel => 'Fons atenuat'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Tanca \$modalRouteContentName'; + } } diff --git a/forui/lib/src/localizations/localizations_cs.dart b/forui/lib/src/localizations/localizations_cs.dart index 0f790c71a..8163de2f7 100644 --- a/forui/lib/src/localizations/localizations_cs.dart +++ b/forui/lib/src/localizations/localizations_cs.dart @@ -50,4 +50,15 @@ class FLocalizationsCs extends FLocalizations { @override String get dialogLabel => 'Dialogové okno'; + + @override + String get sheetLabel => 'tabulka'; + + @override + String get barrierLabel => 'Scrim'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Zavřít \$modalRouteContentName'; + } } diff --git a/forui/lib/src/localizations/localizations_cy.dart b/forui/lib/src/localizations/localizations_cy.dart index 64e488749..6bb3e769f 100644 --- a/forui/lib/src/localizations/localizations_cy.dart +++ b/forui/lib/src/localizations/localizations_cy.dart @@ -50,4 +50,15 @@ class FLocalizationsCy extends FLocalizations { @override String get dialogLabel => 'Deialog'; + + @override + String get sheetLabel => 'Taflen'; + + @override + String get barrierLabel => 'Scrim'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Cau \$modalRouteContentName'; + } } diff --git a/forui/lib/src/localizations/localizations_da.dart b/forui/lib/src/localizations/localizations_da.dart index 0f8df543c..297452529 100644 --- a/forui/lib/src/localizations/localizations_da.dart +++ b/forui/lib/src/localizations/localizations_da.dart @@ -50,4 +50,15 @@ class FLocalizationsDa extends FLocalizations { @override String get dialogLabel => 'Dialogboks'; + + @override + String get sheetLabel => 'Felt'; + + @override + String get barrierLabel => 'Dæmpeskærm'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Luk \$modalRouteContentName'; + } } diff --git a/forui/lib/src/localizations/localizations_de.dart b/forui/lib/src/localizations/localizations_de.dart index bf0043c7f..ea369d24b 100644 --- a/forui/lib/src/localizations/localizations_de.dart +++ b/forui/lib/src/localizations/localizations_de.dart @@ -50,6 +50,17 @@ class FLocalizationsDe extends FLocalizations { @override String get dialogLabel => 'Dialogfeld'; + + @override + String get sheetLabel => 'Ansicht'; + + @override + String get barrierLabel => 'Gitter'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return '\$modalRouteContentName schließen'; + } } /// The translations for German, as used in Switzerland (`de_CH`). diff --git a/forui/lib/src/localizations/localizations_el.dart b/forui/lib/src/localizations/localizations_el.dart index 0dcaf679c..9674a3297 100644 --- a/forui/lib/src/localizations/localizations_el.dart +++ b/forui/lib/src/localizations/localizations_el.dart @@ -50,4 +50,15 @@ class FLocalizationsEl extends FLocalizations { @override String get dialogLabel => 'Παράθυρο διαλόγου'; + + @override + String get sheetLabel => 'Φύλλο'; + + @override + String get barrierLabel => 'Επικάλυψη'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Κλείσιμο \$modalRouteContentName'; + } } diff --git a/forui/lib/src/localizations/localizations_en.dart b/forui/lib/src/localizations/localizations_en.dart index a96f68353..564ab36ca 100644 --- a/forui/lib/src/localizations/localizations_en.dart +++ b/forui/lib/src/localizations/localizations_en.dart @@ -50,6 +50,17 @@ class FLocalizationsEn extends FLocalizations { @override String get dialogLabel => 'Dialog'; + + @override + String get sheetLabel => 'Sheet'; + + @override + String get barrierLabel => 'Barrier'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Close $modalRouteContentName'; + } } /// The translations for English, as used in Australia (`en_AU`). @@ -58,6 +69,17 @@ class FLocalizationsEnAu extends FLocalizationsEn { @override String get dialogLabel => 'Dialogue'; + + @override + String get sheetLabel => 'Sheet'; + + @override + String get barrierLabel => 'Scrim'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Close \$modalRouteContentName'; + } } /// The translations for English, as used in Canada (`en_CA`). @@ -66,6 +88,17 @@ class FLocalizationsEnCa extends FLocalizationsEn { @override String get dialogLabel => 'Dialog'; + + @override + String get sheetLabel => 'Sheet'; + + @override + String get barrierLabel => 'Scrim'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Close \$modalRouteContentName'; + } } /// The translations for English, as used in the United Kingdom (`en_GB`). @@ -74,6 +107,17 @@ class FLocalizationsEnGb extends FLocalizationsEn { @override String get dialogLabel => 'Dialogue'; + + @override + String get sheetLabel => 'sheet'; + + @override + String get barrierLabel => 'Scrim'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Close \$modalRouteContentName'; + } } /// The translations for English, as used in Ireland (`en_IE`). @@ -82,6 +126,17 @@ class FLocalizationsEnIe extends FLocalizationsEn { @override String get dialogLabel => 'Dialogue'; + + @override + String get sheetLabel => 'sheet'; + + @override + String get barrierLabel => 'Scrim'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Close \$modalRouteContentName'; + } } /// The translations for English, as used in India (`en_IN`). @@ -90,6 +145,17 @@ class FLocalizationsEnIn extends FLocalizationsEn { @override String get dialogLabel => 'Dialogue'; + + @override + String get sheetLabel => 'sheet'; + + @override + String get barrierLabel => 'Scrim'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Close \$modalRouteContentName'; + } } /// The translations for English, as used in New Zealand (`en_NZ`). @@ -98,6 +164,17 @@ class FLocalizationsEnNz extends FLocalizationsEn { @override String get dialogLabel => 'Dialogue'; + + @override + String get sheetLabel => 'Sheet'; + + @override + String get barrierLabel => 'Scrim'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Close \$modalRouteContentName'; + } } /// The translations for English, as used in Singapore (`en_SG`). @@ -106,6 +183,17 @@ class FLocalizationsEnSg extends FLocalizationsEn { @override String get dialogLabel => 'Dialogue'; + + @override + String get sheetLabel => 'sheet'; + + @override + String get barrierLabel => 'Scrim'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Close \$modalRouteContentName'; + } } /// The translations for English, as used in South Africa (`en_ZA`). @@ -114,4 +202,15 @@ class FLocalizationsEnZa extends FLocalizationsEn { @override String get dialogLabel => 'Dialogue'; + + @override + String get sheetLabel => 'sheet'; + + @override + String get barrierLabel => 'Scrim'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Close \$modalRouteContentName'; + } } diff --git a/forui/lib/src/localizations/localizations_es.dart b/forui/lib/src/localizations/localizations_es.dart index 2782220f3..6853862c9 100644 --- a/forui/lib/src/localizations/localizations_es.dart +++ b/forui/lib/src/localizations/localizations_es.dart @@ -50,6 +50,17 @@ class FLocalizationsEs extends FLocalizations { @override String get dialogLabel => 'Cuadro de diálogo'; + + @override + String get sheetLabel => 'Hoja'; + + @override + String get barrierLabel => 'Sombreado'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Cerrar \$modalRouteContentName'; + } } /// The translations for Spanish Castilian, as used in Latin America and the Caribbean (`es_419`). @@ -58,6 +69,17 @@ class FLocalizationsEs419 extends FLocalizationsEs { @override String get dialogLabel => 'Diálogo'; + + @override + String get sheetLabel => 'Hoja'; + + @override + String get barrierLabel => 'Lámina'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Cerrar \$modalRouteContentName'; + } } /// The translations for Spanish Castilian, as used in Argentina (`es_AR`). @@ -66,6 +88,17 @@ class FLocalizationsEsAr extends FLocalizationsEs { @override String get dialogLabel => 'Diálogo'; + + @override + String get sheetLabel => 'Hoja'; + + @override + String get barrierLabel => 'Lámina'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Cerrar \$modalRouteContentName'; + } } /// The translations for Spanish Castilian, as used in Bolivia (`es_BO`). @@ -74,6 +107,17 @@ class FLocalizationsEsBo extends FLocalizationsEs { @override String get dialogLabel => 'Diálogo'; + + @override + String get sheetLabel => 'Hoja'; + + @override + String get barrierLabel => 'Lámina'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Cerrar \$modalRouteContentName'; + } } /// The translations for Spanish Castilian, as used in Chile (`es_CL`). @@ -82,6 +126,17 @@ class FLocalizationsEsCl extends FLocalizationsEs { @override String get dialogLabel => 'Diálogo'; + + @override + String get sheetLabel => 'Hoja'; + + @override + String get barrierLabel => 'Lámina'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Cerrar \$modalRouteContentName'; + } } /// The translations for Spanish Castilian, as used in Colombia (`es_CO`). @@ -90,6 +145,17 @@ class FLocalizationsEsCo extends FLocalizationsEs { @override String get dialogLabel => 'Diálogo'; + + @override + String get sheetLabel => 'Hoja'; + + @override + String get barrierLabel => 'Lámina'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Cerrar \$modalRouteContentName'; + } } /// The translations for Spanish Castilian, as used in Costa Rica (`es_CR`). @@ -98,6 +164,17 @@ class FLocalizationsEsCr extends FLocalizationsEs { @override String get dialogLabel => 'Diálogo'; + + @override + String get sheetLabel => 'Hoja'; + + @override + String get barrierLabel => 'Lámina'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Cerrar \$modalRouteContentName'; + } } /// The translations for Spanish Castilian, as used in the Dominican Republic (`es_DO`). @@ -106,6 +183,17 @@ class FLocalizationsEsDo extends FLocalizationsEs { @override String get dialogLabel => 'Diálogo'; + + @override + String get sheetLabel => 'Hoja'; + + @override + String get barrierLabel => 'Lámina'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Cerrar \$modalRouteContentName'; + } } /// The translations for Spanish Castilian, as used in Ecuador (`es_EC`). @@ -114,6 +202,17 @@ class FLocalizationsEsEc extends FLocalizationsEs { @override String get dialogLabel => 'Diálogo'; + + @override + String get sheetLabel => 'Hoja'; + + @override + String get barrierLabel => 'Lámina'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Cerrar \$modalRouteContentName'; + } } /// The translations for Spanish Castilian, as used in Guatemala (`es_GT`). @@ -122,6 +221,17 @@ class FLocalizationsEsGt extends FLocalizationsEs { @override String get dialogLabel => 'Diálogo'; + + @override + String get sheetLabel => 'Hoja'; + + @override + String get barrierLabel => 'Lámina'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Cerrar \$modalRouteContentName'; + } } /// The translations for Spanish Castilian, as used in Honduras (`es_HN`). @@ -130,6 +240,17 @@ class FLocalizationsEsHn extends FLocalizationsEs { @override String get dialogLabel => 'Diálogo'; + + @override + String get sheetLabel => 'Hoja'; + + @override + String get barrierLabel => 'Lámina'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Cerrar \$modalRouteContentName'; + } } /// The translations for Spanish Castilian, as used in Mexico (`es_MX`). @@ -138,6 +259,17 @@ class FLocalizationsEsMx extends FLocalizationsEs { @override String get dialogLabel => 'Diálogo'; + + @override + String get sheetLabel => 'Hoja'; + + @override + String get barrierLabel => 'Lámina'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Cerrar \$modalRouteContentName'; + } } /// The translations for Spanish Castilian, as used in Nicaragua (`es_NI`). @@ -146,6 +278,17 @@ class FLocalizationsEsNi extends FLocalizationsEs { @override String get dialogLabel => 'Diálogo'; + + @override + String get sheetLabel => 'Hoja'; + + @override + String get barrierLabel => 'Lámina'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Cerrar \$modalRouteContentName'; + } } /// The translations for Spanish Castilian, as used in Panama (`es_PA`). @@ -154,6 +297,17 @@ class FLocalizationsEsPa extends FLocalizationsEs { @override String get dialogLabel => 'Diálogo'; + + @override + String get sheetLabel => 'Hoja'; + + @override + String get barrierLabel => 'Lámina'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Cerrar \$modalRouteContentName'; + } } /// The translations for Spanish Castilian, as used in Peru (`es_PE`). @@ -162,6 +316,17 @@ class FLocalizationsEsPe extends FLocalizationsEs { @override String get dialogLabel => 'Diálogo'; + + @override + String get sheetLabel => 'Hoja'; + + @override + String get barrierLabel => 'Lámina'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Cerrar \$modalRouteContentName'; + } } /// The translations for Spanish Castilian, as used in Puerto Rico (`es_PR`). @@ -170,6 +335,17 @@ class FLocalizationsEsPr extends FLocalizationsEs { @override String get dialogLabel => 'Diálogo'; + + @override + String get sheetLabel => 'Hoja'; + + @override + String get barrierLabel => 'Lámina'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Cerrar \$modalRouteContentName'; + } } /// The translations for Spanish Castilian, as used in Paraguay (`es_PY`). @@ -178,6 +354,17 @@ class FLocalizationsEsPy extends FLocalizationsEs { @override String get dialogLabel => 'Diálogo'; + + @override + String get sheetLabel => 'inferior'; + + @override + String get barrierLabel => 'Lámina'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Cerrar \$modalRouteContentName'; + } } /// The translations for Spanish Castilian, as used in El Salvador (`es_SV`). @@ -186,6 +373,17 @@ class FLocalizationsEsSv extends FLocalizationsEs { @override String get dialogLabel => 'Diálogo'; + + @override + String get sheetLabel => 'Hoja'; + + @override + String get barrierLabel => 'Lámina'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Cerrar \$modalRouteContentName'; + } } /// The translations for Spanish Castilian, as used in the United States (`es_US`). @@ -194,6 +392,17 @@ class FLocalizationsEsUs extends FLocalizationsEs { @override String get dialogLabel => 'Diálogo'; + + @override + String get sheetLabel => 'Hoja'; + + @override + String get barrierLabel => 'Lámina'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Cerrar \$modalRouteContentName'; + } } /// The translations for Spanish Castilian, as used in Uruguay (`es_UY`). @@ -202,6 +411,17 @@ class FLocalizationsEsUy extends FLocalizationsEs { @override String get dialogLabel => 'Diálogo'; + + @override + String get sheetLabel => 'Hoja'; + + @override + String get barrierLabel => 'Lámina'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Cerrar \$modalRouteContentName'; + } } /// The translations for Spanish Castilian, as used in Venezuela (`es_VE`). @@ -210,4 +430,15 @@ class FLocalizationsEsVe extends FLocalizationsEs { @override String get dialogLabel => 'Diálogo'; + + @override + String get sheetLabel => 'Hoja'; + + @override + String get barrierLabel => 'Lámina'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Cerrar \$modalRouteContentName'; + } } diff --git a/forui/lib/src/localizations/localizations_et.dart b/forui/lib/src/localizations/localizations_et.dart index a11b8f356..6d2ff2be0 100644 --- a/forui/lib/src/localizations/localizations_et.dart +++ b/forui/lib/src/localizations/localizations_et.dart @@ -50,4 +50,15 @@ class FLocalizationsEt extends FLocalizations { @override String get dialogLabel => 'Dialoog'; + + @override + String get sheetLabel => 'leht'; + + @override + String get barrierLabel => 'Sirm'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Sule \$modalRouteContentName'; + } } diff --git a/forui/lib/src/localizations/localizations_eu.dart b/forui/lib/src/localizations/localizations_eu.dart index 6a9878501..eb4c2daf8 100644 --- a/forui/lib/src/localizations/localizations_eu.dart +++ b/forui/lib/src/localizations/localizations_eu.dart @@ -50,4 +50,15 @@ class FLocalizationsEu extends FLocalizations { @override String get dialogLabel => 'Leihoa'; + + @override + String get sheetLabel => 'orria'; + + @override + String get barrierLabel => 'Barrera'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Itxi \$modalRouteContentName'; + } } diff --git a/forui/lib/src/localizations/localizations_fa.dart b/forui/lib/src/localizations/localizations_fa.dart index bace9f316..ae9653df0 100644 --- a/forui/lib/src/localizations/localizations_fa.dart +++ b/forui/lib/src/localizations/localizations_fa.dart @@ -50,4 +50,15 @@ class FLocalizationsFa extends FLocalizations { @override String get dialogLabel => 'کادر گفتگو'; + + @override + String get sheetLabel => 'برگ'; + + @override + String get barrierLabel => 'رویه'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'بستن \$modalRouteContentName'; + } } diff --git a/forui/lib/src/localizations/localizations_fi.dart b/forui/lib/src/localizations/localizations_fi.dart index fb758c63a..bef0bdb7f 100644 --- a/forui/lib/src/localizations/localizations_fi.dart +++ b/forui/lib/src/localizations/localizations_fi.dart @@ -50,4 +50,15 @@ class FLocalizationsFi extends FLocalizations { @override String get dialogLabel => 'Valintaikkuna'; + + @override + String get sheetLabel => 'arkki'; + + @override + String get barrierLabel => 'Sermi'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Sulje \$modalRouteContentName'; + } } diff --git a/forui/lib/src/localizations/localizations_fil.dart b/forui/lib/src/localizations/localizations_fil.dart index 967b8612b..35b01a9f7 100644 --- a/forui/lib/src/localizations/localizations_fil.dart +++ b/forui/lib/src/localizations/localizations_fil.dart @@ -50,4 +50,15 @@ class FLocalizationsFil extends FLocalizations { @override String get dialogLabel => 'Dialog'; + + @override + String get sheetLabel => 'sheet'; + + @override + String get barrierLabel => 'Scrim'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Isara ang \$modalRouteContentName'; + } } diff --git a/forui/lib/src/localizations/localizations_fr.dart b/forui/lib/src/localizations/localizations_fr.dart index 1860d97df..f17460216 100644 --- a/forui/lib/src/localizations/localizations_fr.dart +++ b/forui/lib/src/localizations/localizations_fr.dart @@ -50,6 +50,17 @@ class FLocalizationsFr extends FLocalizations { @override String get dialogLabel => 'Boîte de dialogue'; + + @override + String get sheetLabel => 'sheet'; + + @override + String get barrierLabel => 'Fond'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Fermer \$modalRouteContentName'; + } } /// The translations for French, as used in Canada (`fr_CA`). @@ -58,4 +69,15 @@ class FLocalizationsFrCa extends FLocalizationsFr { @override String get dialogLabel => 'Boîte de dialogue'; + + @override + String get sheetLabel => 'Zone de contenu'; + + @override + String get barrierLabel => 'Grille'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Fermer \$modalRouteContentName'; + } } diff --git a/forui/lib/src/localizations/localizations_gl.dart b/forui/lib/src/localizations/localizations_gl.dart index 8b1e9df55..95287d153 100644 --- a/forui/lib/src/localizations/localizations_gl.dart +++ b/forui/lib/src/localizations/localizations_gl.dart @@ -50,4 +50,15 @@ class FLocalizationsGl extends FLocalizations { @override String get dialogLabel => 'Cadro de diálogo'; + + @override + String get sheetLabel => 'Panel'; + + @override + String get barrierLabel => 'Sombreado'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Pechar \$modalRouteContentName'; + } } diff --git a/forui/lib/src/localizations/localizations_gsw.dart b/forui/lib/src/localizations/localizations_gsw.dart index 65c7cb7da..f79e466cf 100644 --- a/forui/lib/src/localizations/localizations_gsw.dart +++ b/forui/lib/src/localizations/localizations_gsw.dart @@ -50,4 +50,15 @@ class FLocalizationsGsw extends FLocalizations { @override String get dialogLabel => 'Dialogfeld'; + + @override + String get sheetLabel => 'Ansicht'; + + @override + String get barrierLabel => 'Gitter'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return '\$modalRouteContentName schließen'; + } } diff --git a/forui/lib/src/localizations/localizations_gu.dart b/forui/lib/src/localizations/localizations_gu.dart index 83d0259f9..c2dd39aa0 100644 --- a/forui/lib/src/localizations/localizations_gu.dart +++ b/forui/lib/src/localizations/localizations_gu.dart @@ -50,4 +50,15 @@ class FLocalizationsGu extends FLocalizations { @override String get dialogLabel => 'સંવાદ'; + + @override + String get sheetLabel => 'શીટ'; + + @override + String get barrierLabel => 'સ્ક્રિમ'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return '\$modalRouteContentNameને બંધ કરો'; + } } diff --git a/forui/lib/src/localizations/localizations_he.dart b/forui/lib/src/localizations/localizations_he.dart index e16fdcdc5..68f56a624 100644 --- a/forui/lib/src/localizations/localizations_he.dart +++ b/forui/lib/src/localizations/localizations_he.dart @@ -50,4 +50,15 @@ class FLocalizationsHe extends FLocalizations { @override String get dialogLabel => 'תיבת דו-שיח'; + + @override + String get sheetLabel => 'גיליו '; + + @override + String get barrierLabel => 'מיסוך'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'סגירת \$modalRouteContentName'; + } } diff --git a/forui/lib/src/localizations/localizations_hi.dart b/forui/lib/src/localizations/localizations_hi.dart index 752bd4eef..dde3069a0 100644 --- a/forui/lib/src/localizations/localizations_hi.dart +++ b/forui/lib/src/localizations/localizations_hi.dart @@ -50,4 +50,15 @@ class FLocalizationsHi extends FLocalizations { @override String get dialogLabel => 'डायलॉग'; + + @override + String get sheetLabel => 'शीट'; + + @override + String get barrierLabel => 'स्क्रिम'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return '\$modalRouteContentName को बंद करें'; + } } diff --git a/forui/lib/src/localizations/localizations_hr.dart b/forui/lib/src/localizations/localizations_hr.dart index fe0d82253..c904fdebe 100644 --- a/forui/lib/src/localizations/localizations_hr.dart +++ b/forui/lib/src/localizations/localizations_hr.dart @@ -50,4 +50,15 @@ class FLocalizationsHr extends FLocalizations { @override String get dialogLabel => 'Dijalog'; + + @override + String get sheetLabel => 'tablica'; + + @override + String get barrierLabel => 'Rubno'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Zatvori \$modalRouteContentName'; + } } diff --git a/forui/lib/src/localizations/localizations_hu.dart b/forui/lib/src/localizations/localizations_hu.dart index 58af6960f..97e471dfb 100644 --- a/forui/lib/src/localizations/localizations_hu.dart +++ b/forui/lib/src/localizations/localizations_hu.dart @@ -50,4 +50,15 @@ class FLocalizationsHu extends FLocalizations { @override String get dialogLabel => 'Párbeszédablak'; + + @override + String get sheetLabel => 'lap'; + + @override + String get barrierLabel => 'Borítás'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return '\$modalRouteContentName bezárása'; + } } diff --git a/forui/lib/src/localizations/localizations_hy.dart b/forui/lib/src/localizations/localizations_hy.dart index 40d8beb6f..6c6b8bc15 100644 --- a/forui/lib/src/localizations/localizations_hy.dart +++ b/forui/lib/src/localizations/localizations_hy.dart @@ -50,4 +50,15 @@ class FLocalizationsHy extends FLocalizations { @override String get dialogLabel => 'Երկխոսության պատուհան'; + + @override + String get sheetLabel => 'էկրան'; + + @override + String get barrierLabel => 'Դիմակ'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Փակել՝ \$modalRouteContentName'; + } } diff --git a/forui/lib/src/localizations/localizations_id.dart b/forui/lib/src/localizations/localizations_id.dart index 7fa8e079a..7a0d121dd 100644 --- a/forui/lib/src/localizations/localizations_id.dart +++ b/forui/lib/src/localizations/localizations_id.dart @@ -50,4 +50,15 @@ class FLocalizationsId extends FLocalizations { @override String get dialogLabel => 'Dialog'; + + @override + String get sheetLabel => 'Sheet'; + + @override + String get barrierLabel => 'Scrim'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Tutup \$modalRouteContentName'; + } } diff --git a/forui/lib/src/localizations/localizations_is.dart b/forui/lib/src/localizations/localizations_is.dart index 62614947e..166bdf2f3 100644 --- a/forui/lib/src/localizations/localizations_is.dart +++ b/forui/lib/src/localizations/localizations_is.dart @@ -50,4 +50,15 @@ class FLocalizationsIs extends FLocalizations { @override String get dialogLabel => 'Gluggi'; + + @override + String get sheetLabel => 'Blað'; + + @override + String get barrierLabel => 'Möskvi'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Loka \$modalRouteContentName'; + } } diff --git a/forui/lib/src/localizations/localizations_it.dart b/forui/lib/src/localizations/localizations_it.dart index 99b51163a..f239f7b88 100644 --- a/forui/lib/src/localizations/localizations_it.dart +++ b/forui/lib/src/localizations/localizations_it.dart @@ -50,4 +50,15 @@ class FLocalizationsIt extends FLocalizations { @override String get dialogLabel => 'Finestra di dialogo'; + + @override + String get sheetLabel => 'Riquadro'; + + @override + String get barrierLabel => 'Rete'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Chiudi \$modalRouteContentName'; + } } diff --git a/forui/lib/src/localizations/localizations_ja.dart b/forui/lib/src/localizations/localizations_ja.dart index 03c3ae453..10e0c7cc6 100644 --- a/forui/lib/src/localizations/localizations_ja.dart +++ b/forui/lib/src/localizations/localizations_ja.dart @@ -50,4 +50,15 @@ class FLocalizationsJa extends FLocalizations { @override String get dialogLabel => 'ダイアログ'; + + @override + String get sheetLabel => 'シート'; + + @override + String get barrierLabel => 'スクリム'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return '\$modalRouteContentName を閉じる'; + } } diff --git a/forui/lib/src/localizations/localizations_ka.dart b/forui/lib/src/localizations/localizations_ka.dart index 044ffcd23..280ee28c4 100644 --- a/forui/lib/src/localizations/localizations_ka.dart +++ b/forui/lib/src/localizations/localizations_ka.dart @@ -50,4 +50,15 @@ class FLocalizationsKa extends FLocalizations { @override String get dialogLabel => 'დიალოგი'; + + @override + String get sheetLabel => 'ფურცელი'; + + @override + String get barrierLabel => 'სკრიმი'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return '\$modalRouteContentName-ის დახურვა'; + } } diff --git a/forui/lib/src/localizations/localizations_kk.dart b/forui/lib/src/localizations/localizations_kk.dart index b086439a5..3592220b1 100644 --- a/forui/lib/src/localizations/localizations_kk.dart +++ b/forui/lib/src/localizations/localizations_kk.dart @@ -50,4 +50,15 @@ class FLocalizationsKk extends FLocalizations { @override String get dialogLabel => 'Диалогтық терезе'; + + @override + String get sheetLabel => 'парақша'; + + @override + String get barrierLabel => 'Кенеп'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return '\$modalRouteContentName жабу'; + } } diff --git a/forui/lib/src/localizations/localizations_km.dart b/forui/lib/src/localizations/localizations_km.dart index 12d84310d..eaf0482bf 100644 --- a/forui/lib/src/localizations/localizations_km.dart +++ b/forui/lib/src/localizations/localizations_km.dart @@ -50,4 +50,15 @@ class FLocalizationsKm extends FLocalizations { @override String get dialogLabel => 'ប្រអប់'; + + @override + String get sheetLabel => 'សន្លឹក'; + + @override + String get barrierLabel => 'ផ្ទាំងស្រអាប់'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'បិទ \$modalRouteContentName'; + } } diff --git a/forui/lib/src/localizations/localizations_kn.dart b/forui/lib/src/localizations/localizations_kn.dart index 986c68ffd..9c5e542b2 100644 --- a/forui/lib/src/localizations/localizations_kn.dart +++ b/forui/lib/src/localizations/localizations_kn.dart @@ -50,4 +50,15 @@ class FLocalizationsKn extends FLocalizations { @override String get dialogLabel => 'ಡೈಲಾಗ್'; + + @override + String get sheetLabel => 'ಶೀಟ್'; + + @override + String get barrierLabel => 'ಸ್ಕ್ರಿಮ್'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return '\$modalRouteContentName ಅನ್ನು ಮುಚ್ಚಿರಿ'; + } } diff --git a/forui/lib/src/localizations/localizations_ko.dart b/forui/lib/src/localizations/localizations_ko.dart index 17189f89b..ffa94e4f5 100644 --- a/forui/lib/src/localizations/localizations_ko.dart +++ b/forui/lib/src/localizations/localizations_ko.dart @@ -50,4 +50,15 @@ class FLocalizationsKo extends FLocalizations { @override String get dialogLabel => '대화상자'; + + @override + String get sheetLabel => '시트'; + + @override + String get barrierLabel => '스크림'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return '\$modalRouteContentName 닫기'; + } } diff --git a/forui/lib/src/localizations/localizations_ky.dart b/forui/lib/src/localizations/localizations_ky.dart index 7626f7c70..2218f204c 100644 --- a/forui/lib/src/localizations/localizations_ky.dart +++ b/forui/lib/src/localizations/localizations_ky.dart @@ -50,4 +50,15 @@ class FLocalizationsKy extends FLocalizations { @override String get dialogLabel => 'Диалог'; + + @override + String get sheetLabel => 'экран'; + + @override + String get barrierLabel => 'Кенеп'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return '\$modalRouteContentName жабуу'; + } } diff --git a/forui/lib/src/localizations/localizations_lo.dart b/forui/lib/src/localizations/localizations_lo.dart index bb22d2b92..d51a2048e 100644 --- a/forui/lib/src/localizations/localizations_lo.dart +++ b/forui/lib/src/localizations/localizations_lo.dart @@ -50,4 +50,15 @@ class FLocalizationsLo extends FLocalizations { @override String get dialogLabel => 'ຂໍ້ຄວາມ'; + + @override + String get sheetLabel => 'ແຜ່ນ'; + + @override + String get barrierLabel => 'Scrim'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'ປິດ \$modalRouteContentName'; + } } diff --git a/forui/lib/src/localizations/localizations_lt.dart b/forui/lib/src/localizations/localizations_lt.dart index 47aa8b68e..647304bdd 100644 --- a/forui/lib/src/localizations/localizations_lt.dart +++ b/forui/lib/src/localizations/localizations_lt.dart @@ -50,4 +50,15 @@ class FLocalizationsLt extends FLocalizations { @override String get dialogLabel => 'Dialogo langas'; + + @override + String get sheetLabel => 'lapas'; + + @override + String get barrierLabel => 'Užsklanda'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Uždaryti „\$modalRouteContentName“'; + } } diff --git a/forui/lib/src/localizations/localizations_lv.dart b/forui/lib/src/localizations/localizations_lv.dart index ac757bc50..b1e35cdee 100644 --- a/forui/lib/src/localizations/localizations_lv.dart +++ b/forui/lib/src/localizations/localizations_lv.dart @@ -50,4 +50,15 @@ class FLocalizationsLv extends FLocalizations { @override String get dialogLabel => 'Dialoglodziņš'; + + @override + String get sheetLabel => 'lapa'; + + @override + String get barrierLabel => 'Pārklājums'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Aizvērt \$modalRouteContentName'; + } } diff --git a/forui/lib/src/localizations/localizations_mk.dart b/forui/lib/src/localizations/localizations_mk.dart index 8fc8cc6ed..b46e0a497 100644 --- a/forui/lib/src/localizations/localizations_mk.dart +++ b/forui/lib/src/localizations/localizations_mk.dart @@ -50,4 +50,15 @@ class FLocalizationsMk extends FLocalizations { @override String get dialogLabel => 'Дијалог'; + + @override + String get sheetLabel => 'лист'; + + @override + String get barrierLabel => 'Скрим'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Затворете ја \$modalRouteContentName'; + } } diff --git a/forui/lib/src/localizations/localizations_ml.dart b/forui/lib/src/localizations/localizations_ml.dart index bc788a6e3..67847c804 100644 --- a/forui/lib/src/localizations/localizations_ml.dart +++ b/forui/lib/src/localizations/localizations_ml.dart @@ -50,4 +50,15 @@ class FLocalizationsMl extends FLocalizations { @override String get dialogLabel => 'ഡയലോഗ്'; + + @override + String get sheetLabel => 'ഷീറ്റ്'; + + @override + String get barrierLabel => 'സ്ക്രിം'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return '\$modalRouteContentName അടയ്ക്കുക'; + } } diff --git a/forui/lib/src/localizations/localizations_mn.dart b/forui/lib/src/localizations/localizations_mn.dart index 4e59419a8..58c9a96ed 100644 --- a/forui/lib/src/localizations/localizations_mn.dart +++ b/forui/lib/src/localizations/localizations_mn.dart @@ -50,4 +50,15 @@ class FLocalizationsMn extends FLocalizations { @override String get dialogLabel => 'Харилцах цонх'; + + @override + String get sheetLabel => 'хүснэгт'; + + @override + String get barrierLabel => 'Скрим'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return '\$modalRouteContentName-г хаах'; + } } diff --git a/forui/lib/src/localizations/localizations_mr.dart b/forui/lib/src/localizations/localizations_mr.dart index 07d3709d9..87daea5c3 100644 --- a/forui/lib/src/localizations/localizations_mr.dart +++ b/forui/lib/src/localizations/localizations_mr.dart @@ -50,4 +50,15 @@ class FLocalizationsMr extends FLocalizations { @override String get dialogLabel => 'डायलॉग'; + + @override + String get sheetLabel => 'शीट'; + + @override + String get barrierLabel => 'स्क्रिम'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return '\$modalRouteContentName बंद करा'; + } } diff --git a/forui/lib/src/localizations/localizations_ms.dart b/forui/lib/src/localizations/localizations_ms.dart index b8004dc82..1bdcb45c2 100644 --- a/forui/lib/src/localizations/localizations_ms.dart +++ b/forui/lib/src/localizations/localizations_ms.dart @@ -50,4 +50,15 @@ class FLocalizationsMs extends FLocalizations { @override String get dialogLabel => 'Dialog'; + + @override + String get sheetLabel => 'Helaian'; + + @override + String get barrierLabel => 'Scrim'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Tutup \$modalRouteContentName'; + } } diff --git a/forui/lib/src/localizations/localizations_my.dart b/forui/lib/src/localizations/localizations_my.dart index c152bf823..575c1a8a5 100644 --- a/forui/lib/src/localizations/localizations_my.dart +++ b/forui/lib/src/localizations/localizations_my.dart @@ -50,4 +50,15 @@ class FLocalizationsMy extends FLocalizations { @override String get dialogLabel => 'ဒိုင်ယာလော့'; + + @override + String get sheetLabel => 'ပိုဆောင်း စာမျက်နှာ'; + + @override + String get barrierLabel => 'Scrim'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return '\$modalRouteContentName ပိတ်ရန်'; + } } diff --git a/forui/lib/src/localizations/localizations_nb.dart b/forui/lib/src/localizations/localizations_nb.dart index 22b721deb..5bf29f917 100644 --- a/forui/lib/src/localizations/localizations_nb.dart +++ b/forui/lib/src/localizations/localizations_nb.dart @@ -50,4 +50,15 @@ class FLocalizationsNb extends FLocalizations { @override String get dialogLabel => 'Dialogboks'; + + @override + String get sheetLabel => 'Felt'; + + @override + String get barrierLabel => 'Vev'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Lukk \$modalRouteContentName'; + } } diff --git a/forui/lib/src/localizations/localizations_ne.dart b/forui/lib/src/localizations/localizations_ne.dart index 3112d7312..d975d8041 100644 --- a/forui/lib/src/localizations/localizations_ne.dart +++ b/forui/lib/src/localizations/localizations_ne.dart @@ -50,4 +50,15 @@ class FLocalizationsNe extends FLocalizations { @override String get dialogLabel => 'संवाद'; + + @override + String get sheetLabel => 'पाना'; + + @override + String get barrierLabel => 'स्क्रिम'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return '\$modalRouteContentName बन्द गर्नुहोस्'; + } } diff --git a/forui/lib/src/localizations/localizations_nl.dart b/forui/lib/src/localizations/localizations_nl.dart index 0df6bddba..f829a652b 100644 --- a/forui/lib/src/localizations/localizations_nl.dart +++ b/forui/lib/src/localizations/localizations_nl.dart @@ -50,4 +50,15 @@ class FLocalizationsNl extends FLocalizations { @override String get dialogLabel => 'Dialoogvenster'; + + @override + String get sheetLabel => 'Blad'; + + @override + String get barrierLabel => 'Scrim'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return '\$modalRouteContentName sluiten'; + } } diff --git a/forui/lib/src/localizations/localizations_no.dart b/forui/lib/src/localizations/localizations_no.dart index 266f6acc7..a16015a97 100644 --- a/forui/lib/src/localizations/localizations_no.dart +++ b/forui/lib/src/localizations/localizations_no.dart @@ -50,4 +50,15 @@ class FLocalizationsNo extends FLocalizations { @override String get dialogLabel => 'Dialogboks'; + + @override + String get sheetLabel => 'Felt'; + + @override + String get barrierLabel => 'Vev'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Lukk \$modalRouteContentName'; + } } diff --git a/forui/lib/src/localizations/localizations_or.dart b/forui/lib/src/localizations/localizations_or.dart index cf703b6e2..d895b8d5e 100644 --- a/forui/lib/src/localizations/localizations_or.dart +++ b/forui/lib/src/localizations/localizations_or.dart @@ -50,4 +50,15 @@ class FLocalizationsOr extends FLocalizations { @override String get dialogLabel => 'ଡାୟଲଗ୍'; + + @override + String get sheetLabel => 'ସିଟ'; + + @override + String get barrierLabel => 'ସ୍କ୍ରିମ'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return '\$modalRouteContentNameକୁ ବନ୍ଦ କରନ୍ତୁ'; + } } diff --git a/forui/lib/src/localizations/localizations_pa.dart b/forui/lib/src/localizations/localizations_pa.dart index bdc0d7e5c..944a6d451 100644 --- a/forui/lib/src/localizations/localizations_pa.dart +++ b/forui/lib/src/localizations/localizations_pa.dart @@ -50,4 +50,15 @@ class FLocalizationsPa extends FLocalizations { @override String get dialogLabel => 'ਵਿੰਡੋ'; + + @override + String get sheetLabel => 'ਸ਼ੀਟ'; + + @override + String get barrierLabel => 'ਸਕ੍ਰਿਮ'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return '\$modalRouteContentName ਨੂੰ ਬੰਦ ਕਰੋ'; + } } diff --git a/forui/lib/src/localizations/localizations_pl.dart b/forui/lib/src/localizations/localizations_pl.dart index c387ab7cd..b11dab5aa 100644 --- a/forui/lib/src/localizations/localizations_pl.dart +++ b/forui/lib/src/localizations/localizations_pl.dart @@ -50,4 +50,15 @@ class FLocalizationsPl extends FLocalizations { @override String get dialogLabel => 'Okno dialogowe'; + + @override + String get sheetLabel => 'Plansza'; + + @override + String get barrierLabel => 'Siatka'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Zamknij: \$modalRouteContentName'; + } } diff --git a/forui/lib/src/localizations/localizations_ps.dart b/forui/lib/src/localizations/localizations_ps.dart index f4456edd4..070ae95c3 100644 --- a/forui/lib/src/localizations/localizations_ps.dart +++ b/forui/lib/src/localizations/localizations_ps.dart @@ -50,4 +50,15 @@ class FLocalizationsPs extends FLocalizations { @override String get dialogLabel => 'خبرې اترې'; + + @override + String get sheetLabel => 'Sheet'; + + @override + String get barrierLabel => 'Scrim'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Close \$modalRouteName'; + } } diff --git a/forui/lib/src/localizations/localizations_pt.dart b/forui/lib/src/localizations/localizations_pt.dart index e61975d3d..94fc7dcda 100644 --- a/forui/lib/src/localizations/localizations_pt.dart +++ b/forui/lib/src/localizations/localizations_pt.dart @@ -50,6 +50,17 @@ class FLocalizationsPt extends FLocalizations { @override String get dialogLabel => 'Caixa de diálogo'; + + @override + String get sheetLabel => 'inferior'; + + @override + String get barrierLabel => 'Scrim'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Fechar \$modalRouteContentName'; + } } /// The translations for Portuguese, as used in Portugal (`pt_PT`). @@ -58,4 +69,15 @@ class FLocalizationsPtPt extends FLocalizationsPt { @override String get dialogLabel => 'Caixa de diálogo'; + + @override + String get sheetLabel => 'Secção'; + + @override + String get barrierLabel => 'Scrim'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Fechar \$modalRouteContentName'; + } } diff --git a/forui/lib/src/localizations/localizations_ro.dart b/forui/lib/src/localizations/localizations_ro.dart index 0c751722c..24bf13299 100644 --- a/forui/lib/src/localizations/localizations_ro.dart +++ b/forui/lib/src/localizations/localizations_ro.dart @@ -50,4 +50,15 @@ class FLocalizationsRo extends FLocalizations { @override String get dialogLabel => 'Casetă de dialog'; + + @override + String get sheetLabel => 'Foaie'; + + @override + String get barrierLabel => 'Material'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Închideți \$modalRouteContentName'; + } } diff --git a/forui/lib/src/localizations/localizations_ru.dart b/forui/lib/src/localizations/localizations_ru.dart index cf65500e8..8670f349f 100644 --- a/forui/lib/src/localizations/localizations_ru.dart +++ b/forui/lib/src/localizations/localizations_ru.dart @@ -50,4 +50,15 @@ class FLocalizationsRu extends FLocalizations { @override String get dialogLabel => 'Диалоговое окно'; + + @override + String get sheetLabel => 'экран'; + + @override + String get barrierLabel => 'Маска'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Закрыть \$modalRouteContentName'; + } } diff --git a/forui/lib/src/localizations/localizations_si.dart b/forui/lib/src/localizations/localizations_si.dart index ed705d34a..51abd75c6 100644 --- a/forui/lib/src/localizations/localizations_si.dart +++ b/forui/lib/src/localizations/localizations_si.dart @@ -50,4 +50,15 @@ class FLocalizationsSi extends FLocalizations { @override String get dialogLabel => 'සංවාදය'; + + @override + String get sheetLabel => 'පත්‍රය'; + + @override + String get barrierLabel => 'ස්ක්‍රිම්'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return '\$modalRouteContentName වසන්න'; + } } diff --git a/forui/lib/src/localizations/localizations_sk.dart b/forui/lib/src/localizations/localizations_sk.dart index de66737bf..4d6065148 100644 --- a/forui/lib/src/localizations/localizations_sk.dart +++ b/forui/lib/src/localizations/localizations_sk.dart @@ -50,4 +50,15 @@ class FLocalizationsSk extends FLocalizations { @override String get dialogLabel => 'Dialógové okno'; + + @override + String get sheetLabel => 'hárok'; + + @override + String get barrierLabel => 'Scrim'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Zavrieť \$modalRouteContentName'; + } } diff --git a/forui/lib/src/localizations/localizations_sl.dart b/forui/lib/src/localizations/localizations_sl.dart index f1ff399a0..e7cbba291 100644 --- a/forui/lib/src/localizations/localizations_sl.dart +++ b/forui/lib/src/localizations/localizations_sl.dart @@ -50,4 +50,15 @@ class FLocalizationsSl extends FLocalizations { @override String get dialogLabel => 'Pogovorno okno'; + + @override + String get sheetLabel => 'Razdelek'; + + @override + String get barrierLabel => 'Scrim'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Zapiranje »\$modalRouteContentName«'; + } } diff --git a/forui/lib/src/localizations/localizations_sq.dart b/forui/lib/src/localizations/localizations_sq.dart index 986b49ecf..d789133b8 100644 --- a/forui/lib/src/localizations/localizations_sq.dart +++ b/forui/lib/src/localizations/localizations_sq.dart @@ -50,4 +50,15 @@ class FLocalizationsSq extends FLocalizations { @override String get dialogLabel => 'Dialogu'; + + @override + String get sheetLabel => 'Fleta'; + + @override + String get barrierLabel => 'Kanavacë'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Mbyll \$modalRouteContentName'; + } } diff --git a/forui/lib/src/localizations/localizations_sr.dart b/forui/lib/src/localizations/localizations_sr.dart index 9a32890ec..8a1fec626 100644 --- a/forui/lib/src/localizations/localizations_sr.dart +++ b/forui/lib/src/localizations/localizations_sr.dart @@ -50,6 +50,17 @@ class FLocalizationsSr extends FLocalizations { @override String get dialogLabel => 'Дијалог'; + + @override + String get sheetLabel => 'табела'; + + @override + String get barrierLabel => 'Скрим'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Затвори: \$modalRouteContentName'; + } } /// The translations for Serbian, using the Latin script (`sr_Latn`). @@ -58,4 +69,15 @@ class FLocalizationsSrLatn extends FLocalizationsSr { @override String get dialogLabel => 'Dijalog'; + + @override + String get sheetLabel => 'tabela'; + + @override + String get barrierLabel => 'Skrim'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Zatvori: \$modalRouteContentName'; + } } diff --git a/forui/lib/src/localizations/localizations_sv.dart b/forui/lib/src/localizations/localizations_sv.dart index 1598e424b..34c45e910 100644 --- a/forui/lib/src/localizations/localizations_sv.dart +++ b/forui/lib/src/localizations/localizations_sv.dart @@ -50,4 +50,15 @@ class FLocalizationsSv extends FLocalizations { @override String get dialogLabel => 'Dialogruta'; + + @override + String get sheetLabel => 'Ark'; + + @override + String get barrierLabel => 'Scrim'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Stäng \$modalRouteContentName'; + } } diff --git a/forui/lib/src/localizations/localizations_sw.dart b/forui/lib/src/localizations/localizations_sw.dart index 7954e8a91..6f9d30bbe 100644 --- a/forui/lib/src/localizations/localizations_sw.dart +++ b/forui/lib/src/localizations/localizations_sw.dart @@ -50,4 +50,15 @@ class FLocalizationsSw extends FLocalizations { @override String get dialogLabel => 'Kidirisha'; + + @override + String get sheetLabel => 'Safu'; + + @override + String get barrierLabel => 'Scrim'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Funga \$modalRouteContentName'; + } } diff --git a/forui/lib/src/localizations/localizations_ta.dart b/forui/lib/src/localizations/localizations_ta.dart index 8bbf465b5..30012c468 100644 --- a/forui/lib/src/localizations/localizations_ta.dart +++ b/forui/lib/src/localizations/localizations_ta.dart @@ -50,4 +50,15 @@ class FLocalizationsTa extends FLocalizations { @override String get dialogLabel => 'உரையாடல்'; + + @override + String get sheetLabel => 'திரை'; + + @override + String get barrierLabel => 'ஸ்க்ரிம்'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return '\$modalRouteContentName ஐ மூடுக'; + } } diff --git a/forui/lib/src/localizations/localizations_te.dart b/forui/lib/src/localizations/localizations_te.dart index 130312c52..fcfe5999b 100644 --- a/forui/lib/src/localizations/localizations_te.dart +++ b/forui/lib/src/localizations/localizations_te.dart @@ -50,4 +50,15 @@ class FLocalizationsTe extends FLocalizations { @override String get dialogLabel => 'డైలాగ్'; + + @override + String get sheetLabel => 'షీట్'; + + @override + String get barrierLabel => 'స్క్రిమ్'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return '\$modalRouteContentName‌ను మూసివేయండి'; + } } diff --git a/forui/lib/src/localizations/localizations_th.dart b/forui/lib/src/localizations/localizations_th.dart index 2a29b194b..795e48bd1 100644 --- a/forui/lib/src/localizations/localizations_th.dart +++ b/forui/lib/src/localizations/localizations_th.dart @@ -50,4 +50,15 @@ class FLocalizationsTh extends FLocalizations { @override String get dialogLabel => 'กล่องโต้ตอบ'; + + @override + String get sheetLabel => 'Sheet'; + + @override + String get barrierLabel => 'Scrim'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'ปิด \$modalRouteContentName'; + } } diff --git a/forui/lib/src/localizations/localizations_tl.dart b/forui/lib/src/localizations/localizations_tl.dart index fc4b811ba..ab780dc26 100644 --- a/forui/lib/src/localizations/localizations_tl.dart +++ b/forui/lib/src/localizations/localizations_tl.dart @@ -50,4 +50,15 @@ class FLocalizationsTl extends FLocalizations { @override String get dialogLabel => 'Dialog'; + + @override + String get sheetLabel => 'sheet'; + + @override + String get barrierLabel => 'Scrim'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Isara ang \$modalRouteContentName'; + } } diff --git a/forui/lib/src/localizations/localizations_tr.dart b/forui/lib/src/localizations/localizations_tr.dart index cdb6c6095..384fc1dc1 100644 --- a/forui/lib/src/localizations/localizations_tr.dart +++ b/forui/lib/src/localizations/localizations_tr.dart @@ -50,4 +50,15 @@ class FLocalizationsTr extends FLocalizations { @override String get dialogLabel => 'İletişim kutusu'; + + @override + String get sheetLabel => 'sayfa'; + + @override + String get barrierLabel => 'opaklık katmanı'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return '\$modalRouteContentName içeriğini kapat'; + } } diff --git a/forui/lib/src/localizations/localizations_uk.dart b/forui/lib/src/localizations/localizations_uk.dart index 65525a65f..48ab856f3 100644 --- a/forui/lib/src/localizations/localizations_uk.dart +++ b/forui/lib/src/localizations/localizations_uk.dart @@ -50,4 +50,15 @@ class FLocalizationsUk extends FLocalizations { @override String get dialogLabel => 'Вікно'; + + @override + String get sheetLabel => 'екран'; + + @override + String get barrierLabel => 'Маскувальний фон'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Закрити: \$modalRouteContentName'; + } } diff --git a/forui/lib/src/localizations/localizations_ur.dart b/forui/lib/src/localizations/localizations_ur.dart index 1b2460f10..8b0cb7c1c 100644 --- a/forui/lib/src/localizations/localizations_ur.dart +++ b/forui/lib/src/localizations/localizations_ur.dart @@ -50,4 +50,15 @@ class FLocalizationsUr extends FLocalizations { @override String get dialogLabel => 'ڈائلاگ'; + + @override + String get sheetLabel => 'شیٹ'; + + @override + String get barrierLabel => 'اسکریم'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return '\$modalRouteContentName بند کریں'; + } } diff --git a/forui/lib/src/localizations/localizations_uz.dart b/forui/lib/src/localizations/localizations_uz.dart index 4c411f57b..cff824125 100644 --- a/forui/lib/src/localizations/localizations_uz.dart +++ b/forui/lib/src/localizations/localizations_uz.dart @@ -50,4 +50,15 @@ class FLocalizationsUz extends FLocalizations { @override String get dialogLabel => 'Muloqot oynasi'; + + @override + String get sheetLabel => 'ekran'; + + @override + String get barrierLabel => 'Kanop'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Yopish: \$modalRouteContentName'; + } } diff --git a/forui/lib/src/localizations/localizations_vi.dart b/forui/lib/src/localizations/localizations_vi.dart index 58d001f8d..c6193244e 100644 --- a/forui/lib/src/localizations/localizations_vi.dart +++ b/forui/lib/src/localizations/localizations_vi.dart @@ -50,4 +50,15 @@ class FLocalizationsVi extends FLocalizations { @override String get dialogLabel => 'Hộp thoại'; + + @override + String get sheetLabel => 'Bảng'; + + @override + String get barrierLabel => 'Scrim'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Đóng \$modalRouteContentName'; + } } diff --git a/forui/lib/src/localizations/localizations_zh.dart b/forui/lib/src/localizations/localizations_zh.dart index 35186c86d..54636ff42 100644 --- a/forui/lib/src/localizations/localizations_zh.dart +++ b/forui/lib/src/localizations/localizations_zh.dart @@ -50,6 +50,17 @@ class FLocalizationsZh extends FLocalizations { @override String get dialogLabel => '对话框'; + + @override + String get sheetLabel => '动作条'; + + @override + String get barrierLabel => '纱罩'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return '关闭 \$modalRouteContentName'; + } } /// The translations for Chinese, as used in Hong Kong (`zh_HK`). @@ -58,6 +69,17 @@ class FLocalizationsZhHk extends FLocalizationsZh { @override String get dialogLabel => '對話方塊'; + + @override + String get sheetLabel => '面板'; + + @override + String get barrierLabel => 'Scrim'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return '關閉 \$modalRouteContentName'; + } } /// The translations for Chinese, as used in Taiwan (`zh_TW`). @@ -66,4 +88,15 @@ class FLocalizationsZhTw extends FLocalizationsZh { @override String get dialogLabel => '對話方塊'; + + @override + String get sheetLabel => '功能表'; + + @override + String get barrierLabel => '紗罩'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return '關閉「\$modalRouteContentName」'; + } } diff --git a/forui/lib/src/localizations/localizations_zu.dart b/forui/lib/src/localizations/localizations_zu.dart index 9c89b6627..74d1a7dba 100644 --- a/forui/lib/src/localizations/localizations_zu.dart +++ b/forui/lib/src/localizations/localizations_zu.dart @@ -50,4 +50,15 @@ class FLocalizationsZu extends FLocalizations { @override String get dialogLabel => 'Ingxoxo'; + + @override + String get sheetLabel => 'Ishidi'; + + @override + String get barrierLabel => 'I-Scrim'; + + @override + String barrierOnTapHint(String modalRouteContentName) { + return 'Vala i-\$modalRouteContentName'; + } } diff --git a/forui/lib/src/theme/theme_data.dart b/forui/lib/src/theme/theme_data.dart index 8256045e1..fdf936a09 100644 --- a/forui/lib/src/theme/theme_data.dart +++ b/forui/lib/src/theme/theme_data.dart @@ -91,6 +91,9 @@ final class FThemeData with Diagnosticable { /// The select menu tile style. final FSelectMenuTileStyle selectMenuTileStyle; + /// The sheet style. + final FSheetStyle sheetStyle; + /// The slider styles. final FSliderStyles sliderStyles; @@ -139,6 +142,7 @@ final class FThemeData with Diagnosticable { required this.scaffoldStyle, required this.selectGroupStyle, required this.selectMenuTileStyle, + required this.sheetStyle, required this.sliderStyles, required this.switchStyle, required this.tabsStyle, @@ -186,6 +190,7 @@ final class FThemeData with Diagnosticable { scaffoldStyle: FScaffoldStyle.inherit(colorScheme: colorScheme, style: style), selectGroupStyle: FSelectGroupStyle.inherit(colorScheme: colorScheme, typography: typography, style: style), selectMenuTileStyle: FSelectMenuTileStyle.inherit(colorScheme: colorScheme, typography: typography, style: style), + sheetStyle: FSheetStyle.inherit(colorScheme: colorScheme), sliderStyles: FSliderStyles.inherit(colorScheme: colorScheme, typography: typography, style: style), switchStyle: FSwitchStyle.inherit(colorScheme: colorScheme, style: style), tabsStyle: FTabsStyle.inherit(colorScheme: colorScheme, typography: typography, style: style), @@ -263,6 +268,7 @@ final class FThemeData with Diagnosticable { FScaffoldStyle? scaffoldStyle, FSelectGroupStyle? selectGroupStyle, FSelectMenuTileStyle? selectMenuTileStyle, + FSheetStyle? sheetStyle, FSliderStyles? sliderStyles, FSwitchStyle? switchStyle, FTabsStyle? tabsStyle, @@ -295,6 +301,7 @@ final class FThemeData with Diagnosticable { scaffoldStyle: scaffoldStyle ?? this.scaffoldStyle, selectGroupStyle: selectGroupStyle ?? this.selectGroupStyle, selectMenuTileStyle: selectMenuTileStyle ?? this.selectMenuTileStyle, + sheetStyle: sheetStyle ?? this.sheetStyle, sliderStyles: sliderStyles ?? this.sliderStyles, switchStyle: switchStyle ?? this.switchStyle, tabsStyle: tabsStyle ?? this.tabsStyle, @@ -332,6 +339,7 @@ final class FThemeData with Diagnosticable { ..add(DiagnosticsProperty('scaffoldStyle', scaffoldStyle, level: DiagnosticLevel.debug)) ..add(DiagnosticsProperty('selectGroupStyle', selectGroupStyle, level: DiagnosticLevel.debug)) ..add(DiagnosticsProperty('selectMenuTileStyle', selectMenuTileStyle, level: DiagnosticLevel.debug)) + ..add(DiagnosticsProperty('sheetStyle', sheetStyle, level: DiagnosticLevel.debug)) ..add(DiagnosticsProperty('sliderStyles', sliderStyles, level: DiagnosticLevel.debug)) ..add(DiagnosticsProperty('switchStyle', switchStyle, level: DiagnosticLevel.debug)) ..add(DiagnosticsProperty('tabsStyle', tabsStyle, level: DiagnosticLevel.debug)) @@ -370,6 +378,7 @@ final class FThemeData with Diagnosticable { scaffoldStyle == other.scaffoldStyle && selectGroupStyle == other.selectGroupStyle && selectMenuTileStyle == other.selectMenuTileStyle && + sheetStyle == other.sheetStyle && sliderStyles == other.sliderStyles && switchStyle == other.switchStyle && tabsStyle == other.tabsStyle && @@ -404,6 +413,7 @@ final class FThemeData with Diagnosticable { scaffoldStyle.hashCode ^ selectGroupStyle.hashCode ^ selectMenuTileStyle.hashCode ^ + sheetStyle.hashCode ^ sliderStyles.hashCode ^ switchStyle.hashCode ^ tabsStyle.hashCode ^ diff --git a/forui/lib/src/widgets/sheet/modal_sheet.dart b/forui/lib/src/widgets/sheet/modal_sheet.dart index 6bc8eadee..5394f1340 100644 --- a/forui/lib/src/widgets/sheet/modal_sheet.dart +++ b/forui/lib/src/widgets/sheet/modal_sheet.dart @@ -1,14 +1,279 @@ +import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; +import 'package:flutter/rendering.dart'; import 'package:forui/forui.dart'; import 'package:forui/src/widgets/sheet/sheet.dart'; import 'package:forui/src/widgets/sheet/shifted_sheet.dart'; -const double _defaultScrollControlDisabledMaxHeightRatio = 9.0 / 16.0; +Future showFModalSheet({ + required BuildContext context, + required WidgetBuilder builder, + required Layout side, + bool useRootNavigator = false, + FSheetStyle? style, + double? mainAxisMaxRatio = 9 / 16, + String? barrierLabel, + bool barrierDismissible = true, + Color? barrierColor, + BoxConstraints constraints = const BoxConstraints(), + bool draggable = true, + RouteSettings? routeSettings, + AnimationController? transitionAnimationController, + Offset? anchorPoint, + bool useSafeArea = false, +}) { + assert(debugCheckHasMediaQuery(context), ''); + + final navigator = Navigator.of(context, rootNavigator: useRootNavigator); + final localizations = FLocalizations.of(context); + + final platformBarrierColor = switch (defaultTargetPlatform) { + TargetPlatform.iOS || TargetPlatform.macOS => CupertinoDynamicColor.resolve(kCupertinoModalBarrierColor, context), + _ => Theme.of(context).dialogTheme.barrierColor ?? Colors.black54, + }; + + return navigator.push( + FModalSheetRoute( + style: style ?? context.theme.sheetStyle, + side: side, + builder: builder, + mainAxisMaxRatio: mainAxisMaxRatio, + capturedThemes: InheritedTheme.capture(from: context, to: navigator.context), + barrierOnTapHint: localizations.barrierOnTapHint(localizations.sheetLabel), + barrierLabel: barrierLabel ?? localizations.barrierLabel, + barrierDismissible: barrierDismissible, + barrierColor: barrierColor ?? platformBarrierColor, + constraints: constraints, + draggable: draggable, + settings: routeSettings, + transitionAnimationController: transitionAnimationController, + anchorPoint: anchorPoint, + useSafeArea: useSafeArea, + ), + ); +} + +/// A route that represents a modal sheet. [showFModalSheet] should be preferred in most cases. +/// +/// A modal sheet is an alternative to a menu or a dialog and prevents the user from interacting with the rest of the +/// app. +/// +/// A closely related widget is a persistent sheet, which shows information that supplements the primary content of the +/// app without preventing the user from interacting with the app. Persistent bottom sheets can be . +// TODO: reference persistent bottom sheet when implemented. +/// +/// See: +/// * https://forui.dev/docs/overlay/modal-sheet for working examples. +/// * [FSheetStyle] for customizing a switch's appearance. +/// * [showFModalSheet] for displaying a FModalSheetRoute. +// TODO: reference persistent bottom sheet when implemented. +/// * [DraggableScrollableSheet], creates a bottom sheet that grows and then becomes scrollable once it reaches its +/// maximum size. +/// +/// This is based on Material's `ModalBottomSheetRoute`. +class FModalSheetRoute extends PopupRoute { + /// The style. + final FSheetStyle style; + + /// The side. + final Layout side; + + /// Stores a list of captured [InheritedTheme]s that are wrapped around the sheet. + /// + /// Consider setting this attribute when the [FModalSheetRoute] is created through [Navigator.push] and its friends. + final CapturedThemes? capturedThemes; + + /// The main axis's max constraint ratio for the sheet, depending on [side]. Defaults to 9 / 16. + /// + /// The main axis is the width if [side] is [Layout.ltr] or [Layout.rtl], and the height if [side] is [Layout.ttb] or + /// [Layout.btt]. + /// + /// Consider setting this to null if this sheet has a scrollable child, i.e. [ListView], along the main axis, to have + /// the sheet be draggable. + final double? mainAxisMaxRatio; + + /// The minimum and maximum sizes for a sheet. Default to being unconstrained. + final BoxConstraints constraints; + + /// True if the sheet can be dragged up and down/left and right. Defaults is true. + final bool draggable; + + /// The animation controller that controls the sheet's entrance and exit animations. + /// + /// The sheet widget will manipulate the position of this animation, it is not just a passive observer. + final AnimationController? transitionAnimationController; + + /// The anchor point used to pick the closest sub-screen. + /// + /// If the anchor point sits inside one of these sub-screens, then that sub-screen is picked. If not, then the + /// sub-screen with the closest edge to the point is used. + /// + /// [Offset.zero] is the top-left corner of the available screen space. For a vertically split dual-screen device, + /// this is the top-left corner of the left screen. + /// + /// When this is null, [Directionality] is used: + /// * for [TextDirection.ltr], [anchorPoint] is [Offset.zero], which will cause the top-left sub-screen to be picked. + /// * for [TextDirection.rtl], [anchorPoint] is `Offset(double.maxFinite, 0)`, which will cause the top-right + /// sub-screen to be picked. + final Offset? anchorPoint; + + /// True if a [SafeArea] should be inserted o keep the sheet away from system intrusions on the sides other than + /// [side]. Defaults to false. + /// + /// If false, the sheet will extend through any system intrusions other than [side]. In addition, + /// [MediaQuery.removePadding] is used to remove opposite [side]'s padding so that a [SafeArea] widget inside the + /// sheet will not have any effect on the opposite side. If this is undesired, consider setting [useSafeArea] to true. + /// Alternatively, wrap the [SafeArea] in a [MediaQuery] that restates an ambient [MediaQueryData] from outside + /// [builder]. + /// + /// In either case, the sheet extends all the way to the [side] of the screen, including any system intrusions. + final bool useSafeArea; + + /// The semantic hint text that informs users what will happen if they tap on the widget. Announced in the format of + /// 'Double tap to ...'. + /// + /// If the field is null, the default hint will be used, which results in an announcement of 'Double tap to activate'. + /// + /// See: + /// * [barrierDismissible], which controls the behavior of the barrier when tapped. + /// * [ModalBarrier], which uses this field as onTapHint when it has an onTap action. + final String? barrierOnTapHint; + + /// A builder for the contents of the sheet. + final WidgetBuilder builder; + + @override + final String? barrierLabel; + + @override + final bool barrierDismissible; + + @override + final Color barrierColor; + + final ValueNotifier _clipDetailsNotifier = ValueNotifier(EdgeInsets.zero); + + AnimationController? _animationController; + + /// Creates a [FModalSheetRoute]. + FModalSheetRoute({ + required this.style, + required this.side, + required this.builder, + required this.mainAxisMaxRatio, + this.capturedThemes, + this.barrierOnTapHint, + this.barrierLabel, + this.barrierDismissible = true, + this.barrierColor = Colors.black54, + this.constraints = const BoxConstraints(), + this.draggable = true, + this.transitionAnimationController, + this.anchorPoint, + this.useSafeArea = false, + super.settings, + }); + + @override + AnimationController createAnimationController() { + if (transitionAnimationController != null) { + _animationController = transitionAnimationController; + willDisposeAnimationController = false; + } else { + _animationController = Sheet.createAnimationController(navigator!, style); + } + + return _animationController!; + } + + @override + Widget buildPage(BuildContext context, Animation animation, Animation secondaryAnimation) { + final content = DisplayFeatureSubScreen( + anchorPoint: anchorPoint, + child: Builder( + builder: (context) => _ModalSheet( + route: this, + side: side, + style: style, + constraints: constraints, + mainAxisMaxRatio: mainAxisMaxRatio, + draggable: draggable, + ), + ), + ); + + final sheet = switch ((side, useSafeArea)) { + (Layout.ttb, true) => SafeArea(top: false, child: content), + (Layout.btt, true) => SafeArea(bottom: false, child: content), + (Layout.ltr, true) => SafeArea(left: false, child: content), + (Layout.rtl, true) => SafeArea(right: false, child: content), + (Layout.ttb, false) => MediaQuery.removePadding(context: context, removeBottom: true, child: content), + (Layout.btt, false) => MediaQuery.removePadding(context: context, removeTop: true, child: content), + (Layout.ltr, false) => MediaQuery.removePadding(context: context, removeRight: true, child: content), + (Layout.rtl, false) => MediaQuery.removePadding(context: context, removeLeft: true, child: content), + }; + + return capturedThemes?.wrap(sheet) ?? sheet; + } + + @override + Widget buildModalBarrier() { + if (barrierColor.alpha != 0 && !offstage) { + // changedInternalState is called if barrierColor or offstage updates + final color = animation!.drive( + ColorTween( + begin: barrierColor.withOpacity(0.0), + end: barrierColor, // changedInternalState is called if barrierColor updates + ).chain(CurveTween(curve: barrierCurve)), // changedInternalState is called if barrierCurve updates + ); + return AnimatedModalBarrier( + color: color, + dismissible: barrierDismissible, // changedInternalState is called if barrierDismissible updates + semanticsLabel: barrierLabel, // changedInternalState is called if barrierLabel updates + barrierSemanticsDismissible: semanticsDismissible, + clipDetailsNotifier: _clipDetailsNotifier, + semanticsOnTapHint: barrierOnTapHint, + ); + } else { + return ModalBarrier( + dismissible: barrierDismissible, // changedInternalState is called if barrierDismissible updates + semanticsLabel: barrierLabel, // changedInternalState is called if barrierLabel updates + barrierSemanticsDismissible: semanticsDismissible, + clipDetailsNotifier: _clipDetailsNotifier, + semanticsOnTapHint: barrierOnTapHint, + ); + } + } + + /// Updates the details regarding how the [SemanticsNode.rect] (focus) of the barrier for this [FModalSheetRoute] + /// should be clipped. + /// + /// Returns true if the clipDetails did change and false otherwise. + bool _didChangeBarrierSemanticsClip(EdgeInsets details) { + if (_clipDetailsNotifier.value == details) { + return false; + } + + _clipDetailsNotifier.value = details; + return true; + } + + @override + void dispose() { + _clipDetailsNotifier.dispose(); + super.dispose(); + } + + @override + Duration get transitionDuration => style.enterDuration; + + @override + Duration get reverseTransitionDuration => style.exitDuration; +} class _ModalSheet extends StatefulWidget { - final PopupRoute route; // TODO: Change route to more specific. + final FModalSheetRoute route; final Layout side; final FSheetStyle style; final double? mainAxisMaxRatio; @@ -46,8 +311,6 @@ class _ModalSheetState extends State<_ModalSheet> { ParametricCurve _curve = _cubic; - EdgeInsets _getNewClipDetails(Size topLayerSize) => EdgeInsets.fromLTRB(0, 0, 0, topLayerSize.height); - @override Widget build(BuildContext context) { assert(debugCheckHasMediaQuery(context), ''); @@ -65,7 +328,14 @@ class _ModalSheetState extends State<_ModalSheet> { child: ClipRect( child: ShiftedSheet( side: widget.side, - onChange: (size) => widget.route._didChangeBarrierSemanticsClip(_getNewClipDetails(size)), + onChange: (size) => widget.route._didChangeBarrierSemanticsClip( + switch (widget.side) { + Layout.ttb => EdgeInsets.fromLTRB(0, size.height, 0, 0), + Layout.btt => EdgeInsets.fromLTRB(0, 0, 0, size.height), + Layout.ltr => EdgeInsets.fromLTRB(size.width, 0, 0, 0), + Layout.rtl => EdgeInsets.fromLTRB(0, 0, size.width, 0), + }, + ), value: _curve.transform(widget.route.animation!.value), mainAxisMaxRatio: widget.mainAxisMaxRatio, child: child, diff --git a/forui/lib/src/widgets/sheet/sheet.dart b/forui/lib/src/widgets/sheet/sheet.dart index e362832c3..b436a3712 100644 --- a/forui/lib/src/widgets/sheet/sheet.dart +++ b/forui/lib/src/widgets/sheet/sheet.dart @@ -6,6 +6,12 @@ import 'package:meta/meta.dart'; @internal class Sheet extends StatefulWidget { + static AnimationController createAnimationController(TickerProvider vsync, FSheetStyle style) => AnimationController( + duration: style.enterDuration, + reverseDuration: style.exitDuration, + vsync: vsync, + ); + static void _onClosing() {} /// The animation controller that controls the bottom sheet's entrance and exit animations. @@ -60,7 +66,7 @@ class Sheet extends StatefulWidget { this.onDragEnd, this.onClosing = _onClosing, super.key, - }): assert(!draggable || controller != null, 'Draggable sheets must have a controller.'); + }) : assert(!draggable || controller != null, 'Draggable sheets must have a controller.'); @override State createState() => _SheetState(); @@ -88,12 +94,7 @@ class _SheetState extends State with SingleTickerProviderStateMixin { @override void initState() { super.initState(); - _controller = widget.controller ?? - AnimationController( - vsync: this, - duration: widget.style.enterDuration, - reverseDuration: widget.style.exitDuration, - ); + _controller = widget.controller ?? Sheet.createAnimationController(this, widget.style); } @override @@ -104,12 +105,7 @@ class _SheetState extends State with SingleTickerProviderStateMixin { _controller.dispose(); } - _controller = widget.controller ?? - AnimationController( - vsync: this, - duration: widget.style.enterDuration, - reverseDuration: widget.style.exitDuration, - ); + _controller = widget.controller ?? Sheet.createAnimationController(this, widget.style); } } @@ -127,14 +123,15 @@ class _SheetState extends State with SingleTickerProviderStateMixin { child: ConstrainedBox( constraints: widget.constraints, child: NotificationListener( - key: _key, - onNotification: (notification) { - if (notification.extent == notification.minExtent && notification.shouldCloseOnMinExtent) { - widget.onClosing(); - } - return false; - }, - child: widget.builder(context)), + key: _key, + onNotification: (notification) { + if (notification.extent == notification.minExtent && notification.shouldCloseOnMinExtent) { + widget.onClosing(); + } + return false; + }, + child: widget.builder(context), + ), ), ); @@ -230,8 +227,6 @@ extension on GlobalKey { double get currentChildHeight => (currentContext!.findRenderObject()! as RenderBox).size.height; } -// TODO: make abstract - /// A sheet's style. class FSheetStyle with Diagnosticable { /// The sheet's background color. @@ -264,12 +259,8 @@ class FSheetStyle with Diagnosticable { this.closeProgressThreshold = 0.5, }); - /// Creates a [FSheetStyle] that inherits its colors from the given [FColorScheme] and [FStyle]. - FSheetStyle.inherit({ - required FColorScheme colorScheme, - }) : this( - backgroundColor: colorScheme.background, - ); + /// Creates a [FSheetStyle] that inherits its colors from the given [FColorScheme]. + FSheetStyle.inherit({required FColorScheme colorScheme}) : this(backgroundColor: colorScheme.background); @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { diff --git a/forui/lib/src/widgets/sheet/shifted_sheet.dart b/forui/lib/src/widgets/sheet/shifted_sheet.dart index 628e8551c..48aa43805 100644 --- a/forui/lib/src/widgets/sheet/shifted_sheet.dart +++ b/forui/lib/src/widgets/sheet/shifted_sheet.dart @@ -4,7 +4,9 @@ import 'package:flutter/rendering.dart'; import 'package:forui/src/foundation/rendering.dart'; import 'package:meta/meta.dart'; + @internal +/// typedef SizeChangeCallback = void Function(Size size); /// This is based on Material's _BottomSheetLayoutWithSizeListener. diff --git a/forui/lib/widgets/sheet.dart b/forui/lib/widgets/sheet.dart index 62f2a9055..23649b869 100644 --- a/forui/lib/widgets/sheet.dart +++ b/forui/lib/widgets/sheet.dart @@ -2,7 +2,9 @@ /// /// A sheet is a panel that slides in from the edge of a screen. /// -/// See https://forui.dev/docs/sheet/modal-sheet for working examples. +/// See: +/// * https://forui.dev/docs/overlay/modal-sheet for working examples of a modal sheet. library forui.widgets.sheet; -export '../src/widgets/sheet/sheet.dart' show FSheetStyle; \ No newline at end of file +export '../src/widgets/sheet/modal_sheet.dart'; +export '../src/widgets/sheet/sheet.dart' show FSheetStyle; diff --git a/forui/tool/add_arb_value.dart b/forui/tool/add_arb_value.dart index 41456e8e0..d076313ac 100644 --- a/forui/tool/add_arb_value.dart +++ b/forui/tool/add_arb_value.dart @@ -6,7 +6,7 @@ import 'dart:io'; final pattern = RegExp(r'material_([\w_]+)\.arb'); // Change this to add other keys. -const key = 'dialogLabel'; +const key = 'scrimLabel'; void main() { // I usually just download all Material localization files into the .temp folder. @@ -17,6 +17,10 @@ void main() { } final locale = pattern.firstMatch(source.path)?.group(1); + if (locale == 'en') { + continue; + } + final target = File('lib/l10n/f_$locale.arb'); final forui = json.decode(target.readAsStringSync()); From aa04c0e094419e6596dfc9b024329635f26354fa Mon Sep 17 00:00:00 2001 From: Matthias Ngeo Date: Thu, 21 Nov 2024 14:50:11 +0800 Subject: [PATCH 07/29] Fix lint issues --- forui/lib/src/widgets/sheet/modal_sheet.dart | 37 ++++++++++++++++++-- forui/tool/add_arb_value.dart | 2 +- 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/forui/lib/src/widgets/sheet/modal_sheet.dart b/forui/lib/src/widgets/sheet/modal_sheet.dart index 5394f1340..a655baaf0 100644 --- a/forui/lib/src/widgets/sheet/modal_sheet.dart +++ b/forui/lib/src/widgets/sheet/modal_sheet.dart @@ -6,6 +6,39 @@ import 'package:forui/forui.dart'; import 'package:forui/src/widgets/sheet/sheet.dart'; import 'package:forui/src/widgets/sheet/shifted_sheet.dart'; +/// Shows a modal sheet that appears from the given [side]. +/// +/// A modal sheet is an alternative to a menu or a dialog and prevents the user from interacting with the rest of the +/// app. +/// +/// [context] is used to look up the [Navigator] and [FSheetStyle] for the sheet. It is only used when the method is +/// called. Its corresponding widget can be safely removed from the tree before the sheet is closed. +/// +/// [useRootNavigator] ensures that the root navigator displays the sheet when`true`. This is useful in the case that a +/// modal sheet needs to be displayed above all other content but the caller is inside another [Navigator]. +/// +/// [style] defaults to [FSheetStyle] from the closest [FTheme] ancestor. +/// +/// [mainAxisMaxRatio] represents the main axis's max constraint ratio for the sheet, depending on [side]. +/// Defaults to 9 / 16. The main axis is the width if [side] is [Layout.ltr] or [Layout.rtl], and the height if [side] +/// is [Layout.ttb] or [Layout.btt]. Consider setting [mainAxisMaxRatio] to null if this sheet has a scrollable child, +/// i.e. [ListView], along the main axis, to have the sheet be draggable. +/// +/// [barrierLabel] defaults to [FLocalizations.barrierLabel]. +/// +/// [barrierColor] defaults to the default Cupertino modal barrier color on iOS & macOS, and [Colors.black54] on other +/// platforms. +/// +/// Returns a `Future` that resolves to the value (if any) that was passed to [Navigator.pop] when the modal sheet was +/// closed. +/// +/// See: +/// * https://forui.dev/docs/overlay/modal-sheet for working examples. +/// * [FModalSheetRoute] for more information about the various arguments. +/// * [FSheetStyle] for customizing a switch's appearance. +// TODO: reference persistent bottom sheet when implemented. +/// * [DraggableScrollableSheet], creates a bottom sheet that grows and then becomes scrollable once it reaches its +/// maximum size. Future showFModalSheet({ required BuildContext context, required WidgetBuilder builder, @@ -30,7 +63,7 @@ Future showFModalSheet({ final platformBarrierColor = switch (defaultTargetPlatform) { TargetPlatform.iOS || TargetPlatform.macOS => CupertinoDynamicColor.resolve(kCupertinoModalBarrierColor, context), - _ => Theme.of(context).dialogTheme.barrierColor ?? Colors.black54, + _ => Colors.black54, }; return navigator.push( @@ -60,7 +93,7 @@ Future showFModalSheet({ /// app. /// /// A closely related widget is a persistent sheet, which shows information that supplements the primary content of the -/// app without preventing the user from interacting with the app. Persistent bottom sheets can be . +/// app without preventing the user from interacting with the app. // TODO: reference persistent bottom sheet when implemented. /// /// See: diff --git a/forui/tool/add_arb_value.dart b/forui/tool/add_arb_value.dart index d076313ac..4b1530d4c 100644 --- a/forui/tool/add_arb_value.dart +++ b/forui/tool/add_arb_value.dart @@ -28,4 +28,4 @@ void main() { target.writeAsStringSync(const JsonEncoder.withIndent(' ').convert(forui)); } -} \ No newline at end of file +} From 15d0675a82185dceb40daacc8b48498fac5c77db Mon Sep 17 00:00:00 2001 From: Matthias Ngeo Date: Thu, 28 Nov 2024 10:30:57 +0800 Subject: [PATCH 08/29] Add quick example --- forui/example/lib/sandbox.dart | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/forui/example/lib/sandbox.dart b/forui/example/lib/sandbox.dart index 5a7ed9f80..b761180b3 100644 --- a/forui/example/lib/sandbox.dart +++ b/forui/example/lib/sandbox.dart @@ -29,7 +29,16 @@ class _SandboxState extends State with SingleTickerProviderStateMixin { child: Column( mainAxisSize: MainAxisSize.min, children: [ - FCalendar(controller: a), + FButton( + label: const Text('Click me'), + onPress: () => showFModalSheet( + context: context, + side: Layout.ltr, + builder: (context) => ListView.builder( + itemBuilder: (context, index) => FTile(title: Text('Tile $index')), + ), + ), + ), ], ), ); From 2161b255a0cadeb268575f8ecfdaa4ecf0db4f1f Mon Sep 17 00:00:00 2001 From: Matthias Ngeo Date: Fri, 29 Nov 2024 14:29:36 +0800 Subject: [PATCH 09/29] Add tests --- docs/pages/docs/overlay/popover.mdx | 2 +- forui/lib/src/widgets/sheet/sheet.dart | 2 +- .../sheet/modal/constrained-Layout.btt.png | Bin 0 -> 26538 bytes .../sheet/modal/constrained-Layout.ltr.png | Bin 0 -> 26632 bytes .../sheet/modal/constrained-Layout.rtl.png | Bin 0 -> 26626 bytes .../sheet/modal/constrained-Layout.ttb.png | Bin 0 -> 26482 bytes .../golden/sheet/modal/default-Layout.btt.png | Bin 0 -> 24643 bytes .../golden/sheet/modal/default-Layout.ltr.png | Bin 0 -> 24507 bytes .../golden/sheet/modal/default-Layout.rtl.png | Bin 0 -> 24476 bytes .../golden/sheet/modal/default-Layout.ttb.png | Bin 0 -> 24488 bytes .../sheet/modal/scrollable-Layout.btt.png | Bin 0 -> 55808 bytes .../sheet/modal/scrollable-Layout.ltr.png | Bin 0 -> 37687 bytes .../sheet/modal/scrollable-Layout.rtl.png | Bin 0 -> 37687 bytes .../sheet/modal/scrollable-Layout.ttb.png | Bin 0 -> 55808 bytes .../sheet/modal_sheet_golden_test.dart | 105 +++++++++++++++++ .../src/widgets/sheet/modal_sheet_test.dart | 108 ++++++++++++++++++ 16 files changed, 215 insertions(+), 2 deletions(-) create mode 100644 forui/test/golden/sheet/modal/constrained-Layout.btt.png create mode 100644 forui/test/golden/sheet/modal/constrained-Layout.ltr.png create mode 100644 forui/test/golden/sheet/modal/constrained-Layout.rtl.png create mode 100644 forui/test/golden/sheet/modal/constrained-Layout.ttb.png create mode 100644 forui/test/golden/sheet/modal/default-Layout.btt.png create mode 100644 forui/test/golden/sheet/modal/default-Layout.ltr.png create mode 100644 forui/test/golden/sheet/modal/default-Layout.rtl.png create mode 100644 forui/test/golden/sheet/modal/default-Layout.ttb.png create mode 100644 forui/test/golden/sheet/modal/scrollable-Layout.btt.png create mode 100644 forui/test/golden/sheet/modal/scrollable-Layout.ltr.png create mode 100644 forui/test/golden/sheet/modal/scrollable-Layout.rtl.png create mode 100644 forui/test/golden/sheet/modal/scrollable-Layout.ttb.png create mode 100644 forui/test/src/widgets/sheet/modal_sheet_golden_test.dart create mode 100644 forui/test/src/widgets/sheet/modal_sheet_test.dart diff --git a/docs/pages/docs/overlay/popover.mdx b/docs/pages/docs/overlay/popover.mdx index 78a43ecd3..4b77dc6bd 100644 --- a/docs/pages/docs/overlay/popover.mdx +++ b/docs/pages/docs/overlay/popover.mdx @@ -105,7 +105,7 @@ const FPopover( ); ``` -### `FPopover.tappable()`. +### `FPopover.tappable()` ```dart const FPopover.tappable( diff --git a/forui/lib/src/widgets/sheet/sheet.dart b/forui/lib/src/widgets/sheet/sheet.dart index b436a3712..2a2937a06 100644 --- a/forui/lib/src/widgets/sheet/sheet.dart +++ b/forui/lib/src/widgets/sheet/sheet.dart @@ -253,7 +253,7 @@ class FSheetStyle with Diagnosticable { /// Creates a [FSheetStyle]. const FSheetStyle({ required this.backgroundColor, - this.enterDuration = const Duration(milliseconds: 250), + this.enterDuration = const Duration(milliseconds: 200), this.exitDuration = const Duration(milliseconds: 200), this.flingVelocity = 700, this.closeProgressThreshold = 0.5, diff --git a/forui/test/golden/sheet/modal/constrained-Layout.btt.png b/forui/test/golden/sheet/modal/constrained-Layout.btt.png new file mode 100644 index 0000000000000000000000000000000000000000..f221474ca5493a038dc70cf7a9d425c934a30ffb GIT binary patch literal 26538 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 literal 0 HcmV?d00001 diff --git a/forui/test/golden/sheet/modal/constrained-Layout.ttb.png b/forui/test/golden/sheet/modal/constrained-Layout.ttb.png new file mode 100644 index 0000000000000000000000000000000000000000..7ae8a55b7bfecc7503550909ffcb69233571b4f0 GIT binary patch literal 26482 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 literal 0 HcmV?d00001 diff --git a/forui/test/golden/sheet/modal/default-Layout.btt.png b/forui/test/golden/sheet/modal/default-Layout.btt.png new file mode 100644 index 0000000000000000000000000000000000000000..4c445b81e980fc37da01824a37c2ca298bf6e5e3 GIT binary patch literal 24643 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 P=%n*!EsaTMoJ0Q!YGI1A literal 0 HcmV?d00001 diff --git a/forui/test/golden/sheet/modal/default-Layout.ltr.png b/forui/test/golden/sheet/modal/default-Layout.ltr.png new file mode 100644 index 0000000000000000000000000000000000000000..99e33aa9eb0687d1f4745d6c9c6cee7c034361c2 GIT binary patch literal 24507 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 U_q?(i5q!$R^n^*_5$CJ_0U0E96aWAK literal 0 HcmV?d00001 diff --git a/forui/test/golden/sheet/modal/default-Layout.ttb.png b/forui/test/golden/sheet/modal/default-Layout.ttb.png new file mode 100644 index 0000000000000000000000000000000000000000..0f4b44fdfa460696a1db802938f262f275f71b57 GIT binary patch literal 24488 zcmeHPc|4SB-yg?mMI|AHiF#5=j$;j3%5s#Yg~&3*$u^dxY%_+VPPTAb6^TQ~&LnHb zSb7*G1{u3dIN4?xVr(T;<9R=y=Y8J${=?k&eB9T4-M{Pm`+mRI@4ARQ zZ)zy8ecyHj0wG}Zlio!HVw(d3v1RMl&ET7|_NDK^2aoSX!_$a-viKOd_}=%lk@;3| zV7LApfj}HU80qPn2Rx_u=n5dDc2!pou`wv6mYq`1E}ZAFQ&dEPTUL+ym0q6pa|HfJ zhrcfLHXmRAKJ;DaruFk(Vz1Uu5z@RO>*qQ@SAVyD9>H(5eu}uy!?%8Z0B(Fe6mVEz zw5($RP9m6F*02CmE-V&nP=GZQwiatpfE^cXMAx7ITWEM@u?7Wr!UfMm*PsAT&*7@Y z8WiBd!vEF6!mDmV=jY=e6n`1A)KQY)(HD@u;BMYC78ROW6oBw}+>{!Sy(eq%s%A=w zWceuFxVS{PCn_)8uT-+yTDNQaMRT3;^E=P$e|lY%C{iPo9+v4LopPW-w-D)f&4h}0 zuYcgs3QiFlfFB8*WbMFyU(e;x6}7`A3F2u6%SVpM%F>o?IV;PKl+61+wStBe+RFI&_~^$k z)z*crY2Hz?`3ruxoB5$Tin{(uGTxgpeWZ>2&QC6!c;VGF&dwQGD&%8r@pzO%0fQGg9i7q~Js% z{U+s7w*`r9adk;s>BtS#R=?FF-&5jQHP$Rw+Sfy=haP<3YJ9pD_(UL>g+IT4a73Py zVMPowN$Naz_H3#p9_6zza4OBIKDGe6_%$;(_uex_myX3oAu~;}ktBaz;}`7e9crhN z=UNT-tFjndK{Glt(p=_qJ!}xObiv%hLbwsb92c%yVG@1bNp0y|>`PE))bs9SA2x_v zaXW5PlG{-%rs!Ood!^8^I+Uk(q7Uj!%Y(p8P-t}&r@nr`*WTGC#5Wv|QrDCW!FD(g z2dhpC~^v+!%PQp`l@WzJ18DKnxBA-Mo;yi%Ymlym6Xef2yH>JQrS{SK7au zFi~Pd>=^BP`KkOC1RH%56O**u(tn^k^J8{uEjSPuZRRYfnHEj@N6Hqc8xAy7 z(AXF2;eNUi6Iak4~JrDqBA4Scx4Reb80ZlulE-9FZ3pQEg9Jcei8QJEDJd< zOr4_@lNIX4C5Gzb&gnZ9x->`LKWIquZ9Zj>XAy4EMA8hYd+L$Ysv3+Zez^m0kHk#A zu^iVt_k=As*X@!_Ddavf1f>fBr-grZv^C9Pu2IoU_5BrTX|Jl~5oRo2T6&lqtP(V* zsVO3l%hP4u6H`>#yhAgqU%_0jHf$5$;LC@mu}IE>i~vq}Ft#6hqtIcqwUGoZ5*_>| ziaEQzE2c?1v_Dh?&I}T$#Qd7(JQVTpiHfPzt}-7d;$+ppT}FMoWr&Q=TaL0jCC+hn zG?5m}iS5T%`hB|9X<#n|wM!Zjz5{i+Nk?B_e|F5*xTXRyN4oJd+Y!~DmG73LbQk9D z?l>h|xx!RT&CNXyy|R22`>f{TpAQwh`WDm~RWoFb!HOC3r@@3cttD4}NzIpJw5aWM zUH*MHFVd?xE3MfUIRQg4s*Vkhs3ZV;T1Ch><>&Qr0D$aC45HrDgCf{yn(z|`PJ7$;>7Kf8XY>{f$9U7l11Q$YBh_9UekU)Hy8WraLp57u>XQ8XFW^}t&B;h@_CSo! zpZAGrhH)=^0F~B-BXMOWF0P&Vo&X9rhzxBeMR!x-_;`604|=lCg%35R>P~sr1z2gE zNDbxTO$7r~?5yZQz9+C>MQITSqKYWeTpRWD%*-QX4Mv|;iHBPsj^&vcEH^;Ke0gl? zR2zXFeD%+u+S*8te3ryT&U?9T_$LvbNktrxf;(|dcTn_G)%QZ~U}-LJ3tOxMNN zK6Akx1W7>s9IW9#*_Xm1+&r1$P=X8oMBTxB%O_7+vPGdJfwp;m-gdBZp-x_;u^&6r zbeOt2ZZ7N6)SC~Ks5QqDzxU)zT$%sJm+uSa`!V&+xVg3< zyuG^_3V+rD}Iejb8-%9rWwr@?2ahzFiH7X>Il6~|#+0gMoQ zs}jYC)tI~|YLCq_BG0>lckIrm;q3?|Myt18Tb(;#4frLo&g?O>nKYN?7n?c{n?CP4 z{*GEjuyjJ%AcpB*@twRpTYU=CPH`?gTPEN;5m!;Yj76TbALM$7bxnL+E z44I|qwG1=lX4tETiR#SX7e3g#hn#8u5^paeq2XtYzhYZqlh>ScnV5*mQINQ<6K}0c zX*1(Usd#kl^6V*c6I_+euUokjBflG$GE8H#E+Mm(Y5hdZb05-J78CGtv-Rf18#t292F30E7qgD;L)20=!+23jkxdA`>NW7Sd}R06-=9%D`t zylrc8(Va;LtJRs5OMK2%3w2cnK*eu&EH-&dMtFy?8UjXt4|l4I64q$K*}V3f=%M&R z4JyfT5npXO`R-uc@uxt#^FG@YjHjihN_&+J+zks%)(ZYOf;I+L>-;ReyRd^kU5|`o zO%m|^=;LYW=?h9c>MS=v!AOlN#R_| zaFFq*7u4_3J1rb8Rx%+k z|BbU=4c&%XE=`KrU)AnnnP)8=Z@-ckw%G7k7U=k#Mjb%@L~p6=Qj4c70ojf&aAHIXnThYZ zy=CXo2q4h;#JPkcCrAyU9p&C%Ah z`hn?MAu~YU3XXb3?iTa-w|=v@&iFImt^xlR)6?9ZkaEKHW_u&Kq8$Dly?o{c=vGR@_JJvH840TLNg1V+P_x36O zc!GFy;WERf#N!HaFy|NEEhPDnMQ=+|K^OF*) zR84h};|u8L!E>sKb?Aw?KHuhmg@G&u7xEA|`JkM7r2<+Cx6dG_dfB?XyH z;EkdI9cV&!&Y3_hzeOATRTLFbO2uiY-|Ui|>&0IZ5BU5`ObK^36tn6ep)MeP`*YRx zaWCL95C{WY#DZV}SNMQkg3F%(3NR_aqyQoS4ww``5MWY(pa7Es2m9ROxS4V!!cY5#KD_-v4HS z_M3%Ry>HfYf8x$@;Ko4&;IM2g=fh~>rUdi@P9mt}!aZPa+1UI7Q|>w{5U>(${EZSU z(Ce@W{jakYsot3CJYVu0w>%5I=7EG~6Wc5|3|DnRC+~4l?m9U)3b1s*(y^8fFh{~1 zxdw&*#Cb*-4(*0OAl0G&3jn$a8$H-`KgO-a8kxUbjb7$7yaFMC>WmE;RHTW5ii&`U^rj}Rnt=2YMrWjhh)M?q6%hpK zoiIw17Li_q1PHwa2q7eVYdf=X-t)Edo!=kloa-mo<@Js)CVTIvtY_W#y4Sq}E^Dgo z+{U$yg@tA3gGOv z$Lq%%{wyp9SuQA_({+oR?6ZETHyk}Wm%^r6^i$GK-RoP5?iTt-X0ay?J{c3MJ+ked zYVs4^UB~uovx}>4{_|Xz|F3d?k`8aFtJiJV!500~Vcl)YMXx#4f-75gnL9bLkUEe3 za)0Lwi$qp(?S&HAme>wE$#*!sJ-y4iY~uK6*jjhm>x_&H5xAwlexz>-&zGTpVW|ke z=(`#H+rwYK|2Hxg-^byv74dx>zK_HIb`89?Eax~VRpO#ob8j=D`l+ySvL|)gp=xh( zl5I~u&20N$L&w6h?W(pZ{FFyZ|J)EQE_K`5I+h`0TH+ECE+CpI)l*=PiF0m`G;evO zvDNCxkur?vo_gpVgr44*&XaemW%{8!_R}*bi?Pou zbFD2}YbUEiN)(-@f;m|$D+8n~M}qbV2c~5d7x&w=z1gdM^=kJHZnBp1;SJuVl?~#{qfiz`(#q1oDqD93fCLsNBT0%V*<+G7p$Gs5QQ{Yd3>N8BHW&`WwfWtsS~`Hf!M{?ji` zVPuw5sYIMoT|Hk@!wh~6SN*o2|MP$XubfLTA9Hplxv)@r8jtfRn}L538f%}hKVHt& zE8Y`u-9o?I^zym;nKm|~m(a`BK4A%po9fo%&CAPk zcX!dy&}fL!ONiErbwv=D^)X?D7o<9FNHT71u0(yyKC(X{e{SFHT=l@bY zQErx2k6~W96m!=gMeRovsuvH?0eYkTyE;DJHovv$;b)Am$GFxLZoIKF|&T>Z8SEbjDq!HcKnyQmj>ZPA++p|RIm$GUY zJtms?B$^N}Cnag$-+P1Zz0e%mFiH8rkXQC@?HDI|U!V4G(ErVo(kPXjl$6w;o}PZv z4$rW6D#ooYa}Uyqcwuo&?r5Y&K1q$w`*E~)Im^UyTmm}mEFo;y_7-AR&97T6&3+ix z*42GX;Z$1wb1E8EGXXc0_g-z&XxdbXs+@Xv#!iI?$C*PJ7W1W#9Wt@HELTh`wd!CLSy$2@n8_4c)Tn8jn8cM5Q)KUsMn!uk7;Mqk)BD#sO!F;UW72mvaR;Vene3%$ zN5r*cS@<>BP^ZU-C|uhJT>qGwYM~#u8=lAi(DwND?Ip>NGQ6@kNUvRq4DWgOwM9(V zZ2EI7`ZQ-PelXmeu9t?t*-q)nz14S^e0MU+TVWtAGXtKWjM`uSk0;oldGO>l)8e~L z4H+fV-G$S|6N=QXx5j)NFJHb)q{l7e9CQop`pjW8w_4$8jrH0F1{|s;?9w?o! z6I!(DD|TkThR)(cWnaAtS=Xj5hAHtbSL0m!pOsEhh{uKK6K>lF-ooP^ zi{tK>$)(GK>d^+GPoFTHBc^`(`vJ~gpWF6+qs#lB1aDZ0mM>p1bGg+}L{5l}W~`Ex zlt!Jnic_BFpw~Od0aMqWq!M&YNGMIpxbV*P$=)JydpU*-YMg;G5L)Ty?LrV1c7;mKMQr=M_``=&g`~FY`|0|8y zeK3z{QfY7A1a22Cm42mJCMapw`?v^8omOyIW3-SO#Me&17@Q_*MV)&7kt#nDWnn(v zni}nHIlLl0mD^%5(%?53@7f=rrARx>&#$;Va6d|c9==>>&}27jko`(Co~wq(=~BeZ z`aFNR89lSP7EcPZ=L=I#yoc5$_@hbgb?Kp+!|xj3tqV(7Tx_2d`YHBv?kyY#pV#a;dD@W91uAaBm>7Jkg_-e@ zicZ6`S+~uHw(j6OeONz}NgZuYt~p0EhQUt2`54L1RxI3XPI6yMhm^v6X_Bwn)V0t3 z6SW_b2{F$l*5uc(UmLlgAqzPPW6n7^IFu0tVWtf~%~uz3IbT!@*{_4mu2 zg$~}A66B9x&0qLnk1otJAxXvX<0bm%mx(@CVu))$jnG-_Y;Dt%FB~d2U3l!oi9pSG z*{al(r7$?*dH3Ou>KPkzBdMN7tYnSnOc@6o8KhX#vjsqLN__8ziR?BZj z7cR^g7CEZi9sP93sTxj7i;s_vEFyV$u!w2#8PW(X$DUXYQIDL3B_w!I(lVJIcPBf= z?AJ5%I}7aBhF@#My7&#r+}{$CeCeb zi&km+Z~Z@i{%qALjrXDV5UUFvI%>M}>@CYZNg+g)nf|i*Yz{P-{qbC-oa32;kU@sc z9cBvNU+?D9bRT!it3GaWyz9C9b9>Q$$g@qDQpOT80o1^Kin=JTW38(UPw7&(_1u*G zS{USzi8Jfa{@5LW_D`NZt*+sl`8d}7z$ZKvgMT3KhA`fhgSC=$ne22MiKb;)HO6ep z*)AfjR99E$C`-Ait)s)vDt}7As>$mZF%7-&+22`&T;Y*wY2A{x-EDOFI|CJl<*T$I zY=J#dL_gi_5U?EkAaI9F_pP1Y!g_!QQnioR1Gmh)7u)vBxx``0(1{y($6q1)OYZHq z6AyMAZ!p+Z4w)E&%x^?)>=4WDZE?%7jtB_rX zN?7}FfAC{f8j?d3va`#ZPwuLQh12{>W8!AlX*^D{s;X)(nNNZ1yx*?Ii38}v9E9u3 zuZ${Hett>dU0xj)#T`GYQJmJ5U;u{?ex+?NN(tu!7*tHs#*h!-mjJ(ch3^K3k!Y+k z-iI;xNS%39Q(>{ys)v-5QMSbW6(m~Jg!)ZJqgR+E|Ic`{M_^)nd@w*T!GEj;TbXa$ z!&Uk!DTyD_HGY1`$Ucg}>U5j^le0Mo8)ns&YEi?U1fczZ=cJn0joOD+?&wgkyx4us zp@PYvlU~IhMKI#RxxNBGnTC0{E#>DbNsaSYD<}jd(SDB!r6kB;G<+n{+wwZlND;rt zH{o`yKy`TP6BDJ=R_6cZke%(Pw6 z@Kb5}WKObifnAoXy+$d+1-U5uPBYx_6N75&%(tNtkcI8G-GyG0CQ!kzpJ~RMgH?JI z9ma<{-|IP(i)`gG8VVJ$3DJDS)scd6Zv)dZxdUFa&mn!AiS=I3BWk5G4<5EFoqN?_ zGv0b!+e}f29m7Z!vrtuYr=>S|P4^aMxl=~IC6+9^q#!q^j>Oul!ZIu~f}dU=I&tLg z+VY%KB^8e|wkp5bEE;R0hTf&L$xo1wi~3}p68BvGG7pJK9W9t|bzrFh7!9%#b)90m zQ^*cj5v~S%;O3{I<}?Gsec5DS4;&gL3_4+)w4c+@lw z``0QTmdsEedIJN$emYIu{!j^iLui;TBsCcVt#>XF@ZVO~$>n2#K|v8zG>7y35YO^I zBRKT8EPg@=vI2&z(ZffhvENF85535|20)~%c`HFy3V4m!_C^my^fyDX2D|sY6ET&= zT6LJZ+M2lbIVaL5+uw!-K@1~!ug@k=6N2!Z$Tq&t-M3Pz+{ruZ>es*I&WnEwpU|!8 zD-aHMoOiRCAEL~7<316S{lEn@^k|~jzjGLY;4q_DD+uNaqfQ7I>h-2RcKh!pa%M>fmsBq$IChgPGs^$MzeBD@*|;1bp}VDs*94Id)lztX%S|d z&Aa}AJ4gQC!HJP8x=VdOoU8W|JC+`rD+@I9oauG8#c$JweQa!EZnITz7Ow7>xPA9N5g`NX>J~#1oG6X# zq;}(+%)=P^q zpA{As_LCztWyc;W;&oEk#dAV=wQ9%uVY$}K_)t9>VyRjV%_Mko?}veV8~n znS+0nYp=6BiFa34_S;oMwp>5TwyFJ1X%EaUPM6G71IdN8=_{6ic()ID3X?s1_o}35 z#t*jY(A6NACcS=rjA)I9oU>*>zC%|8%g^qc521fK%fDgY_x}cB{QEe3T?XIB;ji8B z-)0<=5W2E=63PbK_sJswAM(VKn!N_Wfe;u*JcVItZ|-@EY61RwxMMd}oZ*LNHu&o) zY*X*+w{LBi$akl@B~(L8OZ#nz<=zhMMwmcg3V5TQKtO#WWB|d4_cRts-JYH_x?(SR zyR~){m{D=N1U{g~p&%1z2no7PcdksoJJzX`+V9z%XWcQ{&v-07{8$Ir*Xs^*RUB&d zPd(0~;U?xOi;x=BbmR^bIM0ms8W!jJ$S*FmC`xs7|1Mb7p@0`!>&B|F;#h zd0W6jkU750vgx8+pdzeXXr}kn{PHp>EY?d3eY|a2a7^8KaZFe^BuuG4q6LPd{7LlU zM8_TFMI!~zrG|#;P+o3=ytq<(x{=d0mp?a?)gYbH#2yf4F4rhk7vL2nPY88j%dMf# zrz<1aL+nZN%7ox>v^UrW1PkPwzbS9oygIS#Sb@H>aqcPpV|9)1FQ}nv0ZsGn6S+PUPHOF>e zCP{1@{89Ob&Eot0pFXbiPgZ`v<6!WnBwtysih!fG!6wdy!C5LB`}_~tu6RkSh4!>v z%;{|0w?xr3YWL|dTU)%^=HqFdX<7f7Vct^1gh4`>bc>c(jm_D^ACblJ+8}d;(R*+6 z_QCA>^7wFtwbl7!$B)ZA+f}sGs-so)GLmV*4`|L)eyKCLxzK@BnYYFuu7xleTdjgS z6!X1kP7X_5*bXBM`pCO*J{u->Ys2ApOt=wmu*>K3!kCiQ4d6h7YWQ#`xd3#K6a*98 z%ukxFCeD@3>00y}U1l9ll^s!aKcA!B9H zqVwJJ0I!Mmw?<=I(Y56>zwQ0`N&wOTo3TqiiuB3M>et!=6O-Yy~orsvIFaB{E%qo!5f*d zzAGg`|e02{XZnKkDb6+t~a<*W}FXupq?|)IQJ$SM5;!k z^<;dPx7oR0m6e0Jr4*4FtPKi`sdVlz<$%I$DBMV;AKx^9-1cfv23W5$Uq+g7WtL{k zLaO%Seru^qf~TEP>B5x}mb4cy4r9I1#U(Aj{~BAGK_*f>)*3qhz=WMt9TEc320Mi0 zzQ1kSS{b3$6!7PLe4@kKq@>dji=zbM40VmSxzh5rSF)A>2|{H-xX| z`opz`(ow3P#c%7Tbb0E^L?#kFRNLPg7ZeUZjkR`Odw8g$QbVdQs+QxV+X-u4)=G#U zyzEDN<7=UejY%?7P+~#vq~bTRiaIAKw`tv=_DLPtwr$&OZ=}xssP?Id_mXc3?`s2$ zx5Ub#IO| zT6eML3=kZ9h%5R;<^ETVw;;Gz{_{&Le4o@H@EN29^|c<<>G<(+&`1pvSnD)wG zmmQHwJ|-ff*(Vy(SK?Y@8Og9HovY?!?>GRPn89=wMQ3?gev6^|Brxi4#WHVQdIAv| z*HkBy2fJ~vfyta!mU$H=z#69W?Aq?c@i}9!$YLcXDTxjFS~VpQO!A zC}U`BeT&Wz3#|&SU`QFM5zIb!znuI2mYuQ#IZzDR4HA^CUYfR-VkH$|%?XBMd}sw0 zuxGcvMDLD;_K`&>4DgbpuQO0B)tfo)e!P%)1_GfATtqma)F9Jrj*_Sq_Wl>8`Sozo zm!|qF!DAJ}b>-O{zHh~QFA+-bUH`--=pyXl; zWW~%eQBgu|P*4y_X^k=_4a`jrb6wi8EWhYz>f6gL=VEixr0^K1RkEdoL`B1ps+?Up z?bUvHw>!CZeJ4l>b#Nfx(rDh|I(Cmm$9Rv=h)f^4+8tHL=ml0aCZ>@iw7ky)^y2 zWtUfywwgiML{ly(&>q^hov{v|AM%~F96t-7xSC9YQr0s?yitw?yHU%ln%41tAfIcj zGa1N%EH6?#`rg|I4|$(z*nz!BA-lPVQk1$fas>jJlj-_hpEo>*WV;#avsHP(+QBoe z1vJJ=)xg=11R4zO%a@U<58B1stybbPmGtb{!43)Z!v_U-e8bIG=C}QV1`6ND|NO=2 z3Ut}9{QB`9<+CH3PJaIYIs#X|kJ9(0@n3sCj1L#Hy6HwrC%C+e_y+WPg zfNZA88L;$UKeg7ILE+X`B;s()ZS*;(Hlzn+g3OoS*^}&vikw{-=6obbB+9wCrR;iR z^KLm^O*hPv4^>m2Ou=j^^6ng`X&XAGD*pBOz-c(3yL33L9=!p8@Q~@y*QH{vW zl(N_G8t_2=3V-s05l}CMH{#mKb*9$Y6upsM0$U98T3>5N+@FsVF>MMvqJFwY2Xq&i zbNBg7;+Ll@16*tT**>t-{w>N%yfevcUQIIOO3VKt zF1SUH6-VrQ3A1PR#y&g@7EkS5MYZ%m;z{cycyy%aX?#@TiY=ASzQ!s z;t5M{iy?aVFZ5xSE*m2{O@4Y8!Dp$6lolpo+kFPgjnd(SSSeBKZ&RbR#jv%zDSj`k z+$TBYwWR`ltR^x1`~8BGY#Erd!whSudU4~=Q3G)RSmt$e2~HJ1BkNdfcjJU z94ZBbD-s~TF~SlMkhT~eqAZc>>ZWT9n@|j@8d0aNBl_5v)iaNuJW+w<55OOngsjKHC|kr)jbOk;ZOaUs zXhrYt4T;UUw;XReLoJkdwrKsk1^;iDRg-S{q3($gyAhIFd`5d$e9tE$WrQr4uF;kh z`-YfB!#8xH6DKSxeAO*L7-}^0R2bnbctP@p;e=ZGg*|)r{1duKLiLTGA3!8u{ZnDB zAr%#k!QzRGpr&{^HPD3*eqeR2iIK1d6;`x_&l*g6h=G|AFQP6wciT)3($PRDbqLPG zQXYB1iaw0rR=lrDx>=bl$i0-pSvegw5YaC%d&0#oWztR3q=iwCg6`mvJ_uNNf0+Dy zP^ALwN3mO<%eJP{%JmEkYI=*-_HmfGIUwn=i8ZVQa^&?`tU&^Dhm?|k9d3-p4vWQc zgTX2e%&$8#6(z0PMU%}G)=(h9@-SiXLV_p!t7MRy3IJtd-0N81m{*LeeQ0eCe|4BC zix8jRygeZhYJMLwisx4*aQ?sxwU3uXnmArq9TFrVD73?U9oOx$H#-+ahIpG;J6&Rb z5vHMaB{;_Cxb@g)ENh{$X_Ul7v)f<*PGY@Cdr%1S|K7>29C1b0F-N9PSOk}p9Zw{N zITdUJieqHwJPGYu=$qLU2+*bqw_1Z6Dn>fBzW(@a08pL}k_W>Q7gN>t64x1BY@Th8 zWVkJ{T*0}3p=W4FR~m+cKy8h=$zpXmv69GKDv+H*S60QBw`LjJAIgEW(~O@!7iJ#> z2gD@RNTST~4t+^U4btOrA3EvY_TtK|e7e&N6WFOe`DGlSHJma3@?K?bG&$#IDyZIn zM^s^#5*4SO-9_{9fmsA<_j^%p z&Btpe}{{IMl^Ld?HwH?~@463}Tj57j6kh!0+@0Z7xp_3tfhV$BR7AZ_?*SjWpN<-nm zJrS8Pr+2Mqb^uT{jdL|4$1R}8&%h^37@Sa+tf8@P|}10l(EMXXrswtgTHM(@aqsVf8+n4<6t3nfbcMKKKWRS^6R;oNHpYTSvdHVKWmG z9z_1D?}1MJL(IPqA*(8zxP9qJ0@xQ&>PfYSwwDN?O~;*PaBB=|vOUoU052oJTB_ge z{F$4d4yJjd!--@Nm7Q4@$tpqnIE~!h-Qjzx9BO#ic!2k~)T?7uBs5)Y{R?#R5LMu} zgDcQok<$$)&kAUVI=M0tI%T<9>LO{bCegpc%+q#8Xg3j#WJ6GogH~cln%YY-hXBA% z-N(TJB@>hIwhVO5425|ViJYD0b=K9EUmnuY#{*6UR1PGVz2ohXkv-pI!th7KBuvX?F|7gsC>a@RhXyYmZ0nz7IVhmCzN z8V(PZ{1eH4hxq>-jqiy4J7WK@joAO6SL=TY#1{p`Bw3Y-Q;<4(DQY)4p+}~i*7(`q ze;MiMNJ;EJ+Odd6Jn2f#Yi(DORW)|iIThcPQF?mvBafECQYXHe)#r}$UGsl@1%dd2;D_>X_ZnBjcPA;ap4@0?7g78O$tdqD)S%#tEvqz7=E!{ba08x0$l%> zFMwazdlQapME!I_Z42f{OeOyqpz2oX^$gh8Myx{i2j~~euU;i}jD;^S=`+A42soOe zth?_AlQI(yY2C+z^vbu5=+MCT*S!$Mwss zTP-6uyXJ>RyYs9ek$<5`xdX-EK)0cA%t$d>zF={$U_ooai*#A$>;v!x!j z;eXWNKt?GKEw_>iPfxmA&5&~l%-euKvzrnOpmMaGLnIKIkt%^O2Waf94Y@iS8`3|T z(=@&ZIkrIAdk9*}E@KsLPb7ya1_GcHoTtyMMc#zAAx&8{AG)(F{{OLptILgFt`aqe zmSIjK=o3uJ%{>FK{7H@(Iw(B-rS~3|A!WD@6Y;|jSn*3x_LeXLX$Q1@xo1H)j4UL+ z`F4F=0;(pF;Rwy*IUW5tVtv>Erk@1WEhr?QFPaFjDodAYpsQQ$yCJfAepo2G-xgz6 zJT{^%=`h&m0PSEr3nJ*XhdBPjXn3sb&X@PgR9s?Yxbv8!kJpSRQSKN4t(_gjbN&ZQ zxBW#q{2*#iKq{upV<#6#>v?sng3#XEJYszgHBnKgEgj9h7B6hty37B#&QZa6PI0SB zWBalviwTL46fS=)3?U^7+nxk%G67wozNab%7dtRWn{;qG01=0JVX2OB=ArW$0kL+) zV&S5Ov%2lF?Kc2^&*da))Yl^A8@s|UYR)Sr=#VWRhU{L-zJFEOh3KsVrHg0n*j|qb z;Q*VjxV8sNo4~AbDXo6-R|b%}aP!l%bMXr6!9cN*MTpRtpdd$biWDK&q^9KeXNvzX zP;TN9Twi_lb_eVbPDlzdf`s)5K!Dos|GsRyWYnHX+zs6TO|=M{wLE8$!(2a4IwQZP z*oamrV6sN3To{x^*+gvHLfxNJJ!?FmGf1U-Uq#BOKuZRAb?4p!?xrPO0i9Ns+x1Y^ zECY3?#E3*l>gUcZ62VA@Y@sDDCfEEHmiCq%qls-~bga(Wx^KRI0IF`8Efm)o<|%6| zM7Fop7<}uG`5Gq=nULfD#sey1;E zc<=A->FyK~d)Kpb#1JSa@y>SbrX9{k^34R2>HC$MqXz4u&0Dk}e{V3$ns**@Ac$S4) z(|Ta3cwPw~?FHe%U^F)2W9YUl*%4KobDQ0O7UO!9@ZW)$vHcOK;<(kO^T3?o^&+ zP!T0T;+mI-zN`;fF0#h8+{t~M?mE@Ix2md9Jp1p%%knudI@+`bxXXV>NfrgD6&z1C z>=Ogw0E8_SRp2NNAf#5WLyb}mY-)C@uKsjj$#l$a=w@-%HZw~oRD^n~?9>kQdYB(T zN5b=eLVzv&{9s~03=ZLrNKOw6;ZqVp__creihm!bLqq()ouR$IPwIiq0!U4Q!S-N^ zT4viFw~wG$at4IkzwFt!l7l|pK_$bw*59B?8%zL1)_cy|C&#MhX!a|Ou++9PP)&q& zn9*$!wUWu*=0E7GKEN3TA5b{qLy3({2Fg`uvGEV!F^1Qv92URd?v2BbN#sC~HJs6N zOFe7sKrSHl2xZV4AeB*oRr`2lbHfla7qC~xH-WL{{%_rZFW@22L1a13`Hx@RSl3yx zJbd(R>7Kp#jmZB0`3F|{mZl}@-ppT`UDnyG{KGc>E9S3${PEtshx>%{&INNk==^d2 z<_*Sb`qZoE&VHy0EegDMj=l7UV6jfIg9Bx3gO{EOd!E%jH73TJBz>Iw<+01p&qRFQ zFFdWEGNP{T>9|eUOw(Z_nM$v8Z|a|M*B4e~cJ#wk1^lpHNcjHWe=ptdWAfKP{HKk> z)e+APF(da`k=`z!eUKsr+4U7ySw@DeOPl|?L69@=gddPI-#LY2-g}*yX}?620U`++ z7S+YAK)MqE(l-G_bz|QSZAHLmYCxnvG!Z;L-k9Y$To>F0qDzR0O^t=L=aiPjrm(f; zur=vXr}E`0goyKz=|VX*-}i?rZYP0|jrS1|RLhfwc_+jZJch#6NaJaOH%vY0Qw3Fz zk4NN;2)#bUYyJOjgAe1fdDkA%cJ=nqd z`Gt7cVNfzP#w?Dvi9>yJcCD_jIR0TWNXP&BIi|ZY{ip|%CZSQD5AB+qi3Hh+bhqgu z>?2&six;NpMid*Q>IB#TaUBTx^Zr&fKsxi$era!wa}s?QCvynOpa-L5uUD%6(C~GR zLJEyLc(1x;@~k>#;+Y=pm%LEo|7`glvgZcr-M9nSBo^C3(Hr^1^Mm1;uC08nD&F4S zX0DyNsj?&|a5R|DUoRlJZT@oIyuZ}bqU}uz)mssgDD#yC?wBd+_{0S1qo9yE*pFzN zmdU(HlTtD5Tk`iG?a0I|%;0V>jI{`gl+LO*LrWfXA(CJSIYHmfnUi6vg!|Qp8@&gx zCy~7bQm#{yHg3*D^5EczyPMJZ^XEa|dd!MYu5kPIZLYFc;1zX3NC=u7;o>0wy$;N2 z0Z3~5Vl7j`N*PNt*;dekZ`)2psYqX~K{)+$Txa^Dq#dq+cFh?-r)L3ujOJi^1cTX} zPPc`QAM5s)>XB9q4fJM~4<{hHEKuVLfMk@Lpipphj9FYfCFZfv2@V~B(lez_PUV<0 zhbp>@oUk@v9r5OkqzZiB-LWhCz$YXCbXFN%3H#9$`0RD|Yiw+61-*{e$#Z%aE|f$` z+FsqU|I|TfF@w^BX_kY99wOvzo`Ct}2H{n)mHTNuiw*j>ZrwU*Rw@mKBYxU?d8y5G z$ZNeIw=J?}BO4?cL41tSgml`A3+xt@k#VRQ&QuQk$x#XN{yixP z9=C%z#br;NNC@6~z%b5P3#O`&6v}s|J^_)yx7&<<3L5OT7Mzhn6#S{F0roh$oVNZF z4MZ7!v6fQk_-u<{2`XIb{%DjFEsm{3xOLbv^fLQ~sAe&+%t`;MjsPe|pd~=M(-hOz z+RF0@JUBE1LDs*rJo|ywsc_v7=MTgZ1bVfeyiQMVh}sFp5kTeGpBZCbh&Wo^0j?tL zUR8m(rmj%FuEMMnf@CO0Qmf!GoE*{go(0yu-T+{MVWS*KKap+)4MmbMamA|LW^o+5 z%cCHS4%bZ1&(Ck3X@X4#?b8W{Me{f{XJ@_Eb|&5s&wL5qLwst9ie=no0vkKIK7N4HwZ~d@9S6nqUZaFV(I{PYDF({bJ_Inl9+}cs2{(E}fu^iIAX!WFcbVc6qg# z%yPdcuEEIH`4ki{NYEG;2nt_I`IkccpqALWc|EN;4Be&gh-*x0NE3HZ>Xp(pCZCg| zrU;_sw=1!A(f8HU)(&qmID%%^mkp6{Ow%zo?nx)lbmx^A5tJ??O7D6R?k5uV(|8o> zu&9Y_(BEL)HZBfbp|O%`QWLb}b@lZ*R`z9!`erU@cpsQ0msukXo}_FmQnl$`pq%7J zbHYHolANVe?hMTv)=O~rBi|bScHyAa)}_~>YePFn`RpIyb#>0Yi+uTYT3UTfo;~r9 zXbHN&?<^w^hoDL8r6A1e>7!cA+h$9&!`xE(RXz6jcriKpn{;^ zc_^VDhy9V}i>v_XZyW?yyM8I-axZrnA$s%k514kH=K#!q&cPC&ih0g|#DzjjJN_dU zv2~l%TFX6b%`75#iwMfC51iZAfs+7-sdOlRZr`;W7i$;8Ce?Qayxx|II`gazLi6dO z-t?u$80huZ*?PAcQFVNcvPgIJ)%?~&=yyF-MH*6B`JPI|idk6c>O&)S@Nj)(4TwxE zn&OHOTRG{a&d-G-G1gASSc?tqVK{kF<|1ZIE5dbk+#uyfV@()eV#K=e1vx!8c7V_| z>eQFT{63J-G_Fj4@#72dD1A&8fc?XaMX^8jMTnUk3 zM^r@4U!VY?m*;o9KQFqPr02i)>wX>N|2BP?-}{HZ&)2_a4Sem_eMK9%UkrM)#H#kU zJxK`p-(~r~u(16rwn+0dB;pSOa*1WQhAJ_a_sh(G4(>v%EEie`{y@%6#v+&vG_vf7 zb)#%@v4>N-NzrMGuT8p;?n09;21x}V!6OYvuGyC|S0=7y_rTQbFLxeS=s1#tG&4BmfcsE$;mY_=Mjib=bXzgYx}kI$sDr^- zGqW}d+BjpN;$iM6v==H1o+IKLuZXDm9-p(Y96&~_o9?OIb;#wnq4*|k;5;9LzK zLg`9+5Xg$uBIxA4{`hfj*yio~Zg^44X1tY-UMiG@q#)MWe*Nn%Rng2?V%~rO<49AP zkOc_K_Q8{U@&VOx38kqAWXenD3F|}SIClTB^`x4#Od5Os|mWfl)efu6Hu5I3lK|!(PFP1~i-&sjp; zcNby++X4gxfiv7qFrp?04jzm_?%F?%=jZSDqBH`(;$3a?{`a2{@gLtO8R*OmZA&Y2 z-2L}>`1a0%Jgck3)&5eP^l|7?D<&?#5rY&&3@o5PJAE_1F9FBoFv`KN(ed{AM0D-@ zzMB03sj&k17PD&T1PVst0=1*fHVn)Qt97*WDna5FOJN`;EWrfGV1fbtg**3w4jb{i zMre<#&@yXUvU@+N64e6uC@QYe2x{OT;#j`kS^72AGqx+rYhHc>3=fpIg}3b3zuVH% z5`bDpC%{`!5Vwvlg6J%SxN2nzZrMjt=!~U;C!C2T&T`j@co4u9Pes4{44yj%X6{E$2#I56q`+lrc|;1|{DLm15wjn&wz6nM*(=19!ODTb zlDIV@G_5o!Kdne>fV&P7Oju6bTJ()@(EPu#1wi~HUm#m1;0h zeu8Y&2;PbDeB2=Q$dM^fUmTfhN$lr<;l2=e=lxG$hs%RtVz3W)OgCfPy%cjMtJyQN zWV$$R@|%GI48}VM)v9`JuY$Wk^Bs3r9|+7GD@5EpZ^u`FB}_AX46b|@G4q;}g4jB% zB~Jnm=i0!^L8ZhOdAD?&HNW{y&wd3wgmo5x9jFiJgyr%)GT=GG5Q8WcL8aGftL632 zxPn+e2y$yJ1w=tQ7q;eRzxsuBrV0;cuMpV4Ik`IBh^R374a3O;JX`{)Z+Wx3g_vF- zmAGc1*>wE)t&UMIpznZBv(!*b0U;~2qc<9DXm8QV+_zrbdI&Yt?S|l>o0EXI?qFhg z-44Q8N*skI^_l~-Mo3(OrD)jzb1+5qK<8ljFkG_zO&d05aaGbbw5eIfmMea(4a3m; z>^?l4g7wNs>p9@;+!N7+V&Z4-ppLy^qL)^f-i2Tla7Ng*GMOA^$2&YcywzJ%8G#u{ z9|RbPSC?W5>=8|JOPv;9hue=)K8}VTmL)attO}JAk*ipF&r!ac94CHEl`hHQcN7>Qa3S9|+cEdgcV6rMv(jt%!v_qz+J$ zW&>Gk*Npd9Ivqj~?3R1*lp~#` zGIDm^<=$#uYxEpAf?JZ{mlO2AxQ2XaP6PFFLb^LFQlN8B0Z}asUUqN2DKLP*LaMAb z5_dqCH(zaWCd7L%2{V=Xhox{cVxxwe>WQobo&90e;6mw%5-_1U*XvGZO#*{%hrs{^ z0e-}kgkCAA*#|Ndhxw0!67?ByJ_LXQx#m2pLY!D8tY?H-hK`Q68j9AS%58>&(W>+3 zzlYEF7qBko=ikCweh?bejX*_J+&q&8d^JQ5Ed?yN)H(DycV!-Kcv&*TygmsOBS@~~ zX~Ce)mQxKYKbf-bEP2@tv`pR)cJXpev@?wFLU)4i%oH#p&;l@CIF;X}ZPHu1_7+wv z?{rH8hS##qvkd%;|;E3EcHsd$J{5t$ypLPoEyn99gbk1Ph2NZu?T`@30MuiHSi7AjInnj(-r( z>wr6kB7FDb840K}Km$B9rtHNtY%L+u;rx+CqDT?bB=yK_#I2{i1I-}@emwk-mgRqz z>;KcLecvn4Uw6Rw@&79jd>@DZ;5hteRL$Kfw=(byDBAJd-->xiaYE^XV?0nZz72M} zhiLIg9ZE0lG$|E)GtOj`d;HR#S3vYJz7&00#=0DIa)qn&LZ__=O8BEtJ&C8Q!*KRachw<^LM~Vc2HP=jRJW&1?wGR(z$WrdO9>mcZARG=8 ze1JaCL#O{>5j>lqIXz>!eVQB|&77?Y}gcm2a)sGJ@6O%+Sk zYo;P~cckJZfuE}$*}ksXM&5K&s|baHkN|eUDo}1yxiJ!m*Dvzg7C_F8#l+tL+&Z+k zWU2=5XM@9)@XZO8$LQ-jU;qaXepXjQicXL2;($g0EN266Es`XcyhLP?4KWfz*1#UP z&VN%Xs2%+(O$LwNb_8x4Q6Re&1B>oaRJ#hg^Fc%Y26?{Zjxcx=5{T@ao1sd7 zKG&TDZwI;#qezJIh8OdM!dqb^?B&q)bZ3a|8d3(QuTA#dx~sofBsCy+T$<&a%BB+v zD#|x`K)@d+(JQPkSwus#nl|Ho;EwXEU&} zwE4l^=F+7&!?j8aEK{#d28==gr&5U4)M%`K%t@g+ncRGMFij^6S+ zPo0W72jD{Lm;1`-uE`p)=dC4@9Z1!PpPc0lsD=dqxg*<^^$OmW0a^T|Uxy4#ho=nC z&$qI|mGgnlI3{cw6CMxgU#b-pWEI09kri3Ay9EicX+QyHal-ZL-RWNU$Z7PM&raWb zIJLPp0ipcD0etX}G{qZF7`1sj-svk|)HXDX^1yc^w9y_84#9cwPU}7LO~fvB{Mzt4 zAXA=omlmJagM=|XGeSlJX~y%QuiKcH#A)pwc?X!+BOdQg!B03dv0xp?2MM=2KcATS zvWWY-Qol%jgOHzuO`%#@lYQ&W8ISn2=pOsTI5&FRSPC@=ULG;^Xx(1vVTsqhQ-0tw zEFTUA6sMr`F1IBIblaKGgE65==nBU%DT$EPN*#8z$D=^?n!)9Yy6cUxg4+$%cpQ{L zl;4+=t;GfIPBP)~J|6f{*lqet=-3=ASpMPqE}$?OKX+{xJy};La?1;NGmwsi1gySE zQ@!zR$vK8?)ZbN4AcVo93AO>rOBT>?=~KGg1$|3B%97X4uE7hY&i~`9smM};)h(EP zT<2B0N7HDth55p$*c?cbs-P!);%3PdLhQ_u1P{Zg`*qOQUqv$@zRgf3Ln|=?@s+Yb zx@@Y&ts0`(s;bzN3*F2Y#+)1{VSB^-Lvll<8t+cLEjW@bPLLOXhD1yz0mW;+1Z2S> zCPPSpJDfV^bP;qiZhqv*lgC4XM9a^F&j2oS&L?p&NPKJlgM$G9t93$|=>=GHEYCXc zdH1zs487IS;ZGps%+*l+vn(=0!3*zjldi5!AiNt3IyQOsLRbx$0F0el;GO14Z!^L& z4g(KiVE@gJY5Yv>(#9K@mRFk{z>>Nej_pTNAEHK_Syg31)yEe{*QGr(DG@;bG4E{5rrC<(VV~ttGFH8ldo_R zd7m7-ysEI4keR5I2D+z8+X9AUxaYU^-j(F5#|oBX;y!$LDmIiX&>CZ=5^I?)ax?4w^jyaeRd$LeA2Jxoj|C1?vq2XZ_a0g4$NeM;X99UalU%wQC4#&g2 z+t!6AEXQd-972C__ToQ(aeSRTVtMi6pUUWs>sq1jA2|Mfl)f*G|JwUuXLcEjM2>@n z`=vytA(UQEATGV2qY{N?s<^2TLr6-)D%^4rO59<52R~S$-a8$!GELc2w|+B zQ6lDQXXQTr+>a>;L4UQf4BoM5Vd6EX65s{aGsx>XEN=iXI|!CXS6R8S1irOpw;kLr zmZ0}7R;4DwSq>GJSJI=;?vHz~t1cbS`{Z+6tAS@Qv}Mwy%!eN#mC|SDltO@EHYCmK zDTBL_Mwp0cXdsw%&Uy5q^*7(%=e~=3Kb3paZ&Uafuc;!$BRxpR;ij$3GY33vJl;@- zhxdYBY7;3nCE*RF4;|iG1(=5l0~Ms2jalo~P4*;uOiU@aKR>^Cpmt8+ z2Fsh9$eUeyvPq$IAE46OZjMafsPs<*#jtyu*#uO~5&sU5bv8lq=)p22kpp?#ELcpa z4EDEZ@$H7P^2Ly~b@d%`Hs2nlkvUqI`&C0?ZmcT8Yt-OPD+w1EllSf&MP9apynYk> zZ}f6+FNTc5OJd;gc$q-c``S@E^wIV3JoIKoNmyG!x+vo?1!DCOcs+Dm7~YCVMD8m~TV1Mf9dW!2qm;;rtARiq#o_n+L!E3A|kcL5hux|Cr+qM4|7o zC@UuGJg#f+=`{jnvyOZ+?v-iD2gueTXJ_vkZ?kss__p98H?|v8Do}gbL3z29Po&Wn zDf8K2&Yqhg=>9y1SJ!9Tb1U34xlE#+UK zDhcd6X=q3;@g8}dTzunywD+A+QC@Ak8l%P-C5VDFu|$cn5Cud)KqDnK(4Z8hCxxEJu{n+{8~$l>-uXdRGA@)R-nxdWiUar{sC69ep12Wb!4f9%)jsX66_3-lwl0 zfME?)f#PW@<6O4HwWz!Lo;yv1Qm>AwMsEl&+GU3BA9L0p`o`$s!2E;= z)|(Z=+?T~U|MO~TA5Y(4hBR`{_Z?Q zZraRP!|qJOJ8u?{H@FzbG7$9G{xNsYUSeXkTI=CE{cY&c(gOcw-VCK{OMW!R#{ z&=I(1FgvhDN}Jsc0)cUq0-D*|%?3~tEH`oAeYN?clnNnzW-;lA?h{?#Q6yaVTsGVu z=dxbF1<>E7oQyvUM7W6SJ@=;AZ4oB|VKk8bqe6P(u-BF?5$LXbQKWn2D~hifHN;>= z1Kgtn9iO&|1Cw{I0|?8`!%xqL2jJPS^)hmelQDxS`h0QmJ1wkWP#eyY+?A|4tljG$ z>R1m$TKC~Zgz4{TxDw{$@-|3vA^}1?{{0MLB?nr(-tO0xo;@sVw*v!AvX6USjx;_D7s(j$)csjWLn-J%N*w)M>~+B= z2!=V^DmO3TpntMqwr|;F`dEz^275EQW3TvTci>z6dKk~rsU%Z=zZ_q5`t)7vzcoh* z(Wn2}{xX1zk{(!?04&sxHnUKn0J- zBT-Lfq*<2U@WX6_hHB(EXlH}ezc&+8&Uw&Bl@Uq%>Y)>YJ*I5~Zm9~k5bX^%&#U)W zN@{rRgkp8YByGIF(?!;S!zV!qzaECo*_nQjmg>A}2RkV{5BE08#(s7X-1y2Uth=h? zPvUu1k4%Ak{SaW-YCH9p{J1uDq3>w4%oxjZA$sK0Oj+!%i_V^nikq_<2mnsptn2LI zCRPa`f_a{(B;3991YgfN0&fc=Nz-V`glAxZL7X9po>t#fe0bYY6ic@QePF%_#ELyI zfV_)$fjn6Gg(Dg^3}BLM1sN4HKP2SC0y$Z60CfR~6myd@Ke<1x!3L{bXC{WHl3s>C zX&qsD!~M#b2HS*rc0c{J0nzCp!K7RQyi+m+0aYGTrd^M0_4a*srP!hs`z`ss~ zHJ0Yi&q_gsd}c7O_AE5#R2YY(M3_!KwX7oVTU(~dY76ehYs1G@H;@iNTb0gJC6t41 z_?a#eCwUqt3Y^T^I_em4`+!H>dN>#}(jQKV?()Ib1qZbzs0kN^L-}08^%J}q*-X54 z1Apru^Pe`i{&uBf?Qy<#Hmhi?=EHFeTA4$2e5tBCQ5#zVis1Dbk*kk770St3>gLPT^HBuKxb7O!og6 zU+4-$F!?sbuSoF`5ONFNh%oAms4w7J0yAGmO|0Hiy}c(hFLG5PY-g;Ns$%Rc7? zgo-JPmw*1k{LfsjfBS4QyltvbQ}^W$E`Pa7UzW!I*U!W484VWx*C9OIgj}T6Q1~rC zaS&8x@V9~W@P5IraG`1deNj?IVTtjR%PS4h&SkX3xxD>-CiUpuq4F|KXs0)hesC-W z6p?L1wpCad1^5m($gi_*$aufbt|B@FsWeqM(Zz>yJ>4+IBcv(x&)j~e$qG|EsL^uo#%ioQp1ah$06(E1P((dcrQXk zdM06;nB!bQpBsOo&CYwO+i|3~*R;n`mKm*`bj*BMHCl@Nz+-!%AVqx}055D^Op#&U z`-Ug1mgDr+Ow9 zx8rRxDE4Xn=@f^gSA}Ry-IjL0yg53rMnV>Zx4@n^E|sBVAZ`In*`dLS=BtIQ@ncFZ z?j&jlW=)h6oK#~Ba>IaxxD)dkGLmvE;@a-KF?_zn7cEwQL|nA2LgAp*{P{iC4R#1G ztoLuYurSlw&GeR5e!hB0#)VGILpxjQk>i7VAimmT191XHI7g6CYLO@+GDve$tymls z6f94@r9;`?cJ}O9$doj`r^#~0OR}7pC&&e&qHer=G2P_B(zV6B0a#+GcYmUpyE%Sq zVkrs-oRF467gofXxRto7Xx*=CTi`RH=ruz8?}J8{nTtFQLh{*0LbDJhvZy?F7$39{ zwz280AD=eWHnj-WYER2RX5p0T5@xuTg~LR(VP?*OqEUKX(Qwwa_3!&2aWighL|}`# z-KYBbbC_aPr61PyyatTkB}lCsTETiiTh#w@YjH5DBiptJd4}kM1vk1r(PEv04Zio& zf!}J|HFfuvYzA@WwQ4I%?&|d<>&?ElheYX;2LSY1yBj;o++Tj=O|BD+wDO#WYKkk$_ydu}CAj6qpXjZmaq!i_qR=48 zKaOKDah6&N3dCC*z=R4lG=C-L59YlZ05J9d#}E~TI57w*lPjs=#VhA(JajGWd5Ch% z;eC4LU~iKOc%R|>D-moYxBOd^UL!W~{A^>9Z?VOl)|km>#SXOwD;V7{HZr=?@(G;0?XUCsxLXFOW=r2BEKw3z8tBtieUI#c zwVh#jYAZ&}Ei6P0G*y$06tAvcnVNk>Tomlw2Zo<|7-g(WVTsB?vvS+gEBls}AzXEJAZ>`t_BQY<;tNN~i5jU9GAig2LKp-NLaX-BXwn_b zF3#6TcLUAiw&qEi!* zzQ;rbk9GFlE!h%_y-6#GA)#W1p}y+!niPmNumkWs$%m=;{b5q*<=W~67)1MKPcX>6u{|Gg7u;;3M zi1*;Wmtb~i@hh*XI9jAu3?tuWk;mJjk#zp3jjl!H@^ymuaNYqle6jbjQO}}>8vrU4 z(jCxAq6s^!89HZakL!tN)&_u=8<~|KGgye%7|X8{=rrpU7Bj{ee*%_m5f`+Yweh= z?%HMID1_Q32@!|Z>{l{4Od3kKnDq|!AVzBy0RKl-E^cjz7}`JB*Q^ePm3hJ#7RCI@ zdln|UK-f3@sz>MqjU;C$P;_e6`h52v{ zJ_OT-^#&S4dtuSy+Qfp5FKH1|I|!3PvKXvrNxX$h_b2-H=M(^3`j%_~4WJ&YGviT{ z1YuY7cRsdxv7Lz>BdI@xOiJw23$I>`aiaQTTAQ3Hr2Utz;i7Enk@`8Fvh>D!n`5aR z1a*L8pID{lm>K*s@*r5}>m!X@d-&tis$Tcz;2mFb%$c=od)|{yqE;g?LzH%h*>Asu z>-N_y8f_g-#_(THGv`UyGakEgM;p+KdDzKY-f@@j*v`ZTwW|%(XSNZ1rbskh{wNChI_r!A6-zef)bz38_4CH+T(R17~Zewl<(d zqXXZL?IaVQ+5;5B&mc&Y063N*k_5XfTo+C^$%PjCA1Q6$5!rXLVtJ&QOr-f$ALd?j ztb|}3@Yy48&txEMvBHftmNBpoyFXKe;;~Um`Pg2CPj$rspVJo{@C?Y}jOid(I<+zz zn-K`(JTR1;F2-3>C`PCQ^)?NZJzNMnRBGj1&}A&VI!h;qW1lQZ$okdzarJ8Yi0|X6 zGkaclsMu#ymNvOF#*dvM@#XzUGzdLfYV5Ku`L9%T2&KF1B7$$ukQX;Xgt z{Dm)o!vA~NWkSK5BW3RDyTXe%Yno2q)chLd2fs}{@Ri#WrJ%64p*NM5?pHWC`-)BE z>08sRYW6QU>+<;C>Fw$p!?JeYW2XN4@NS~a^et=EvYl7D-P%3v^tbv4qHlfOwm#|# zyZy2a@2)bhe#tDZPs{rTZ>_QZfr0#CxhekIUkU5LFaQ4gG5c~I{$F2*HPWL~x@>7- z&k1#UHw_BkEBL5Ux_$9@FR^dqOl#pHVNz?IqlGDY)IX8$(rs5nsZQL1BhWDrsQIFg z?t;Dd<-@EaAEu2Qhq5i*m3Vv~J3+jiK|v3lI;|p6xoCTqOGnzmO(We--1o-SBncZf z+Ik7Ox$c|B2Ned~1pM4B>}qCO{vAv<84;XjlKF%Rzyqj|z3;d>BX2cwj{iK; zkg=}-QYp-MXD7h>j$OpAw@nH>oM1|P^+V%OE+pay;W7RL>-aI^mxV}+z@VTxLm7OC@(>#8rKZR~ zPg%GSfi*oFyAl(Q(d7+d=V#jSmC}kQ&e82A$MWy5EGX|P7BrBXU6wySwv-TrZr?6v zUp%8w%-jCmBHqw`%NOsRNlRK9tgtpLj(6DT^#sgVfpLV%{e0w$#{gBENT7icS2YKoq(Z zsV;abjzoWLva1AY#QCW67<_ktm~5sESyyOkF?&Ax03GOlh9L}tG3NzQ#HrN*b^C>D zn!fu_b-Vc#zS(P1uj-sUXyMujfyPo35h@!~zEd4E!oKee3bTF*QZEGmEMu1N>L#;jFqbKm|&4BjqjTAJo5 zo|}{Z17NOLPSet*U;r5^cpIm9s4A)>#Oab-jPv$ldQT42g0I&KzTx#5Q=e|_DHCu3 zkZy)_9$8`+NiW!Xei%rr7!&N>KH%| z=1dleRK<_I=V9P+zo(=@`4-Xxw)_U6 z3B2JBkzLNrt-<|Rff0Vq9fM+d+X~*ELPm@T8K&Fwe0v_yRcU3C#)Sz%sR#^e3H}BFrtl7w$;(;oN7c1 zi&>uu_hfmNaNYKc9aMH9j)RvYBkQgKJoph7_TH|eaM3m{1qgM4Y~Pul`45VG)UbnY zY`>Ne!9h0D5=Ai~!B?gQ3eq8202Dxai<MQ`7r5@ic%h?v1*3P9*1j9 zZ1iNrO$^?prvSrzCe%zE;qBirI8`YcINxH$d~W*zD{LY&3zD<-NVxW)Hs`#yv91Fc zl`6v1uJK|4t9YWjczq_$%{E`b9ar-ED#f-ZoWiqCWj9(S&6o2XJY+Fk9SKu%JKHN) zI;YlVJ2b?nLW}kJ=WaTEpGaR16!tL+y$uTcD$j%VFGVRv&-^U^*qF|`@Wle*(Z+&V z_pd)NO4T$@2bkhum_EjSR~7!N&rppe!J}TMHGY*+5u$6x;>q!OM-F zUmsGe#q5~g1J9SE7Y<0lu`K#h6u?;PnFSqS6TYCsMLpI>2zHVaS<)VN;X5g%MCx(G zjQ8V*DA(^gzaNM3(#RJzL}WkdL^7?B-Dz1I6!3vj%;jBL_|N^AJc-(gyIvFujWK@? zDJL)>--dX}9oBdc&qsYP6MGp?P;SuGD1J<8jy15jC~o`~{>hg)|MKJWTq9Jf2^Vm)nO(;HZUTMNW4*|3oUA)E5LNB33W; zIgXYj+b~nUy?j+Lz>sCJUR|AZJ8D?rPq1!Os2(d9e5_Kzg$cKAb{LcR3e+kTf0BhKO~?>z7B7 z`1(Mgh4Nhw??UVk0o|S2r)Pzqr0Yk>77I6i>_PpUQ9RcDq1bQ)iYeckl3Br{b2^;!pw$oTM~=l$$S%M9r#Jg%_Q52m zF1F>9Pw1{ImaMvKK+?PUHJq!^-QzA@n(rW7or8kbK*@r{k{5tlMx1C!ETRm6N|OFf zEcn1A(Lw2sT2E;(YUmDJG7e_~K{LQD6Q&xhTI}lfR$MFW2F}!FAa4;+&@cqlO0w>p@Pt=fNsm^9m?v?nrAe zDpa>QzCuZg(%)&|b9}W8f5vbavWz4S3+6c1P)aK#u4{t9m(NhLd@1&l;Y$6DH}%k! zt_G|9as!xiO~hwRDiZ_PpGiQtS3$u$;%U-e;kzCf$3AOKtCE~s_wRpB-u&bt5nd2Es>4D=uk44{nV=z-<#6eSDh zfbN@HU5TJDYEF0<$Fv-1Qdqx0qHfV1UrfxJ*JlC`p%r-A zJiw(I&s40~sDWA7-n%j9gHa&U%-wedLjx?&%8&DC?SN}coep}+0+zt${O!l(|94Qp zy-3SKDJ{QWNdNZfD<4^e?ou1BR7ltI)O7xcaxM^==N8@ed1h<-iupxAE=ob#psU3f zB3wJ5$d})zFws?Wc_m*R+>h3vRl4%c0-E0Acj-D?<)*~hAoRCJO%4Yv!qry5)8_g^ zcSeyfE-}W&54?t+6NNOfoZXf$SQAGU@xBsw&9>IFf$#SU^u+ai2hy{Cd^}E?*#cG( zGwdETB1~ysoM0;Je`kx$Yi+Rii^2a;=;M#IMHmDHiaDm{z=9_!s3Z2kr289Lwoc4* zf1-3T8vG9=7z=^J^tLt)&FgohWX<2w$7od$hC?v?DSB zwje@yw#de!(Mq!I%WWT1c{E;=N>EihfM=r=B$tiP_Q4TT{$-qf}Q-wa9RzeIa= z-6L*5$fXD)MJz0*sz)bwtj+rY+>Qk>Z0lL_NJj7`QejhqO|p*dqepvM+G+yzK|6l= z2w>1q&;Lz}ELcKQ=9Dk{CeS`jGBRpc?535r^jsA&OW)TY-#xXWhIlKo@%Yjpf@b>( zjU<#dpik=~7Vwx0No8UjT)IoeH(fuD)aPWOt!LZCdTwx35p*w`t$}H^`*B}zqZ&jg z8<&0i?YCV8%rQpsO2q>O9?!Ng1drU5(3mO7Q8(1xPlOhaakSQ;)OFje4q!?GJQiS| zu#DKdZ{Pd(x`Lm7Bn54AJ)~f_Zdq*&ZGf|3F>(t}?W8Q6VhkNC8*GBFr5+DOpq|~PxDGt-LCLYv!I>6-(tKnw_Z^0+V zKN$GtFJj{CF!YFmREeQS0vW~>sq3WUs_AkWdQ|MtwBcV~(ffXbHRwfqZDG248==XG zXIh%?l#2rGbbk5iz1LyMTkFYQnRCBr;7WQ4h$zx+iv*v1?0ciwZRSx|*e*%gTEDy`{bVv8{Ko@p&EW4#f`D3mYVp|B0O4|NA^J3^q$DSMwl^;4sTcLyp^Qj>#=b51vzH@q zg3ViN{;1@Nao96DsO|;eC%m`wn@G+135Uz9C{H}EY&RkESjh;6=+7^TgDjcy`) zBR~>hjQj#qtgQJEUo{wg#_g#}BL1bM+wt{y#^4+BC$K&7a zXjKN0r8*LGl81(X;ev(pPLTr&(nxOKqn>561luMOxJ3WxF(wIIMup-uISOwoW%v&< zuaZm4gMmW#g@~`=ISTtCcKqdgGxN;SsEmKNn|W8ouUNJe<$%XaZxDtiywwNF*3K*x zwE6x|w{AfMp6gb*EzBVjzzO3+X_9_Srn91YG7xP{pJZ1y=NrQ{LJzpo);NK4>XbRZ z2oLTl7s{4>n#sTqTIer*Jl+(&jl$Er zd_`jc&VX>>>e!}^hY=N`L~*?`SY%Qt7;Mc>KABF+vrRlh!R|~>wys2nCWv_vzqEh# z{=G=k0;X?GzqU$|6|D3Q2k9rLM4S5f?Qi?Oa(Zj zm=4?Fbds$k;?Z$wxk4#Y8RwCs&5NJw#9tU8Z!i#iSn#3cyMuACR3bEZV1Gv(PbZ}v z+FcD`fz|M84B5|2u8x5((GIXYEn=9-0Ra?lhFlAaS2;kc?{8 zv^t_+Z}r<@eIJb(aWW(IN{gEj;+SEt#O$ZV{W|Ic_>GKO`(f?!!+4jlf82%ml`xnf zwKBuqYdQtw*9Ue3c*O z;zS%M@@}V(O<4K3KAFx4z&M876@->9MYx4!X=~|@^{nKSH@)_!`HUFiN=(Fy0i}8lZd}I{fifrKXa9ZvF zo0qAWPC|gv3f+DIB`QI=eZd0h*1KBcN6p-u|0rMx&Z*7Js#`Zj;!pfN6}^p__lJd> zJWhh{?$ekTY3a8dcJMv8FPJB8nW zZcQb0d!*imlk8@$u)w+w|MAe4;a*CTtEO{X0D%2n-^r>C#t&D*14a=p>wIZTUaJJZ zs{;jWE19NGPFEZe=mD~n?`{=AjqpdD)i1#Vm+29NQHmJ2=3f$m-eswBZb zKwKMy*W+(S+>XD=UGmc^cQ~a5%0s>gX)Z!Pv6AdxA(_N0pINoGaIlHAMTAiHqA2wM zqmmBtUCOk^SDAKBwj@?)QMJ$!PiYP;>{@T0UlfG(#p37d1dnq2Gsvh}(M}(P%ZGG@ zt>dPio)DNu>S>ph1m=_?7YMdKM_;8j^$$549y-)f_TCxbwTL#{QZ3vmBkzXsKa_20 za{M|ujgh0c0Caj+w{YY=B{XN`;7YF!oD^T z*lx#oc0gj}$WNB&ry`;jNZ85k5R4NZzoTI+C@N}rw?!0lrWbVeQ%B_B@D)I8+0cE% zLA4po`vqhYyq`gNwmh-~gX~t&=ryz>RZ>u7JMjDe$_SHc`|MIAO#I`@=!no8oslP?ZTN4+z>i*tmJRs<7Sy+txIG{rVeoQjO! z^}gbm#q`e0rJg|>PgbSnu4mSqfeCpC zD&u9)`22J6PPWau|Lq$dm)-5tS9RC@)Q6L!OJXprmx8~SuT(XRxa5?Tl}#Jg#q|Ic zI48pQ+G})zo=X%Hy4$vG)Bi;5Rr%Uv`f;SCOD=hZ_Ulqb7dkZRam=-!<-bp8Y;0Vp zKHQF_Y(vc=X6rbNu0|9Jw$`#3Yv;l#d61@NhamFVy#y}2BHWZw3)NiTu`tjbcC;uk zz=1H>H2T3>k`3c@MK~X?msc13j0*>dB{`8gtEVg6+5W(#BP=C4Ld3RwG!pD$TdGf6 znf;_$`ZM8Rt1Z^}d-40&Lv%GLtQG_5A>Ok0BtVl%v(q)gnYhlrRwN-Y@ke>#wYuO< zOvwM-R;8;^Y?^sVSA+kn39{p`Nl*Vd0QzT1t8Lm__9ljS;+SM&`__8(=eCIG9$^>c z_wn1mzN*dc-6okSx~xcanQq9&p3EKF!-7GIk{MRbgS0~d;bKqMw`0^2M&WbL64u0L zS4j?^@Ai6I)YMvV3uGnCUdqb@dLrh4X}PUIA)dI{%*bLNHK2YmpZ%Ev@geUD4j|8Y zggGL#<$S&$9}_{WXR~WNyaf8`iUu^;n?+}SGKo?6$Auhz?8yY3aO!~tzn%Jf_}({J zy^QCJVo>Y~JOrMgS9w1XW6S7X0erD}LKJHf)Qzj_ZYbLIEs0Y+^j8TW9V-Yig6e_u zUd>j|NJ@66y?wGZA;a04ngs*s1~@Ofe72k@WL+X^d%dlge2W-NE9YohLq`r_6`kDC z?_@kYVfJkrBI#m%RmH&!KRp<%g-PzZlf$!1mZg{l-}vkzIN}G@0b7Qz!7EAj@6%?M zVgly%a*W}dvmRT~a%(@-Q??E?>M(Q)s?a^l!oj36H~Zwf2&Y#%677c-1dDZmu`bWT z{|#c!e*>jCldxc>WnvwDXyRPL5ROHK0V8v;s;Mr|4!{VOQA#eWNUqwu9p78Zmvua^ zH@gWFVjW2~%m}n$b^!vA#nn@N+zw6`h!Y{8BzjrvhHp)Yz3$P!`a0Z`fg1Y4XZfL`MmXH32_eF_ zKN>}MPcM_hBLd%_Rj+_L&G5-jgA*bZH8IJt++)_GwMuZczCH8X9Z{Hn)^L4@qWl%Z zv8w%#5K{oZ(x)6z9b<0DfSZazNvQ-!;{)df6#Y1egHX<_^cor+`_nh`9h=f2DvI5# z?AcoGz?k5Tm5Od*S7|g;*fIe=VtDH~M~kHVl%Tv}BK|TMB@a0xqg{>ah^aRWjNW_w zvsF)-Qa0P~_ZoNriC=#jX z*7dItf+t3SxERH-E;&(%b;X&C@FWb!*mDmaHTcQe%JOoGj=!$ z5^Zy_KX%Nj{CXDA`cVlciFRxY*ni7mzbtt-dVtY-*-$^wqR^}K{-LeRKg9IQ{)!Wz z)&2>gQ<8s2&ovRi(?^D_b?56x{naS37bWOf#`QPD)CtBXDmHXDXmyS>)}`H3JdkzF z2AaPF(G3-;L<$B5@DNeR+L?_tvo?@i>A74w?4C)+gbeJiD0_`rCthkiJ#Q%nEJM^v za5T)n)@r8k_(>tAxI-0uw%CJj%V9qv1=kd53A2-X3j6mZLE}_{6ARkF+{`EaaH)gv zShOS7+X9ofwf6afUHSq)?Ag#)GG-kWG2Jm7mZe{b`?HyZ8^){BGMBh=MLN@~4~|8x z880TrmYg-_o1(55?B8p3k7V)9@U zH|K_mmZnjf&k|5b#pV2RmlFogq)->-BbS~~PV}9~0Ie7`OrJP5&~|T#x|ihKsJhtd zVf84c!7{)O-F#^O2-BcC3NBfy?d4+(c>1mh%@7`>+=PvFvtRxU@>n3|O;C321>@5O zdC_O9DnOiDF*;oMXUj+u>`suG99KG27p|{Ksk*}3rrfw*oG1WJvHbK&%+}ic9y!90I`&XQlZ7;9FN}4o zNgir##U^HmK2QhFv^dBeq|g{``cu)1qp3x_rtOB$Yw?!Ye^Ru?eQlx_7>A5%@-WGb z_}n*U-cCYzttY#k*sBv6^pM|O07(cTU%Ipv^N+Bp(`J-R6WJMBW#Gv8Q9bKejT){D zG-u~YX_o-= zKMwP-X&FUzpw@p68)#c_Fb|LS9Ow2rT2@}ma-{6n{}iTNb~Kvyqf<4Z9+-K)f4em- zeIn_Rmpio6t|?|*t6KNqfP%1e1nG(a1`<(hhZep9 zv^6wW;TU{+eYRceSay&3uA zvsw9FNr(E;<&>o6_}#7Wfdbg6JC#X76JLy`={1sh7_0$1mM$e>K-ei1h$A@Q#AKC% zpn#D&O3eGAGlDBK{TE~xwLs&7{JBJ8&u0lzsKcB`{BzP1s^F(2fCH}^!>uylqqivk zEKJ1$_dIFnTD}DzR^{&IynEVTC_`9_nff9m#gJWM~y6|0Z_3DJ3N) z2C#fO^5Mh4UkJGB`H*ltDl?VV<~7wB{?iVU$b)1Bz`A77fay@7^GU>Il62<+OU)xd z%Xys!`650o==zQ`iZsY|jfD_*q|-ny6g`s~XElP=*5urd`BBLS&o}hNZCg$Y`P?MfNBi2t#$*j~=Uz;0mpg*kI=nAty>lH%Bf{~^b z_%4LNODNJSK&wBX+8{5X31Jm%tvIf>cG0g^Lf+H1RWlj-R7t2%+!odP2`*$?4o>sU zePr$l6;BskT){#{-CbN?2?t!p2L@$x45htd-08I`5eq2V_BO>`J-bFw3X~b6adxlS z_jJ829RD@iTvqJ7M$G<0U~?ymh>7yoZlUQrBGV)@q4W6(Wz<}5iX7j=f||1R{M={x zg15QA#}7U6_VHB7%s?>~)ImWr;vRVPw~}5S4ZY%wxdod*`dUp5$y@j0#)hyobH!;X z#ID!2!sp|K3e)=s57A?8NTv<-`QnHW0C$`H2>JykN(qj;ifbY=8-FBuj%QlKpEeuenYuyI5yS$B*PoF4HxWZpv}w|20Mmw7>oc1jA<;33G_lBSlBv zTEVsR)b-ba^}tGui;V4z5E|t>W-$-!>TxjL$|X5HErs$3u5doZny3Mz?Rl;yevNLk z>W#i!Yo9_knr|enbx^_UMr~mcg!=-!If&07jf=!#pm&SHpGqJNFIF+TVpQma|JIQ< zi7|k;?n#dwKWXO2jSsO$HyeJm>JH*3WfQiZhu1|v@t$ulkJ?jf308C=aUfRes%SVx zQoMn_Syd;}<$p&(h44Fu=EpowHWN`LoGq2niX9h;aZpClr|Lq7C}ZG$w;VA0Y4Ds) z3hP#_Qqi?}PdyXs!Y;RlGc4VBUVA>`76K8kmHY0Tf}gYT*4E^sRf_`BDZU=!IRYif zVoT5IOJ)KWr;QG!YXg}P;kNt>Jm7O`!p;>J9F_4tVDFWGj^(>{i{lUtgbNZiMMyo{ z?5C!-BWe?zMT|Pw0QEhzDaE^Ph^@DUUDJt|g=CaBN7_#s7NMdNmTx%m3lCK8aSHJJ%{B|ih`ti1~B-Kv+3IRem z?YeSuD-IsjHin=Wdi!DD-UCRq>|S1GNw_2haOe>7q5*Cbf)YTPz|4v+DZ-Bi=wO!K za6}V!)E?||m4u{Y2f)- literal 0 HcmV?d00001 diff --git a/forui/test/golden/sheet/modal/scrollable-Layout.ltr.png b/forui/test/golden/sheet/modal/scrollable-Layout.ltr.png new file mode 100644 index 0000000000000000000000000000000000000000..1fb608d8023e788d12e734167f3571a20ac2eb57 GIT binary patch literal 37687 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 aA?#6zQ+v$v9K(h@qs$$}+gZ0BJ^w#$8)(V^ literal 0 HcmV?d00001 diff --git a/forui/test/golden/sheet/modal/scrollable-Layout.rtl.png b/forui/test/golden/sheet/modal/scrollable-Layout.rtl.png new file mode 100644 index 0000000000000000000000000000000000000000..1fb608d8023e788d12e734167f3571a20ac2eb57 GIT binary patch literal 37687 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 aA?#6zQ+v$v9K(h@qs$$}+gZ0BJ^w#$8)(V^ literal 0 HcmV?d00001 diff --git a/forui/test/golden/sheet/modal/scrollable-Layout.ttb.png b/forui/test/golden/sheet/modal/scrollable-Layout.ttb.png new file mode 100644 index 0000000000000000000000000000000000000000..44bbf8f28572647e61aef0020ec88b10e16fe65e GIT binary patch literal 55808 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 literal 0 HcmV?d00001 diff --git a/forui/test/src/widgets/sheet/modal_sheet_golden_test.dart b/forui/test/src/widgets/sheet/modal_sheet_golden_test.dart new file mode 100644 index 000000000..7d9a727f4 --- /dev/null +++ b/forui/test/src/widgets/sheet/modal_sheet_golden_test.dart @@ -0,0 +1,105 @@ +@Tags(['golden']) +library; + +import 'package:flutter/material.dart'; + +import 'package:flutter_test/flutter_test.dart'; + +import 'package:forui/forui.dart'; +import '../../test_scaffold.dart'; + +void main() { + group('FModalSheet', () { + for (final side in Layout.values) { + testWidgets('default - $side', (tester) async { + await tester.pumpWidget( + TestScaffold.app( + child: Builder( + builder: (context) => FButton.icon( + child: FIcon(FAssets.icons.chevronRight), + onPress: () => showFModalSheet( + context: context, + side: side, + builder: (context) => Container( + height: double.infinity, + width: double.infinity, + color: context.theme.colorScheme.background, + child: const Center(child: Text('Sheet')), + ), + ), + ), + ), + ), + ); + + await tester.tap(find.byType(FButton)); + await tester.pumpAndSettle(); + + await expectLater(find.byType(TestScaffold), matchesGoldenFile('sheet/modal/default-$side.png')); + }); + + testWidgets('constrained - $side', (tester) async { + await tester.pumpWidget( + TestScaffold.app( + child: Builder( + builder: (context) => FButton.icon( + child: FIcon(FAssets.icons.chevronRight), + onPress: () => showFModalSheet( + context: context, + side: side, + constraints: const BoxConstraints(maxHeight: 200, maxWidth: 200), + builder: (context) => Container( + height: double.infinity, + width: double.infinity, + color: context.theme.colorScheme.background, + child: const Center(child: Text('Sheet')), + ), + ), + ), + ), + ), + ); + + await tester.tap(find.byType(FButton)); + await tester.pumpAndSettle(); + + await expectLater(find.byType(TestScaffold), matchesGoldenFile('sheet/modal/constrained-$side.png')); + }); + + testWidgets('scrollable - $side', (tester) async { + await tester.pumpWidget( + TestScaffold.app( + child: Builder( + builder: (context) => FButton.icon( + child: FIcon(FAssets.icons.chevronRight), + onPress: () => showFModalSheet( + context: context, + side: side, + mainAxisMaxRatio: null, + builder: (context) => Container( + height: double.infinity, + width: double.infinity, + color: context.theme.colorScheme.background, + child: ListView.builder( + scrollDirection: side.vertical ? Axis.vertical : Axis.horizontal, + itemBuilder: (context, index) => Padding( + padding: const EdgeInsets.all(8.0), + child: Text('Tile $index'), + ), + itemCount: 20, + ), + ), + ), + ), + ), + ), + ); + + await tester.tap(find.byType(FButton)); + await tester.pumpAndSettle(); + + await expectLater(find.byType(TestScaffold), matchesGoldenFile('sheet/modal/scrollable-$side.png')); + }); + } + }); +} diff --git a/forui/test/src/widgets/sheet/modal_sheet_test.dart b/forui/test/src/widgets/sheet/modal_sheet_test.dart new file mode 100644 index 000000000..1c5590c6d --- /dev/null +++ b/forui/test/src/widgets/sheet/modal_sheet_test.dart @@ -0,0 +1,108 @@ +import 'package:flutter/material.dart'; + +import 'package:flutter_test/flutter_test.dart'; + +import 'package:forui/forui.dart'; +import '../../test_scaffold.dart'; + +void main() { + group('FModalSheet', () { + testWidgets('tap on barrier dismisses', (tester) async { + await tester.pumpWidget( + TestScaffold.app( + child: Builder( + builder: (context) => FButton.icon( + child: FIcon(FAssets.icons.chevronRight), + onPress: () => showFModalSheet( + context: context, + side: Layout.btt, + builder: (context) => Container( + height: double.infinity, + width: double.infinity, + color: context.theme.colorScheme.background, + child: const Center(child: Text('sheet')), + ), + ), + ), + ), + ), + ); + + await tester.tap(find.byType(FButton)); + await tester.pumpAndSettle(const Duration(seconds: 1)); + expect(find.text('sheet'), findsOne); + + await tester.tapAt(const Offset(100, 100)); + await tester.pumpAndSettle(const Duration(seconds: 1)); + expect(find.text('sheet'), findsNothing); + }); + + for (final (side, offset) in [ + (Layout.btt, const Offset(0, 300)), + (Layout.ttb, const Offset(0, -300)), + (Layout.ltr, const Offset(-300, 0)), + (Layout.rtl, const Offset(300, 0)), + ]) { + testWidgets('drag to dismiss - $side', (tester) async { + await tester.pumpWidget( + TestScaffold.app( + child: Builder( + builder: (context) => FButton.icon( + child: FIcon(FAssets.icons.chevronRight), + onPress: () => showFModalSheet( + context: context, + side: side, + builder: (context) => Container( + height: double.infinity, + width: double.infinity, + color: context.theme.colorScheme.background, + child: const Center(child: Text('sheet')), + ), + ), + ), + ), + ), + ); + + await tester.tap(find.byType(FButton)); + await tester.pumpAndSettle(const Duration(seconds: 1)); + expect(find.text('sheet'), findsOne); + + await tester.drag(find.text('sheet'), offset); + await tester.pumpAndSettle(const Duration(seconds: 1)); + expect(find.text('sheet'), findsNothing); + }); + + testWidgets('drag to dismiss on non-draggable - $side', (tester) async { + await tester.pumpWidget( + TestScaffold.app( + child: Builder( + builder: (context) => FButton.icon( + child: FIcon(FAssets.icons.chevronRight), + onPress: () => showFModalSheet( + context: context, + side: side, + draggable: false, + builder: (context) => Container( + height: double.infinity, + width: double.infinity, + color: context.theme.colorScheme.background, + child: const Center(child: Text('sheet')), + ), + ), + ), + ), + ), + ); + + await tester.tap(find.byType(FButton)); + await tester.pumpAndSettle(const Duration(seconds: 1)); + expect(find.text('sheet'), findsOne); + + await tester.drag(find.text('sheet'), offset); + await tester.pumpAndSettle(const Duration(seconds: 1)); + expect(find.text('sheet'), findsOne); + }); + } + }); +} From 34cd9981dcb5e70880b074ed3fbf8ae49aaf5ff3 Mon Sep 17 00:00:00 2001 From: Matthias Ngeo Date: Fri, 29 Nov 2024 17:33:50 +0800 Subject: [PATCH 10/29] Add docs --- docs/pages/docs/overlay/modal-sheet.mdx | 189 ++++++++++++++++++++++++ forui/lib/src/widgets/sheet/sheet.dart | 33 +---- samples/lib/main.dart | 2 + samples/lib/widgets/modal_sheet.dart | 156 +++++++++++++++++++ 4 files changed, 348 insertions(+), 32 deletions(-) create mode 100644 docs/pages/docs/overlay/modal-sheet.mdx create mode 100644 samples/lib/widgets/modal_sheet.dart diff --git a/docs/pages/docs/overlay/modal-sheet.mdx b/docs/pages/docs/overlay/modal-sheet.mdx new file mode 100644 index 000000000..464c28041 --- /dev/null +++ b/docs/pages/docs/overlay/modal-sheet.mdx @@ -0,0 +1,189 @@ +import { Tabs } from 'nextra/components'; +import { Widget } from "../../../components/widget.tsx"; +import LinkBadge from "../../../components/link-badge/link-badge.tsx"; +import LinkBadgeGroup from "../../../components/link-badge/link-badge-group.tsx"; + +# Modal Sheet + +A modal sheet is an alternative to a menu or a dialog and prevents the user from interacting with the rest of the app. + + + + + + + + + + + ```dart + class ModalSheet extends StatelessWidget { + @override + Widget build(BuildContext context) => Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + FButton( + label: const Text('Left'), + onPress: () => showFModalSheet( + context: context, + side: Layout.ltr, + builder: (context) => const Form(side: Layout.ltr), + ), + ), + const SizedBox(height: 5), + FButton( + label: const Text('Top'), + onPress: () => showFModalSheet( + context: context, + side: Layout.ttb, + builder: (context) => const Form(side: Layout.ttb), + ), + ), + const SizedBox(height: 5), + FButton( + label: const Text('Right'), + onPress: () => showFModalSheet( + context: context, + side: Layout.rtl, + builder: (context) => const Form(side: Layout.btt), + ), + ), + const SizedBox(height: 5), + FButton( + label: const Text('Bottom'), + onPress: () => showFModalSheet( + context: context, + side: Layout.btt, + builder: (context) => const Form(side: Layout.btt), + ), + ), + ], + ); + } + + class Form extends StatelessWidget { + final Layout side; + + const Form({required this.side, super.key}); + + @override + Widget build(BuildContext context) => Container( + height: double.infinity, + width: double.infinity, + decoration: BoxDecoration( + color: context.theme.colorScheme.background, + border: side.vertical + ? Border.symmetric(horizontal: BorderSide(color: context.theme.colorScheme.border)) + : Border.symmetric(vertical: BorderSide(color: context.theme.colorScheme.border)), + ), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 8.0), + child: Center( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Account', + style: context.theme.typography.xl2.copyWith( + fontWeight: FontWeight.w600, + color: context.theme.colorScheme.foreground, + height: 1.5, + ), + ), + Text( + 'Make changes to your account here. Click save when you are done.', + style: context.theme.typography.sm.copyWith( + color: context.theme.colorScheme.mutedForeground, + ), + ), + const SizedBox(height: 8), + SizedBox( + width: 450, + child: Column( + children: [ + const FTextField( + label: Text('Name'), + hint: 'John Renalo', + ), + const SizedBox(height: 10), + const FTextField( + label: Text('Email'), + hint: 'john@doe.com', + ), + const SizedBox(height: 16), + FButton( + label: const Text('Save'), + onPress: () => Navigator.of(context).pop(), + ), + ], + ), + ), + ], + ), + ), + ), + ); + } + ``` + + + +## Usage + +### `showFModalSheet(...)` + +```dart +showFModalSheet( + context: context, + side: Layout.ltr, + useRootNavigator: true, + useSafeArea: false, + mainAxisMaxRatio: null, + constraints: const BoxConstraints(maxWidth: 450, maxHeight: 450), + barrierDismissible: true, + draggable: true, + builder: (context) => const Placeholder(), +); +``` + +## Examples + +### With `DraggableScrollableSheet` + + + + + + + ```dart + FButton( + label: const Text('Click me'), + onPress: () => showFModalSheet( + context: context, + side: Layout.btt, + mainAxisMaxRatio: null, + builder: (context) => DraggableScrollableSheet( + expand: false, + builder: (context, controller) => ScrollConfiguration( + // This is required to enable dragging on desktop. + // See https://github.com/flutter/flutter/issues/101903 for more information. + behavior: ScrollConfiguration.of(context).copyWith(dragDevices: { + PointerDeviceKind.touch, + PointerDeviceKind.mouse, + PointerDeviceKind.trackpad, + }), + child: FTileGroup.builder( + count: 25, + controller: controller, + tileBuilder: (context, index) => FTile(title: Text('Tile $index')), + ), + ), + ), + ), + ); + ``` + + + diff --git a/forui/lib/src/widgets/sheet/sheet.dart b/forui/lib/src/widgets/sheet/sheet.dart index 2a2937a06..24ed0d7da 100644 --- a/forui/lib/src/widgets/sheet/sheet.dart +++ b/forui/lib/src/widgets/sheet/sheet.dart @@ -14,45 +14,14 @@ class Sheet extends StatefulWidget { static void _onClosing() {} - /// The animation controller that controls the bottom sheet's entrance and exit animations. - /// - /// This widget will manipulate the position of this animation, it is not just a passive observer. final AnimationController? controller; - - /// The sheet's layout. - final Layout layout; - - /// The sheet's style. final FSheetStyle style; - - /// The minimum and maximum size. + final Layout layout; final BoxConstraints constraints; - - /// True if the sheet can be dragged up and down/left and right, and dismissed by swiping in the opposite direction. - /// - /// Defaults to true. - /// - /// If this is true, the [controller] must not be null. final bool draggable; - - /// A builder for the sheet's contents. final WidgetBuilder builder; - - /// Called when the user begins dragging the bottom sheet vertically, if [draggable] is true. - /// - /// Would typically be used to change the bottom sheet animation curve so that it tracks the user's finger accurately. final GestureDragStartCallback? onDragStart; - - /// Called when the user stops dragging the sheet, if [draggable] is true. - /// - /// Would typically be used to reset the bottom sheet animation curve, so that it animates non-linearly. Called before - /// [onClosing] if the sheet is closing. final void Function(DragEndDetails details, {required bool closing})? onDragEnd; - - /// Called when the sheet begins to close. - /// - /// A sheet might be prevented from closing (e.g., by user interaction) even after this callback is called. For this - /// reason, this callback might be call multiple times for a given sheet. final VoidCallback onClosing; const Sheet({ diff --git a/samples/lib/main.dart b/samples/lib/main.dart index b60e08667..4d071203e 100644 --- a/samples/lib/main.dart +++ b/samples/lib/main.dart @@ -67,6 +67,8 @@ class _AppRouter extends RootStackRouter { AutoRoute(path: '/icon/image', page: ImageIconRoute.page), AutoRoute(path: '/label/vertical', page: VerticalLabelRoute.page), AutoRoute(path: '/label/horizontal', page: HorizontalLabelRoute.page), + AutoRoute(path: '/modal-sheet/default', page: ModalSheetRoute.page), + AutoRoute(path: '/modal-sheet/draggable', page: DraggableModalSheetRoute.page), AutoRoute(path: '/popover/default', page: PopoverRoute.page), AutoRoute(path: '/popover-menu/default', page: PopoverMenuRoute.page), AutoRoute(path: '/portal/default', page: PortalRoute.page), diff --git a/samples/lib/widgets/modal_sheet.dart b/samples/lib/widgets/modal_sheet.dart new file mode 100644 index 000000000..58daa14b9 --- /dev/null +++ b/samples/lib/widgets/modal_sheet.dart @@ -0,0 +1,156 @@ +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; + +import 'package:auto_route/auto_route.dart'; +import 'package:forui/forui.dart'; + +import 'package:forui_samples/sample.dart'; + +@RoutePage() +class ModalSheetPage extends Sample { + ModalSheetPage({ + @queryParam super.theme, + }); + + @override + Widget sample(BuildContext context) => Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + FButton( + label: const Text('Left'), + onPress: () => showFModalSheet( + context: context, + side: Layout.ltr, + builder: (context) => const Form(side: Layout.ltr), + ), + ), + const SizedBox(height: 5), + FButton( + label: const Text('Top'), + onPress: () => showFModalSheet( + context: context, + side: Layout.ttb, + builder: (context) => const Form(side: Layout.ttb), + ), + ), + const SizedBox(height: 5), + FButton( + label: const Text('Right'), + onPress: () => showFModalSheet( + context: context, + side: Layout.rtl, + builder: (context) => const Form(side: Layout.btt), + ), + ), + const SizedBox(height: 5), + FButton( + label: const Text('Bottom'), + onPress: () => showFModalSheet( + context: context, + side: Layout.btt, + builder: (context) => const Form(side: Layout.btt), + ), + ), + ], + ); +} + +class Form extends StatelessWidget { + final Layout side; + + const Form({required this.side, super.key}); + + @override + Widget build(BuildContext context) => Container( + height: double.infinity, + width: double.infinity, + decoration: BoxDecoration( + color: context.theme.colorScheme.background, + border: side.vertical + ? Border.symmetric(horizontal: BorderSide(color: context.theme.colorScheme.border)) + : Border.symmetric(vertical: BorderSide(color: context.theme.colorScheme.border)), + ), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 8.0), + child: Center( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Account', + style: context.theme.typography.xl2.copyWith( + fontWeight: FontWeight.w600, + color: context.theme.colorScheme.foreground, + height: 1.5, + ), + ), + Text( + 'Make changes to your account here. Click save when you are done.', + style: context.theme.typography.sm.copyWith( + color: context.theme.colorScheme.mutedForeground, + ), + ), + const SizedBox(height: 8), + SizedBox( + width: 450, + child: Column( + children: [ + const FTextField( + label: Text('Name'), + hint: 'John Renalo', + ), + const SizedBox(height: 10), + const FTextField( + label: Text('Email'), + hint: 'john@doe.com', + ), + const SizedBox(height: 16), + FButton( + label: const Text('Save'), + onPress: () => Navigator.of(context).pop(), + ), + ], + ), + ), + ], + ), + ), + ), + ); +} + +@RoutePage() +class DraggableModalSheetPage extends Sample { + DraggableModalSheetPage({ + @queryParam super.theme, + }); + + @override + Widget sample(BuildContext context) => FButton( + label: const Text('Click me'), + onPress: () => showFModalSheet( + context: context, + side: Layout.btt, + mainAxisMaxRatio: null, + builder: (context) => DraggableScrollableSheet( + expand: false, + builder: (context, controller) => ScrollConfiguration( + // This is required to enable dragging on desktop. + // See https://github.com/flutter/flutter/issues/101903 for more information. + behavior: ScrollConfiguration.of(context).copyWith(dragDevices: { + PointerDeviceKind.touch, + PointerDeviceKind.mouse, + PointerDeviceKind.trackpad, + }), + child: FTileGroup.builder( + count: 25, + controller: controller, + tileBuilder: (context, index) => FTile(title: Text('Tile $index')), + ), + ), + ), + ), + ); +} From c913e1337b3cd2983f81c7f0879cd60175b0260b Mon Sep 17 00:00:00 2001 From: Matthias Ngeo Date: Fri, 29 Nov 2024 17:36:27 +0800 Subject: [PATCH 11/29] Format --- samples/lib/widgets/modal_sheet.dart | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/samples/lib/widgets/modal_sheet.dart b/samples/lib/widgets/modal_sheet.dart index 58daa14b9..a11d90fb5 100644 --- a/samples/lib/widgets/modal_sheet.dart +++ b/samples/lib/widgets/modal_sheet.dart @@ -139,11 +139,13 @@ class DraggableModalSheetPage extends Sample { builder: (context, controller) => ScrollConfiguration( // This is required to enable dragging on desktop. // See https://github.com/flutter/flutter/issues/101903 for more information. - behavior: ScrollConfiguration.of(context).copyWith(dragDevices: { - PointerDeviceKind.touch, - PointerDeviceKind.mouse, - PointerDeviceKind.trackpad, - }), + behavior: ScrollConfiguration.of(context).copyWith( + dragDevices: { + PointerDeviceKind.touch, + PointerDeviceKind.mouse, + PointerDeviceKind.trackpad, + }, + ), child: FTileGroup.builder( count: 25, controller: controller, From dc7acfe7417d5befe7b30e6440e5f074abd28f1c Mon Sep 17 00:00:00 2001 From: Pante Date: Fri, 29 Nov 2024 09:37:54 +0000 Subject: [PATCH 12/29] Commit from GitHub Actions (Forui Presubmit) --- .../lib/src/localizations/localizations.dart | 510 ++++++++++++------ .../src/localizations/localizations_de.dart | 2 +- .../src/localizations/localizations_en.dart | 16 +- .../src/localizations/localizations_es.dart | 40 +- .../src/localizations/localizations_fr.dart | 2 +- .../src/localizations/localizations_pt.dart | 2 +- .../src/localizations/localizations_sr.dart | 2 +- .../src/localizations/localizations_zh.dart | 4 +- .../src/widgets/sheet/gesture_detector.dart | 4 +- forui/lib/src/widgets/sheet/modal_sheet.dart | 1 + forui/lib/src/widgets/sheet/sheet.dart | 4 +- .../lib/src/widgets/sheet/shifted_sheet.dart | 6 +- 12 files changed, 399 insertions(+), 194 deletions(-) diff --git a/forui/lib/src/localizations/localizations.dart b/forui/lib/src/localizations/localizations.dart index f683803ca..8ee8fcdc2 100644 --- a/forui/lib/src/localizations/localizations.dart +++ b/forui/lib/src/localizations/localizations.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; + import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:intl/intl.dart' as intl; @@ -348,178 +349,375 @@ class _FLocalizationsDelegate extends LocalizationsDelegate { } @override - bool isSupported(Locale locale) => ['af', 'am', 'ar', 'as', 'az', 'be', 'bg', 'bn', 'bs', 'ca', 'cs', 'cy', 'da', 'de', 'el', 'en', 'es', 'et', 'eu', 'fa', 'fi', 'fil', 'fr', 'gl', 'gsw', 'gu', 'he', 'hi', 'hr', 'hu', 'hy', 'id', 'is', 'it', 'ja', 'ka', 'kk', 'km', 'kn', 'ko', 'ky', 'lo', 'lt', 'lv', 'mk', 'ml', 'mn', 'mr', 'ms', 'my', 'nb', 'ne', 'nl', 'no', 'or', 'pa', 'pl', 'ps', 'pt', 'ro', 'ru', 'si', 'sk', 'sl', 'sq', 'sr', 'sv', 'sw', 'ta', 'te', 'th', 'tl', 'tr', 'uk', 'ur', 'uz', 'vi', 'zh', 'zu'].contains(locale.languageCode); + bool isSupported(Locale locale) => [ + 'af', + 'am', + 'ar', + 'as', + 'az', + 'be', + 'bg', + 'bn', + 'bs', + 'ca', + 'cs', + 'cy', + 'da', + 'de', + 'el', + 'en', + 'es', + 'et', + 'eu', + 'fa', + 'fi', + 'fil', + 'fr', + 'gl', + 'gsw', + 'gu', + 'he', + 'hi', + 'hr', + 'hu', + 'hy', + 'id', + 'is', + 'it', + 'ja', + 'ka', + 'kk', + 'km', + 'kn', + 'ko', + 'ky', + 'lo', + 'lt', + 'lv', + 'mk', + 'ml', + 'mn', + 'mr', + 'ms', + 'my', + 'nb', + 'ne', + 'nl', + 'no', + 'or', + 'pa', + 'pl', + 'ps', + 'pt', + 'ro', + 'ru', + 'si', + 'sk', + 'sl', + 'sq', + 'sr', + 'sv', + 'sw', + 'ta', + 'te', + 'th', + 'tl', + 'tr', + 'uk', + 'ur', + 'uz', + 'vi', + 'zh', + 'zu' + ].contains(locale.languageCode); @override bool shouldReload(_FLocalizationsDelegate old) => false; } FLocalizations lookupFLocalizations(Locale locale) { - // Lookup logic when language+script codes are specified. switch (locale.languageCode) { - case 'sr': { - switch (locale.scriptCode) { - case 'Latn': return FLocalizationsSrLatn(); - } - break; - } + case 'sr': + { + switch (locale.scriptCode) { + case 'Latn': + return FLocalizationsSrLatn(); + } + break; + } } // Lookup logic when language+country codes are specified. switch (locale.languageCode) { - case 'de': { - switch (locale.countryCode) { - case 'CH': return FLocalizationsDeCh(); - } - break; - } - case 'en': { - switch (locale.countryCode) { - case 'AU': return FLocalizationsEnAu(); -case 'CA': return FLocalizationsEnCa(); -case 'GB': return FLocalizationsEnGb(); -case 'IE': return FLocalizationsEnIe(); -case 'IN': return FLocalizationsEnIn(); -case 'NZ': return FLocalizationsEnNz(); -case 'SG': return FLocalizationsEnSg(); -case 'ZA': return FLocalizationsEnZa(); - } - break; - } - case 'es': { - switch (locale.countryCode) { - case '419': return FLocalizationsEs419(); -case 'AR': return FLocalizationsEsAr(); -case 'BO': return FLocalizationsEsBo(); -case 'CL': return FLocalizationsEsCl(); -case 'CO': return FLocalizationsEsCo(); -case 'CR': return FLocalizationsEsCr(); -case 'DO': return FLocalizationsEsDo(); -case 'EC': return FLocalizationsEsEc(); -case 'GT': return FLocalizationsEsGt(); -case 'HN': return FLocalizationsEsHn(); -case 'MX': return FLocalizationsEsMx(); -case 'NI': return FLocalizationsEsNi(); -case 'PA': return FLocalizationsEsPa(); -case 'PE': return FLocalizationsEsPe(); -case 'PR': return FLocalizationsEsPr(); -case 'PY': return FLocalizationsEsPy(); -case 'SV': return FLocalizationsEsSv(); -case 'US': return FLocalizationsEsUs(); -case 'UY': return FLocalizationsEsUy(); -case 'VE': return FLocalizationsEsVe(); - } - break; - } - case 'fr': { - switch (locale.countryCode) { - case 'CA': return FLocalizationsFrCa(); - } - break; - } - case 'pt': { - switch (locale.countryCode) { - case 'PT': return FLocalizationsPtPt(); - } - break; - } - case 'zh': { - switch (locale.countryCode) { - case 'HK': return FLocalizationsZhHk(); -case 'TW': return FLocalizationsZhTw(); - } - break; - } + case 'de': + { + switch (locale.countryCode) { + case 'CH': + return FLocalizationsDeCh(); + } + break; + } + case 'en': + { + switch (locale.countryCode) { + case 'AU': + return FLocalizationsEnAu(); + case 'CA': + return FLocalizationsEnCa(); + case 'GB': + return FLocalizationsEnGb(); + case 'IE': + return FLocalizationsEnIe(); + case 'IN': + return FLocalizationsEnIn(); + case 'NZ': + return FLocalizationsEnNz(); + case 'SG': + return FLocalizationsEnSg(); + case 'ZA': + return FLocalizationsEnZa(); + } + break; + } + case 'es': + { + switch (locale.countryCode) { + case '419': + return FLocalizationsEs419(); + case 'AR': + return FLocalizationsEsAr(); + case 'BO': + return FLocalizationsEsBo(); + case 'CL': + return FLocalizationsEsCl(); + case 'CO': + return FLocalizationsEsCo(); + case 'CR': + return FLocalizationsEsCr(); + case 'DO': + return FLocalizationsEsDo(); + case 'EC': + return FLocalizationsEsEc(); + case 'GT': + return FLocalizationsEsGt(); + case 'HN': + return FLocalizationsEsHn(); + case 'MX': + return FLocalizationsEsMx(); + case 'NI': + return FLocalizationsEsNi(); + case 'PA': + return FLocalizationsEsPa(); + case 'PE': + return FLocalizationsEsPe(); + case 'PR': + return FLocalizationsEsPr(); + case 'PY': + return FLocalizationsEsPy(); + case 'SV': + return FLocalizationsEsSv(); + case 'US': + return FLocalizationsEsUs(); + case 'UY': + return FLocalizationsEsUy(); + case 'VE': + return FLocalizationsEsVe(); + } + break; + } + case 'fr': + { + switch (locale.countryCode) { + case 'CA': + return FLocalizationsFrCa(); + } + break; + } + case 'pt': + { + switch (locale.countryCode) { + case 'PT': + return FLocalizationsPtPt(); + } + break; + } + case 'zh': + { + switch (locale.countryCode) { + case 'HK': + return FLocalizationsZhHk(); + case 'TW': + return FLocalizationsZhTw(); + } + break; + } } // Lookup logic when only language code is specified. switch (locale.languageCode) { - case 'af': return FLocalizationsAf(); - case 'am': return FLocalizationsAm(); - case 'ar': return FLocalizationsAr(); - case 'as': return FLocalizationsAs(); - case 'az': return FLocalizationsAz(); - case 'be': return FLocalizationsBe(); - case 'bg': return FLocalizationsBg(); - case 'bn': return FLocalizationsBn(); - case 'bs': return FLocalizationsBs(); - case 'ca': return FLocalizationsCa(); - case 'cs': return FLocalizationsCs(); - case 'cy': return FLocalizationsCy(); - case 'da': return FLocalizationsDa(); - case 'de': return FLocalizationsDe(); - case 'el': return FLocalizationsEl(); - case 'en': return FLocalizationsEn(); - case 'es': return FLocalizationsEs(); - case 'et': return FLocalizationsEt(); - case 'eu': return FLocalizationsEu(); - case 'fa': return FLocalizationsFa(); - case 'fi': return FLocalizationsFi(); - case 'fil': return FLocalizationsFil(); - case 'fr': return FLocalizationsFr(); - case 'gl': return FLocalizationsGl(); - case 'gsw': return FLocalizationsGsw(); - case 'gu': return FLocalizationsGu(); - case 'he': return FLocalizationsHe(); - case 'hi': return FLocalizationsHi(); - case 'hr': return FLocalizationsHr(); - case 'hu': return FLocalizationsHu(); - case 'hy': return FLocalizationsHy(); - case 'id': return FLocalizationsId(); - case 'is': return FLocalizationsIs(); - case 'it': return FLocalizationsIt(); - case 'ja': return FLocalizationsJa(); - case 'ka': return FLocalizationsKa(); - case 'kk': return FLocalizationsKk(); - case 'km': return FLocalizationsKm(); - case 'kn': return FLocalizationsKn(); - case 'ko': return FLocalizationsKo(); - case 'ky': return FLocalizationsKy(); - case 'lo': return FLocalizationsLo(); - case 'lt': return FLocalizationsLt(); - case 'lv': return FLocalizationsLv(); - case 'mk': return FLocalizationsMk(); - case 'ml': return FLocalizationsMl(); - case 'mn': return FLocalizationsMn(); - case 'mr': return FLocalizationsMr(); - case 'ms': return FLocalizationsMs(); - case 'my': return FLocalizationsMy(); - case 'nb': return FLocalizationsNb(); - case 'ne': return FLocalizationsNe(); - case 'nl': return FLocalizationsNl(); - case 'no': return FLocalizationsNo(); - case 'or': return FLocalizationsOr(); - case 'pa': return FLocalizationsPa(); - case 'pl': return FLocalizationsPl(); - case 'ps': return FLocalizationsPs(); - case 'pt': return FLocalizationsPt(); - case 'ro': return FLocalizationsRo(); - case 'ru': return FLocalizationsRu(); - case 'si': return FLocalizationsSi(); - case 'sk': return FLocalizationsSk(); - case 'sl': return FLocalizationsSl(); - case 'sq': return FLocalizationsSq(); - case 'sr': return FLocalizationsSr(); - case 'sv': return FLocalizationsSv(); - case 'sw': return FLocalizationsSw(); - case 'ta': return FLocalizationsTa(); - case 'te': return FLocalizationsTe(); - case 'th': return FLocalizationsTh(); - case 'tl': return FLocalizationsTl(); - case 'tr': return FLocalizationsTr(); - case 'uk': return FLocalizationsUk(); - case 'ur': return FLocalizationsUr(); - case 'uz': return FLocalizationsUz(); - case 'vi': return FLocalizationsVi(); - case 'zh': return FLocalizationsZh(); - case 'zu': return FLocalizationsZu(); + case 'af': + return FLocalizationsAf(); + case 'am': + return FLocalizationsAm(); + case 'ar': + return FLocalizationsAr(); + case 'as': + return FLocalizationsAs(); + case 'az': + return FLocalizationsAz(); + case 'be': + return FLocalizationsBe(); + case 'bg': + return FLocalizationsBg(); + case 'bn': + return FLocalizationsBn(); + case 'bs': + return FLocalizationsBs(); + case 'ca': + return FLocalizationsCa(); + case 'cs': + return FLocalizationsCs(); + case 'cy': + return FLocalizationsCy(); + case 'da': + return FLocalizationsDa(); + case 'de': + return FLocalizationsDe(); + case 'el': + return FLocalizationsEl(); + case 'en': + return FLocalizationsEn(); + case 'es': + return FLocalizationsEs(); + case 'et': + return FLocalizationsEt(); + case 'eu': + return FLocalizationsEu(); + case 'fa': + return FLocalizationsFa(); + case 'fi': + return FLocalizationsFi(); + case 'fil': + return FLocalizationsFil(); + case 'fr': + return FLocalizationsFr(); + case 'gl': + return FLocalizationsGl(); + case 'gsw': + return FLocalizationsGsw(); + case 'gu': + return FLocalizationsGu(); + case 'he': + return FLocalizationsHe(); + case 'hi': + return FLocalizationsHi(); + case 'hr': + return FLocalizationsHr(); + case 'hu': + return FLocalizationsHu(); + case 'hy': + return FLocalizationsHy(); + case 'id': + return FLocalizationsId(); + case 'is': + return FLocalizationsIs(); + case 'it': + return FLocalizationsIt(); + case 'ja': + return FLocalizationsJa(); + case 'ka': + return FLocalizationsKa(); + case 'kk': + return FLocalizationsKk(); + case 'km': + return FLocalizationsKm(); + case 'kn': + return FLocalizationsKn(); + case 'ko': + return FLocalizationsKo(); + case 'ky': + return FLocalizationsKy(); + case 'lo': + return FLocalizationsLo(); + case 'lt': + return FLocalizationsLt(); + case 'lv': + return FLocalizationsLv(); + case 'mk': + return FLocalizationsMk(); + case 'ml': + return FLocalizationsMl(); + case 'mn': + return FLocalizationsMn(); + case 'mr': + return FLocalizationsMr(); + case 'ms': + return FLocalizationsMs(); + case 'my': + return FLocalizationsMy(); + case 'nb': + return FLocalizationsNb(); + case 'ne': + return FLocalizationsNe(); + case 'nl': + return FLocalizationsNl(); + case 'no': + return FLocalizationsNo(); + case 'or': + return FLocalizationsOr(); + case 'pa': + return FLocalizationsPa(); + case 'pl': + return FLocalizationsPl(); + case 'ps': + return FLocalizationsPs(); + case 'pt': + return FLocalizationsPt(); + case 'ro': + return FLocalizationsRo(); + case 'ru': + return FLocalizationsRu(); + case 'si': + return FLocalizationsSi(); + case 'sk': + return FLocalizationsSk(); + case 'sl': + return FLocalizationsSl(); + case 'sq': + return FLocalizationsSq(); + case 'sr': + return FLocalizationsSr(); + case 'sv': + return FLocalizationsSv(); + case 'sw': + return FLocalizationsSw(); + case 'ta': + return FLocalizationsTa(); + case 'te': + return FLocalizationsTe(); + case 'th': + return FLocalizationsTh(); + case 'tl': + return FLocalizationsTl(); + case 'tr': + return FLocalizationsTr(); + case 'uk': + return FLocalizationsUk(); + case 'ur': + return FLocalizationsUr(); + case 'uz': + return FLocalizationsUz(); + case 'vi': + return FLocalizationsVi(); + case 'zh': + return FLocalizationsZh(); + case 'zu': + return FLocalizationsZu(); } - throw FlutterError( - 'FLocalizations.delegate failed to load unsupported locale "$locale". This is likely ' - 'an issue with the localizations generation tool. Please file an issue ' - 'on GitHub with a reproducible sample app and the gen-l10n configuration ' - 'that was used.' - ); + throw FlutterError('FLocalizations.delegate failed to load unsupported locale "$locale". This is likely ' + 'an issue with the localizations generation tool. Please file an issue ' + 'on GitHub with a reproducible sample app and the gen-l10n configuration ' + 'that was used.'); } diff --git a/forui/lib/src/localizations/localizations_de.dart b/forui/lib/src/localizations/localizations_de.dart index ea369d24b..bbb792063 100644 --- a/forui/lib/src/localizations/localizations_de.dart +++ b/forui/lib/src/localizations/localizations_de.dart @@ -65,7 +65,7 @@ class FLocalizationsDe extends FLocalizations { /// The translations for German, as used in Switzerland (`de_CH`). class FLocalizationsDeCh extends FLocalizationsDe { - FLocalizationsDeCh(): super('de_CH'); + FLocalizationsDeCh() : super('de_CH'); @override String get dialogLabel => 'Dialogfeld'; diff --git a/forui/lib/src/localizations/localizations_en.dart b/forui/lib/src/localizations/localizations_en.dart index 564ab36ca..3651b7c09 100644 --- a/forui/lib/src/localizations/localizations_en.dart +++ b/forui/lib/src/localizations/localizations_en.dart @@ -65,7 +65,7 @@ class FLocalizationsEn extends FLocalizations { /// The translations for English, as used in Australia (`en_AU`). class FLocalizationsEnAu extends FLocalizationsEn { - FLocalizationsEnAu(): super('en_AU'); + FLocalizationsEnAu() : super('en_AU'); @override String get dialogLabel => 'Dialogue'; @@ -84,7 +84,7 @@ class FLocalizationsEnAu extends FLocalizationsEn { /// The translations for English, as used in Canada (`en_CA`). class FLocalizationsEnCa extends FLocalizationsEn { - FLocalizationsEnCa(): super('en_CA'); + FLocalizationsEnCa() : super('en_CA'); @override String get dialogLabel => 'Dialog'; @@ -103,7 +103,7 @@ class FLocalizationsEnCa extends FLocalizationsEn { /// The translations for English, as used in the United Kingdom (`en_GB`). class FLocalizationsEnGb extends FLocalizationsEn { - FLocalizationsEnGb(): super('en_GB'); + FLocalizationsEnGb() : super('en_GB'); @override String get dialogLabel => 'Dialogue'; @@ -122,7 +122,7 @@ class FLocalizationsEnGb extends FLocalizationsEn { /// The translations for English, as used in Ireland (`en_IE`). class FLocalizationsEnIe extends FLocalizationsEn { - FLocalizationsEnIe(): super('en_IE'); + FLocalizationsEnIe() : super('en_IE'); @override String get dialogLabel => 'Dialogue'; @@ -141,7 +141,7 @@ class FLocalizationsEnIe extends FLocalizationsEn { /// The translations for English, as used in India (`en_IN`). class FLocalizationsEnIn extends FLocalizationsEn { - FLocalizationsEnIn(): super('en_IN'); + FLocalizationsEnIn() : super('en_IN'); @override String get dialogLabel => 'Dialogue'; @@ -160,7 +160,7 @@ class FLocalizationsEnIn extends FLocalizationsEn { /// The translations for English, as used in New Zealand (`en_NZ`). class FLocalizationsEnNz extends FLocalizationsEn { - FLocalizationsEnNz(): super('en_NZ'); + FLocalizationsEnNz() : super('en_NZ'); @override String get dialogLabel => 'Dialogue'; @@ -179,7 +179,7 @@ class FLocalizationsEnNz extends FLocalizationsEn { /// The translations for English, as used in Singapore (`en_SG`). class FLocalizationsEnSg extends FLocalizationsEn { - FLocalizationsEnSg(): super('en_SG'); + FLocalizationsEnSg() : super('en_SG'); @override String get dialogLabel => 'Dialogue'; @@ -198,7 +198,7 @@ class FLocalizationsEnSg extends FLocalizationsEn { /// The translations for English, as used in South Africa (`en_ZA`). class FLocalizationsEnZa extends FLocalizationsEn { - FLocalizationsEnZa(): super('en_ZA'); + FLocalizationsEnZa() : super('en_ZA'); @override String get dialogLabel => 'Dialogue'; diff --git a/forui/lib/src/localizations/localizations_es.dart b/forui/lib/src/localizations/localizations_es.dart index 6853862c9..40a8fa347 100644 --- a/forui/lib/src/localizations/localizations_es.dart +++ b/forui/lib/src/localizations/localizations_es.dart @@ -65,7 +65,7 @@ class FLocalizationsEs extends FLocalizations { /// The translations for Spanish Castilian, as used in Latin America and the Caribbean (`es_419`). class FLocalizationsEs419 extends FLocalizationsEs { - FLocalizationsEs419(): super('es_419'); + FLocalizationsEs419() : super('es_419'); @override String get dialogLabel => 'Diálogo'; @@ -84,7 +84,7 @@ class FLocalizationsEs419 extends FLocalizationsEs { /// The translations for Spanish Castilian, as used in Argentina (`es_AR`). class FLocalizationsEsAr extends FLocalizationsEs { - FLocalizationsEsAr(): super('es_AR'); + FLocalizationsEsAr() : super('es_AR'); @override String get dialogLabel => 'Diálogo'; @@ -103,7 +103,7 @@ class FLocalizationsEsAr extends FLocalizationsEs { /// The translations for Spanish Castilian, as used in Bolivia (`es_BO`). class FLocalizationsEsBo extends FLocalizationsEs { - FLocalizationsEsBo(): super('es_BO'); + FLocalizationsEsBo() : super('es_BO'); @override String get dialogLabel => 'Diálogo'; @@ -122,7 +122,7 @@ class FLocalizationsEsBo extends FLocalizationsEs { /// The translations for Spanish Castilian, as used in Chile (`es_CL`). class FLocalizationsEsCl extends FLocalizationsEs { - FLocalizationsEsCl(): super('es_CL'); + FLocalizationsEsCl() : super('es_CL'); @override String get dialogLabel => 'Diálogo'; @@ -141,7 +141,7 @@ class FLocalizationsEsCl extends FLocalizationsEs { /// The translations for Spanish Castilian, as used in Colombia (`es_CO`). class FLocalizationsEsCo extends FLocalizationsEs { - FLocalizationsEsCo(): super('es_CO'); + FLocalizationsEsCo() : super('es_CO'); @override String get dialogLabel => 'Diálogo'; @@ -160,7 +160,7 @@ class FLocalizationsEsCo extends FLocalizationsEs { /// The translations for Spanish Castilian, as used in Costa Rica (`es_CR`). class FLocalizationsEsCr extends FLocalizationsEs { - FLocalizationsEsCr(): super('es_CR'); + FLocalizationsEsCr() : super('es_CR'); @override String get dialogLabel => 'Diálogo'; @@ -179,7 +179,7 @@ class FLocalizationsEsCr extends FLocalizationsEs { /// The translations for Spanish Castilian, as used in the Dominican Republic (`es_DO`). class FLocalizationsEsDo extends FLocalizationsEs { - FLocalizationsEsDo(): super('es_DO'); + FLocalizationsEsDo() : super('es_DO'); @override String get dialogLabel => 'Diálogo'; @@ -198,7 +198,7 @@ class FLocalizationsEsDo extends FLocalizationsEs { /// The translations for Spanish Castilian, as used in Ecuador (`es_EC`). class FLocalizationsEsEc extends FLocalizationsEs { - FLocalizationsEsEc(): super('es_EC'); + FLocalizationsEsEc() : super('es_EC'); @override String get dialogLabel => 'Diálogo'; @@ -217,7 +217,7 @@ class FLocalizationsEsEc extends FLocalizationsEs { /// The translations for Spanish Castilian, as used in Guatemala (`es_GT`). class FLocalizationsEsGt extends FLocalizationsEs { - FLocalizationsEsGt(): super('es_GT'); + FLocalizationsEsGt() : super('es_GT'); @override String get dialogLabel => 'Diálogo'; @@ -236,7 +236,7 @@ class FLocalizationsEsGt extends FLocalizationsEs { /// The translations for Spanish Castilian, as used in Honduras (`es_HN`). class FLocalizationsEsHn extends FLocalizationsEs { - FLocalizationsEsHn(): super('es_HN'); + FLocalizationsEsHn() : super('es_HN'); @override String get dialogLabel => 'Diálogo'; @@ -255,7 +255,7 @@ class FLocalizationsEsHn extends FLocalizationsEs { /// The translations for Spanish Castilian, as used in Mexico (`es_MX`). class FLocalizationsEsMx extends FLocalizationsEs { - FLocalizationsEsMx(): super('es_MX'); + FLocalizationsEsMx() : super('es_MX'); @override String get dialogLabel => 'Diálogo'; @@ -274,7 +274,7 @@ class FLocalizationsEsMx extends FLocalizationsEs { /// The translations for Spanish Castilian, as used in Nicaragua (`es_NI`). class FLocalizationsEsNi extends FLocalizationsEs { - FLocalizationsEsNi(): super('es_NI'); + FLocalizationsEsNi() : super('es_NI'); @override String get dialogLabel => 'Diálogo'; @@ -293,7 +293,7 @@ class FLocalizationsEsNi extends FLocalizationsEs { /// The translations for Spanish Castilian, as used in Panama (`es_PA`). class FLocalizationsEsPa extends FLocalizationsEs { - FLocalizationsEsPa(): super('es_PA'); + FLocalizationsEsPa() : super('es_PA'); @override String get dialogLabel => 'Diálogo'; @@ -312,7 +312,7 @@ class FLocalizationsEsPa extends FLocalizationsEs { /// The translations for Spanish Castilian, as used in Peru (`es_PE`). class FLocalizationsEsPe extends FLocalizationsEs { - FLocalizationsEsPe(): super('es_PE'); + FLocalizationsEsPe() : super('es_PE'); @override String get dialogLabel => 'Diálogo'; @@ -331,7 +331,7 @@ class FLocalizationsEsPe extends FLocalizationsEs { /// The translations for Spanish Castilian, as used in Puerto Rico (`es_PR`). class FLocalizationsEsPr extends FLocalizationsEs { - FLocalizationsEsPr(): super('es_PR'); + FLocalizationsEsPr() : super('es_PR'); @override String get dialogLabel => 'Diálogo'; @@ -350,7 +350,7 @@ class FLocalizationsEsPr extends FLocalizationsEs { /// The translations for Spanish Castilian, as used in Paraguay (`es_PY`). class FLocalizationsEsPy extends FLocalizationsEs { - FLocalizationsEsPy(): super('es_PY'); + FLocalizationsEsPy() : super('es_PY'); @override String get dialogLabel => 'Diálogo'; @@ -369,7 +369,7 @@ class FLocalizationsEsPy extends FLocalizationsEs { /// The translations for Spanish Castilian, as used in El Salvador (`es_SV`). class FLocalizationsEsSv extends FLocalizationsEs { - FLocalizationsEsSv(): super('es_SV'); + FLocalizationsEsSv() : super('es_SV'); @override String get dialogLabel => 'Diálogo'; @@ -388,7 +388,7 @@ class FLocalizationsEsSv extends FLocalizationsEs { /// The translations for Spanish Castilian, as used in the United States (`es_US`). class FLocalizationsEsUs extends FLocalizationsEs { - FLocalizationsEsUs(): super('es_US'); + FLocalizationsEsUs() : super('es_US'); @override String get dialogLabel => 'Diálogo'; @@ -407,7 +407,7 @@ class FLocalizationsEsUs extends FLocalizationsEs { /// The translations for Spanish Castilian, as used in Uruguay (`es_UY`). class FLocalizationsEsUy extends FLocalizationsEs { - FLocalizationsEsUy(): super('es_UY'); + FLocalizationsEsUy() : super('es_UY'); @override String get dialogLabel => 'Diálogo'; @@ -426,7 +426,7 @@ class FLocalizationsEsUy extends FLocalizationsEs { /// The translations for Spanish Castilian, as used in Venezuela (`es_VE`). class FLocalizationsEsVe extends FLocalizationsEs { - FLocalizationsEsVe(): super('es_VE'); + FLocalizationsEsVe() : super('es_VE'); @override String get dialogLabel => 'Diálogo'; diff --git a/forui/lib/src/localizations/localizations_fr.dart b/forui/lib/src/localizations/localizations_fr.dart index f17460216..e602f0f20 100644 --- a/forui/lib/src/localizations/localizations_fr.dart +++ b/forui/lib/src/localizations/localizations_fr.dart @@ -65,7 +65,7 @@ class FLocalizationsFr extends FLocalizations { /// The translations for French, as used in Canada (`fr_CA`). class FLocalizationsFrCa extends FLocalizationsFr { - FLocalizationsFrCa(): super('fr_CA'); + FLocalizationsFrCa() : super('fr_CA'); @override String get dialogLabel => 'Boîte de dialogue'; diff --git a/forui/lib/src/localizations/localizations_pt.dart b/forui/lib/src/localizations/localizations_pt.dart index 94fc7dcda..9ac42bd55 100644 --- a/forui/lib/src/localizations/localizations_pt.dart +++ b/forui/lib/src/localizations/localizations_pt.dart @@ -65,7 +65,7 @@ class FLocalizationsPt extends FLocalizations { /// The translations for Portuguese, as used in Portugal (`pt_PT`). class FLocalizationsPtPt extends FLocalizationsPt { - FLocalizationsPtPt(): super('pt_PT'); + FLocalizationsPtPt() : super('pt_PT'); @override String get dialogLabel => 'Caixa de diálogo'; diff --git a/forui/lib/src/localizations/localizations_sr.dart b/forui/lib/src/localizations/localizations_sr.dart index 8a1fec626..65d80df43 100644 --- a/forui/lib/src/localizations/localizations_sr.dart +++ b/forui/lib/src/localizations/localizations_sr.dart @@ -65,7 +65,7 @@ class FLocalizationsSr extends FLocalizations { /// The translations for Serbian, using the Latin script (`sr_Latn`). class FLocalizationsSrLatn extends FLocalizationsSr { - FLocalizationsSrLatn(): super('sr_Latn'); + FLocalizationsSrLatn() : super('sr_Latn'); @override String get dialogLabel => 'Dijalog'; diff --git a/forui/lib/src/localizations/localizations_zh.dart b/forui/lib/src/localizations/localizations_zh.dart index 54636ff42..3052b2c75 100644 --- a/forui/lib/src/localizations/localizations_zh.dart +++ b/forui/lib/src/localizations/localizations_zh.dart @@ -65,7 +65,7 @@ class FLocalizationsZh extends FLocalizations { /// The translations for Chinese, as used in Hong Kong (`zh_HK`). class FLocalizationsZhHk extends FLocalizationsZh { - FLocalizationsZhHk(): super('zh_HK'); + FLocalizationsZhHk() : super('zh_HK'); @override String get dialogLabel => '對話方塊'; @@ -84,7 +84,7 @@ class FLocalizationsZhHk extends FLocalizationsZh { /// The translations for Chinese, as used in Taiwan (`zh_TW`). class FLocalizationsZhTw extends FLocalizationsZh { - FLocalizationsZhTw(): super('zh_TW'); + FLocalizationsZhTw() : super('zh_TW'); @override String get dialogLabel => '對話方塊'; diff --git a/forui/lib/src/widgets/sheet/gesture_detector.dart b/forui/lib/src/widgets/sheet/gesture_detector.dart index a137e4e58..810db3b41 100644 --- a/forui/lib/src/widgets/sheet/gesture_detector.dart +++ b/forui/lib/src/widgets/sheet/gesture_detector.dart @@ -1,9 +1,11 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/widgets.dart'; -import 'package:forui/forui.dart'; + import 'package:meta/meta.dart'; +import 'package:forui/forui.dart'; + /// The sheet's gesture detector. We use a [RawGestureDetector] instead of a [GestureDetector] because the latter /// doesn't allow `onlyAcceptDragOnThreshold` to be configured. /// diff --git a/forui/lib/src/widgets/sheet/modal_sheet.dart b/forui/lib/src/widgets/sheet/modal_sheet.dart index a655baaf0..5238eddda 100644 --- a/forui/lib/src/widgets/sheet/modal_sheet.dart +++ b/forui/lib/src/widgets/sheet/modal_sheet.dart @@ -2,6 +2,7 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; + import 'package:forui/forui.dart'; import 'package:forui/src/widgets/sheet/sheet.dart'; import 'package:forui/src/widgets/sheet/shifted_sheet.dart'; diff --git a/forui/lib/src/widgets/sheet/sheet.dart b/forui/lib/src/widgets/sheet/sheet.dart index 24ed0d7da..5033ca55a 100644 --- a/forui/lib/src/widgets/sheet/sheet.dart +++ b/forui/lib/src/widgets/sheet/sheet.dart @@ -1,8 +1,10 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; + +import 'package:meta/meta.dart'; + import 'package:forui/forui.dart'; import 'package:forui/src/widgets/sheet/gesture_detector.dart'; -import 'package:meta/meta.dart'; @internal class Sheet extends StatefulWidget { diff --git a/forui/lib/src/widgets/sheet/shifted_sheet.dart b/forui/lib/src/widgets/sheet/shifted_sheet.dart index 48aa43805..7e6ff4d02 100644 --- a/forui/lib/src/widgets/sheet/shifted_sheet.dart +++ b/forui/lib/src/widgets/sheet/shifted_sheet.dart @@ -1,11 +1,13 @@ import 'package:flutter/foundation.dart'; -import 'package:flutter/widgets.dart'; import 'package:flutter/rendering.dart'; -import 'package:forui/src/foundation/rendering.dart'; +import 'package:flutter/widgets.dart'; + import 'package:meta/meta.dart'; +import 'package:forui/src/foundation/rendering.dart'; @internal + /// typedef SizeChangeCallback = void Function(Size size); From 65f7f6ba6b75068f45ac36b9b0f1e44e65d0c1ca Mon Sep 17 00:00:00 2001 From: Matthias Ngeo Date: Tue, 3 Dec 2024 10:26:23 +0800 Subject: [PATCH 13/29] Refactor sheet, WIP page sheet --- forui/lib/src/widgets/sheet/modal_sheet.dart | 110 +++----------- forui/lib/src/widgets/sheet/page_sheet.dart | 138 ++++++++++++++++++ forui/lib/src/widgets/sheet/sheet.dart | 71 ++++++--- .../lib/src/widgets/sheet/shifted_sheet.dart | 37 ++--- forui/lib/widgets/sheet.dart | 1 + 5 files changed, 219 insertions(+), 138 deletions(-) create mode 100644 forui/lib/src/widgets/sheet/page_sheet.dart diff --git a/forui/lib/src/widgets/sheet/modal_sheet.dart b/forui/lib/src/widgets/sheet/modal_sheet.dart index 5238eddda..71228e8d5 100644 --- a/forui/lib/src/widgets/sheet/modal_sheet.dart +++ b/forui/lib/src/widgets/sheet/modal_sheet.dart @@ -226,13 +226,28 @@ class FModalSheetRoute extends PopupRoute { final content = DisplayFeatureSubScreen( anchorPoint: anchorPoint, child: Builder( - builder: (context) => _ModalSheet( - route: this, + builder: (context) => Sheet( + controller: controller, + animation: animation, side: side, style: style, constraints: constraints, mainAxisMaxRatio: mainAxisMaxRatio, draggable: draggable, + builder: builder, + onChange: (size) => _didChangeBarrierSemanticsClip( + switch (side) { + Layout.ttb => EdgeInsets.fromLTRB(0, size.height, 0, 0), + Layout.btt => EdgeInsets.fromLTRB(0, 0, 0, size.height), + Layout.ltr => EdgeInsets.fromLTRB(size.width, 0, 0, 0), + Layout.rtl => EdgeInsets.fromLTRB(0, 0, size.width, 0), + }, + ), + onClosing: () { + if (isCurrent) { + Navigator.pop(context); + } + }, ), ), ); @@ -305,94 +320,3 @@ class FModalSheetRoute extends PopupRoute { @override Duration get reverseTransitionDuration => style.exitDuration; } - -class _ModalSheet extends StatefulWidget { - final FModalSheetRoute route; - final Layout side; - final FSheetStyle style; - final double? mainAxisMaxRatio; - final BoxConstraints constraints; - final bool draggable; - - const _ModalSheet({ - required this.route, - required this.side, - required this.style, - required this.mainAxisMaxRatio, - required this.constraints, - required this.draggable, - super.key, - }); - - @override - _ModalSheetState createState() => _ModalSheetState(); - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties - ..add(DiagnosticsProperty('route', route)) - ..add(EnumProperty('side', side)) - ..add(DiagnosticsProperty('style', style)) - ..add(DoubleProperty('mainAxisMaxRatio', mainAxisMaxRatio)) - ..add(DiagnosticsProperty('constraints', constraints)) - ..add(FlagProperty('draggable', value: draggable, ifTrue: 'draggable')); - } -} - -class _ModalSheetState extends State<_ModalSheet> { - static const _cubic = Cubic(0.0, 0.0, 0.2, 1.0); - - ParametricCurve _curve = _cubic; - - @override - Widget build(BuildContext context) { - assert(debugCheckHasMediaQuery(context), ''); - - return AnimatedBuilder( - animation: widget.route.animation!, - builder: (context, child) => Semantics( - scopesRoute: true, - namesRoute: true, - label: switch (defaultTargetPlatform) { - TargetPlatform.iOS || TargetPlatform.macOS => null, - _ => FLocalizations.of(context).dialogLabel, - }, - explicitChildNodes: true, - child: ClipRect( - child: ShiftedSheet( - side: widget.side, - onChange: (size) => widget.route._didChangeBarrierSemanticsClip( - switch (widget.side) { - Layout.ttb => EdgeInsets.fromLTRB(0, size.height, 0, 0), - Layout.btt => EdgeInsets.fromLTRB(0, 0, 0, size.height), - Layout.ltr => EdgeInsets.fromLTRB(size.width, 0, 0, 0), - Layout.rtl => EdgeInsets.fromLTRB(0, 0, size.width, 0), - }, - ), - value: _curve.transform(widget.route.animation!.value), - mainAxisMaxRatio: widget.mainAxisMaxRatio, - child: child, - ), - ), - ), - child: Sheet( - controller: widget.route._animationController, - layout: widget.side, - style: widget.style, - constraints: widget.constraints, - draggable: widget.draggable, - builder: widget.route.builder, - // Allow the bottom sheet to track the user's finger accurately. - onDragStart: (details) => _curve = Curves.linear, - // Allow the sheet to animate smoothly from its current position. - onDragEnd: (details, {required closing}) => _curve = Split(widget.route.animation!.value, endCurve: _cubic), - onClosing: () { - if (widget.route.isCurrent) { - Navigator.pop(context); - } - }, - ), - ); - } -} diff --git a/forui/lib/src/widgets/sheet/page_sheet.dart b/forui/lib/src/widgets/sheet/page_sheet.dart new file mode 100644 index 000000000..11d73943f --- /dev/null +++ b/forui/lib/src/widgets/sheet/page_sheet.dart @@ -0,0 +1,138 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; + +import 'package:forui/forui.dart'; +import 'package:forui/src/widgets/sheet/sheet.dart'; +import 'package:forui/src/widgets/sheet/shifted_sheet.dart'; + +/// A route that represents a modal sheet. [showFModalSheet] should be preferred in most cases. +/// +/// A modal sheet is an alternative to a menu or a dialog and prevents the user from interacting with the rest of the +/// app. +/// +/// A closely related widget is a persistent sheet, which shows information that supplements the primary content of the +/// app without preventing the user from interacting with the app. +// TODO: reference persistent bottom sheet when implemented. +/// +/// See: +/// * https://forui.dev/docs/overlay/modal-sheet for working examples. +/// * [FSheetStyle] for customizing a switch's appearance. +/// * [showFModalSheet] for displaying a FModalSheetRoute. +// TODO: reference persistent bottom sheet when implemented. +/// * [DraggableScrollableSheet], creates a bottom sheet that grows and then becomes scrollable once it reaches its +/// maximum size. +/// +/// This is based on Material's `ModalBottomSheetRoute`. +class FSheet extends StatelessWidget { + /// The style. + final FSheetStyle style; + + /// The side. + final Layout side; + + /// The main axis's max constraint ratio for the sheet, depending on [side]. Defaults to 9 / 16. + /// + /// The main axis is the width if [side] is [Layout.ltr] or [Layout.rtl], and the height if [side] is [Layout.ttb] or + /// [Layout.btt]. + /// + /// Consider setting this to null if this sheet has a scrollable child, i.e. [ListView], along the main axis, to have + /// the sheet be draggable. + final double? mainAxisMaxRatio; + + /// The minimum and maximum sizes for a sheet. Default to being unconstrained. + final BoxConstraints constraints; + + /// True if the sheet can be dragged up and down/left and right. Defaults is true. + final bool draggable; + + /// The animation controller that controls the sheet's entrance and exit animations. + /// + /// The sheet widget will manipulate the position of this animation, it is not just a passive observer. + final AnimationController? controller; + + /// The anchor point used to pick the closest sub-screen. + /// + /// If the anchor point sits inside one of these sub-screens, then that sub-screen is picked. If not, then the + /// sub-screen with the closest edge to the point is used. + /// + /// [Offset.zero] is the top-left corner of the available screen space. For a vertically split dual-screen device, + /// this is the top-left corner of the left screen. + /// + /// When this is null, [Directionality] is used: + /// * for [TextDirection.ltr], [anchorPoint] is [Offset.zero], which will cause the top-left sub-screen to be picked. + /// * for [TextDirection.rtl], [anchorPoint] is `Offset(double.maxFinite, 0)`, which will cause the top-right + /// sub-screen to be picked. + final Offset? anchorPoint; + + /// True if a [SafeArea] should be inserted o keep the sheet away from system intrusions on the sides other than + /// [side]. Defaults to false. + /// + /// If false, the sheet will extend through any system intrusions other than [side]. In addition, + /// [MediaQuery.removePadding] is used to remove opposite [side]'s padding so that a [SafeArea] widget inside the + /// sheet will not have any effect on the opposite side. If this is undesired, consider setting [useSafeArea] to true. + /// Alternatively, wrap the [SafeArea] in a [MediaQuery] that restates an ambient [MediaQueryData] from outside + /// [sheetBuilder]. + /// + /// In either case, the sheet extends all the way to the [side] of the screen, including any system intrusions. + final bool useSafeArea; + + /// A builder for the contents of the sheet. + final WidgetBuilder sheetBuilder; + + final Widget child; + + /// Creates a [FSheet]. + const FSheet({ + required this.style, + required this.side, + required this.sheetBuilder, + required this.mainAxisMaxRatio, + required this.child, + this.constraints = const BoxConstraints(), + this.draggable = true, + this.controller, + this.anchorPoint, + this.useSafeArea = false, + super.key, + }); + + + + @override + Widget build(BuildContext context) { + final content = DisplayFeatureSubScreen( + anchorPoint: anchorPoint, + child: Builder( + builder: (context) => Sheet( + style: style, + controller: controller, + side: side, + constraints: constraints, + mainAxisMaxRatio: mainAxisMaxRatio, + draggable: draggable, + builder: sheetBuilder, + ), + ), + ); + + final sheet = switch ((side, useSafeArea)) { + (Layout.ttb, true) => SafeArea(top: false, child: content), + (Layout.btt, true) => SafeArea(bottom: false, child: content), + (Layout.ltr, true) => SafeArea(left: false, child: content), + (Layout.rtl, true) => SafeArea(right: false, child: content), + (Layout.ttb, false) => MediaQuery.removePadding(context: context, removeBottom: true, child: content), + (Layout.btt, false) => MediaQuery.removePadding(context: context, removeTop: true, child: content), + (Layout.ltr, false) => MediaQuery.removePadding(context: context, removeRight: true, child: content), + (Layout.rtl, false) => MediaQuery.removePadding(context: context, removeLeft: true, child: content), + }; + + return Stack( + children: [ + child, + sheet, + ], + ); + } +} diff --git a/forui/lib/src/widgets/sheet/sheet.dart b/forui/lib/src/widgets/sheet/sheet.dart index 5033ca55a..d32b17a7e 100644 --- a/forui/lib/src/widgets/sheet/sheet.dart +++ b/forui/lib/src/widgets/sheet/sheet.dart @@ -1,5 +1,6 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; +import 'package:forui/src/widgets/sheet/shifted_sheet.dart'; import 'package:meta/meta.dart'; @@ -17,24 +18,26 @@ class Sheet extends StatefulWidget { static void _onClosing() {} final AnimationController? controller; + final Animation? animation; final FSheetStyle style; - final Layout layout; + final Layout side; + final double? mainAxisMaxRatio; final BoxConstraints constraints; final bool draggable; final WidgetBuilder builder; - final GestureDragStartCallback? onDragStart; - final void Function(DragEndDetails details, {required bool closing})? onDragEnd; + final ValueChanged? onChange; final VoidCallback onClosing; const Sheet({ required this.controller, required this.style, - required this.layout, + required this.side, + required this.mainAxisMaxRatio, required this.builder, + this.animation, this.constraints = const BoxConstraints(), this.draggable = true, - this.onDragStart, - this.onDragEnd, + this.onChange, this.onClosing = _onClosing, super.key, }) : assert(!draggable || controller != null, 'Draggable sheets must have a controller.'); @@ -47,25 +50,31 @@ class Sheet extends StatefulWidget { super.debugFillProperties(properties); properties ..add(DiagnosticsProperty('controller', controller)) + ..add(DiagnosticsProperty('animation', animation)) ..add(DiagnosticsProperty('style', style)) - ..add(EnumProperty('layout', layout)) + ..add(EnumProperty('side', side)) + ..add(DoubleProperty('mainAxisMaxRatio', mainAxisMaxRatio)) ..add(DiagnosticsProperty('constraints', constraints)) ..add(FlagProperty('draggable', value: draggable, ifTrue: 'draggable')) ..add(ObjectFlagProperty.has('builder', builder)) - ..add(ObjectFlagProperty.has('onDragStart', onDragStart)) - ..add(ObjectFlagProperty.has('onDragEnd', onDragEnd)) + ..add(ObjectFlagProperty.has('onChange', onChange)) ..add(ObjectFlagProperty.has('onClosing', onClosing)); } } class _SheetState extends State with SingleTickerProviderStateMixin { + static const _cubic = Cubic(0.0, 0.0, 0.2, 1.0); + final GlobalKey _key = GlobalKey(debugLabel: 'Sheet child'); late AnimationController _controller; + late Animation _animation; + ParametricCurve _curve = _cubic; @override void initState() { super.initState(); _controller = widget.controller ?? Sheet.createAnimationController(this, widget.style); + _animation = widget.animation ?? _controller.view; } @override @@ -82,15 +91,17 @@ class _SheetState extends State with SingleTickerProviderStateMixin { @override Widget build(BuildContext context) { + assert(debugCheckHasMediaQuery(context), ''); + Widget sheet = Align( - alignment: switch (widget.layout) { + alignment: switch (widget.side) { Layout.ttb => Alignment.topCenter, Layout.btt => Alignment.bottomCenter, Layout.ltr => Alignment.centerLeft, Layout.rtl => Alignment.centerRight, }, - heightFactor: widget.layout.vertical ? 1 : null, - widthFactor: widget.layout.vertical ? null : 1, + heightFactor: widget.side.vertical ? 1 : null, + widthFactor: widget.side.vertical ? null : 1, child: ConstrainedBox( constraints: widget.constraints, child: NotificationListener( @@ -108,18 +119,41 @@ class _SheetState extends State with SingleTickerProviderStateMixin { if (widget.draggable) { sheet = SheetGestureDetector( - layout: widget.layout, - onStart: widget.onDragStart, + layout: widget.side, + // Allow the sheet to track the user's finger accurately. + onStart: (details) => _curve = Curves.linear, onUpdate: _dragUpdate, + // Allow the sheet to animate smoothly from its current position. onEnd: _dragEnd, child: sheet, ); } - return sheet; + return AnimatedBuilder( + animation: _animation, + builder: (context, child) => Semantics( + scopesRoute: true, + namesRoute: true, + label: switch (defaultTargetPlatform) { + TargetPlatform.iOS || TargetPlatform.macOS => null, + _ => FLocalizations.of(context).dialogLabel, + }, + explicitChildNodes: true, + child: ClipRect( + child: ShiftedSheet( + side: widget.side, + onChange: widget.onChange, + value: _curve.transform(_animation.value), + mainAxisMaxRatio: widget.mainAxisMaxRatio, + child: child, + ), + ), + ), + child: sheet, + ); } - GestureDragUpdateCallback get _dragUpdate => switch (widget.layout) { + GestureDragUpdateCallback get _dragUpdate => switch (widget.side) { Layout.ttb => (details) { if (!_dismissing) { _controller.value += details.primaryDelta! / _key.currentChildHeight; @@ -143,7 +177,7 @@ class _SheetState extends State with SingleTickerProviderStateMixin { }; GestureDragEndCallback get _dragEnd { - final double Function(DragEndDetails) velocity = switch (widget.layout) { + final double Function(DragEndDetails) velocity = switch (widget.side) { Layout.ttb => (details) => details.primaryVelocity! / _key.currentChildHeight, Layout.btt => (details) => -details.primaryVelocity! / _key.currentChildHeight, Layout.ltr => (details) => details.primaryVelocity! / _key.currentChildWidth, @@ -174,7 +208,8 @@ class _SheetState extends State with SingleTickerProviderStateMixin { _controller.forward(); } - widget.onDragEnd?.call(details, closing: closing); + // Allow the sheet to animate smoothly from its current position. + _curve = Split(_animation.value, endCurve: _cubic); if (closing) { widget.onClosing(); } diff --git a/forui/lib/src/widgets/sheet/shifted_sheet.dart b/forui/lib/src/widgets/sheet/shifted_sheet.dart index 7e6ff4d02..a963a3c10 100644 --- a/forui/lib/src/widgets/sheet/shifted_sheet.dart +++ b/forui/lib/src/widgets/sheet/shifted_sheet.dart @@ -6,18 +6,13 @@ import 'package:meta/meta.dart'; import 'package:forui/src/foundation/rendering.dart'; -@internal - -/// -typedef SizeChangeCallback = void Function(Size size); - /// This is based on Material's _BottomSheetLayoutWithSizeListener. @internal class ShiftedSheet extends SingleChildRenderObjectWidget { final Layout side; final double value; final double? mainAxisMaxRatio; - final SizeChangeCallback onChange; + final ValueChanged? onChange; const ShiftedSheet({ required this.side, @@ -61,14 +56,14 @@ class _ShiftedSheet extends RenderShiftedBox { Layout _side; double _value; double? _mainAxisMaxRatio; - SizeChangeCallback _onChange; + ValueChanged? _onChange; Size _previous = Size.zero; _ShiftedSheet({ required Layout side, required double value, required double? mainAxisMaxRatio, - required SizeChangeCallback onChange, + required ValueChanged? onChange, }) : _side = side, _value = value, _mainAxisMaxRatio = mainAxisMaxRatio, @@ -90,7 +85,7 @@ class _ShiftedSheet extends RenderShiftedBox { if (_previous != childSize) { _previous = childSize; - _onChange.call(_previous); + _onChange?.call(_previous); } } } @@ -135,28 +130,16 @@ class _ShiftedSheet extends RenderShiftedBox { Size computeDryLayout(BoxConstraints constraints) => constraints.biggest; @override - double computeMinIntrinsicWidth(double height) { - final width = BoxConstraints.tightForFinite(height: height).biggest.width; - return width.isFinite ? width : 0.0; - } + double computeMinIntrinsicWidth(double height) => 0.0; @override - double computeMaxIntrinsicWidth(double height) { - final width = BoxConstraints.tightForFinite(height: height).biggest.width; - return width.isFinite ? width : 0.0; - } + double computeMaxIntrinsicWidth(double height) => 0.0; @override - double computeMinIntrinsicHeight(double width) { - final height = BoxConstraints.tightForFinite(width: width).biggest.height; - return height.isFinite ? height : 0.0; - } + double computeMinIntrinsicHeight(double width) => 0.0; @override - double computeMaxIntrinsicHeight(double width) { - final height = BoxConstraints.tightForFinite(width: width).biggest.height; - return height.isFinite ? height : 0.0; - } + double computeMaxIntrinsicHeight(double width) => 0.0; Layout get side => _side; @@ -185,9 +168,9 @@ class _ShiftedSheet extends RenderShiftedBox { } } - SizeChangeCallback get onChange => _onChange; + ValueChanged? get onChange => _onChange; - set onChange(SizeChangeCallback value) { + set onChange(ValueChanged? value) { if (_onChange != value) { _onChange = value; markNeedsLayout(); diff --git a/forui/lib/widgets/sheet.dart b/forui/lib/widgets/sheet.dart index 23649b869..ebf1772a8 100644 --- a/forui/lib/widgets/sheet.dart +++ b/forui/lib/widgets/sheet.dart @@ -7,4 +7,5 @@ library forui.widgets.sheet; export '../src/widgets/sheet/modal_sheet.dart'; +export '../src/widgets/sheet/page_sheet.dart'; export '../src/widgets/sheet/sheet.dart' show FSheetStyle; From c98a66f3cf89f8279ae0a99f25da5d0ea109a664 Mon Sep 17 00:00:00 2001 From: Matthias Ngeo Date: Tue, 3 Dec 2024 17:16:44 +0800 Subject: [PATCH 14/29] Finalize scaffold sheet --- forui/lib/src/widgets/sheet/modal_sheet.dart | 62 ++++----- .../{page_sheet.dart => scaffold_sheet.dart} | 119 ++++++++++-------- forui/lib/src/widgets/sheet/sheet.dart | 63 ++++++---- forui/lib/widgets/sheet.dart | 2 +- 4 files changed, 131 insertions(+), 115 deletions(-) rename forui/lib/src/widgets/sheet/{page_sheet.dart => scaffold_sheet.dart} (54%) diff --git a/forui/lib/src/widgets/sheet/modal_sheet.dart b/forui/lib/src/widgets/sheet/modal_sheet.dart index 71228e8d5..dc4117d4c 100644 --- a/forui/lib/src/widgets/sheet/modal_sheet.dart +++ b/forui/lib/src/widgets/sheet/modal_sheet.dart @@ -5,7 +5,6 @@ import 'package:flutter/rendering.dart'; import 'package:forui/forui.dart'; import 'package:forui/src/widgets/sheet/sheet.dart'; -import 'package:forui/src/widgets/sheet/shifted_sheet.dart'; /// Shows a modal sheet that appears from the given [side]. /// @@ -95,7 +94,6 @@ Future showFModalSheet({ /// /// A closely related widget is a persistent sheet, which shows information that supplements the primary content of the /// app without preventing the user from interacting with the app. -// TODO: reference persistent bottom sheet when implemented. /// /// See: /// * https://forui.dev/docs/overlay/modal-sheet for working examples. @@ -195,7 +193,7 @@ class FModalSheetRoute extends PopupRoute { required this.style, required this.side, required this.builder, - required this.mainAxisMaxRatio, + this.mainAxisMaxRatio = 9 / 16, this.capturedThemes, this.barrierOnTapHint, this.barrierLabel, @@ -223,46 +221,32 @@ class FModalSheetRoute extends PopupRoute { @override Widget buildPage(BuildContext context, Animation animation, Animation secondaryAnimation) { - final content = DisplayFeatureSubScreen( + final sheet = Sheet( + controller: controller, + animation: animation, + side: side, + style: style, + constraints: constraints, + mainAxisMaxRatio: mainAxisMaxRatio, anchorPoint: anchorPoint, - child: Builder( - builder: (context) => Sheet( - controller: controller, - animation: animation, - side: side, - style: style, - constraints: constraints, - mainAxisMaxRatio: mainAxisMaxRatio, - draggable: draggable, - builder: builder, - onChange: (size) => _didChangeBarrierSemanticsClip( - switch (side) { - Layout.ttb => EdgeInsets.fromLTRB(0, size.height, 0, 0), - Layout.btt => EdgeInsets.fromLTRB(0, 0, 0, size.height), - Layout.ltr => EdgeInsets.fromLTRB(size.width, 0, 0, 0), - Layout.rtl => EdgeInsets.fromLTRB(0, 0, size.width, 0), - }, - ), - onClosing: () { - if (isCurrent) { - Navigator.pop(context); - } - }, - ), + draggable: draggable, + useSafeArea: useSafeArea, + builder: builder, + onChange: (size) => _didChangeBarrierSemanticsClip( + switch (side) { + Layout.ttb => EdgeInsets.fromLTRB(0, size.height, 0, 0), + Layout.btt => EdgeInsets.fromLTRB(0, 0, 0, size.height), + Layout.ltr => EdgeInsets.fromLTRB(size.width, 0, 0, 0), + Layout.rtl => EdgeInsets.fromLTRB(0, 0, size.width, 0), + }, ), + onClosing: () { + if (isCurrent) { + Navigator.pop(context); + } + }, ); - final sheet = switch ((side, useSafeArea)) { - (Layout.ttb, true) => SafeArea(top: false, child: content), - (Layout.btt, true) => SafeArea(bottom: false, child: content), - (Layout.ltr, true) => SafeArea(left: false, child: content), - (Layout.rtl, true) => SafeArea(right: false, child: content), - (Layout.ttb, false) => MediaQuery.removePadding(context: context, removeBottom: true, child: content), - (Layout.btt, false) => MediaQuery.removePadding(context: context, removeTop: true, child: content), - (Layout.ltr, false) => MediaQuery.removePadding(context: context, removeRight: true, child: content), - (Layout.rtl, false) => MediaQuery.removePadding(context: context, removeLeft: true, child: content), - }; - return capturedThemes?.wrap(sheet) ?? sheet; } diff --git a/forui/lib/src/widgets/sheet/page_sheet.dart b/forui/lib/src/widgets/sheet/scaffold_sheet.dart similarity index 54% rename from forui/lib/src/widgets/sheet/page_sheet.dart rename to forui/lib/src/widgets/sheet/scaffold_sheet.dart index 11d73943f..baa95f8db 100644 --- a/forui/lib/src/widgets/sheet/page_sheet.dart +++ b/forui/lib/src/widgets/sheet/scaffold_sheet.dart @@ -1,33 +1,52 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; import 'package:forui/forui.dart'; import 'package:forui/src/widgets/sheet/sheet.dart'; -import 'package:forui/src/widgets/sheet/shifted_sheet.dart'; -/// A route that represents a modal sheet. [showFModalSheet] should be preferred in most cases. +/// A controller for a [FSheet]. +class FSheetController { + final AnimationController _controller; + + /// Creates a [FSheetController]. + FSheetController({required TickerProvider vsync, required FSheetStyle style}) + : _controller = Sheet.createAnimationController(vsync, style); + + /// Shows the sheet if it is hidden. + TickerFuture show() => _controller.forward(); + + /// Shows the sheet if it is hidden and hides it if it is shown. + TickerFuture toggle() => _controller.toggle(); + + /// Hides the sheet if it is shown. + TickerFuture hide() => _controller.reverse(); + + /// True if the sheet is shown. + bool get shown => _controller.value != 0; + + /// Disposes of the controller. + void dispose() => _controller.dispose(); +} + +/// A sheet that is displayed above its [child]. It is part of [FScaffold], which provides a higher-level interface and +/// should be preferred in most cases. /// -/// A modal sheet is an alternative to a menu or a dialog and prevents the user from interacting with the rest of the -/// app. +/// A sheet shows information that supplements the primary content of the app without preventing the user from +/// interacting with the app. /// -/// A closely related widget is a persistent sheet, which shows information that supplements the primary content of the -/// app without preventing the user from interacting with the app. -// TODO: reference persistent bottom sheet when implemented. +/// A closely related widget is a modal sheet, which is an alternative to a menu or a dialog and prevents the user from +/// interacting with the rest of the app. /// /// See: -/// * https://forui.dev/docs/overlay/modal-sheet for working examples. +/// * https://forui.dev/docs/overlay/sheet for working examples. /// * [FSheetStyle] for customizing a switch's appearance. /// * [showFModalSheet] for displaying a FModalSheetRoute. -// TODO: reference persistent bottom sheet when implemented. /// * [DraggableScrollableSheet], creates a bottom sheet that grows and then becomes scrollable once it reaches its /// maximum size. -/// -/// This is based on Material's `ModalBottomSheetRoute`. class FSheet extends StatelessWidget { /// The style. - final FSheetStyle style; + final FSheetStyle? style; /// The side. final Layout side; @@ -47,10 +66,8 @@ class FSheet extends StatelessWidget { /// True if the sheet can be dragged up and down/left and right. Defaults is true. final bool draggable; - /// The animation controller that controls the sheet's entrance and exit animations. - /// - /// The sheet widget will manipulate the position of this animation, it is not just a passive observer. - final AnimationController? controller; + /// The controller that controls the sheet. + final FSheetController? controller; /// The anchor point used to pick the closest sub-screen. /// @@ -81,15 +98,16 @@ class FSheet extends StatelessWidget { /// A builder for the contents of the sheet. final WidgetBuilder sheetBuilder; + /// The child. final Widget child; /// Creates a [FSheet]. const FSheet({ - required this.style, required this.side, required this.sheetBuilder, - required this.mainAxisMaxRatio, required this.child, + this.style, + this.mainAxisMaxRatio = 9 / 16, this.constraints = const BoxConstraints(), this.draggable = true, this.controller, @@ -98,41 +116,36 @@ class FSheet extends StatelessWidget { super.key, }); - + @override + Widget build(BuildContext context) => Stack( + children: [ + child, + Sheet( + style: style ?? context.theme.sheetStyle, + controller: controller?._controller, + side: side, + constraints: constraints, + mainAxisMaxRatio: mainAxisMaxRatio, + anchorPoint: anchorPoint, + draggable: draggable, + useSafeArea: useSafeArea, + builder: sheetBuilder, + ), + ], + ); @override - Widget build(BuildContext context) { - final content = DisplayFeatureSubScreen( - anchorPoint: anchorPoint, - child: Builder( - builder: (context) => Sheet( - style: style, - controller: controller, - side: side, - constraints: constraints, - mainAxisMaxRatio: mainAxisMaxRatio, - draggable: draggable, - builder: sheetBuilder, - ), - ), - ); - - final sheet = switch ((side, useSafeArea)) { - (Layout.ttb, true) => SafeArea(top: false, child: content), - (Layout.btt, true) => SafeArea(bottom: false, child: content), - (Layout.ltr, true) => SafeArea(left: false, child: content), - (Layout.rtl, true) => SafeArea(right: false, child: content), - (Layout.ttb, false) => MediaQuery.removePadding(context: context, removeBottom: true, child: content), - (Layout.btt, false) => MediaQuery.removePadding(context: context, removeTop: true, child: content), - (Layout.ltr, false) => MediaQuery.removePadding(context: context, removeRight: true, child: content), - (Layout.rtl, false) => MediaQuery.removePadding(context: context, removeLeft: true, child: content), - }; - - return Stack( - children: [ - child, - sheet, - ], - ); + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(DiagnosticsProperty('controller', controller)) + ..add(DiagnosticsProperty('style', style)) + ..add(EnumProperty('side', side)) + ..add(DoubleProperty('mainAxisMaxRatio', mainAxisMaxRatio)) + ..add(DiagnosticsProperty('constraints', constraints)) + ..add(DiagnosticsProperty('anchorPoint', anchorPoint)) + ..add(FlagProperty('draggable', value: draggable, ifTrue: 'draggable')) + ..add(FlagProperty('useSafeArea', value: useSafeArea, ifTrue: 'useSafeArea')) + ..add(ObjectFlagProperty.has('sheetBuilder', sheetBuilder)); } } diff --git a/forui/lib/src/widgets/sheet/sheet.dart b/forui/lib/src/widgets/sheet/sheet.dart index d32b17a7e..3a85e09cd 100644 --- a/forui/lib/src/widgets/sheet/sheet.dart +++ b/forui/lib/src/widgets/sheet/sheet.dart @@ -1,11 +1,11 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; -import 'package:forui/src/widgets/sheet/shifted_sheet.dart'; import 'package:meta/meta.dart'; import 'package:forui/forui.dart'; import 'package:forui/src/widgets/sheet/gesture_detector.dart'; +import 'package:forui/src/widgets/sheet/shifted_sheet.dart'; @internal class Sheet extends StatefulWidget { @@ -23,7 +23,9 @@ class Sheet extends StatefulWidget { final Layout side; final double? mainAxisMaxRatio; final BoxConstraints constraints; + final Offset? anchorPoint; final bool draggable; + final bool useSafeArea; final WidgetBuilder builder; final ValueChanged? onChange; final VoidCallback onClosing; @@ -33,6 +35,8 @@ class Sheet extends StatefulWidget { required this.style, required this.side, required this.mainAxisMaxRatio, + required this.anchorPoint, + required this.useSafeArea, required this.builder, this.animation, this.constraints = const BoxConstraints(), @@ -55,7 +59,9 @@ class Sheet extends StatefulWidget { ..add(EnumProperty('side', side)) ..add(DoubleProperty('mainAxisMaxRatio', mainAxisMaxRatio)) ..add(DiagnosticsProperty('constraints', constraints)) + ..add(DiagnosticsProperty('anchorPoint', anchorPoint)) ..add(FlagProperty('draggable', value: draggable, ifTrue: 'draggable')) + ..add(FlagProperty('useSafeArea', value: useSafeArea, ifTrue: 'useSafeArea')) ..add(ObjectFlagProperty.has('builder', builder)) ..add(ObjectFlagProperty.has('onChange', onChange)) ..add(ObjectFlagProperty.has('onClosing', onClosing)); @@ -93,26 +99,29 @@ class _SheetState extends State with SingleTickerProviderStateMixin { Widget build(BuildContext context) { assert(debugCheckHasMediaQuery(context), ''); - Widget sheet = Align( - alignment: switch (widget.side) { - Layout.ttb => Alignment.topCenter, - Layout.btt => Alignment.bottomCenter, - Layout.ltr => Alignment.centerLeft, - Layout.rtl => Alignment.centerRight, - }, - heightFactor: widget.side.vertical ? 1 : null, - widthFactor: widget.side.vertical ? null : 1, - child: ConstrainedBox( - constraints: widget.constraints, - child: NotificationListener( - key: _key, - onNotification: (notification) { - if (notification.extent == notification.minExtent && notification.shouldCloseOnMinExtent) { - widget.onClosing(); - } - return false; - }, - child: widget.builder(context), + Widget sheet = DisplayFeatureSubScreen( + anchorPoint: widget.anchorPoint, + child: Align( + alignment: switch (widget.side) { + Layout.ttb => Alignment.topCenter, + Layout.btt => Alignment.bottomCenter, + Layout.ltr => Alignment.centerLeft, + Layout.rtl => Alignment.centerRight, + }, + heightFactor: widget.side.vertical ? 1 : null, + widthFactor: widget.side.vertical ? null : 1, + child: ConstrainedBox( + constraints: widget.constraints, + child: NotificationListener( + key: _key, + onNotification: (notification) { + if (notification.extent == notification.minExtent && notification.shouldCloseOnMinExtent) { + widget.onClosing(); + } + return false; + }, + child: widget.builder(context), + ), ), ), ); @@ -123,12 +132,22 @@ class _SheetState extends State with SingleTickerProviderStateMixin { // Allow the sheet to track the user's finger accurately. onStart: (details) => _curve = Curves.linear, onUpdate: _dragUpdate, - // Allow the sheet to animate smoothly from its current position. onEnd: _dragEnd, child: sheet, ); } + sheet = switch ((widget.side, widget.useSafeArea)) { + (Layout.ttb, true) => SafeArea(top: false, child: sheet), + (Layout.btt, true) => SafeArea(bottom: false, child: sheet), + (Layout.ltr, true) => SafeArea(left: false, child: sheet), + (Layout.rtl, true) => SafeArea(right: false, child: sheet), + (Layout.ttb, false) => MediaQuery.removePadding(context: context, removeBottom: true, child: sheet), + (Layout.btt, false) => MediaQuery.removePadding(context: context, removeTop: true, child: sheet), + (Layout.ltr, false) => MediaQuery.removePadding(context: context, removeRight: true, child: sheet), + (Layout.rtl, false) => MediaQuery.removePadding(context: context, removeLeft: true, child: sheet), + }; + return AnimatedBuilder( animation: _animation, builder: (context, child) => Semantics( diff --git a/forui/lib/widgets/sheet.dart b/forui/lib/widgets/sheet.dart index ebf1772a8..b3483ff58 100644 --- a/forui/lib/widgets/sheet.dart +++ b/forui/lib/widgets/sheet.dart @@ -7,5 +7,5 @@ library forui.widgets.sheet; export '../src/widgets/sheet/modal_sheet.dart'; -export '../src/widgets/sheet/page_sheet.dart'; +export '../src/widgets/sheet/scaffold_sheet.dart'; export '../src/widgets/sheet/sheet.dart' show FSheetStyle; From e6a06a2bcbdec145b82e5d676b65dda81f56060a Mon Sep 17 00:00:00 2001 From: Matthias Ngeo Date: Wed, 4 Dec 2024 21:04:05 +0800 Subject: [PATCH 15/29] Next iteration of sheets --- forui/lib/src/widgets/scaffold.dart | 35 +-- forui/lib/src/widgets/sheet/modal_sheet.dart | 4 +- .../lib/src/widgets/sheet/scaffold_sheet.dart | 151 ------------ forui/lib/src/widgets/sheet/sheets.dart | 218 ++++++++++++++++++ forui/lib/widgets/sheet.dart | 2 +- 5 files changed, 242 insertions(+), 168 deletions(-) delete mode 100644 forui/lib/src/widgets/sheet/scaffold_sheet.dart create mode 100644 forui/lib/src/widgets/sheet/sheets.dart diff --git a/forui/lib/src/widgets/scaffold.dart b/forui/lib/src/widgets/scaffold.dart index 859758e55..c96c9870e 100644 --- a/forui/lib/src/widgets/scaffold.dart +++ b/forui/lib/src/widgets/scaffold.dart @@ -13,7 +13,7 @@ import 'package:forui/forui.dart'; /// See: /// * https://forui.dev/docs/layout/scaffold for working examples. /// * [FScaffoldStyle] for customizing a scaffold's appearance. -class FScaffold extends StatelessWidget { +class FScaffold extends StatefulWidget { /// The content. final Widget content; @@ -39,12 +39,27 @@ class FScaffold extends StatelessWidget { super.key, }); + @override + State createState() => _State(); + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(DiagnosticsProperty('style', style)) + ..add(FlagProperty('contentPad', value: contentPad, defaultValue: true, ifTrue: 'pad')); + } +} + +class _State extends State { + FSheetController? _sheet; + @override Widget build(BuildContext context) { - final style = this.style ?? context.theme.scaffoldStyle; - Widget content = this.content; + final style = widget.style ?? context.theme.scaffoldStyle; + Widget content = widget.content; - if (contentPad) { + if (widget.contentPad) { content = Padding(padding: style.contentPadding, child: content); } @@ -52,21 +67,13 @@ class FScaffold extends StatelessWidget { color: style.backgroundColor, child: Column( children: [ - if (header != null) DecoratedBox(decoration: style.headerDecoration, child: header!), + if (widget.header != null) DecoratedBox(decoration: style.headerDecoration, child: widget.header!), Expanded(child: content), - if (footer != null) DecoratedBox(decoration: style.footerDecoration, child: footer!), + if (widget.footer != null) DecoratedBox(decoration: style.footerDecoration, child: widget.footer!), ], ), ); } - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties - ..add(DiagnosticsProperty('style', style)) - ..add(FlagProperty('contentPad', value: contentPad, defaultValue: true, ifTrue: 'pad')); - } } /// [FScaffold]'s style. diff --git a/forui/lib/src/widgets/sheet/modal_sheet.dart b/forui/lib/src/widgets/sheet/modal_sheet.dart index dc4117d4c..660391e93 100644 --- a/forui/lib/src/widgets/sheet/modal_sheet.dart +++ b/forui/lib/src/widgets/sheet/modal_sheet.dart @@ -34,9 +34,9 @@ import 'package:forui/src/widgets/sheet/sheet.dart'; /// /// See: /// * https://forui.dev/docs/overlay/modal-sheet for working examples. +/// * [showFSheet] for displaying a sheet above the current widget. /// * [FModalSheetRoute] for more information about the various arguments. /// * [FSheetStyle] for customizing a switch's appearance. -// TODO: reference persistent bottom sheet when implemented. /// * [DraggableScrollableSheet], creates a bottom sheet that grows and then becomes scrollable once it reaches its /// maximum size. Future showFModalSheet({ @@ -99,7 +99,7 @@ Future showFModalSheet({ /// * https://forui.dev/docs/overlay/modal-sheet for working examples. /// * [FSheetStyle] for customizing a switch's appearance. /// * [showFModalSheet] for displaying a FModalSheetRoute. -// TODO: reference persistent bottom sheet when implemented. +/// * [showFSheet] for displaying a sheet above the current widget. /// * [DraggableScrollableSheet], creates a bottom sheet that grows and then becomes scrollable once it reaches its /// maximum size. /// diff --git a/forui/lib/src/widgets/sheet/scaffold_sheet.dart b/forui/lib/src/widgets/sheet/scaffold_sheet.dart deleted file mode 100644 index baa95f8db..000000000 --- a/forui/lib/src/widgets/sheet/scaffold_sheet.dart +++ /dev/null @@ -1,151 +0,0 @@ -import 'package:flutter/cupertino.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; - -import 'package:forui/forui.dart'; -import 'package:forui/src/widgets/sheet/sheet.dart'; - -/// A controller for a [FSheet]. -class FSheetController { - final AnimationController _controller; - - /// Creates a [FSheetController]. - FSheetController({required TickerProvider vsync, required FSheetStyle style}) - : _controller = Sheet.createAnimationController(vsync, style); - - /// Shows the sheet if it is hidden. - TickerFuture show() => _controller.forward(); - - /// Shows the sheet if it is hidden and hides it if it is shown. - TickerFuture toggle() => _controller.toggle(); - - /// Hides the sheet if it is shown. - TickerFuture hide() => _controller.reverse(); - - /// True if the sheet is shown. - bool get shown => _controller.value != 0; - - /// Disposes of the controller. - void dispose() => _controller.dispose(); -} - -/// A sheet that is displayed above its [child]. It is part of [FScaffold], which provides a higher-level interface and -/// should be preferred in most cases. -/// -/// A sheet shows information that supplements the primary content of the app without preventing the user from -/// interacting with the app. -/// -/// A closely related widget is a modal sheet, which is an alternative to a menu or a dialog and prevents the user from -/// interacting with the rest of the app. -/// -/// See: -/// * https://forui.dev/docs/overlay/sheet for working examples. -/// * [FSheetStyle] for customizing a switch's appearance. -/// * [showFModalSheet] for displaying a FModalSheetRoute. -/// * [DraggableScrollableSheet], creates a bottom sheet that grows and then becomes scrollable once it reaches its -/// maximum size. -class FSheet extends StatelessWidget { - /// The style. - final FSheetStyle? style; - - /// The side. - final Layout side; - - /// The main axis's max constraint ratio for the sheet, depending on [side]. Defaults to 9 / 16. - /// - /// The main axis is the width if [side] is [Layout.ltr] or [Layout.rtl], and the height if [side] is [Layout.ttb] or - /// [Layout.btt]. - /// - /// Consider setting this to null if this sheet has a scrollable child, i.e. [ListView], along the main axis, to have - /// the sheet be draggable. - final double? mainAxisMaxRatio; - - /// The minimum and maximum sizes for a sheet. Default to being unconstrained. - final BoxConstraints constraints; - - /// True if the sheet can be dragged up and down/left and right. Defaults is true. - final bool draggable; - - /// The controller that controls the sheet. - final FSheetController? controller; - - /// The anchor point used to pick the closest sub-screen. - /// - /// If the anchor point sits inside one of these sub-screens, then that sub-screen is picked. If not, then the - /// sub-screen with the closest edge to the point is used. - /// - /// [Offset.zero] is the top-left corner of the available screen space. For a vertically split dual-screen device, - /// this is the top-left corner of the left screen. - /// - /// When this is null, [Directionality] is used: - /// * for [TextDirection.ltr], [anchorPoint] is [Offset.zero], which will cause the top-left sub-screen to be picked. - /// * for [TextDirection.rtl], [anchorPoint] is `Offset(double.maxFinite, 0)`, which will cause the top-right - /// sub-screen to be picked. - final Offset? anchorPoint; - - /// True if a [SafeArea] should be inserted o keep the sheet away from system intrusions on the sides other than - /// [side]. Defaults to false. - /// - /// If false, the sheet will extend through any system intrusions other than [side]. In addition, - /// [MediaQuery.removePadding] is used to remove opposite [side]'s padding so that a [SafeArea] widget inside the - /// sheet will not have any effect on the opposite side. If this is undesired, consider setting [useSafeArea] to true. - /// Alternatively, wrap the [SafeArea] in a [MediaQuery] that restates an ambient [MediaQueryData] from outside - /// [sheetBuilder]. - /// - /// In either case, the sheet extends all the way to the [side] of the screen, including any system intrusions. - final bool useSafeArea; - - /// A builder for the contents of the sheet. - final WidgetBuilder sheetBuilder; - - /// The child. - final Widget child; - - /// Creates a [FSheet]. - const FSheet({ - required this.side, - required this.sheetBuilder, - required this.child, - this.style, - this.mainAxisMaxRatio = 9 / 16, - this.constraints = const BoxConstraints(), - this.draggable = true, - this.controller, - this.anchorPoint, - this.useSafeArea = false, - super.key, - }); - - @override - Widget build(BuildContext context) => Stack( - children: [ - child, - Sheet( - style: style ?? context.theme.sheetStyle, - controller: controller?._controller, - side: side, - constraints: constraints, - mainAxisMaxRatio: mainAxisMaxRatio, - anchorPoint: anchorPoint, - draggable: draggable, - useSafeArea: useSafeArea, - builder: sheetBuilder, - ), - ], - ); - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties - ..add(DiagnosticsProperty('controller', controller)) - ..add(DiagnosticsProperty('style', style)) - ..add(EnumProperty('side', side)) - ..add(DoubleProperty('mainAxisMaxRatio', mainAxisMaxRatio)) - ..add(DiagnosticsProperty('constraints', constraints)) - ..add(DiagnosticsProperty('anchorPoint', anchorPoint)) - ..add(FlagProperty('draggable', value: draggable, ifTrue: 'draggable')) - ..add(FlagProperty('useSafeArea', value: useSafeArea, ifTrue: 'useSafeArea')) - ..add(ObjectFlagProperty.has('sheetBuilder', sheetBuilder)); - } -} diff --git a/forui/lib/src/widgets/sheet/sheets.dart b/forui/lib/src/widgets/sheet/sheets.dart new file mode 100644 index 000000000..9fd6e4608 --- /dev/null +++ b/forui/lib/src/widgets/sheet/sheets.dart @@ -0,0 +1,218 @@ +import 'dart:math'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/widgets.dart'; +import 'package:forui/forui.dart'; +import 'package:forui/src/widgets/sheet/sheet.dart'; +import 'package:meta/meta.dart'; + +/// Shows a sheet that appears above the current widget. +/// +/// A closely related widget is a modal sheet which prevents the user from interacting with the rest of the app. +/// +/// [context] is used to look up the [Navigator] and [FSheetStyle] for the sheet. It is only used when the method is +/// called. Its corresponding widget can be safely removed from the tree before the sheet is closed. +/// +/// [style] defaults to [FSheetStyle] from the closest [FTheme] ancestor. +/// +/// [mainAxisMaxRatio] represents the main axis's max constraint ratio for the sheet, depending on [side]. +/// Defaults to 9 / 16. The main axis is the width if [side] is [Layout.ltr] or [Layout.rtl], and the height if [side] +/// is [Layout.ttb] or [Layout.btt]. Consider setting [mainAxisMaxRatio] to null if this sheet has a scrollable child, +/// i.e. [ListView], along the main axis, to have the sheet be draggable. +/// +/// ## Contract +/// Throws [FlutterError] if the [context] does not contain a [FSheets] or [FScaffold] ancestor. +/// +/// See: +/// * https://forui.dev/docs/overlay/sheets for working examples. +/// * [showFModalSheet] for showing a sheet in a modal that prevents the user from interacting with the rest of the app. +/// * [FSheetStyle] for customizing a switch's appearance. +/// * [DraggableScrollableSheet], creates a bottom sheet that grows and then becomes scrollable once it reaches its +/// maximum size. +@useResult +FSheetController showFSheet({ + required BuildContext context, + required Layout side, + required WidgetBuilder builder, + FSheetStyle? style, + double? mainAxisMaxRatio = 9 / 16, + BoxConstraints constraints = const BoxConstraints(), + bool draggable = true, + Offset? anchorPoint, + bool useSafeArea = false, + bool keepAliveOffstage = false, + Key? key, +}) { + final state = context.findAncestorStateOfType<_FSheetsState>(); + if (state == null) { + throw FlutterError.fromParts([ + ErrorSummary( + 'showFSheet(...) called with a context that does not contain a FSheets/FScaffold.', + ), + ErrorDescription( + 'No FSheets/FScaffold ancestor could be found starting from the context that was passed to FSheets/FScaffold.of(). ' + 'This usually happens when the context provided is from the same StatefulWidget as that whose build function ' + 'actually creates the FSheets/FScaffold widget being sought.', + ), + ErrorHint( + 'There are several ways to avoid this problem. The simplest is to use a Builder to get a ' + 'context that is "under" the FSheets/FScaffold.', + ), + context.describeElement('The context used was'), + ]); + } + + key ??= ValueKey(Random.secure().nextInt(2147483647)); + style ??= context.theme.sheetStyle; + + final controller = FSheetController._( + vsync: state, + style: style, + key: key, + keepAliveOffstage: keepAliveOffstage, + setState: (function) { + if (state.mounted) { + // ignore: invalid_use_of_protected_member + state.setState(function); + } + }, + onDispose: () => state._remove(key!), + ); + + state._add( + controller, + Sheet( + controller: controller._controller, + style: style, + side: side, + mainAxisMaxRatio: mainAxisMaxRatio, + anchorPoint: anchorPoint, + useSafeArea: useSafeArea, + builder: builder, + ), + ); + + controller.show(); + + return controller; +} + +/// A sheet controller. +class FSheetController { + /// The sheet's key. + final Key key; + + /// True if the sheet to which this controller is attached should be kept alive even when it is offstage. Defaults to + /// false. Keeping multiple sheets alive even when offstage can negatively impact performance. + final bool keepAliveOffstage; + + /// Marks the sheet as needing to be rebuilt. + final StateSetter setState; + + final AnimationController _controller; + final VoidCallback _onDispose; + + FSheetController._({ + required TickerProvider vsync, + required FSheetStyle style, + required VoidCallback onDispose, + required this.key, + required this.keepAliveOffstage, + required this.setState, + }) : _controller = Sheet.createAnimationController(vsync, style), + _onDispose = onDispose { + if (kFlutterMemoryAllocationsEnabled) { + FlutterMemoryAllocations.instance.dispatchObjectCreated( + library: 'package:flutter/forui.dart', + className: '$FSheetController', + object: this, + ); + } + + _controller.addStatusListener((status) => setState.call(() {})); + } + + /// Shows the sheet if it is hidden. + TickerFuture show() => _controller.forward(); + + /// Shows the sheet if it is hidden and hides it if it is shown. + TickerFuture toggle() => _controller.toggle(); + + /// Hides the sheet if it is shown. + TickerFuture hide() => _controller.reverse(); + + /// True if the sheet is shown. + bool get shown => _controller.value != 0; + + /// Disposes of the controller. + void dispose() { + _controller.dispose(); + _onDispose(); + } +} + +/// Sheets that are displayed above its [child]. It is part of [FScaffold], which should be preferred in most cases. +/// +/// A sheet shows information that supplements the primary content of the app without preventing the user from +/// interacting with the app. +/// +/// A closely related widget is a modal sheet, which is an alternative to a menu or a dialog and prevents the user from +/// interacting with the rest of the app. +/// +/// See: +/// * https://forui.dev/docs/overlay/sheets for working examples. +/// * [FSheetStyle] for customizing a switch's appearance. +/// * [showFSheet] for for displaying a sheet above the current widget. +/// * [showFModalSheet] for displaying a modal sheet. +/// * [DraggableScrollableSheet], creates a bottom sheet that grows and then becomes scrollable once it reaches its +/// maximum size. +class FSheets extends StatefulWidget { + /// The child. + final Widget child; + + /// Creates a [FSheets]. + const FSheets({required this.child, super.key}); + + @override + State createState() => _FSheetsState(); +} + +class _FSheetsState extends State with TickerProviderStateMixin { + final Map _sheets = {}; + + @override + Widget build(BuildContext context) => Stack( + children: [ + widget.child, + for (final (controller, sheet) in _sheets.values) + if (controller.shown || controller.keepAliveOffstage || controller._controller.status.isAnimating) sheet, + ], + ); + + void _add(FSheetController controller, Sheet sheet) { + if (!mounted) { + return; + } + + if (_sheets.containsKey(controller.key)) { + throw FlutterError.fromParts([ + ErrorSummary('showFSheet(...) called with a key that already exists.'), + ErrorDescription( + 'A sheet with the key, "${controller.key}", already exists. Each sheet must have a unique key.', + ), + ErrorHint( + 'To solve this problem, pass a different key to `showFSheet(...)` or dispose of the other sheet with the same ' + 'key first', + ), + ]); + } + + setState(() => _sheets[controller.key] = (controller, sheet)); + } + + void _remove(Key key) { + if (mounted) { + setState(() => _sheets.remove(key)); + } + } +} diff --git a/forui/lib/widgets/sheet.dart b/forui/lib/widgets/sheet.dart index b3483ff58..1500e7758 100644 --- a/forui/lib/widgets/sheet.dart +++ b/forui/lib/widgets/sheet.dart @@ -7,5 +7,5 @@ library forui.widgets.sheet; export '../src/widgets/sheet/modal_sheet.dart'; -export '../src/widgets/sheet/scaffold_sheet.dart'; +export '../src/widgets/sheet/sheets.dart'; export '../src/widgets/sheet/sheet.dart' show FSheetStyle; From 8aa956141428d341da2780fcca2285246fe3603b Mon Sep 17 00:00:00 2001 From: Matthias Ngeo Date: Thu, 5 Dec 2024 10:49:57 +0800 Subject: [PATCH 16/29] Add golden tests --- forui/lib/src/widgets/sheet/sheets.dart | 28 +- forui/lib/widgets/sheet.dart | 2 +- .../sheet/sheets/constrained-Layout.btt.png | Bin 0 -> 26835 bytes .../sheet/sheets/constrained-Layout.ltr.png | Bin 0 -> 27094 bytes .../sheet/sheets/constrained-Layout.rtl.png | Bin 0 -> 27111 bytes .../sheet/sheets/constrained-Layout.ttb.png | Bin 0 -> 26726 bytes .../sheet/sheets/default-Layout.btt.png | Bin 0 -> 24798 bytes .../sheet/sheets/default-Layout.ltr.png | Bin 0 -> 24541 bytes .../sheet/sheets/default-Layout.rtl.png | Bin 0 -> 24536 bytes .../sheet/sheets/default-Layout.ttb.png | Bin 0 -> 24592 bytes .../sheet/sheets/scrollable-Layout.btt.png | Bin 0 -> 56422 bytes .../sheet/sheets/scrollable-Layout.ltr.png | Bin 0 -> 37881 bytes .../sheet/sheets/scrollable-Layout.rtl.png | Bin 0 -> 37881 bytes .../sheet/sheets/scrollable-Layout.ttb.png | Bin 0 -> 56422 bytes .../src/widgets/sheet/sheets_golden_test.dart | 139 +++++++++ forui/test/src/widgets/sheet/sheets_test.dart | 264 ++++++++++++++++++ 16 files changed, 423 insertions(+), 10 deletions(-) create mode 100644 forui/test/golden/sheet/sheets/constrained-Layout.btt.png create mode 100644 forui/test/golden/sheet/sheets/constrained-Layout.ltr.png create mode 100644 forui/test/golden/sheet/sheets/constrained-Layout.rtl.png create mode 100644 forui/test/golden/sheet/sheets/constrained-Layout.ttb.png create mode 100644 forui/test/golden/sheet/sheets/default-Layout.btt.png create mode 100644 forui/test/golden/sheet/sheets/default-Layout.ltr.png create mode 100644 forui/test/golden/sheet/sheets/default-Layout.rtl.png create mode 100644 forui/test/golden/sheet/sheets/default-Layout.ttb.png create mode 100644 forui/test/golden/sheet/sheets/scrollable-Layout.btt.png create mode 100644 forui/test/golden/sheet/sheets/scrollable-Layout.ltr.png create mode 100644 forui/test/golden/sheet/sheets/scrollable-Layout.rtl.png create mode 100644 forui/test/golden/sheet/sheets/scrollable-Layout.ttb.png create mode 100644 forui/test/src/widgets/sheet/sheets_golden_test.dart create mode 100644 forui/test/src/widgets/sheet/sheets_test.dart diff --git a/forui/lib/src/widgets/sheet/sheets.dart b/forui/lib/src/widgets/sheet/sheets.dart index 9fd6e4608..887ec1e4c 100644 --- a/forui/lib/src/widgets/sheet/sheets.dart +++ b/forui/lib/src/widgets/sheet/sheets.dart @@ -6,7 +6,7 @@ import 'package:forui/forui.dart'; import 'package:forui/src/widgets/sheet/sheet.dart'; import 'package:meta/meta.dart'; -/// Shows a sheet that appears above the current widget. +/// Shows a sheet that appears above the current widget. It should have a [FSheets] or [FScaffold] ancestor. /// /// A closely related widget is a modal sheet which prevents the user from interacting with the rest of the app. /// @@ -43,7 +43,7 @@ FSheetController showFSheet({ bool keepAliveOffstage = false, Key? key, }) { - final state = context.findAncestorStateOfType<_FSheetsState>(); + final state = context.findAncestorStateOfType(); if (state == null) { throw FlutterError.fromParts([ ErrorSummary( @@ -86,6 +86,8 @@ FSheetController showFSheet({ style: style, side: side, mainAxisMaxRatio: mainAxisMaxRatio, + constraints: constraints, + draggable: draggable, anchorPoint: anchorPoint, useSafeArea: useSafeArea, builder: builder, @@ -174,17 +176,19 @@ class FSheets extends StatefulWidget { const FSheets({required this.child, super.key}); @override - State createState() => _FSheetsState(); + State createState() => FSheetsState(); } -class _FSheetsState extends State with TickerProviderStateMixin { - final Map _sheets = {}; +@visibleForTesting +@internal +class FSheetsState extends State with TickerProviderStateMixin { + final Map sheets = {}; @override Widget build(BuildContext context) => Stack( children: [ widget.child, - for (final (controller, sheet) in _sheets.values) + for (final (controller, sheet) in sheets.values) if (controller.shown || controller.keepAliveOffstage || controller._controller.status.isAnimating) sheet, ], ); @@ -194,7 +198,7 @@ class _FSheetsState extends State with TickerProviderStateMixin { return; } - if (_sheets.containsKey(controller.key)) { + if (sheets.containsKey(controller.key)) { throw FlutterError.fromParts([ ErrorSummary('showFSheet(...) called with a key that already exists.'), ErrorDescription( @@ -207,12 +211,18 @@ class _FSheetsState extends State with TickerProviderStateMixin { ]); } - setState(() => _sheets[controller.key] = (controller, sheet)); + setState(() => sheets[controller.key] = (controller, sheet)); } void _remove(Key key) { if (mounted) { - setState(() => _sheets.remove(key)); + setState(() => sheets.remove(key)); } } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(DiagnosticsProperty>('sheets', sheets)); + } } diff --git a/forui/lib/widgets/sheet.dart b/forui/lib/widgets/sheet.dart index 1500e7758..2fe60f50d 100644 --- a/forui/lib/widgets/sheet.dart +++ b/forui/lib/widgets/sheet.dart @@ -7,5 +7,5 @@ library forui.widgets.sheet; export '../src/widgets/sheet/modal_sheet.dart'; -export '../src/widgets/sheet/sheets.dart'; +export '../src/widgets/sheet/sheets.dart' hide FSheetsState; export '../src/widgets/sheet/sheet.dart' show FSheetStyle; diff --git a/forui/test/golden/sheet/sheets/constrained-Layout.btt.png b/forui/test/golden/sheet/sheets/constrained-Layout.btt.png new file mode 100644 index 0000000000000000000000000000000000000000..a7fe2c551718e06099656c98858810aa0f61c34e GIT binary patch literal 26835 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 literal 0 HcmV?d00001 diff --git a/forui/test/golden/sheet/sheets/constrained-Layout.ltr.png b/forui/test/golden/sheet/sheets/constrained-Layout.ltr.png new file mode 100644 index 0000000000000000000000000000000000000000..535853022e42e91b9eb7c37a9c14191df203dfbd GIT binary patch literal 27094 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 O>$9iKjSEgV-~B&d24H;v literal 0 HcmV?d00001 diff --git a/forui/test/golden/sheet/sheets/constrained-Layout.rtl.png b/forui/test/golden/sheet/sheets/constrained-Layout.rtl.png new file mode 100644 index 0000000000000000000000000000000000000000..42926476eddb688cad95221db931326ecd0eca4b GIT binary patch literal 27111 zcmeHwXH-*J+jcC7V?#!1B1L#c96*W)B1lkCu_8(d(gg)EltCZ?5{f!%q(uiQ(xReB z50Ty(B}A!%(yKHBLVyrT0)%|~B=G2;@5i^k^}cI8&&v6eeR9s(<=)rbuDwt4*x1N$ z`<6XhU@+MBb7xOog~5KYhrt9lZ{7sHDQaEZ2tL+%T{S!j%Wm8|22M75ojhl{864Qn zH*heREbQE=6Q;fi6I~~^!}jg0sv26x*dG2zXy5ZI#_Mb}G-SXdyo0jRy>6`xBObE< z_sOYE%4^>Te+(8_EAN!ZSu4WiHi)j3kKd?TzgEU=vsf#_p03-vR+i;gz9tI3SommJ z!vbH4__k#g3w)EycNVKq;QLU1Xt4?fe#FHOL|37}525*)#VQo|2^T*PU4;TaJ?FC) zt5Dz*3;(IaLQZGt{X{LITF9$*@rjLUY0s{_uHZzP)&A?mIoN#~6D|1q?BlLa*_M$x z(KoKmj2^3+XX7^hkQit_FVyCk|k$AuSWIWgXh_wIpll1tNuj$lrzF5{o z0h8mSWla`4`AW1VieSEN`LS-oH@R!DkmY-#HBrEt$4G*_ld7iS-qL=&-a6RVn3)x} z3?*rr==;+$+0Q~V+R0m0J3gCBs9OiqjByB;p%T z$Bwzy9KJ+JnpLi+DmWHfM~vJ#YFlo(`5jcbuN;>jv+wEG59{tOCG}25=#5uB_d?0|h9Q?48tTZ7M<2xdPi6|qWK+mwmM_Ce(AK%>XO zcx$=~E6ZaM??F8!gf zci-!=RCy~BSMVe{R5r%^#EaXqIO}a^PY$0m!-e?QzD&wHyK{Zo@oj3w7oGn4RDZ*1 ziXoU2d42z<;h1x6H=3x7V}3p3h3&TEiRB#o9+p#ok+4FKCGsuc_ibZNGRDN|Mn%Kl`bSm z<6>+sv>j7zV_qTpl$X~9ztZ${#hP$r*vXeFUy2n^yfhXYs?j`S*7}Xu6&G*ys=QqO zOEJ`1haNBb5XsKSP-@F`QSm?^5ELdo{ECT5;+S>R>y&Q|3wb5}3`~jBB`j z&~v3p+!*)8y>h<`W%*YWqvZNZW?DN)$?}9IXFW^uCn`f7H8DC9m2>{h)lA#+0&JZj z^qgYk>T_9E?R$EAdxeFc)}21A6+%S4!NO(2!;|G>FkYn@8M+2IvOib+Vf%d2d>#cTueSU%a0exvW*1{BlaMo!uHZ?Kn9ZGjRcyL@J5lXCsZ49{l zw(<24vI9QDPV;csM^L3}-9kljvPKB`Y6=6~1yh?|6@5y1dGc~mLBakR7B+>k?IsHg zzkU05ZMT$^)LPScp48sEO4y5R@p;~OvO4E_y#D=g$!?8AXwO>kT?MW^NR@qabxdlV z`MxiHqY{4?uZQ^b<0Hac(_;E0JA3j#)cFxwT-^7I)P4Rv_i`+hPlNeh?N82Xe_mTC zN6R1(p~Ow0Sh!ta*@!bF)T*S*yiuJf2*b?y*|E2YwzkG^$eeWNP0w%igL|RY1jZ!n zM+%EoOYus)W>t9C1%&Ol8(GKYsj z#q>D^d`Y?Fxx%8-W}9GDUk63Gmg>gf`>m?D=Ne68jN*8Yir=!!?##OregS&tTFIs{ z=*@T|yef7eGphz+#i-sDI+U6m5fQ4gSa%DFyr2`5W_sRVN-ygCn**YuBl>*^StO69 zJfwka6R`@FyqjxtA7gYr!%#q4?A!Pk*+G07wDdviKRE9b_K zRKu4p;)Lb*)CRd14Ir=K1-5y*pMV_d@f4?q61l;wuiq2C2vLcVx|skp38W54U3s$#DK{zL*J8XU%ucuWnzM_C!tFot;8LHJi#S62R`qYHn zAwzx3yjG^7oI^FPd@wV&F@zi{gFhF!f6jj;M9FD8vkW%j$5Wzhd*lEH?O(9J3hIyM zqZ*GoQ`##~1}&|vbK_hXDO=835a*ne{PqWOmimQ0Ccq|&S07d6J}P_Asvxty>rIU9 zyAPD-+MW&xsIIi~HUeg{@Kdf^T5__yrKRO7Q^oBc=>>1HvJPsw_Y~DNMYghFsKW1= zTsAQn9j7@Sf-Ah2f%eDHXaQgj3PuVm11cz}05&dG?fS{jBqKO$m`UXLr%)^}UApv{ zWS(Uy;zjM-)z4We^JR_1B&VgNE%&@W7daT~7!eV98GaN#`!elm6E(7tUhp=_U-4Ug zu`WP`R`fv(37ZXsK_33}sAj2ep(0kt=k{LAMBc}dJGwsEcj0zuG&YYX<>|NF?UwYMcq*6M49)PL+cWlhV~1%dg5toU1e` z7T5>64Z9!REe!Nr7dbQhsk|+4g+aJ^=)$S$OGkQprT~BjKPdzWKa!eX@uibvP@~5R z`vVR4qI)QdQU<3_9b?pM&`J1!V=H5X?7ji3eUp=nb=&syRC1Fhq=-2h`!B=uAatxu z`OdZW2IWUVb5Su9RflH!WMz#HZMD-@Dk&*h%;!KN7PFa+`DIsy%lt%87#K))|I*YX zV-DfwMhlkN^+J`0dgBv{EORu%F5ptnow~|dR?kRG&~J^pQ$4+KlOVGh5FZ*``K?z) z@Zr7RE<{(iq#4dz5&$lbF~70{Z1*8$XMMK5N9(YLo5;>^uag(!4*#yBt2@M^+TjSx z!wQg<444cW&+5m0xy)JC!m~z`@imVXl3J)FMcUNQj}o1uJC$ z62DMafDaJYaH{_}i+ywT_dxczT})wn<~2zIvswW&p#f}h(O?L1)Cl&D1)OCE__0eq@f-L(yNM z7mdE!I)vviaUZFS4X8$%fQA0@zMH!&%7Lux~Oc;95u%m zyZ4r8&;Iklzuf(Mi~i%%sS2g}UUWa)uF!kzbF3DvV}|45*L^}zO8l}uJ1DuN#NRk! zisoe$t45-9MIlxUtnYjxTLo-a(>D7&Wx8sDq?3&gxH3Y0ft9RSruEwj3(8>sAT%Ac z$dQH5JjK^w`n>F|eFsjf2dykyl%i-ViBu9Lun00wgB^}<$ww;vkiOt!$wdl%Z~Vs#=EKEJI#q;b$#_1|Hm`|6?E|6bEo-&coUKW(Ww@=-#t6wiugZ zOB1;pbn1GF(UfMxAm7rZhFEp^l*@!ZB%3T|_uY$=ot<68Xw=1Ih6AhbUdb*H*K+MZ zHKD784XZy0HI3&7_6IBog@7(OtwO(CiI~t!%@UNCb80-M(5TO;D-GBWtZdV}g+2^r zgHVrHVc%kSAdNHoK#VnbYQXz+q;18 zUE(%q=FH8RVY8>PAfBDrVUlw3@$V)n)n*7AiOQwksX;nL1`ix)&HD#i3m4-~hl-Lr zoe8_peSU_+3|1f^gGBOt8*EZvV_f|uGpzL#14Tc%pVIYHPt!ShV!wcP#Rn(TIZQ5(Y*2+OC50aK+@E4N%- z!^Vl6+m(1i-N+{2!G>tnDXBwjCPiQ3i6habREq%tXU(0I!cV17Y%{~L-25?MD3W;=0pwhf^1Z#$!q#O!3^IlekO zbSH9bn|i&P^q$w}y@`vn!7wt)=ev}?fEH0}Ey{9R%zeB|p@vr2FKW1#uAtWzqs(fm zck;Ia8nn15te1UJ6FBW6YEtorJInGBO#2k-2C%({yKm=)5m)NJ?0_@B#vXRLs%%$L zRyJSS&qk+cl)FK8^34T;l1I?=eVMT22%UEhjsM2T$7hffJIuZ{U=FM>^f9(CzxQ}K z*D&crk@#x|TIM?3-ECvAnRjQi(X@Vf++t@_;2wbR5Mb3pv}LO7_g4X7!DKZCm4I#` z;*NOO*2gaxd8uW+T_tc) z)fE@)uzZlYFc?mK`a5aJAqKx3`xejf%b>Rcx2pgN2h}z3NTv@-TUnAh3-3c$XuNIj zIw80{0yZ8=SiV8bw{mAuL2jh$oq(BQ+a{p<1RxtliPJ=GYG83go-rTThSS{K<@o;W z%9V%kcGaSjcXbpy`xG>Mu6q2X*^dMwNKrCWzHy6@Qpx$F2H9OpK0d&UbrofE~Y_TwHvV!6-i% zGoE-9nvj0##txCSfR8IKSt*bnl*_%u;Y=>;9aJfses#;mWvty(I$*Xr7S0YjgB)L! z9v`X+58ZWnc_O%>G*_i~c+eIJ0u2`AA-e;Fq1KuEP&$ud-m+vL}tm!?b-7k zlLeHR4fIA%Syq>45f6EG-i(>=r~p2T44H*s;5$PqIZJ(rtPot$P=xN#6NCK}8+5PK zg=po++a$A(#UpeFCXha{${b0Fe9~5o>l7v=PXL; zHAG;of?P6)ejvvf`o}B~IP(3>4&aZ+nGW z0CNE%UM1jw(D6$x?RZ?ft(8QvwR`;1y3RBZbfo95!hQVDU2vP`0WelI?fRquGuNIX zb@x(Qe0PrrIYfl5)8|Q%60_qhR=OV9UHiTdGbMEy&bop9ra^ctW^2(l&Pqv1@g00j z?$&E0usaDgl`G>?-E0Xo)C1sbn})z6;e?f0XRF?~AbBcd4qov5dRNeO!52iG)9iLg z>7Zkiu}VxRF@W|EvNP(y-V6^x-3HUIC++*SA~hpJ@*fGo&vyl-cZQ1T3x9cgxqqO& z4cy@o$SCj~ekxNv+MFyn!rJoSWIcg%7E2FxcJtCN+_w=W_HSOm;Qd>Db{aI>gAXOM z@$&d(<4QZOBll^yk!(7~u=A|_J&0u3)8^iidWAmyf#Eig75xF4Tw0& zJ!fv{{R$U@rE33-m5GGb3(+f2FRMoMV>eqEw*mkm7@oj2eky(@~G!jSu?Zv%E{kFL!URkcd`l;wF*1~H8R1% zc5eWm#wP%s#qtDcSW0eAXEcEvO%R5zV|Xm`aRE<(%)ir0F%0LYO-tu@fGaQlVirKD z?c_co(z$k^mJ?PmXsHN@iK44vv7i{oj^uusnwsFn|FtjXQ;+zW+Pj; zo=l{skQ+#dq!_0v>AQP)GxgTd|;bAkU5ljA9$a1s058><+Y? zR*9+e=BnnVRi1QxYx|U0U{70tI>?g_B|0DYL1u<^Amf)HiRC!+_S=}g0QaP3^=vidq(*2@4%|p`GB$f{^j|@dyS2ax7=+JebQQ)J2f?1pEq)uzHE7}Q%<#) zH`F=>=X^sP2dR)b(N?mzmz+sSw*bN*`TKZ1JMZC6Ww69GYg>s>uM~L^>x+9M4727A zZJj&C)~8N^`GJUPZ!{XBg~ui*Bg~FRm4Rk>zYCDjc80`s`Wjs~@`~i?ZED8a!b1XU zo{NO{tt~CpvFgdS-8MEh^cu;G-iSY7J}4Am*)k(QOh04kICQH}8tS$9dY*4II1cz; zc|-RK5nGZ)SV~GO>AHbcikI0vK&!t>bGgK-MFqqF!&Cs751`N8?|>a3-nu0&3ZD<$Kf}d|TQ>xd!?nk3+56`K)flVff=> z2a-5Ia_@~V+!uxeu@A}95#!p^0oaoK{QN6sW+G;0#i{AFr&SP9^x;wL-3RdX&Hot7 z`1s^s!$Su3cnwchr+}!yC;&_#K}SS1LLUyK*tuKxPl6Q>A0MA92!tfK!_;hhxYAwj zdap9m~wY;Q*W1+-nmyIXO8BKn57kH&@$CCM}D5;-?JYgrM=uQC~rz z3JcESDOrx0nVCn8p{8cV8LoY=V7|qG%e><;uW#HFewi;5J_h(0;A4P~0X_!!7~o@o zkAeR!3{-KPsXNZYHraL9DiruH zxAI?{UxfnyElw`U&6Nh!T*Yquk=^mX=0Sij6P_G``GDX90>;+{zBa)4rho?mzBa7N;r{~=>v!H#yOFr+FPPlEq?|tvx`@MVn`?@>%Cnsm0v-aML&1in_dT{b*{%BSHQ?jB=C>deY8&dT!SSn}v18pnkK1mKw{ZjiA!u*E)oa=pB2g|TScj_18Cpmuc_R|SRD`O@LUKAG>qrrfXPild5wchd% z)UhkSmjAH)>&#}G70bsv*JdprqW<{F{6CJ*{-Cye9I$hR^z!ksKTtm}A8$JwuyXnM z(N2+g)IT{mm&vwDU_Ar+hd;eOpB;fhHKwOq3yDm8==J5#GR%R<)z#H9xXTot%6419;>sop zZb?>iv@82YP1GlWKo?h;nwc5CQGfByg3^*Tw4d;N7rak!Od{uY2d9bVzvRj77$Q2w z;hA(s<6np9+LNWtHulLAhh0h9XyTZpbLX2b!BDG}t134e+>ScqU^)h#A5o}FTB?}L z(BNSIV56ABZQj(AfnrT19+O8#Q?dBQvwO zSuz(J7=BX~`3eGmXrCt0Q5@dsI3#XIU)-OTmbQ-WGdrO`Tl`AJ^S%VOc=rz0xiWs- zxTr!8=buf-Qj6(%N8JXiO1(I?jfuy7#y&&CX^iz+`3v|yCNb3?Qe*dRV9!csG*0h; zqR;IfF(x@E=&&<4?EJo>oziNa2R_u){G8c)r!s5<2@BoKd$9=_!U_ngiuSM35usf! zC7Rq0`vi1G6PUtNt;wdl>|f7ERk0|vo^3J(S@8i(h_(&m?u$mPrpYv9|8s#u~2$YSSO*(bK_PkaW_AdVl`FOt=YD!hQR* zdMod9zHV&1z7j$!0YsM9)4C|7^yNu&E(*!fM=0(5XxN2(ZOf$n` z6@Oec9RXd7XUv2F`LDRVcS)y0fOam}b>zHcgW{D&2PpOzr>HU8+cd4dQ;D4D9J?bGP-cejx(el6ys97C*F@+gsz+Hq56a> z__)P-_LqB4=B04EiV03*w51iVIqBEt+IY40dXdF4?VQC6V1FwBvkBTbJG4UAhpQ&* zGe43N{CiYTkoE+x0L{RNi~lU6CqeaAkW!~Do}+T*v|N1GEBc;`vr7#Mg4T3TO02y8 zd{YFAuTn*&!c#O#fcMZ6*A92&8dkIu+W6x~gi3+`(5Z^Y_yqT5S39P<(-YwJGr)<_!9j|j4 z9Q*oMaVaUOQ{5D>|0v)w^j(%pUApIwjK67is(qcB8nnfQcQGuRJKkmJL=4wtjcxTcC4+{BQ?ORmh=<5`Es!3Z_blE3m%lz9NHa-(7<@0r}gY*L%$d$B|I?4Q6Q2!>WM_OGl>Clp9n%q8_tgB5>A!~5&Df#MWQi;=IlPlzv^{)Wk>w|Z- zP)1cAG@q01Kw(;)+y-kOMqWf871N!bDja-nqT$0GGpCXGinhn_8GNOR%LsC2yW4~HeMH8GxsgJzhbr0twReC zeKwY^fwy9x2Yvkb@u}{@7g-(8DX}47h}Ar{gza$SbrUnaD=S<=G4 zBu%acT^!@=fOn)Fk~#}qm7=YQj*EiXhUzQEdxM&imyQ+_w0)yzGq6*>rj0hOOxi*c5)p(-z9@Ta>;+L26xLh6R0t;#ZR33;yB)0nRRrmKYwPqr{=VF zs7sX1?94>Bwm0xFTHVw4JZD-k%=gL(p}?ci!Tdcu8z8>|sLAf_eRdPjOY|h6?@y~+ zS+`%ld`XC3=yW3A@+D0-8QQ&j)I6GpGpJIfr0)KbW-nt1GzATMDUi$P1yUY?t@c_JC&1s-rdd%_r{K_b1c6i<@|Ms3yWD$*# zMKlg_t3RqOm+R`8cM0GTuXGUJ zEVPp;g1l7w`7_b`tZh4Th6?=kxb1eyI2tpi?(a11w98=aYNoM&+T8s#RZ8i0G4yca z^z)Z57e4VyuUA@)u?X!b+K#o)B z%y83=dNix{lQ;0d*s$T<+xs~QllfNmw|Daw5;k!L>$(J9fN`>IDkl41M3!}`2`$ah z1PO7n+zgfc+$-AOI5s!4x;=WU?q<7m%Nqs|fPaw*1*^NH*wWH6V>yJOd2cJ5$sjWU zQ3MlMt(wpI#G5rydtWa=L)*O%2@`gB)M_v!L+d~o*!S9;U}9k*r`6+WSK--P=GQ#r zbS6-N=rBFnLZ-LdMd(V;c6;FB+C0be+WPxL)E|N}2C#PsX~{cWfZ`bQ8w&l7FU`&DD{ipthvcqw>K9{MRSFYO**Q$@+~`Tc*jFjCfO~ zb=TeO*H==iRVhIT6AFW%9c{qp@Y?+M`rZN@3&^nl-3}l6i?g$aH*VZ01;IlXB?Cv( zi}xDrkku!hi1q!J2>Gp*5F-=XthWI3@|pHYjmWJ>AH1kN{^l-QHM8&lh@{?nP82Pv z6avG}f2!wqdV0+3s*Zpsv9irDLQ!F_6uE z)HJWAsFz32lGU1sSD>E&(+|tE*2mb54aWFy#o+u*;~J

z*GO%W~1AyU_UgvPZw= zDD-d!V_Z*1DC#_r^iW6b4M|)sNgVR$ z!C<1lr?_?IJ4?8hX74(8?i>-laknDk;*dOzQPooot!faKe*Rk8LdLZ1DU;XnytBAC zw3J8IKwrHj{BiiK*1Nk6`SV(qp^jhlnBb8{LuR{qS6 zy%qedXvsaYHd@=s$%)z5$K)-}HMjTnE+ji~xjms29EfK5R2qpMh;@au(`T0G%bOyN zO_T}7k18uG`xA`8AW@2~9}gKdCk2ATzAtq{>Li7PI6vI5S~>q34i`~bS&7H9?XF?5 z;bbyd!>GBvy1lW01+Jf(x_U%ONlA8D znO=TD0fUTDXN-=HCR+7om_B2Zy}SI8g@Q<$=$@0K=y@eU~=g4s#HE`q+1A;Gpla$$$ASYy4gE`CnJ~ zWfB9_1|YQn02vWP|4}I*(wx5)R)`D=3M}Byzb+Mk>50r=Wd0&OhY|RcGGOwgB+OE`{uX=zJ5Q0jm3S1|rb-manMBl%7*O(O|Hw}Ew=NgLsi zkp#!9>k8HCl(W#>w3n@d$;OrZgVj{|)%_D@R+M_^RIygt0w08#TYt{dhSw z?ZAV|>+1t6Wy4n8g?GlJgXc3<5TqjC&yeL(n#sH& z!&_EXG1&zL5~obw99D(|jU&Z9>CcKYnNw4|)=bPPlPWIv=GfTnkRVc(uUY}>3u=eimhiNKSan3ED2ofnN z_INzL=m;k2#%CIB@(J{w4a&&?-h|KE1;!l2WHwh9?+z~X_t!t2e4Xr;Q4DZ3G-MPI zD?598!!k1J%!Z)SkUkfrw4k-zQ|Do2rA!FHB8uHt!5^OW$*6CU!eDYe1&hP2^|q^5 z&sI6Z-ISMogT58CV(R*bhdr|=X1v+C2?{}!o+Q%J{By21C3B>y3153NSJ*|j1RSBe zn>Qa~FV2Njv)Gv)WyLZe+ofv>iWsCeDt->hDJ2aY29QrpRcBbkHDAMuNCGo3E;ja* zb(^@jiDVn4S^`Ja24xQw71Z6qteM+pjQ8&?y6hkxo)SY659ra+ThcNz(IGPe0e1Z= zzL~w{>U+oaxwEseQ@wJnUfv~u$B#b5Hd6J z+8RzZ7N0|sN5>=I@7xtRVoNP3XdcyJIe5&rXevc0Ys6jjpMo>4>B1tn)p2puYg=7i zTns2}PK0>Er^#8DaWv7}yJu7f0SmT~rRrlwMSl7Dvmg2$O47w97N05QOn-{(=JjXZ)43v<(fYqFx6>$=||!|2|=JkrwfwVqU4`~duj z=N|H1hUg#iUg0q(0k?p{#L(tvdGjnpgjXhDW_o%gn%!X^v15Bbs5gA* zO5-0^)LTp)ht;-EIr~TWoyZIxCxKR&C#b;*R2B6FrFmYElx-(rZ7Toh`E7v0=CKnx z6`}eKl%N*@;Y~lN7-HrPCFppmyoDCf<_2P*4%LB5q)nivfYnCg4!m#XO*iZJ%w2%) zow|aokV9RvVM3|KTTpMODh`j~yfNI{F|q;t;$8XyBp;U{aUHUltTd!gwUx-#WF(*~ z|F{Whz9npy5;i0JQvOjKX;u+7|0--gCY;%3q(1C={cKz-P&x`ZDR7;Xhllu^I!(PmjfR!P=J<-{Zfe#pWa|onK@s zElJRL)ik=g|D3CH1dNov1>lDvXQ+$;Fbdw=ThZQrNL)NSH&+4BmvhAZ1qhl(N9^%6 zkX-2VkBK>lA0;{X{6Grzfri<*7a>-$JvEpJAF%sFkj55yskr7mCNZPkEV&Lk;^E%_utcM@P;2Y|O1Bse-WQD8` zAH`sUvR}x0XK`HLFdWw1^Tiovg7B)G7MrA^Cmb3?`nOy9xH(J?*lB zJ`YH;xvtP16v^3GW7lPM5;=>YdC(OF)t*!(o$2tOV5w$!VENE9!(u=YFcA1**+Fc(sqkLc)Nt3Wv~2vZ`y z+-V%W2HjWcgTStdCy~UJl~W4p$0sN0t*tkm4iYMAqGj;DW5tkSrK`d)mCMTk+3xOJ zwUpL|ovv)}>I%bBZV@zlZF-k$0rE``#UAUW2&K< zWU{J@l7iYhJA=Es$9D%Owai6XH`g-9#??fToFXA+%;5fNb`gh8Yy%Rq>X1VKW?5F&;U(c>~Jh^#?m4I*n0Spz^o zLJE;Fr;#hhA7w&3Q-7$ORp(UIu3h{4 z>N{13n@1dMWTjQ4VKA8Np@UY(V6b(*Fqov2)LP)m^Nxkpz@JrN$83Ivl~UA3fgh{G zem-F-1+S~BG+}8U?kF4@CFn|NMETtwv z_bPE7hTH4=_YbSJyTsSy-^Q;I=jFGQiLj8$r74rsqxOfU_La>OTfZc-FBE}*KnnYqK zeuA_`3%|Wcyd0cXLwrKTj;;CBNxdb$`2}*WV5mvvXK^ve zlY)XYVlMpWL?foouwwn{N?9i9WL2U1je|;Cb&cMfVHhe+tlKY8``#{+t(j(U=E~{~ z?Y?^}-fXcr@_TUGbDbUAom=jVY*aj>l&5;i#7;`muTnZ8V)WO*CyA@755`ZHef+qY zFl%kg|1@~ZaFoU7#Uinh-Ap!JZwW#96_KrLE5aFDSFB-IE?l7E5Hb*FU=Rr)5%p!?scLZ zy}#dAcKu?d16FXt$k_M<3Wd`3d|q}}*TWq}D}FjOG^90wu(0q%AaLo#;K0CVcoh6; zG<&G^g`+4KoK|=)97xrP&o}Do64Ee8lPEuz05JIb+quid#=SsU=k6EV3cG|SFbH@YIz9J5jPA6gFo>f;@uVW$EEqBjhmBE`yI!p0E+5VhJ#{IJD z(7_uqqXo*$$JxPIA2ei?cNZhjf;}gR1OmY!*TPgc3>@7Tk!edfu2M6P%AR~ zt7S<^3Fo6fGPg`H-DES+Nt$fdBNw+9I?_i*MykfSpo;$f{gH{D`4}R9mKEsh`_LiB z%xKoz!^5M*wY=WU+?+|`-Te?j_fpQ8{yjlb&c%_6>Y#J!W|zk2KDq@31$8iDBYUHV zbMU9${pOAjJZ)rT6ac1SY@Fq%EM1S>5l za#u$X4FZ+9#XkSU;9!!$lY%eR- zleI;)b%c&*&N_vcX?8i00Ijl&S-dt22?^m7j}W3!EjVQT-DB>7vEm`GA`l#1yU9Xo z2M+M4yBXC|2<~vW#SI?1J2Hz*;(2FIsTK}IKg!- zr1W$k7M%S*4JwM>KN!Z(&erWL4q_~_%|Zvp;>@P{UnX#7+R2$;F#(hZB@s*-{kn|u zjtKr;T`KLdz2h21fz1heSVu3v`H)W>o|;{(8d4wH#RX5U`z}PS-U>ck!sPPY1zop_ z@K-T_kPtbv(q=(o@#uvb8+ieNLcw#UUJK8#yc4Q+Q6$)S7@)O%q@>12#RQqU0@OGDZYS!@IaG zgln7`H5ltbp8M;~cLqa4+bzRJ|0>Y;d-K)|*L$&9S3i8j$7Yz4lkZk}rW_d6Ok)<- zf2hSRViJpt^FDt3xZy~BR#sLNyVY2Z&%hU%-H=uFMmbtrTU$)M=%cx#dTS%XC%QOE z0U+FGlars$D=ZMlEZV7*GX^>`=yTnR@5QQOpo7b+D#xOg}}liSd;LEWsw9Xf@aDwt-}wwGClZdu>;rnv2f+$7fDwAO$H`nFnsHzxji$5`5o{o0@dJ%=aM4XTb(<1ZkP9B_jh|wy*pFdv%psJQs_di5B4B3BM>S>+ovOsVaQ$H#D(Yp^runKqj|`|N$3 zT;r&z{_lXHaz{1a)lHF*++a9o0allsv816lwY0Qu>iY+$PjnL++Z`QE#sk&~$!V&> zO@mE+%ETDXO}9#c{ss+;%q(R1$osQxdDcWO79C8uihqr{dZ8`vmE(dJdIH}R^(yJs zb{nN)XBU@!|D}pRfP6idx=W@Lk@X5VVzqW-hA?}iEuVLk)lI^ndt#VDp|558QusVB zoZXYIZm!WT*zHBx4JZqFl5hafs8Sj$IXU@99aMDc&QudtJzJUv7&iXeCGnUxEqEjc zcIw46laBM5Vbb+9qCbC%ViCE14au9!Pra)EnA&-ggX{BvA^e_Q&?ATf)K?CnKBv7iP{y#CnGeyg4*YF&B1f4)ZDy zXiNTKEIE?JSeqkK%+RIRW|!?#zY9IEIGusY59uSVp`U5Z>d*{Ws8G@+b=|{bLmRiq znt|BF4}4a<24dv1J;y8}`Q2@7nt-oYiuZP#cS*<@l_@AFIO;;Hpk+V(v$@%yR(yZw z=XpNQ=fgubc+-y#qTO}zxch+d|Ak)a)_5*u%qWgr7S#r|ckTF_~ zzQys*6$!nRFU|Mh3&a3wVR>K&Yw%f7>8|9Z(ZimR#ekiGrH@~g+5Mwywn0GfLNtK8 zo-4C0KXkP#;CSk}@;Yz=%fP_E^ifmtd@HgcBQ`v8muuOcOA}okXNT0^F^Fg?P3w`*B7(B`WIzYd$zr%zkV^(U-hN~~Rf5X-U}qfPXTbQ3~K@b`RTO&{B5 zyRZVz_tqN4P9?w_*;FLlxYtnIEOK&V!di^+B^IN%pG`V)?ATo2MUU$9Pq}tri&f;7 zn72K0wBX(*tDhAV@_$K7M^DxmTh4#J9fJq}jYZUyPeU#OOLN!L)5}oU9&B=Q7~#$B zH75B^l-9+nwHH!N#)x&1tn|>qNo`kLDPwa9;E!x#Z`SP3b|hG2rH_c-&unE>d1`hXv*X1|&S7EjEDJI?8244RZaz zejeVSDl^ejV^AAzT1e}n#t9-rxxL6zZcXI)M}^*6&J+B;ldqgYc@qTn*<3l~;+`1p zq*K5iB_WSi8iHZ!H~21BSwa8eXRgQs zJrAJfI{LRiZneRPHlfKDPV-qRV8s#IfYKM{#_R@Oe#x8AzoNG9Mn=Zg0HrCbcUkdgy-n zg-?sF_(1Da4a75VZmLRz({UF88u&GqDQvurzybZ7ZuYTMSKMi-D6!Vlb2wMmqgt)q z0GxUzHHU#28mO`$-;|$8l3WK|`gIy`r5m!0Py?^!gyzqlJ@W&+rK3(xia<}>0Es?J zFSUr_jBN(E5IB;rK>!vqO~73AFoYQnC1S_hWEk-{GqnPd-p9ks%7E$^}$Zva(`~T2>Jk+#P3T&n*{kDXS zD1Yc%x%lr_?1uPFWQ#>bG!Kc~08#$e6$c;=uGl5<{fZs%(BlE9AaDQ>Am#udK+_6T z4oDOL5Fk+iK!8L6009yO00c-BKoB5N06>650RRCK1#mt@BnkiskSG8kK%xME z0E&XJouZxzlakmkZ&h|Po==#cEn9un#OdYcGBvOSnEn+knLFpa?|IL?bLK{! zv@+-WQu0d(g7_?snVf>4FWexAcjwL>;7Cc=(suB(#qX5)_fSr=^aR-1?)SZg-A=G! zcm5a&L3<$!6C=Bz2UC5o_+A?dZZ|Tt8s0x9Cvp3YW*Dnom*3cayRe}*Q-ACM0{oe~ z^)sCGHrvqPv+YiQ?EC`l+HCLLgepe%R z!QkQ;0&IUX|HFia;~W>b5FGwtRos9Atmkl=vjGJ-`-79>4Jg241vtyyfC8N5{`Kex z9usc>1cIju;2D%nEWjg+|249xs?U*GKe+p2aq=7b@J?W>16%$$&27)8_yQm1;t00M z2A^O+z<_{YHo$CvC1V2vFdH@v0c!)S4KN%2p=|h-aawk>762wXOmvv&|4^dCsR_aUV;wg*8_t1e0P7Q~9?Vzt8MEZ)&J^)2`}NfM|`g#4oplJ5Ro~j84{5 zXi`2EHS#2&WBU=K?yY-=*VASHJQ0=xiGom%efKb$*#W)LIuYa~X_X+9>JWJ2QeSFG)(u zV0EcvzMX(zHA2v>5glW2>4)F^#Pc;|D8=mcYpIJ;;E$ebAwIO2wKu6Q|7niejpD5n zam4OB>eG9V940Wc;*2jXEe)EfU>2>+wur2E?IA`GR9Y6CwT#!7ir^K9%}5Roj(>Mw z^{ji0H0wzad%8Gr`l5RObw0Eyc+fOdT{C61H;8(oMt`FeK`3wCWL5M$EbC)t_Hu?3 z5oa7hdfU+8UKPH@_x&#`Y2KuqS+Y056obJu-anG@Dn$0D_idVE59ZvL=8?r!6Rd}U z1AV1^VR2kzeH9O&^$;(~F^H|Lt*X9TRrunF%1q1~ew~6>?4uWh6mcswWX8kFOhV^Aw9Q zU{Co?j*t+xO8tut9gMMu+*-xw zCe5tIQ~$_8axprEOby*7rW|AOD?Rp!WqftCiZZ3h(bUv*o<>6O8!UeiSNA$89k$$h z@X(>2Clv`H#K3`2M6w_J*9luI9TZPdpNO9w5(o>550m4X zOETke&Ns4%Tq(>_C$+*`wYRD%*smh8?!3I43Np>@h;k6 zFp7j+ds8y?!jeia%c#DmCZ=&A2^Gsaemq(CkO;mh5n+&1MlTJTe3~JpL9|ZMSHmqY z_%6>HCzg}wWc1uvzF(k`2yRnR3bHB< zr{(2+UXCc>V+r!|qDn#EEinzgyZdd(Qw#R-d#Y;J1q`0Hso9xS57$IfAOC6tau)WF9d`~uoJkJyO`oAxD_fevbVQa^J-P& zp^l7<_|8;xNMXNs@belMxfbT#nW<7UW)Nm(XJ=PE+LTCTjUgk=8=kz-V#we|xZ#Kd zIWvn;dBCTVb$16L3H!0$w?-tsE<;~K6<}@PVhCNSYH1ohR(EV)G}Tf|HwElZh?mAl$z;d z=QEz2g|$M+bG}VJ%os&P%F-{e->SA+NN`h3DR> z04;p3iFzRc4=%rs^8Nkm8#N>GNTGa>rkjP{B>KBK-T78@u@utOgoFB$6$a(Y+OeiY zq@Ye{D<5Jxb8zXy&>IwE>NExaNM2rlHp;p>`}C1rwaB2Mnv$7HwsRAX>%9UWAdcZj zpA{6Sdo%^_y)GbE*{7wUp`qqGETeYieda-xwPVtOy|=^-R z)BtV5ix=Nr=aX_!t-RP{$=5tkit+CCt&>@(1+H;_eJ!Q#hW`AcBs${qU{%T5sss`v0g#0c%P@|j<@wU)6_b#SJ95Y7cecrkbf#}OO$3^6Q?2?D6oZW-;z{oN0={M_H( z{nm5<$RXIm-&q5VZ>_xp)J6YrLuehJG2WK17ZZ?rvX{LVDIH4^bpN@%wDH_ zj}wgv8ajZFdv=NHo>mPc7fkq8ZQ-p3T}?A1AWxlYZ&X+f>+1UX>yCYKx@0A9f=gM^ zr)zRlAEHbV*H(R-wUAK*D?UEQ6Z{<`2&A%wca-5C&lJT5mcG}@5?>i+1uumV#TcwV zH^kV@N#`W}NADve4OV?^=4S?ogXGSqw$WG81twe1GW8oV1EI`sCpQp2B~gA=5DK3@ ztfCV4g)mNb8!xW3Kghl-B|0FT35>uoF-`COv+Qi8bgQIxC7OWrVtp!|8#JqujR0t> z_!lNR6b>IgoLX8MOzD2BvR0Vs8H{X6)ZIj!TF4-Me(#nYmI7`Z4K(l^p9BA=s#s8n>ojbg^fTjJCg*@Sn_1z9(_S zqdG={*(F7z6r&&b)=oTKIC_a}r=oo`a9Ja4qJwLguP5AuU$>ncKys`H*&6ABOb!YF>YZvw1iM2$X2d%6!I}B*<@0oEdW@ zE@7}MwD_7(W}lq*yX^BC?CIY@dT7h!%6n`1dT!C!W-jNVdem>U@oI*gvXCR5T-$%iSHL)?|gWl`8sQ*L#EVtemQAU-QyV-`&NZ0-;bSZGJ8HZ z7$H!bdv;A6NLMDp)xkm3Gnw_Xht5n+>BojV9u$&Iexi21{e4n@nNMG7$@|*`kr;r( z1KNS~-ouRO$noBnwy(Mi&Ua9s#G7o?pw%4U=p>3<=q)zDvKq3@l9xYVRlYA)GZlF} z85_vSr=8Iih0|nk2DM%xSFN$(~_%MS1f0km0Py$ z_$r1^QvG1MHBsTN(&;^xca@@k-X%uA%*XX=0@A_-Y=4vK&Ph05zW1 zcR3=35d+w_R%3TS?gkV$Ej`^M!;iQ;VxxBU^)vKW^tJ z&V}9*+Hh)g?UaB2Gy5z_5hS0SzAlcDA4WNU&~7)cjQ>d`r`)~4O#SRvG>#sj`-ip2eX>LIJ3axHiVWS9>+ z5tZmuss=x8$BQGbOKfgk3Z*RY+;qCE5&=8N#gE5V3Tt|FsxsK2z+|v2HAM1xpW^3i@)atP5 zZA?CCO;w+gvsfk9<#G=jezye}a3%fD`}4^C4GB$S^%oRr%g*G5X0*~AV@`iD8p;9c6xPvMxDh!*zo>C0Wz30WbybE2=obuey6`%*!qY$rb zkQ*mevoV*E2mwPa*|Gsn%75Q8Im!_ks!{6SV*n5*$}5Mxoc~+^%FXzg1Y$YVx-sT9 zOdS4fWXJ6?Wcbek&Bi!?B+OX*lOuH^Tp0?9X01ONw1zAz%l~x#eu2FK3~a z^-cAQPagyR3WnD3VF-e4vVj5^5L`pRfPeu3K`OG80tv&=nc=QbljliaBAm0}hncl%XM+gBpF(i@O~SEGYh zquYQ2yc*r7321mh?@vpS(>t~WoS|vyaf?6!SQdo@{@PNd9v)U3pTclXlm9QLefI4Z jypYu&D^&d}={LXi;54pX36o~T2|^a8Rwg;$yIuVs2Q5jX literal 0 HcmV?d00001 diff --git a/forui/test/golden/sheet/sheets/default-Layout.rtl.png b/forui/test/golden/sheet/sheets/default-Layout.rtl.png new file mode 100644 index 0000000000000000000000000000000000000000..a1ff39695041eaa3810824f1936915943fbd7452 GIT binary patch literal 24536 zcmeHPX;@QNw>}P3P!T9%D2ON&98dyR1(iuFgA@c2F$fYUDKZlyG6e`!TR=vORX`b9 zv@(Q2WRwsPWzaIo7{&w>WuC$mAVBU8B%j{<^#1w2=l*DW@+bS8egV#uv@dN2UmH9x8hiugH0~Y-2b(>=F}x%Q zJ^_N?he6O@$WZspCEvucz8{2Mofg$QBk}0OInI5dgN&?71oO*;jDEyaC%Nh5pfI?0 z?GqfMbyXnyp-+bLX|KwGFZh$NHBwY z;er$b2E&^4fJ9&$fvJOs1(;D`N5g{x>>}aFfd>URpn~H}9u(m4`_H3HI4j`+1cH+_ zIJ4kk0nRMoMF~DFz?sEgJhSL;$dOqKgSJl>C%>Mc3j)o?Z~nB>X83814nDn(`e0Zl z>wDBMToLxGVH(ms5K1hkeMqsUC+5%>}8~V6mo<*nAJRLT1VYf`0v|ltCmC zmFD*W7zIDb_8iQyCZJ#3@H1=L2t6a>IV&v8AHQU%y0nQrE-fu>W(n^;u~$E;bYHag z(vW^bZgzH*N8gSNbv68K6mIb&&22hi1GJZ@5O{4!?8kLv>di0DAgkW)7YW~nEK4_J zTIg0Kp7dlaFxa&gs6eHTT-%gx+T^Hu4Cvn%j90wOWNn3>Ig0Y0UhHh9S2yW#R#zCq zX(@~6Mk8f3ltXrCDN+3fldfqT!_@k&%u&G2ox0ZWu)SX^MtjLJ(T6Ia z>NSG(el@)Kj79A!Yv)8mP=Ol{l)-Xe9UlobGdDL^p@M!E+H)tuUyJBuRkAy>{WS

ZvXP5@O9okvJ-y1g(Hv5FR})zNK4#3r{DsXT+6#7-oeFW0 zVb&fmPR@5Zrs!uk10=+2vEScf{nbF9_F`q{amv-c4_<%N z)nOKS1F58S$l;D7kJk*^GP<8)_7DM%Ad zoZTj=BvVx0qnON?pk?_A zSqSnLR`AkbP$Yn?gSD&%8*Pf0%Wiy}PE8ho>`=H@LYwR>ZwbuRp#9w)3a~Vf&0Q(N3SG%yf|n?(%^Oh(OTjzVL z7RsGX(6PA8%*-LmWXUZiAefTL@(f|Z*~^|zz{rEJozL>=b++2_hYlUGXVgS7Uu{Fy zU}Cg(i7OhrU0;n?Ev^NYN@_SRiy!*!#7zBf!e~}T4%4_J|J}_jF zpEuC%86eyXYbYPPeq{LdPAGWb=6E5cI=h(K(O+n8s&zc4bmWhPF-NxkXh-%V_oi_H z%L;a1mZZwBLANP;f&xqugH{E&CXEf~f4M=`wd1U{%}j$jEizflAJI$6r47=P{T21& zlx?KS*7)~&|D8PV@lrgak0iTi+pcBDu|f)(R7H>->w4koN6wR7?q}oX+U1M!BGAj^ ztpCA?(@B$85nA|Jr>XAxgrkfn_e`SCifC!(luc*Gt77!C&}4jQ^5FZ>pyKw0Lvr*g z@hvq;KG6pyQ;s@%oEe+_PQ7pT-mTHwTSTH0jyk#>4+#%jm`&4>IeN_)DH+79j-#)# zWjh__H$iqyioEAy2Vz@VTH;k1m6DpiQ|{|j6lx-0kj-Wghb={EoK+EeJZ4Eh7fr_0 z$7|60d}u4@9GxgR?%Th*;qrJeg|Kw@R$g~^NW}(MYFXOWJ;UlQZNhn+Rkk|5;>_(Y zs$c%FX(X!Q;c+E3_wGxxfSXS93GRCZ1qB@N3^m~rb@ZYhkG>I%5QiFpEZ-?_fR-`X z)1{C@3#bg!xp?ALtU@R;w z^k~45@a>EgwnOGr6{UiJTV}>IRf(I{NBu0%Ia%tX6F_2RTjt3rmoJPm@8<>_2RzXE zA&>;<@5v%ym8&X6ILvF>j=8b?rVf7_;G6+_y3>W^wdXQSB_hd7BgD0VKC$e9HsD=` zTGLE>ufGQ>buQHaQFH2LWedjk~Ai=^xjtUIOwa*aBit#&>Mbq`QJRD~z(4#wZ$x;B6d#-RE`;g|srS$^?9h_!uBt1T06UbaiQNG@=v` z^^g3yu)GEmZ13o-IG>rF=p*%ae|UQ@;>J@E*Vb#b+K~>lK-Q5FKzgG88pvM>iHym^ zOoo*Q>Y%V?nIlL&jn*yS8W}ydAr;M)Cu9N|Q8Z0%J3Pu7XD6gifJyG-8ARvG+)y)@ zvrMAv89*XSy6X4TrRUgSt;DwD=q zhC1^w_=c92z!5S!f1qL3s$sbQHmQAEYO*g~B+t3^sZ;CI^AVl@tA|$m?gI8`)ZAFt z(Z&-Dql`H?Z|1IjR=7x?&pEmG6l4BLhjrYp_IcErzyEVnA=FiS|HZ z+>f29=WMe9BJz9^9*ZZFCX+9ybdcFOVs=S{rC|Y#4rj4KAGq>+9gB0hLE^OK0SO#u zMWhPwt#`sok;BT;Tm~CZJXw%eG35Om6Mgcjo!ipvumCN*T@oN42SOu6BnvpTIht8%^-X>>7bWl^F+db)|8jZ-Dle-P<_s$JSniD=DU*e*32v(Bx6 z>~R1Q&P6kXODJ2d=XPV#v=U84iO- z12p8j=peQWI&HL{ukW{3g)R~_Hu`<>Wj)vKoZ)4OFJXyfGD4ukkxk`vDz82 z>qs~Vez2b49VBlZ1+Vjg{l|e?Pm6m^^m^4bDWQ~+BUivr3KX=zO)q}by(bBUM(>eU z_lSJ>@ZoslN;f5>x--wm)yBtavHX3aSSQnuwI+`>p5;xp#0+dD(^u+f~jWA_WsJ- z48Wwt<00QvUw?OIOLdvwOsYTYwR9QU+*}-l#ZkkpY1pG7ORo^xvK7l8OUBD<*M@xe zn{5=pf9F7Ap(~|2Rso6iIReBWOQLcDH?1LmY~Q!veoKE~?GgR<-hMsci||R@*_Gfh zKm%!2+U&8`EJrt!P+5XyeUiq0;KABH`1cgLN`r9Lz&K^q?k4bialN?(1;?({$L~Sd z1~jV;`fc9_ovxGP!R5enWZ-Z_o>TLylEs0P8eFYR&k%cQeq36;@7Sqb%FC_*>=f^a z+V1gU8iDz8Q>*<%Z!I^Rmhu8`l_knpSa2j>ho-cCV3mNt3Xs6^m}7DEcrizAX^wsM zwr3`h_^3b;f=ETNAnz%)m*v*yICY)!nJE1@cwZ?FF$Zc}NVnCgzVZW2DYCg0t27Xu zh!++XnxRk#ZUzG~7r;J;qcx}B96%zG^JY5FkGpnM#VQ!tSBFdFxphrD^_60ys!v=7Y#i1v9`2urI~ zuBBfZSB;ib)+*5#hPe9XGcTCzKOpDkvlY18zu<}iJbMWGn=S^ys)bd%<_Y)yvlc;N z+{3v4H*rtyc~}TRvM$_x0Y1IM54&|B&cD%95||)hg7`NH0w#t3I9gr}wb596K~eGp zRx7lxT5L@f5M=ymbBvc?e|jkiKD{m-o$k6_s*J4e=ezXeN<_G;=V3&@ExM8^tiI zfGAT$K)?`?W{52yGhqlsg3Lphr$BOd1!z6rJrCzTobS8mo~oDZ6qTx7Yp;L(YyY*2 zu&V|-{CkeueJz;@eKTkEUSTg{*!gLt;u z`**+GY9fxoC*Q*2-wc+KQtVq(d-3d(Tm45g`<0s+mQ?fn<3V@h1W&h44Zqtu{G((f zCMRY3tSrozElA)ng4Jb{3$QN2>0*-#a2AEl#U>SC&jnl2O)C7GxkcFi!?U7I=E5!) zcDb8WfL$)^ayO{}yWD@)?r_u^@>UKmUw?AzayxMlr7BBu#HFwvk%fIch`18Y4 zXUog!=@N=#1_yuuGY5e1uLvs_qMal-H6qBmz;m>Ppw7DcJS!`_ zJ=>fzJ1EVFQnHCb^}f;e^Yfb@X+9pUHr4q&Cnpl@QgoS&5>u*8*NrX4$$tB781at7 zPZJd!HmUz4l{VSjvp4^!7FC&*p6RecEB16bm+_1BL3gS{iB2wFFYUi4 z7J=jT|G?sRi(KFCoHSVXNXKDNvu1Tc>`0l7nc1Q3JNM$#qQ@kyN#0TBNStC;cDDV8 zBo%&*x#_ByYD=eNq1H@}qd-#1lK*gWZqGVr7q>^pxKB`=zp0I4U2JP>J6O-VS9E{H zYWq>la(}4eGVLBex)vQUH!iBlrsUsh&%#n28&i&Y41b8aS#@vnwa0eoELKCpzkp9f z?pu#WbxGrAdNKs0dnLhl^A=z2%1ai%`!Wdv#`a@`47!b~pvMSc*+m^BNQFCHWZUD&A^)zC4Z;p(c6(iWHf- zxw+}Zf3Fz8>N%W$XJz*Jix*wqxlf-SySMkSc-rNtaKk|C)j~8~qln^vNcM(k?1^6C zE01KuL~JZxyAi{~!$+t@v^b_(P~N%ev2y<}Pp%mmy}IJBxD>!Fn=?ql)Q| zFfbxypXw=YJYBfb9+x0Vl!6AtnP+uj++5CoZH5y5a~vL@h-SN_4P@i-JbWp5_IgaX zL!Hg-77d{jdXfEAhPOQT3Jd1@&M=fm(_;rhHP^1iB7ZH(T;h(&f)Mu+OyO7Ss|zv& zYfMc=_4|kZ?BeYr09QJD@u7YIYJHU-GgUfV(~)Z>=EZ3@4^)yRO<08qv58P*4^WWw z5!TXtKvdCEpT80-0dx?d@K;Z>va;-&9^3N`4Gs=s8r56H*6!sDH8n}^;`BYgh73Cs zFjELviihqR;&aUT*&p>16iO>uX!1gw@^}t$(!GIK!dJ>b6ZcaH^@GZAlBhf*eWa_v zsnC@wYnFH8Fc5|w!uJlhLY5i{7(){fo?aDi-n?0!OXZYJ&Lt?i4m>b6$n`OFaB#Tc z)m}W_@WylWfUvNz+Icn5(+jR`0M|`^V+J3Z*XS$t(moc&8fvJ3+iY3>bdvWnYjHBs ztudL$qJq_%B>MeN?jckOoTp6^Zc*i$v9U2)!*k?5;q36;$-I@-aiR{re4Q^vOkuijPj6#^{ zg)nr}wYn8h7Q7!cA3t3F;FA{)xT4_ewm8u>Q`(p;8Y+SHy@4Hdkaz9Ku^@R*qSPBh z1lTCjjHy;NU{h2Nid1B)f$m!i?i^jut6)=jsG$Oq5(Q3;-6+6_nVFct^NtM(Ab{B` zB8)zNrmH*)5{ahQySUG2uZOj?v=9`>*`gYEmc5xTUc3kk6GF%Qc3el>ZzXhKc_0)b zF6H-ct|Tm+HhxAE4&jxoXk~pTEp6ZV@+Qw5M8auyu2pgEWHH?aZ3YHL=)~GFjrk`6 zlb#iKxAWHGmKshG3=_|hwI`r>yU=rdLm;*HX)J#%VNJPU#&e4m#@N~shiaB80`feIU4y0kn&oIDA`!ddYjJ7DczTX?N!IdvG%Sbbo-0 z-9%^Iz`NtDnzk1l39Dk1{-mZ|HGZV&$)z-==6qAt9>*Skp8opyUy1XqwP8(qwb12A zag|rLW~Qd5^Xt$xoc%W}aIVQCS!>2PQd5(?Ovz;AQ-&y=`5bYwzhrsquvzYP;o(%y z!g9-_a&e##sM&IL?7VZ!IvI;Av3>35QAOXkFyCrOW!IytRorKRWMwgq~h_K zRZlDRu&*cZF&2AHLPQrMQ}6OhbfyUhBZ59P-*2(i7Yveal-tni=>ldp=XUxgwAg z>}s58AoD)Hk9aAxm*p_Ynj)dEZ787I?4BRMrGf-fLpgbXe6@KP<3ZNw4Fl6^Ds$4GaPE4HDf1viGX zDV|!GzuqufB{^k!29KS{*Q}0{v3hzbbf25u-*J~u$-Xv{AV1KDEhxvaYF#pMe=F*H zrk^;bts^KXx$exgR<-vye13VEpyo66x^bL}#;?qA_NTIFPCeC|XitXYAlMP!6C-Ic zvIPCq03R$_jhSR3H{MHf*kO^Gg1uEa;iSo;KF`i}ZBeaYFQ6HT^s=v~$V=rG1&;a= zU1*(iC>jB~4}y}hF&Qj$r-*y#Ro)(|kLRI>w~K<1z$~*FoxpULUzp71@*z+BGg2$h26hHdN25VV1Q!5sAeHd^Vf3u1$-$A5bMMK^#GnJj; zsK(5Dvo@R0Q-HoRz#u5N%o?Ox7o)6ics48T83H^E0~x&-zYg4#&yWzGDusL8o;+IqF#o0B)fTZ4I zaOsJi^76+J`^sRRX3|nWzYP)OCcn8MN`3rUAJI#=#e&o@B>QKEL13*q8L3tM?l)v~ zWk?LYUmapU$V;@*>ktqJ4eMA`MW}Ve1S9~+3F{@Reggu%WgJQ@Ck&GI`_R>8fTpE7 zs@r?0u1#0jvDf_MZ+E^tq1p4om{KzN8d+T*zoY}S{rabXjEoGBjq8;;YjfVdsnm@r z%v?IKvrCRnzMAs+5L(;dnO)pPDbNAWN~ECG0Nf4sa}xV0Y?KI4RFfXCaBSjn!(&fIK$`uE~j?a&n;N4tE v5HKbiIKVvFzyT)2CJrzmU_v1Nx6$y`AqxJkh;cf1F_5mdfmYrRw!!}mFQ>dP literal 0 HcmV?d00001 diff --git a/forui/test/golden/sheet/sheets/scrollable-Layout.btt.png b/forui/test/golden/sheet/sheets/scrollable-Layout.btt.png new file mode 100644 index 0000000000000000000000000000000000000000..6c4fe6265e46a7b7ba2f647ececa33895efc578d GIT binary patch literal 56422 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 bCglo`K7VUeJ<&$4%TC?BI;r0u`{{oHWPGz! literal 0 HcmV?d00001 diff --git a/forui/test/golden/sheet/sheets/scrollable-Layout.ltr.png b/forui/test/golden/sheet/sheets/scrollable-Layout.ltr.png new file mode 100644 index 0000000000000000000000000000000000000000..3be3228b3ce5792c40d241102f95f3ab85ca7155 GIT binary patch literal 37881 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 L^J3nGn-BjlYI|CI literal 0 HcmV?d00001 diff --git a/forui/test/golden/sheet/sheets/scrollable-Layout.rtl.png b/forui/test/golden/sheet/sheets/scrollable-Layout.rtl.png new file mode 100644 index 0000000000000000000000000000000000000000..3be3228b3ce5792c40d241102f95f3ab85ca7155 GIT binary patch literal 37881 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 L^J3nGn-BjlYI|CI literal 0 HcmV?d00001 diff --git a/forui/test/golden/sheet/sheets/scrollable-Layout.ttb.png b/forui/test/golden/sheet/sheets/scrollable-Layout.ttb.png new file mode 100644 index 0000000000000000000000000000000000000000..6c4fe6265e46a7b7ba2f647ececa33895efc578d GIT binary patch literal 56422 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 bCglo`K7VUeJ<&$4%TC?BI;r0u`{{oHWPGz! literal 0 HcmV?d00001 diff --git a/forui/test/src/widgets/sheet/sheets_golden_test.dart b/forui/test/src/widgets/sheet/sheets_golden_test.dart new file mode 100644 index 000000000..a418e79d2 --- /dev/null +++ b/forui/test/src/widgets/sheet/sheets_golden_test.dart @@ -0,0 +1,139 @@ +@Tags(['golden']) +library; + +import 'package:flutter/material.dart'; + +import 'package:flutter_test/flutter_test.dart'; + +import 'package:forui/forui.dart'; +import '../../test_scaffold.dart'; + +void main() { + FSheetController? controller; + + group('showFSheet', () { + for (final side in Layout.values) { + testWidgets('default - $side', (tester) async { + await tester.pumpWidget( + TestScaffold.app( + child: FSheets( + child: Builder( + builder: (context) => Center( + child: FButton.icon( + child: FIcon(FAssets.icons.chevronRight), + onPress: () { + controller = showFSheet( + context: context, + side: side, + builder: (context) => Container( + height: double.infinity, + width: double.infinity, + decoration: BoxDecoration( + border: Border.all(color: context.theme.colorScheme.primary), + color: context.theme.colorScheme.background, + ), + child: const Center(child: Text('Sheet')), + ), + ); + }, + ), + ), + ), + ), + ), + ); + + await tester.tap(find.byType(FButton)); + await tester.pumpAndSettle(); + + await expectLater(find.byType(TestScaffold), matchesGoldenFile('sheet/sheets/default-$side.png')); + }); + + testWidgets('constrained - $side', (tester) async { + await tester.pumpWidget( + TestScaffold.app( + child: FSheets( + child: Builder( + builder: (context) => Center( + child: FButton.icon( + child: FIcon(FAssets.icons.chevronRight), + onPress: () { + controller = showFSheet( + context: context, + side: side, + constraints: const BoxConstraints(maxHeight: 200, maxWidth: 200), + builder: (context) => Container( + height: double.infinity, + width: double.infinity, + decoration: BoxDecoration( + border: Border.all(color: context.theme.colorScheme.primary), + color: context.theme.colorScheme.background, + ), + child: const Center(child: Text('Sheet')), + ), + ); + }, + ), + ), + ), + ), + ), + ); + + await tester.tap(find.byType(FButton)); + await tester.pumpAndSettle(); + + await expectLater(find.byType(TestScaffold), matchesGoldenFile('sheet/sheets/constrained-$side.png')); + }); + + testWidgets('scrollable - $side', (tester) async { + await tester.pumpWidget( + TestScaffold.app( + child: FSheets( + child: Builder( + builder: (context) => Center( + child: FButton.icon( + child: FIcon(FAssets.icons.chevronRight), + onPress: () { + controller = showFSheet( + context: context, + side: side, + mainAxisMaxRatio: null, + builder: (context) => Container( + height: double.infinity, + width: double.infinity, + decoration: BoxDecoration( + border: Border.all(color: context.theme.colorScheme.primary), + color: context.theme.colorScheme.background, + ), + child: ListView.builder( + scrollDirection: side.vertical ? Axis.vertical : Axis.horizontal, + itemBuilder: (context, index) => Padding( + padding: const EdgeInsets.all(8.0), + child: Text('Tile $index'), + ), + itemCount: 20, + ), + ), + ); + }, + ), + ), + ), + ), + ), + ); + + await tester.tap(find.byType(FButton)); + await tester.pumpAndSettle(); + + await expectLater(find.byType(TestScaffold), matchesGoldenFile('sheet/sheets/scrollable-$side.png')); + }); + } + }); + + tearDown(() { + controller?.dispose(); + controller = null; + }); +} diff --git a/forui/test/src/widgets/sheet/sheets_test.dart b/forui/test/src/widgets/sheet/sheets_test.dart new file mode 100644 index 000000000..8766fb7c5 --- /dev/null +++ b/forui/test/src/widgets/sheet/sheets_test.dart @@ -0,0 +1,264 @@ +import 'package:flutter/material.dart'; + +import 'package:flutter_test/flutter_test.dart'; + +import 'package:forui/forui.dart'; +import 'package:forui/src/widgets/sheet/sheets.dart'; +import '../../test_scaffold.dart'; + +void main() { + FSheetController? controller; + + group('showFSheet', () { + testWidgets('shows sheet', (tester) async { + await tester.pumpWidget( + TestScaffold.app( + child: FSheets( + child: Builder( + builder: (context) => FButton.icon( + child: FIcon(FAssets.icons.chevronRight), + onPress: () { + controller = showFSheet( + context: context, + side: Layout.btt, + builder: (context) => Container( + height: double.infinity, + width: double.infinity, + color: context.theme.colorScheme.background, + child: const Center(child: Text('sheet')), + ), + ); + }, + ), + ), + ), + ), + ); + + await tester.tap(find.byType(FButton)); + await tester.pumpAndSettle(const Duration(seconds: 1)); + expect(find.text('sheet'), findsOne); + + await tester.drag(find.text('sheet'), const Offset(0, 200)); + await tester.pumpAndSettle(const Duration(seconds: 1)); + expect(find.text('sheet'), findsNothing); + }); + + testWidgets('shows sheet when keepAliveOffstage is true', (tester) async { + await tester.pumpWidget( + TestScaffold.app( + child: FSheets( + child: Builder( + builder: (context) => FButton.icon( + child: FIcon(FAssets.icons.chevronRight), + onPress: () { + controller = showFSheet( + context: context, + side: Layout.btt, + keepAliveOffstage: true, + builder: (context) => Container( + height: double.infinity, + width: double.infinity, + color: context.theme.colorScheme.background, + child: const Center(child: Text('sheet')), + ), + ); + }, + ), + ), + ), + ), + ); + + await tester.tap(find.byType(FButton)); + await tester.pumpAndSettle(const Duration(seconds: 1)); + expect(find.text('sheet'), findsOne); + + await tester.drag(find.text('sheet'), const Offset(0, 200)); + await tester.pumpAndSettle(const Duration(seconds: 1)); + expect(find.text('sheet'), findsOne); + }); + + testWidgets('no FSheets ancestor', (tester) async { + await tester.pumpWidget( + TestScaffold.app( + child: Builder( + builder: (context) => FButton.icon( + child: FIcon(FAssets.icons.chevronRight), + onPress: () { + controller = showFSheet( + context: context, + side: Layout.btt, + builder: (context) => Container( + height: double.infinity, + width: double.infinity, + color: context.theme.colorScheme.background, + child: const Center(child: Text('sheet')), + ), + ); + }, + ), + ), + ), + ); + + await tester.tap(find.byType(FButton)); + await tester.pumpAndSettle(const Duration(seconds: 1)); + + expect(tester.takeException(), isA()); + }); + + testWidgets('duplicate key', (tester) async { + await tester.pumpWidget( + TestScaffold.app( + child: FSheets( + child: Builder( + builder: (context) => FButton.icon( + child: FIcon(FAssets.icons.chevronRight), + onPress: () { + controller = showFSheet( + key: const Key('test'), + context: context, + side: Layout.btt, + builder: (context) => Container( + height: double.infinity, + width: double.infinity, + color: context.theme.colorScheme.background, + child: const Center(child: Text('sheet')), + ), + ); + }, + ), + ), + ), + ), + ); + + await tester.tap(find.byType(FButton)); + await tester.pumpAndSettle(const Duration(seconds: 1)); + + await tester.tap(find.byType(FButton)); + await tester.pumpAndSettle(const Duration(seconds: 1)); + + expect(tester.takeException(), isA()); + }); + + testWidgets('dispose removes sheet', (tester) async { + late FSheetController controller; + const key = Key('test'); + + await tester.pumpWidget( + TestScaffold.app( + child: FSheets( + key: key, + child: Builder( + builder: (context) => FButton.icon( + child: FIcon(FAssets.icons.chevronRight), + onPress: () { + controller = showFSheet( + context: context, + side: Layout.btt, + builder: (context) => Container( + height: double.infinity, + width: double.infinity, + color: context.theme.colorScheme.background, + child: const Center(child: Text('sheet')), + ), + ); + }, + ), + ), + ), + ), + ); + + await tester.tap(find.byType(FButton)); + await tester.pumpAndSettle(const Duration(seconds: 1)); + expect(tester.state(find.byKey(key)).sheets.isEmpty, false); + + controller.dispose(); + expect(tester.state(find.byKey(key)).sheets.isEmpty, true); + }); + + for (final (side, offset) in [ + (Layout.btt, const Offset(0, 300)), + (Layout.ttb, const Offset(0, -300)), + (Layout.ltr, const Offset(-300, 0)), + (Layout.rtl, const Offset(300, 0)), + ]) { + testWidgets('drag to dismiss - $side', (tester) async { + await tester.pumpWidget( + TestScaffold.app( + child: FSheets( + child: Builder( + builder: (context) => FButton.icon( + child: FIcon(FAssets.icons.chevronRight), + onPress: () { + controller = showFSheet( + context: context, + side: side, + builder: (context) => Container( + height: double.infinity, + width: double.infinity, + color: context.theme.colorScheme.background, + child: const Center(child: Text('sheet')), + ), + ); + }, + ), + ), + ), + ), + ); + + await tester.tap(find.byType(FButton)); + await tester.pumpAndSettle(const Duration(seconds: 1)); + expect(find.text('sheet'), findsOne); + + await tester.drag(find.text('sheet'), offset); + await tester.pumpAndSettle(const Duration(seconds: 1)); + expect(find.text('sheet'), findsNothing); + }); + + testWidgets('drag to dismiss on non-draggable - $side', (tester) async { + await tester.pumpWidget( + TestScaffold.app( + child: FSheets( + child: Builder( + builder: (context) => FButton.icon( + child: FIcon(FAssets.icons.chevronRight), + onPress: () { + controller = showFSheet( + context: context, + side: side, + draggable: false, + builder: (context) => Container( + height: double.infinity, + width: double.infinity, + color: context.theme.colorScheme.background, + child: const Center(child: Text('sheet')), + ), + ); + }, + ), + ), + ), + ), + ); + + await tester.tap(find.byType(FButton)); + await tester.pumpAndSettle(const Duration(seconds: 1)); + expect(find.text('sheet'), findsOne); + + await tester.drag(find.text('sheet'), offset); + await tester.pumpAndSettle(const Duration(seconds: 1)); + expect(find.text('sheet'), findsOne); + }); + } + + tearDown(() { + controller?.dispose(); + controller = null; + }); + }); +} From a4a87f047761d0c885e4565470f2278a5a775149 Mon Sep 17 00:00:00 2001 From: Matthias Ngeo Date: Thu, 5 Dec 2024 13:09:32 +0800 Subject: [PATCH 17/29] Uh oh --- docs/pages/docs/overlay/_meta.ts | 8 + docs/pages/docs/overlay/sheet.mdx | 212 ++++++++++++++++++ forui/CHANGELOG.md | 10 + forui/example/lib/sandbox.dart | 73 +++++- forui/lib/src/widgets/scaffold.dart | 20 +- forui/lib/src/widgets/sheet/sheet.dart | 2 +- forui/lib/src/widgets/sheet/sheets.dart | 29 ++- .../test/golden/scaffold/zinc-dark-sheets.png | Bin 0 -> 63213 bytes .../golden/scaffold/zinc-light-sheets.png | Bin 0 -> 66121 bytes .../src/widgets/scaffold_golden_test.dart | 55 +++++ .../src/widgets/sheet/sheets_golden_test.dart | 6 +- forui/test/src/widgets/sheet/sheets_test.dart | 14 +- samples/lib/main.dart | 2 + samples/lib/widgets/modal_sheet.dart | 2 +- samples/lib/widgets/sheets.dart | 173 ++++++++++++++ 15 files changed, 572 insertions(+), 34 deletions(-) create mode 100644 docs/pages/docs/overlay/_meta.ts create mode 100644 docs/pages/docs/overlay/sheet.mdx create mode 100644 forui/test/golden/scaffold/zinc-dark-sheets.png create mode 100644 forui/test/golden/scaffold/zinc-light-sheets.png create mode 100644 samples/lib/widgets/sheets.dart diff --git a/docs/pages/docs/overlay/_meta.ts b/docs/pages/docs/overlay/_meta.ts new file mode 100644 index 000000000..be3db23bf --- /dev/null +++ b/docs/pages/docs/overlay/_meta.ts @@ -0,0 +1,8 @@ +export default { + dialog: 'Dialog', + popover: 'Popover', + 'popover-menu': 'Popover Menu', + 'sheet': 'Sheet', + 'modal-sheet': 'Modal Sheet', + tooltip: 'Tooltip', +}; diff --git a/docs/pages/docs/overlay/sheet.mdx b/docs/pages/docs/overlay/sheet.mdx new file mode 100644 index 000000000..b310ec2c6 --- /dev/null +++ b/docs/pages/docs/overlay/sheet.mdx @@ -0,0 +1,212 @@ +import { Callout, Tabs } from 'nextra/components'; +import { Widget } from "../../../components/widget.tsx"; +import LinkBadge from "../../../components/link-badge/link-badge.tsx"; +import LinkBadgeGroup from "../../../components/link-badge/link-badge-group.tsx"; + +# Sheet + +A sheet that are displayed above another widget. It is part of [FScaffold](/docs/layout/scaffold), which should be +preferred in most cases. + + + + + + + All calls to `showFSheet(...)` should be made inside widgets that have either `FScaffold` or `Sheets` as their + + + + + + + + ```dart + class Sheets extends StatefulWidget { + @override + State createState() => _State(); + } + + class _State extends State { + final Map _controllers = {}; + + @override + Widget build(BuildContext context) { + VoidCallback onPress(Layout side) => () { + var controller = _controllers[side]; + if (controller == null) { + controller = _controllers[side] ??= showFSheet( + context: context, + side: Layout.ltr, + builder: (context) => Form(side: side), + ); + } else { + controller.toggle(); + } + }; + + return FScaffold( // This can be replaced with FSheets + content: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + FButton( + label: const Text('Left'), + onPress: onPress(Layout.ltr), + ), + const SizedBox(height: 5), + FButton( + label: const Text('Top'), + onPress: onPress(Layout.ttb), + ), + const SizedBox(height: 5), + FButton( + label: const Text('Right'), + onPress: onPress(Layout.rtl), + ), + const SizedBox(height: 5), + FButton( + label: const Text('Bottom'), + onPress: onPress(Layout.btt), + ), + ], + ), + ); + } + } + + class Form extends StatelessWidget { + final Layout side; + + const Form({required this.side, super.key}); + + @override + Widget build(BuildContext context) => Container( + height: double.infinity, + width: double.infinity, + decoration: BoxDecoration( + color: context.theme.colorScheme.background, + border: side.vertical + ? Border.symmetric(horizontal: BorderSide(color: context.theme.colorScheme.border)) + : Border.symmetric(vertical: BorderSide(color: context.theme.colorScheme.border)), + ), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 8.0), + child: Center( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Account', + style: context.theme.typography.xl2.copyWith( + fontWeight: FontWeight.w600, + color: context.theme.colorScheme.foreground, + height: 1.5, + ), + ), + Text( + 'Make changes to your account here. Click save when you are done.', + style: context.theme.typography.sm.copyWith( + color: context.theme.colorScheme.mutedForeground, + ), + ), + const SizedBox(height: 8), + SizedBox( + width: 450, + child: Column( + children: [ + const FTextField( + label: Text('Name'), + hint: 'John Renalo', + ), + const SizedBox(height: 10), + const FTextField( + label: Text('Email'), + hint: 'john@doe.com', + ), + const SizedBox(height: 16), + FButton( + label: const Text('Save'), + onPress: () => Navigator.of(context).pop(), + ), + ], + ), + ), + ], + ), + ), + ), + ); + + @override + void dispose() { + for (final controller in _controllers.values) { + controller.dispose(); + } + super.dispose(); + } + } + ``` + + + +## Usage + +### `showFSheet(...)` + +```dart +showFSheet( + context: context, + side: Layout.ltr, + useRootNavigator: true, + useSafeArea: false, + keepAliveOffstage: true, + mainAxisMaxRatio: null, + constraints: const BoxConstraints(maxWidth: 450, maxHeight: 450), + draggable: true, + builder: (context) => const Placeholder(), +); +``` + +## Examples + +### With `DraggableScrollableSheet` + + + + + + + ```dart + FScaffold( // This can be replaced with FSheets + content: FButton( + label: const Text('Click me'), + onPress: () => showFSheet( + context: context, + side: Layout.btt, + mainAxisMaxRatio: null, + builder: (context) => DraggableScrollableSheet( + expand: false, + builder: (context, controller) => ScrollConfiguration( + // This is required to enable dragging on desktop. + // See https://github.com/flutter/flutter/issues/101903 for more information. + behavior: ScrollConfiguration.of(context).copyWith(dragDevices: { + PointerDeviceKind.touch, + PointerDeviceKind.mouse, + PointerDeviceKind.trackpad, + }), + child: FTileGroup.builder( + count: 25, + controller: controller, + tileBuilder: (context, index) => FTile(title: Text('Tile $index')), + ), + ), + ), + ), + ), + ); + ``` + + + diff --git a/forui/CHANGELOG.md b/forui/CHANGELOG.md index 6505e7c0c..fe9a3f42a 100644 --- a/forui/CHANGELOG.md +++ b/forui/CHANGELOG.md @@ -2,6 +2,16 @@ ### Additions +* Add `showFSheet(...)`. + +* Add `showFModalSheet(...)`. + +* Add `FModalSheetRoute`. + +* Add `FSheets`. + +* Add `FSheets` internally to `FScaffold`. + * Add `truncateAndStripTimezone` to `FCalendarController.date(...)`. * Add `truncateAndStripTimezone` to `FCalendarController.dates(...)`. diff --git a/forui/example/lib/sandbox.dart b/forui/example/lib/sandbox.dart index b761180b3..869d2388c 100644 --- a/forui/example/lib/sandbox.dart +++ b/forui/example/lib/sandbox.dart @@ -13,14 +13,12 @@ class Sandbox extends StatefulWidget { class _SandboxState extends State with SingleTickerProviderStateMixin { final GlobalKey _formKey = GlobalKey(); - final FRadioSelectGroupController controller = FRadioSelectGroupController(); - late FPopoverController popoverController; - late FCalendarController a = FCalendarController.date(); + late AnimationController controller; @override void initState() { super.initState(); - popoverController = FPopoverController(vsync: this); + controller = AnimationController(vsync: this, duration: const Duration(milliseconds: 300)); } @override @@ -41,7 +39,7 @@ class _SandboxState extends State with SingleTickerProviderStateMixin { ), ], ), - ); + ); @override void dispose() { @@ -49,3 +47,68 @@ class _SandboxState extends State with SingleTickerProviderStateMixin { super.dispose(); } } + +class AForm extends StatelessWidget { + final Layout side; + + const AForm({required this.side, super.key}); + + @override + Widget build(BuildContext context) => Container( + height: double.infinity, + width: double.infinity, + decoration: BoxDecoration( + color: context.theme.colorScheme.background, + border: side.vertical + ? Border.symmetric(horizontal: BorderSide(color: context.theme.colorScheme.border)) + : Border.symmetric(vertical: BorderSide(color: context.theme.colorScheme.border)), + ), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 8.0), + child: Center( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Account', + style: context.theme.typography.xl2.copyWith( + fontWeight: FontWeight.w600, + color: context.theme.colorScheme.foreground, + height: 1.5, + ), + ), + Text( + 'Make changes to your account here. Click save when you are done.', + style: context.theme.typography.sm.copyWith( + color: context.theme.colorScheme.mutedForeground, + ), + ), + const SizedBox(height: 8), + SizedBox( + width: 450, + child: Column( + children: [ + const FTextField( + label: Text('Name'), + hint: 'John Renalo', + ), + const SizedBox(height: 10), + const FTextField( + label: Text('Email'), + hint: 'john@doe.com', + ), + const SizedBox(height: 16), + FButton( + label: const Text('Save'), + onPress: () => Navigator.of(context).pop(), + ), + ], + ), + ), + ], + ), + ), + ), + ); +} diff --git a/forui/lib/src/widgets/scaffold.dart b/forui/lib/src/widgets/scaffold.dart index c96c9870e..abb6b86e2 100644 --- a/forui/lib/src/widgets/scaffold.dart +++ b/forui/lib/src/widgets/scaffold.dart @@ -52,8 +52,6 @@ class FScaffold extends StatefulWidget { } class _State extends State { - FSheetController? _sheet; - @override Widget build(BuildContext context) { final style = widget.style ?? context.theme.scaffoldStyle; @@ -63,14 +61,16 @@ class _State extends State { content = Padding(padding: style.contentPadding, child: content); } - return ColoredBox( - color: style.backgroundColor, - child: Column( - children: [ - if (widget.header != null) DecoratedBox(decoration: style.headerDecoration, child: widget.header!), - Expanded(child: content), - if (widget.footer != null) DecoratedBox(decoration: style.footerDecoration, child: widget.footer!), - ], + return FSheets( + child: ColoredBox( + color: style.backgroundColor, + child: Column( + children: [ + if (widget.header != null) DecoratedBox(decoration: style.headerDecoration, child: widget.header!), + Expanded(child: content), + if (widget.footer != null) DecoratedBox(decoration: style.footerDecoration, child: widget.footer!), + ], + ), ), ); } diff --git a/forui/lib/src/widgets/sheet/sheet.dart b/forui/lib/src/widgets/sheet/sheet.dart index 3a85e09cd..a1a1d159d 100644 --- a/forui/lib/src/widgets/sheet/sheet.dart +++ b/forui/lib/src/widgets/sheet/sheet.dart @@ -239,10 +239,10 @@ class _SheetState extends State with SingleTickerProviderStateMixin { @override void dispose() { - super.dispose(); if (widget.controller == null) { _controller.dispose(); } + super.dispose(); } } diff --git a/forui/lib/src/widgets/sheet/sheets.dart b/forui/lib/src/widgets/sheet/sheets.dart index 887ec1e4c..ab6932528 100644 --- a/forui/lib/src/widgets/sheet/sheets.dart +++ b/forui/lib/src/widgets/sheet/sheets.dart @@ -8,6 +8,9 @@ import 'package:meta/meta.dart'; /// Shows a sheet that appears above the current widget. It should have a [FSheets] or [FScaffold] ancestor. /// +/// The returned [FSheetController] should always be disposed after use. Not doing so can lead to the sheets +/// accumulating over time, which can negatively impact performance. +/// /// A closely related widget is a modal sheet which prevents the user from interacting with the rest of the app. /// /// [context] is used to look up the [Navigator] and [FSheetStyle] for the sheet. It is only used when the method is @@ -20,11 +23,22 @@ import 'package:meta/meta.dart'; /// is [Layout.ttb] or [Layout.btt]. Consider setting [mainAxisMaxRatio] to null if this sheet has a scrollable child, /// i.e. [ListView], along the main axis, to have the sheet be draggable. /// +/// [anchorPoint] is used to pick the closest sub-screen. +/// +/// [keepAliveOffstage] determines whether the sheet should be kept alive even when it is offstage. Setting it to true +/// retains the sheet's state even when it is not visible. Defaults to false. Keeping multiple sheets alive even when +/// offstage can negatively impact performance. +/// +/// [key] is used to identify the sheet. If a key is not provided, a random key will be generated. All sheets in a +/// [FScaffold]/[FSheets] must have unique keys. +/// /// ## Contract -/// Throws [FlutterError] if the [context] does not contain a [FSheets] or [FScaffold] ancestor. +/// Throws [FlutterError] if: +/// * the [context] does not contain a [FSheets] or [FScaffold] ancestor. +/// * a sheet with the same [key] already exists. /// /// See: -/// * https://forui.dev/docs/overlay/sheets for working examples. +/// * https://forui.dev/docs/overlay/sheet for working examples. /// * [showFModalSheet] for showing a sheet in a modal that prevents the user from interacting with the rest of the app. /// * [FSheetStyle] for customizing a switch's appearance. /// * [DraggableScrollableSheet], creates a bottom sheet that grows and then becomes scrollable once it reaches its @@ -33,7 +47,7 @@ import 'package:meta/meta.dart'; FSheetController showFSheet({ required BuildContext context, required Layout side, - required WidgetBuilder builder, + required Widget Function(BuildContext, FSheetController) builder, FSheetStyle? style, double? mainAxisMaxRatio = 9 / 16, BoxConstraints constraints = const BoxConstraints(), @@ -90,7 +104,7 @@ FSheetController showFSheet({ draggable: draggable, anchorPoint: anchorPoint, useSafeArea: useSafeArea, - builder: builder, + builder: (context) => builder(context, controller), ), ); @@ -104,8 +118,9 @@ class FSheetController { /// The sheet's key. final Key key; - /// True if the sheet to which this controller is attached should be kept alive even when it is offstage. Defaults to - /// false. Keeping multiple sheets alive even when offstage can negatively impact performance. + /// True if the sheet to which this controller is attached should be kept alive even when it is offstage. Setting it + /// to true retains the sheet's state even when it is not visible. Defaults to false. Keeping multiple sheets alive + /// even when offstage can negatively impact performance. final bool keepAliveOffstage; /// Marks the sheet as needing to be rebuilt. @@ -162,7 +177,7 @@ class FSheetController { /// interacting with the rest of the app. /// /// See: -/// * https://forui.dev/docs/overlay/sheets for working examples. +/// * https://forui.dev/docs/overlay/sheet for working examples. /// * [FSheetStyle] for customizing a switch's appearance. /// * [showFSheet] for for displaying a sheet above the current widget. /// * [showFModalSheet] for displaying a modal sheet. diff --git a/forui/test/golden/scaffold/zinc-dark-sheets.png b/forui/test/golden/scaffold/zinc-dark-sheets.png new file mode 100644 index 0000000000000000000000000000000000000000..27e6f66d11fda776953676e5d1ee17ff0891be52 GIT binary patch literal 63213 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 z ziirz?FF0@XNj4`Fc>~d|ikgY%bXgmq%Wcir)`&&&{^dR4M*;eA8=uLe?+y7rkG_8- zdbtwju;`tzm|LPZNn+M-=FJRUuYH6!74*H|-TyuS*#Z9j*F?gPCi<@z@mvD_``PgqvZ4w`Tl&455S+Ggx&7)(tS6|S7BzJ01 z)lteIIdJHH-nv2?>14O?$9?TeL&u})Peixc_*Sf{aB+=RP1g?+*D+kYE%*-RR%Z#F zS+eR|=jwcd(!HI(YWP2TE!H;v?()LvYVVO^8Prj>WV=}kEj5{G5MYG7DS_G3LR%fS;ZIXzTj) zt0o-TS1(wD{`xp-gBiKa8dKyXZr#c1YxwqaO+2=%!eH?I38>l5>y(x4zBD^1x##hg zW%gH96ynwEY9rte{T#_VzxxK`)oYkyq-Wf#{Qcs^xDnU_!JfOSbMctzAF7WvMvd-H zruX)$!PVLlJ>SC%x!&uqQ*&QGJ2}8$Ga?nv1=S{2T!9h#4L_pZI$!Jg-pZwu9H*LN z=l!V8Vcog^z#sPhX7&w4qgu+?*jQLP+@U)=r@eZ{>*<5_H;M5w9+Q<;?_ci@oJ4L~ zASN)Bty$KF6SB>#;LM42`lDw%w$xVT8LukoGjeupld+abKv&LQ-=X>@{3$5EH= zxt5}tAT5?a^GtDxAlDZM;r>40U^xI=461Xw9h{(u_ zTR&XK&RkXN_klkkElv*8t84wq#jC>mwxeC;{hd4H!)og;=?vZJNd(&jdZ5o|DY%yq zrU1r#-ail@sE8j8-c4Y4)fRfv4<{MYagFfFH%;m1f~%r)OCw2h5vusPX+15ApMLsj zu9`k~#b>rIKIrY+w_D|B`!XKDC#k_FrIk%va0Z;ZaGV}o*kTC4xP47G4?wXEjq#N?`=A2;guyo)q8D!(fi7gX6( zUHa=zdU@JF)5-y4K6iY|osw5s>&|s1=HWlnm=^E}LqqRj;;}6geRW-hRMv?QseS!% zW3ar+j_s21v-Qb|`7>9l2V1g|6JNZTV9{%0)g|`rTh+NYex_`?T!rnuy8YEoQy7KM zOr=F2X*!tRewq}Y?fmi2X*!2RDhpV#ad=xi9Bo^KoBnaGKLd|?yp#7+N4xYApFbZf zVa|Xprg2M07j_H{i%II`CiDTY*PHV@x#%vXw(pMHju*rD>Cs!07H3{%^*1+7TzNrptiFGI&Fa!WqV#ts<9}Wv zyH6oA3{0)vgU-#quhJYXotq9OO;0Uy+~{kn7>Dw)4 zT;IiMGUJ|;SZy3*pCLQK7@3pv^7^8(XeY-2aCYy*a)c6Z5AZAhS?H&^_H?h_GTm2E z5iXY0;n$z@4Q*X)eh$fqmB^C7NksTE(MA%wQ|tMx+jVg^5vr8+ny(mcNq9 zVKcfyRg}v^rJJm(WA=}J3O6YK?cdl!EB5Q#8+TikKa1g{!$&Qdknlt6u!Zh@hI5k^ zoa6SCqW#tJq~)u&gb?GI`SHOO*m%#1QKN$g5AOJR?3jPNQ{RWpwIq%KwTL;6<6J6y zCs8s|CgwvJIO8@q;*WdRvJUegIiG5}oT3lV7ZSZsWp;^-kHL&v#j=WrL#7EyGmQ&k zQKculFL%9R$#;n)=%_llm0fhI+BZwKGPwl#68E*l;n zyMLvk=abYgX{Nafu)?Q3ee7TUMl7SwRaxli=;#!}Eu^vV(Nv_a@eLcMhT2wLU$}IZ zoC!Uo7VI(OPOz7{r%(0!heRDKtAi8$4XGVg@zbSlqm8D~YE?5EHk^ppn)!8id(zQJ z%Zc91{qYMh$n3S7z7v!szG-za;LO!s zoqgf8FNTv;i+qnhYHQ_~GqS#49Bf&CckQXdi5tC~=8;l0gzM|jLB|Ku(MmRkg;t8B zqAm1sxK&rG1uIR}YvdQ70aK2X#>}VRB==rw_l@=LsXjNFV&JRh33C^19u}jX5`KFQJ__Cj($@* z>RXs_zUr;2+r%#vpP%VLziSZAAG65Y^mcpd%D(SlVD2)IaQqwxJIjKH!n&oDSK9(qB-JJ|#blUoP7azo zv`$n8=oIBvp9YE^j6}LebR@+Dotd(`W&M6m{ z4eNj)_NH|1kF5VNqRM-;)^Qy|EC33W|Uc1r=!`y_u+>f+C_6X)02r zjr3lUTt%rOBE1L#(xvwSr72Z92n|z?Z-KOd# zpAPZM$TnQme4)$AJrn!Ip^mP+lea_gL$z@?5}3u!es5{z^ZixV=qPN%;D9FNBYN*+ zw32A2dmeTwWH>Azdt){QztLc5;v^zXUeWPvYI1jFDHq(*tz)Pb*!=Nt3%^$?t7u&+8Vl>rlq(QoU1qqVMibFpN; zRU18PYQmcs;0-gQnuRtzg!%9iFPKr)&r&MN%8afHa<0s-%kE^wFj!>+z8x}8 zT9aJ&jajX7gp*)Zkv77t#96m*Uy)(wH~iFRQw6KbvUjA=KQS?Jj|}h}EqU>t1Map( zOz{ltPtpaA0HwP**0gW63JfH~nr|*Qie@=mb`z`x(^Fv>N@LJVkDuzChq%c{$0sIq zKRjDHAHD3(eQ!6rw50ULm|{h|%tpco{mgXBk<{g35waxQ^mJC?nOky&%_;w!wkdqS zc1uaAkuv(mMg(&y8^WUO!a-5d%DNDiq5T13^V=T#db#-S_8f4ut%P_yI=@%u2jq2G z9nL-S18#J7QB+GeBFkaEIJg>doXgv~|rF9!8t1p}>_;y3h$Vpw#_zGETImc(zI6f7rNi`SN87ZV>=xod;Q`TVsljs#;oFQfHGdw65~$hGVpO zorkFN@;P`ZM^NW;lC45W?h$>-?6VHHZgI6S!f)7#Qb1zI14F|nOgif~_wCzPKHnh2 z6uCagrMtOarCa`FuhR90B-733$L0HV);-h8BiBE=Ue1~h*UYzw?MYeNTrAnFbDzu9 zah%MiOkj_kam{2$$x67W^+SA1Z3IH3ky_P7c4h=m@eGr`9ECZu8uIe@v`|3p2s||= zAxWxA6VIP8*h3&&TU+<;nfxC2DS$$mCfi+jwC%pE*!&gqI)7W?hPZY&R)ot=tHi9PP~ z_46Tg-zE{%2jm;xyB;B4ou^S1u9oVU}e9wzn z;MC?EUrE>0Y;<(A-Rjsy)}~2=a7p{bo^&Q1r}QqAfu|WSvsy#$=4CL-NjfHha zKYz|FVtK8F*Iqht$F3`sPpRe7Ayp2^W9{E?z57%%f-CKQsTwrW=yAlKeHEFHsqJ`tVIM&QX$rlht zWa&L@-RzN@3-MDc`Dw*V4u!fLvR-x{c2D=(maM758y3F<0CBJGwCG= z5mxH(<^GD&jSuPr<eZ|4qAJ&~|IDqrITPV3tFHcFy)$y7omt@Ch4m&rXHJzgmy`98GAxm6-Dy_K zD=sR+p&O;7p`jtA(K^_wz-*{`C6j`BdD#M=Z);fS@BC?}Zu#p6N~GEhW>Ke`_b6$d zviVR!f~vNCY)?Qaa5rm3j$~KpXJy%Wz$v+Bwz4u#V%UGFuw-reGb;=HcF|&+Z;b79 zcdp(^9v<%iZdDX#JA9a!n5ukOB_t|VT>8gbjoFt8QBg-+rb(Y|zk^gzqn~L$S4uQg z17*ejx!3Fo`EKk`@xA_TF5Thi)lsb;uJi~Ps8Y%cSXRopW<4HPLy2a#>pB}rt_NK= z+Iu};op;Z1G#UN$YF5>Cv1d6`W({wykH% zXB|sOg_Dn!wr}4)%Uv?(JMh8pynyXgm`#I}#o(p0!ooHl^Bd)WoS#|OM#$@t6}=lh zy_E*i^PcH;v;E6Wfi6<8$}Bez1L1m{^YUd!$xu&6k&Crv@k3rbAp=hi+F0O<)?eyA z!F%#5Wtu-}C%&GZ>1K}~A54v088dyDn6zeN$OK`c4@qWVDA3iay^0SGqK2bEpTJ@n z?JaS=siHy@TEmkkrz_hDON$cHHcMZ}kdkJR9;pxa3<>!ssdaIEC6k@`mvCukPR?s# zR_#va=H`b*-|{6UB~35e!E0MAB4*{;#_chQiDyOv5%b+ zm)sQ={N#zwYHUO0c&ja$ybJfK8Is%BMq1&V@ncBGUINYfau3q9?K4eNc+9QZmr!OS zQgXp3L7smXA=YFU22}*kL}6103Bqb?Z^6WX^V*VkNJt2?l!I0MY%7c>XJu1?O5IC z1jB-NnQs_~+-%lyKGq|hh@?PELUVt(Ezvn@MC9z*^75zt128Zy@sc_hE;w&w&VnxJ z2@B?m2qK?@&h624_`SnD**u4I)DMm*9=&;Poyb*><$45b?k%(gD_vI$qWBM^2{(>A zyZ4e~e-`({(5Iciehl_e0^ddV%lk(Hdewu7m@Z7q96=|g$HvB*_m@BIczahjS*L^$ zV=Vm^n9K5Vl?V*@hPS&yD9}xDt z=i;AcR_)=s0g}h9{=vHj*Cn4Sk{E)>+IMX-CrfaBNebPBD0UBbI?nQ7*SU6O$*5og+#ELVlhCioOY<+Qbl&S>kNO>sP#8YUAe zqSKk{TC2UT>6PXz=`sDKS{<$`EvCIjIQrg9tME{laI&Ws9`7|A+CD$L!}k!2WrP-6 zS*2n@JhuV*)_j`rX0?s!8k=XFs!D}lxCTeK8P$eCt7@`|DY~Kb9mR%mo1&R^QK7KY zlDSEPkD+GfnR-^4=OQ}VN(Y+{oc1}X=pp$F`}vK>ySxix`N~HhWJbSzd%_QC@=sc{H`A>XZPra+n3(Jm%S`z5 zPh>RJ+S}OgViOalX!uX9*zH>)F8WxAyMJ&KIeeD-p7J&KoO%WXCdLe6q7_Rh8tI%W zZL6$L+g^9w9_Y)7GrV1R3Vc0(5uL_(omz+0&Y!Jr`J63NGkLBAw?&vz0Eq^0guHxi!Xx$SJr(>$x;o4b;N_i=Du z^L`&)SfZ(^b`vb1daqw&sw&=@UNwhnE);@NIA<_Ca0UJf7T--_|EEA=!8zD(zBKx( zXeEQVUqEkDS-|vNKS)w4B3s$eY*Z=DiOFFkL#Xn{NdQlPnL@IVS)y3@Cr=MXiU148 zwm99p*L-8HqGN8nCOvI-((nOtMq+OWWa;0lP0(RGFY7B$p)yv&wC{H+4UX9ng9s`C zuXH>_;t92&$p`5%lA_3 zFB8bc^?gn=!`VM}>bl3=MT2Q;051w78rj4wVhl9Wg*S1PL4h)ulBck-zYiR7&$JyM zO5jY_SQ|p8Z{1=QjJSQsf7to-l^Vz6l+k2+MDa!8ht84A*M_}2vLBqk$-ul%D0Ac@ zSTgnNZg)A5i)!xFn@YCao?<0V5oI&{dEX;D18n%7fO&(M2a}1SdD$oFOluIBR<4!$ zE@t5~l!Z3KPg|HXmq5#k+TT$;o2q^=o?+VegTCdkyyK$B<$37?=U_Q620AZ+LIqc`2ppLdkuv$K3%zH z!xV)LE<76BR|A~j7G6mPb061DbG>oDSWhkc89M3d9q#%Y&@yGqNBGi#mPFgX%&lCn zX-qW3SmSJ}*8UMiwi>|3WDg29Rx!ywNFzSA0?XOWQK_X7bwxl><(u^u?JevjGPiE~ zk#f`8>H&hiuA?)f63gkL>8`eiyD~YZ_h-SieM*+wsfT5VcT+|d%=NzF$A-oaJ_hrg zIPJBUF}^a);AK_m-WV$U+tT(GKNtV3PJf`~oijyhSU=Q(feu@FJ~tO6I`T0n|BbYR zD(N!iu`vf9CmsOQ4iMoyC1|xp1F4AMvdX9==%~Ff@C7F&MqFq+!MR-<8*b%JU-ZsS zUkmp}(bE0p=BdYCY)q(@pjKB7Ui#%$c=RZDn&%&-EaBR(hK5Pb*3?r$JX}!YrsiSY zxOUlZQ6XxCR^y3ku6f;TZbe!`QxPWPau!c0iary^qjp$1!tNA?3T_d!jceR^2bNMo z)7N@LbSGGh2jJc)sNhLKg#^JE3>6lzz2>dNRQbX@;}(;2$uDhVvWINyO;9leQZPKg zJyZ-qwSp*Y!;L88YW;zQR~z7&Tnv+ZD*~I6*4tfHw^w)*%AOhFB7ACfK|Yxi=Bx+X zO-$=HNd3dzpP8>tXnSyvGz{0NE{rjuYb)EO*eYW6D3KAhhCQzal1(OEZ+UG@KmS}O zk~&hy0MGiK1WOD?grW(dArG6-9uIELm&%2fkR!Ttg!>x0bF=2!L|Aa2CYypQf@ zmNHe@#U{nO$JE%vGhUJNGgPSDQXAwP;0quCZBP{fV(d_RvKN@EBX!gYf;1a~+&PbG zN_P4rMO&nwOta7SdPwcYS2(7nJY`Yk9jPOMT|#li;_7_h=cw0b)6nzNq!us_;WQoA zwGiUdwyruV+6uee09-f#^|Py#+@yuQ4=z;+36)~{LFm(PA%j_G%?^=~n@f|ClvG@R zZGY(S0@C&2&pBctZN>Wn8^S+^PJ?FB=S}qer)9*G=NWUA2J#EvUyYji&-XU`PJRG02TuV-xAH> zV-KQ?tN2SAq6|L!8{S?ZI;AC!2hFxL1&NYAp5U1dpyX9?AKK;Je+@%*U_=97zT`bI z(6(r7Kflf0*Q3DTWyO=r&CyYB`6-Zi4BHras%*&8AQ~Yp(V&gheJ1c}d(yNf<~icpif_O+MQ+gJqw?$HcLUm4oPx=jN+k+-1)Ia3X_f3Zo? z{=)8D3Qw-CPP0V%N-KLswmj3^aMF%l9-oglROJO*M!(4urQDF@Z5lAl?Cr_35F3m zSr^8b?HTErxVeoHNwCr~YztKeCC+dk4vAdZ0dDSr_Xz{`^MGf%mCEwEO-0+4ZWFnw zcO-d{Rg3b_xPq825qx>-RhDRn(x^AVLLy*$TMX~m#j+Ri+krKkirHcb4*zRhZD>L7 zpp=5)FK7OtCFUxO*29imVOb4hd78g?mS;Rd{Q%gRR5rkX?H$6Fj@S&tS8qgdA*Jnw zROa-+J}u}hNf)`UjY)~(6ceIbhBmmDE`fjdwRg_!Y>Eymq|KVpv~d}JBk=cxGKXcA zE?=g2OnEZ2v3>S7R5h)s!pZ8{ zd=(ro1LHJ0HR*Rb9w@hm{JpPU1#h(GoPdJ7paiQ04N2Vgyto`cFq&%GxLjQ=3ZO!C zve&zX>I7)L#TGkI$e~*y_xLCT6@1Q>Pilzhk|bDS63L}#V8IX_sU^9Z*e$S1p1t<9 zYk$?!*AI@{dEi>M-AK*D$L-qS_#?~4EEns;9Zf%*^5j~AZ}ii>^6~^I{n_t2Bp^;< zGwUy~XAtf*2@}uaJJgo^M0p2ERyefoAm2%DN?r=~9FKv*X1Ni3Gq%B1xC+7tyEFkb zbE@@`b)jkWzJxV93~;03v4_4k)s~%v?6r=?rAkABJ%_DmfXBO-N?-tiRc~kgkHUK; zx4`6$!gj`T%%if z;0m+gmJa*0p9Ul#C+RY5Y!W~vj54Zsg&1{FHwEAobyVrI_DB6;F=iOm%BRkS9HAcv zYYzmzyjb_uUchnIQVBc&>gCubTBEO;OjFDa*M<#mlWtH)72+5%NX~luGgqpsDXQ>O zC;e`0F>z}*u}ITld%x9TtuQ1DCYz_I3-jpF{w7*Q63RTFqhXEF>XB=;I~#!%Q*ePU zB1_jYf)&C#awTAqc|lctxGr!p@ySPDKIBGSfFwW(QE^6E2t|bh|42_8n?y1d$VVq2B%vwEO9cfQB5@n?i|E zN$aC{g6b{nT05f$3L&I)3}xM3)3tw;@dH$%GIQX7<$8EPzs?)@S=h>VWwNp*zm}n> zLX_jf>*lA{pf2oMC`~>v!gfc18a<86PU=U#gt2KIMK1XH$IJCJ=?UEF_&~WYNh4aq zF5QM~X$x`$I51#KOaJT#t1WP8d_R(h-xiSil&}Yv&S-ntmF_zKE#9s&cy$62nr9AQ zz%YSrJND?W^38`Vib$VBI_9T*5m%?FTtR87%DskA0b#nEJGQ^2-6*(0zj&u5d+9pb zT;L3^59T?=`_x=;0?nWjNNP%~vi*qtgdYrq`TdbLLrpMZ!X#gUkEFgI(Ju&)Cr#SL zlvtfn+8SNQLg#teuMUp7RFyj{3lUWBM25n}bl)rUd*ms{0#v9!Cuc#EVMq2tqV|rn z=BxOFbSNez`?x_4P#sx?utU}jr#=5DlRJ)jG5TC+%K`Tk&cHAq@1xrNte=@sBNZX5 zNEMkFwVF5Ci<8!lp~76BHvKP*jUPPSrg7-r{A#QD;`{ufm1@F-;uh9Any4)tTvrS0E|Kt=B<>xv(xB7>v49Gy z6Iy@TaTOTW(R>;>xLr$2$rjpUX6l9J4y5$_F!$<$C%SgPnBBL(DdPg-pHi48`J~rf zU?Y@cs>W1EB!U=ALt;#bBF63xa9vC+?K+B>o+>8laZ~M3dK-XT_N^G>@ulJIu7g^P zJ9338Vw<@bC!saV3NJlQQ4Kh&%fKTModlv=nXfB12i3b%y5o%Oz7KXDkOR{NB{a7w zj7E<(Q84#0d)5C}jP+o9hkfGF#Kf3L31dnwk`3Fp!#%zRzwz{szK22)1&CV1R&_x@ zvpd5DN~;k$;)DJfu}sjZ0)(YmgriDeYoZnBHdRLJwj8ygpo4}oa*_Yd`XpVzFn5#< zn+3B840Bi7SfK3>T)HT~7yzm{G}F-b=M9rExHYP5*&tubV>9FLsnxw^7C;hrf3J|n zf3ZHbJbld&;=(-sPPaY-{;T!*X%UNYsVo0K>vJR^6R{+0gWOTSR2>4dhPJcVk`RHF zrw-{`Fg{?ZiGlF}E001;#4+j|B_{#REPxPut4Na`CI}%kZv#S%R3OhvuXmGrIkw|* zRFypR3C%3=K&9svkcl&R0v&Ii>3C~(jh47^4-Zjirqh{5A)~nWm|}=tIJg$wmLN15rnBQxBFOv z>~@E$h#c~?p<)1q1F_7D$72P|+QO)fD^y*3M2!9eC;hKgK^Y=uHXy+KOUrE03az(9 z-~sVZ3~`Sfq|>~pqymHqpR<02YP?5?x@8R5y9O?$Z}&C=xkcVJ>X?Cg7)oDma%KBz zC&fxfgT*7;ToBmb*H#ILOEu{H{Npa7B2?*&A7!4|cGIxR&HV_pY<%42NHK9Cl~GzY zKofG-ZKxqau#lK|4N(nhR|uLr$qS}DJn61Ag-DW6Yp+PnK)X&$Z3xT7HrCM55n&V#AX2M|Kf zbNLK`k)%=qj`+Q~^+#Cef!hvcdXjYT04)fbP+0aB`41&QV>5Wj`rv8kIvbU+GlV$f zhD_*3`sp@6?i_{;NAA*mx`9&1-HmNc&jmH06#&&i#2QZf{=p$jL54gLY{FT84fO{3 zb+Igjy)xmiH6$Fo0$&7Hm5V8s)B3^h3BlCS&l(cHPSs(*{s$dK=?|yShHmW8uX9`v zCqB1!qGWH?WlqPOH zp)atL(sL*H@F8WOALEpVd{4m90@qH{jJHCwcaHMg}Tw=}T>x+*}w7R0A> z0Ud4TL)Rj+lxBRoMPR${M(r&4AI9e)G33wFj8BaVungYrqjcw^g}~O08J}7DHz?&D z&#BEN#k)%8NO%6|%f{rMW9kFQaSR!s1sv>n^jC0){mA%))r$t!z?Ze2GO#BVCHH@0 ze4ew#QrV}gSzvq?|7YW~0W&_&*`mf8^!Zdr$J!9058e1w5j=?=1%x_<8x~+Ed$^g6 z*ZTbhqEHVdSdcaKCjX(Ww*WhL&CTp|Pun5)9J~)=Fp$OPh8T|VyHQLjL>KG0Sh{F_DJb9`d6IH4KRljk)G zee#axsW6!(oVfQBUh8Xx$FiD8&b{X^{eENQ-ehqD(UB*~q)+a5BFRD1D=E<-V)_jO z4ma>e2{&alaSHrHjg6X;=EsVqBrGS_#}ZdA`^VpJ)tJ_wEYxUfX}XPwCo>-wbewO# zyyFsUBq=XBZ(L*}7HbLh3hSzf=Quq-J|V8GO702-6u)y6BRWBSa80(K^mBgnfj|jUyT?2Y|HhyLXp&1 zS5j)2SVv@hS=s(fI89kS&&X6f*CpiO{DFN)hG-w7fer4|slb|it2wn*2b;n1PUXw_ zngYEYl49Jwc3cz0t`KBY8H+-_f<6m`3*7VQY4)F85kwuy?3T zebb^=g0bNVbUXX7V~yQp1{;eDJIPlSeHJ&l&u`ndKQs2m$uwT|m#GZ7Bdy14Zk!7E z3Dxl~VnVx5G2i@)rb9`$-_9zRy3r4pDoo&A{g$L2DVp}i8UN;PX_prqGR}cH z2Q!-pca=kK-{yuP)q3_Ib7Z*bDM$Xp^@puH0ciMD@@eb0RM2vIcyYmXQT-bGXif8% zS00^kR@P~?e9mxovzpqKwEbvMBaUN(8j)a;A666Z6Q64!ml`1kTP&baZ3){Sy7_W( z+Sb6LtA#SEnenkk$$%>tp~B`SgXv|r-@A*fq@4?G zhu0g=A7nk45R{UH|M1+Jb*y9V@@M_pQz%B)m9QAyr*C!t*og08h2B63%lW32#Fe<0 zZOP8I@+!rPW`{z#n2<5G`J{k}W>334HF(%(?z6exkabNaVrh41Q}<^T0hx`~6??s< zZcSP|_v+pROS&qV- zDV%n)g_vr6*d=^}kEWQjB<#s>ujuX#<(Ia_;n;YBe_HB_9i`$X@MUb~;kC(Wd9rHc z5V3CJ);v#|LPKR8yMcODXae5wG>X#oUMxj0EC0yW-SBRjQ0*5!z7%Jz;fo+H=Y>Jw5zMMGTAt*Y*5dOh7()C z{QBNLKEv5Rx&i@3u1AIP2MFa>>+G3&lcE5dGdo*t+urP~3bhmNBq<`1W4TO=bU;8kN{g zM@M}=%^OI^abiU>TxEEYfnqEKCU2zVOB9%0{10xtv?c`aW_NmVQaK)lvfERP=DV3c z7#w?ejs2@4c}gqaao~3A`iq3-j4yxrW)#h*w1`|gh3=gXlQg)>Y{*a+qia%P>jSy= zbE9`#*OMQ4Hn$c_%?GAkOQ^Iw2s@Qu?eXNLW^!D^`$_IVi;>R(wZ=NZ+qtzBO?&V% zk6;^ry~c?NL4(GoFzHW`U8;Qh0k7Qx-7lkVCHU}p&y5=LvdM%IBUtlYHWgaeUw>52 zSe+zg42Rb}2x+>35I~z33+E!M$2%ei?RtGXNsCPOunS)6dP^{zHN4n-TD{8;j&wvx zV#b1=f?^kErY66xt$K!yuAMCVOYxLGG}RC1q+L=aE!C=LWxa(A?M2@ezGxveTqc~z zXEWIUl;fnYk4kNuh;W?q083}y%0O1pnPST2^wSg-{z1wAp9l++!~l3S)jCD9&=3^H z6>%l85Y=dUnO(8z4Z0p7=@3*Vvo5#CxrA#Q1N+UohA{GNw9wyqv@0tQ*u%LmWPhC} z)R9rRWQ*67hshGNG{nnB>`|?S4!WW2)`_OsFY&?Bw!fi;#Y{huDd;WizQG$V8iH>B zbAI!!dH)cA($MMq-#}?4{rE)AqA#!Bg^iL=I+C0ssL8)BD8Pp&^8VOreM@UQ$_sAk zm>$M$y33KK^vNPpV#Kxck0W;7tbKVUwy5B~eL(>v|B9ODHxk}LOREOK`7U2f z92{XNXUh($A=DDTZo;W-ywY$ja zl@TE!R>-)w=lLx>A+&P%<0EKW>FZ2#q;;*}`t;5$FDv;w!$K}KOxlkEsh?V2?ALOwStS(;=9?NJR<=Bkt(!hENAa^S zl-C?HZ5u}NT_)6x`aAh1k7bCUnZ?h`u$*tiuweZiMdtHW;Qj!{? zg;>rw0t^6|gM1%utG--8ee(^HdWv%xc7;t+^ ze*wJG?-kcJv9`7IORmlSkeO8K6vM?NST&?S_6xBnYpCi#M7TZ0#3!!u6=XQQ>4*l) zX!6J|2I+(#p4OK8#EgKkapKF)G@g?H@}(Cr3Wpo$$hM4c>dF)hyvBCb-YV-}4#6CN zwFq(JYY=)np#@-O>%>ZPGXU25!`-214fL?ICk}JvUaf;r&McakJgZ=YfVFh%C`|2N zAoUM^A~{+tyW<6CW_|-;-R{}6@+GHMhafH_6tU+!+@=?ukm2ld%yf!hNVKQjCpPU@ ze>=C>($-4W&&f&U_0-mh6!UyJT>Gv#-+JiYE3NNvl@fwBlo7?*{WCyL&T_WgZ(-?c z?c%%v+||_xSop=EK&dY)%Nrwb(*6+(i(;!fpnj}w4VQXG zDu?xAiL)52`mL~FEG;X{&77X#vnZOb+9hRwgOa;!$2_cT@C{)XCod=5ggTGgELL~M zaXyD7!(U%H{|{+}pp_=A z2C#-foWgZQHmTY#?1Z{k)1>=-U;av537*%HA93%>xHA+2hhH3kpuUq#&q4p3n({Ut z>n-Ls*fUkv{N)Qp1r+6gw8{Z#Wyyr3)tzLFqvLMy23n2{Hi9tx0Fm(=IIGKz`N3qT z`EbOfL3Zo};ltmC-7p1MuE zgGDmQeb;U}xT+TvkRt(P)o+~I4+W&Yi`f0+T$;Ui8Z@sB`DltR8OzGaaqCYUI+S7M ztST<-8rC)@NQuy+m`#A&@9pC?*!^YOe*jnFWnE=UN+`V83OQzW5F*un>?QJDUg{5e z-=4h6ld^waaG2*qmY5}qDNRWi(HIVnM^KPF;jt550zjWqc8mX{tu(3H%4=mOx~uE^ zu*}uRzzu@cY1|Hxgz;d1s$gvi3kcne0N}rBX{>>8AVP%x2Z{&>{MTGAlVK%;=tx|F zM{Q0AYKHH4QSkUN;s}y-c2=shw7gk-c-h9*XLGJ$*B(i#vicTXk+QNI#uB@m!SHa! zJQ|~V_Wz2mlJeM!DHRj~bOp$Wo307Zw;%hx)d^Nr8=>%c6461#yUu?nD2t2@+Q{6$C3;Z^vB1c*_iIS{` zl7mtb5cAEePV$MgwPq7$UcuI$Z#zmX9lHTx-rph~$ z{)wBBqld;Lph01PtRV6Yx8=EOyIBkP}oU;}Xi{%cfG-a63;_tEcOX>&o~G zBT3KiaSe)F`fA3phhTBiHdX6m(Nci=+kSw7jU|5rI2Y|X<&AJ(khWO3V*jqMN^3CbkF$H=1tS`Ko*JAK$vT*mpiXwNRk7OO+3g>Kw0w~! zJ$M4^OUrhMEo?-rua>#eP++IFya6fawA!qLk&$G~_qdWsojuf%DV3k7Z>>QrC`>F% zghSCCq`&dR+~;xYvE`X&g-D4KPy?mQ^w=qCsg8-sx9T^9d^P;7!1~6kyt7Wn49PgF0*@ru9WA|1&8b{s^YtU9IoF z5d&`IFEnJ0XIL5m=LXy$Q_};fw?pewBK0ea9w9MMNw+ZE$XDU~qapvQruIw@wAQMJ zJXS!M{F}t$7p6n&y2xYqA1y7W8#>n(W#;1GE82%$&7*PMG4c-y@By%=czU@BmgUyJRZT35*5gxeJk|1 zTiyvi0O+a+ltC?qFTlSloB-ohOjb282mrPs$&TR|uA#K~)vK`2?VlT6w^GVS05ca_LUfsKgkU~uty^N0LRu3ysMKRY0h;7TontV zsn%8G*Z4q8jMsLenApT>AUL;?`xMKP?aG#Ad6GwczJ55_WujOiL^AdntV0WNR}iqGM5>W$xU9iNurG~?ondh&dC>aV zq?0I|ZY{DfCpJ|7KT4}lhQ1uUl>P>=%b=yf!nChZiAw_YT9We`aw>o0*5&3@fUVaQ z2Y^LM3~*AtZC0PIUFC2=Z?FW9tNg<+zD&&Wt;~jw^Ghg>+^SOy7Uw}=46|^}dEhlf zYUu^KbmjNiCF%6+eDCx}qzwG!P{D;q^9AyyOPs8)2t_>ku1|f-{lF~`U`k7St@^YY z3@PZI;FOf4n&|d+1Bh@j=eIJsX_}|9xN$|bwV^c0TbV$&FvGvGFjKy@FzvABN$|)l z!G}bu3E7g8MUI6=F0cj=9eSBO`Nj@p)*Gye8`pPy_8b55ykZ2!cdIqk@k0-hY53qS z>vw&6SaA|J^E}^X(+U-U{=0uUlR<|NyMIzZ;rtq<;-XWmDI^2t3rZ5Gya6r(#DZHO z*1nA^mH+xN#$9Z^%oVBEGZf_t6_Z#Xq6d=gq(Hg8_%7;D?@L;yV=M(N+*IPIT7UR+ zD9jrrZ`qqJ7Fapu@idR{o&fUXB}ZQ^j28e2Vj1O{*D8DvOE?+GJBLX;JRwgUQ=Lt z;h+@r5#cKm10cp*oj|{|73T_Z_bxjg3JpPGKv!vt&XsluP;g*b>u*-ufAB9$)%s{} z-a*}>0`dr=>SE4Oe2VVwr}T}Dj58k&g;20ym=6^ww+e{3^<3l$M~YLhz+w3Q4PMn+ z5n&+%C{G&nIBGOQX$M5QogaOHy%`<*bp6`Y+HvGRQHxg~Rggl5@*138iwGB=2ZjW= zk{Y_xRwE-QI+I6n+A1c&R*A@$4~(ZeZ9mb)04T)y{*?vie8CZ4wrXlc5U@3Q;u~y@ zIzbPK^}7gLT?g+VG!6~qy;&!corTy|#(0WtbB83VuU`Mx7H4srHU2*etV(gr62>jp z{9Rxr(goH;*<^4&rGC|CPhT^AohJeR9@>dS$B572TH2sGA4uy7+Je__6r$UR8Ne%( z4;5Yq`tzY8h{5X`2Cp*)^!vFU^zM%;v89?4UZ>>yfJ&S5(E=$pa&rSeYnT|9oGo7Yg{ZV6uMSfq_Chm1?$-xXJ9A}B7`Z8P__TW%N)^Jw{P=hjg))!M*gnhPTQd6-z9NN%d;X@FNgc7JW^pW!Nt5xjzFNCayb z;Eh@#gbaXKHWVmO*90FIM)+~shY-9*Psh{Yl@1GS)^VwuxqJrSmE!5Ft}k|;hOmdH z*96Wh{z$D5@@hrYBZSS9I*Ga(N|z02RO~au*OQdXNA)?`rms*ymaU(PvIZ`!^k{1&lERbW~!cNan;Dk7;vO?nGX1+|FR%e zW-m+=0|a-h&0E>!-OGu~5#Fhqf-De0UE-f;hF!L1_zNs5M72=0VDW3hYt7Ukyh%h@ z0KUk7%W~VQDdK|O{&%%SpsB4pCUnTW^WG6G1H=?{i^+L_mD)Xez0qzzWRB3BTrPB-ldyB{k?43=phkt{rQOzHCTO@I6`v$54%AkgQ+DH+MjasdOqp>#< z-h|-x(aTx5&DWuU_3?O8eVB~H34qZ3nbwQDk&O=y^kr~#L2rE{7~M+l{I4w{ZX@yE zEabp)|Q0{GGbZ2LrAIw-b(n z7mFHKAcra(qi1OTJz5g3;>9{&KU6Tv-JtdenkYaaIs-hY2ljdnAjvqfH|wBvDE{w- ztkjUmZegK`-syUetFH28uj3%rioVi==S~>acAH^GJ|+zAbs-tcO=Fnbm#CtC)q4!A zk1xvmXxOOz%m3aZqK$3N0u8pmoJ2i>U}2VY_!*B}gMl$ZH9>;^R!vZwlm4hPzZ_ya zRQq%@5-|?@ha)PjPLMrNpBb{l;9MdwFt#d)@a%x zQ6vqyq^MtsZnpvWiszcufc*&+i@$9v_57d$wZWB^bY!QrW^(yMk${k%4_%kbj!6B1 z69p|C%t`bKcH70Udw7tjlR=tr9efwAace%M*+3uhF}lLyKS2L_s3iVhT11$+x4xg; z|G&0~Ugj$9j^NacL#Op(p+AXQPiKX!_=QkO-ce$k+mRX&49QT%Su*0UxHhoyh^UBd?y zr6r_z?(VX!C@_tbU99~Kw^L+HKf|Uk{1BTHBa`czW7y`GOGWmxMS~m3D?4MH8`{%N zHil2|HN<7??bD*2zXbO`UE%qMT%+UH>zZOK8eTrTn2PJ*P3-8_iRfZWe63c7WVScX zm3BfFTyE$3)1y4sjVlXQlfH$jd~&a@pK#Dt*J4cSl6l$|u5-b3Ah|{V`(wxH6F@9X zZ-n=q3b-76*}P!tUKXX9hV4(0D0y;gl3niNE$dS(-#w=t{RrQmaL{SxX#G08kiEXH zyQ|pc)|?CR`ToYne31hww^@SE1aIS?yW!0IKk)Y z`2KoC$`d`7+q%%{VZNb&m&|t+X-&aZTslv4?%d4%8b$_|Vl5k+t&gzv5R~Q!aXGwg zrfY#6Z=F@4Z6G#dZxnWhJhTy~%0B*a;08(2e0(j{Zev~j<632$ePhmAk{aQz{0jr_ z8=e1{5vEVUo!{+Ntd3keEV0kIxTJD)=6Yk7g1Y)?&1_C_aZ+VbEccDBf6S1#jx1uV z{wq{9rf}k1cfN(dPb*H1T^@R(rsDep@PJU%_bt9@WH za@zZ1Qu{^q;M3pRkuwIQXyb{Cdcj4SE^l@x-TPAgQmshe86J=5pb=45nXwqEyNL$0 z_9=5-d*ryv9S1)LY*qUI{%fS~CShk|4-6==Kzokhpl_PIabFItf1~kn<<5U7U6k( zxRu=9y|>fD19F5v?T9q^fuIB0GOh>W3DX|(Ju(#^`tDGMlRZ^!KWjLdM_M!e6m>lF zX(up(hJP^BILXrJZ0Fidu;PVN5gWTq^z_h|n-&thRy(gInEt@YK+jqHlPG7|Z(5<8 zwT-kYPi%ODe{wZ)>ZuUBsc&M)!32{ZINiV6!8;+;4>MmGUc2g1q^s9sG0T{IYvY!d zR;J>}%!lT+Atgu99Fm9T{ThaDbp52Du!RM2#TXV$S}A&Y`%tmqxUukswGl_%`sm~6 zwm9jxb?yRW|2)S<3oF}6-?jEM_~*sxBqROukQ7&Mbaw|AcPC8#z>*Ul&N80fkCdnAMfh><()`{ zuV8RcNs$<={E9yVk~sW7z7}F+HlXJUx1(&NUXO^f9sO+;nec!fM16QgxFT)|P2Sns z;Ly*qch>3CfV=VmAa(*ltkV&;-h3^{TdC5*Qyr|vGM#&G3F^b`Ftc~gqLU;kAAa>+ z41}kiC2YPhM~&SDLi#Nt`-&qszCtTyD~B|)VedI;VCXQ_v^u^Hf=4=OVQV#IJU1w7aF^E7q&4yf@rmeERyTq|JEuX-8o>UqnQ{o+NvTc=q5 zAkogsgQu9;vy0%g*T6;c5R;1-+j+b;lT7{nd&H)I#@PyjTAtBW*di|rej$i{N=zT? zp*%+k2iWH^bVN~3I*=RkSIUzimYfT8g#E+zn;-BQnqSFt9@9i&A-5qSPi${#t9U$F zc&{hN_33zUHbg6N_f||eo;h=tInZTIE^L*+4J%1y&ZTXAdm~|FLM`W&P<2fvT)%nv zo9mb6#?FO_+MGxYTNaXaclRXfS6AO_Ow4X1=JO5nsQZ1EJ%SzNjDz#&rh4-Z^=PdP zOa;g*o!I9=R8di_N?h`du^wSk>JsIKWWi25fD=aNl9HLp+0^hcZz4x;d8Ql#1gLPm z2Ox3z_>y9DbfS2Gcj+|kq)@n=c?TU18f3~pO{gL`P-kNechqehxAr^f?^Jrhj}?w1 zp?#V={T*%l$Nq9me`|mBw3#~lP-pJQ;h|0swHz1ATAiGuso~OlA!A;)=AI$@pU2?9 zEAw}0_Km;>IotM4JG%+lk89(>*6C(l@#%NhQr{$`$m?;;G|=-GV)$QP<#o?1hpkU_ z{Tslh^HgWtvYvW(fNrEhg zbmtAi5odgpoO)T0L*bhheEH5yYYhT|ur)X*9{&G1>8fX-tm6m~Et%@-V@GEQ%M;kh z1YL+Amar7dF;p&Qavc>BzP*rBB*`M*Zt9WKP~y|M^FS=z4CB_#98>-C1xI6^0X__7YvF7AT zD#W%Th>anzD2PFcCf1JzG;2Fh*82lyiQyeLYG?AfPb<9v`? zL*l50dT_ODkjWMjG}l6#PJatY%X}=?wS1;8G&&bHgOJuFoI+6G&aEQHi8zbGk6V-R zU|fk@hcY|lWTq9()KSx%=rby2X1*|e7t6x(6HNd0ly;Oa%mlyp5QecUoIg$xdF^$S zRoPi=zxrge<9!nk3IgR~RJSR@SO|`P^KoyH&(4y=zJJ5m;ydO}{P^F1d(PSxM{QRQ zpjXIn%Q6u%F3c!aTa~2*gvD`7hU1}i7Hb=*zJGy`weX zw#<~)wCC@yt}hT0^<}e6HsnnI$f6MICQU@ zV8?5bpWc%5er*tI?ZM%GaTJ(2fhYwxm#b&G-xpwnkiZNV3k;{bSu6uj%bRi(DQ-Q* zX4vn)PU)2VLP3Sr8iWcFsw(Y};!PV1<~`q-h6Q|9uw&nfz9L557}y5JN|B-w*kw-J z>i}}xwsqN?^jX>ml6|7|Dvqt1L1R97)lUC&AwWUCHDn7y7>6_Il+D4vt=a}s!i zr_>v|GX;Xbv>@Pc4KsLoSut}lRE8cEhRh|d-9TIflTGVI5L)Z7<(b3F)*4nlP7C5 zEbGEma*P`8Ik=67hn5M#ylFHOAC^(OEl;OZ%fv0rz(aQHZTK68%dMSjYOYi!wTK49 z(La9J=ZFheOx;tj>5+*y<^EAXBiEVf1YoSbW@%;q4d8uE!jRaMYOA}3#xpwe-+vngDjC73dhAU16TW4FL zZg$*0@2S z4u)xN#qSZ2GKakaMhQD2?BB3gz$oD}4M4hAlaXFU87kg70z}d{jYABxzbPo3qus`4 zds>)pLHjw2$*qW9ex1Hq9S^?%d!*j*z8SJ3lIHCLx?sPB*{*&_U-BQ;i&%L*!zb}{ z4S*F&oXGYnzDdS&h{Z>`^OtL$@lflk8 zEyu_FD!z{P9IYHY)m9wX!#lY9t+TtkcLv+3E?%*#;Z(>+7fE~x(30x?1iHXKQ6f>qP`toK&}M#g0RDqL`*ls6PRRQXVC9g7UxybzFwIMMV+WE zl@ztF3W5{};v|O4jMaXe2J|AQ;tfV1cs(yH?IxX_Ap6#r zEG~4XUfmvOFqDFp&pipuo+o_sYx!Y53r^o#7jxNYZ4%{HD~#urSq}ne!8$Y{Vexmq zS_I=@hM>1yFRF-|hz~FoCHJlNu;}V|V%c8jeY3fXgSxuf+QPz0`%gEa#1>{oo}3pd zY(bQM<3@oStmhZPdeZT7K234%eEi(5ZZ3Wm+ynfYaQ&Px4Pzdh>WAX!sdwQfK~#;T z{jJWliGemZ8uQ!Cu%Ki(y0UJ3gCW0BWPLOIeM(xRoZ9RcK|(X;YpX|&UsChrttBua z04>DDbpW+_P~eQ@nMkw`wzV|8@H;RlHgb#QEd`xgD|H3f1WlIV38SH)WgkVTNM@>_ zcV{%}RdLQ(4=2-(S$OQx1mALW?%`&!js^zn7$MKWIt7oKL-1H|aLnhdgRSov6QFd@ zy;#ZU49Pl3aRlKTj{Il%DmFE~6|$?X!H)2Bm4kBlnkB#&MFC&e>^t=dvd5V1YZN^g z8S4;vm6xp2EW&viYjxig&?C#5hS zoWe?h!b%W@p)nZKXot*qYbO7R%R*{F%v7@ zeiDY^aeHQAL^8XtkH!7LJlpH;;bTvIDmI4a*j?#+*6W01BE13Z-v8aR0X(8L38iXe zm$2ybNc$n=EZpzGvE)q7)0e-#tGOiIj53y`o6Cl_yu2ix@)<@U)AU)rPB`BRVnIGZ zhf-5f*RIgdT>+O%hh*}00X^1+s{z0IIlL7W<)#Qv3#M{8o#c)kC_lpN9Z+*IPNUAj zR1kq->L>umRwB;AwrxY7a_%CKYAD}8_8)S%s`i}kNm(MiP2r*JB557qr*fmoOQF;v z*~z7F=&rs}Dr9Y;lnVL&_^+gbG0SN(LjoA~1hBJgABaJY)5M~TV!c0OKF_bSZy(tIu07F?8IYD8{Zb4R|+(Zh2{J(2U zS<&+0{PlycaRQV)7aZQ8JiG5(E>H zM51K1phU6~Bo$aljwPXhBD}SW3bgIG_x*Z*-f@gGPOG1vd#}CroNLat_oweEO|?~j zZ2SX*!K^xd?C=>3=JyL2%<_N#dl~#ncHQ*Yte;?3p8eNu)=vm~e}B#T zZ_KA{MgL;`WXFBX3f6zeoc!+}`2Ty9&g%63)>ey+baH+s%E*h^+Dx0~UCO_~PnP9v zJH9o#N=+r2Ue@4ITYpZ?#>OUPW+pEGhxRUuqUCz5L{e?r`S3(dYpXzOE8a8dStquj zzOL@5jg3ZaLxY+Mb{{rCi?EdS@PlXh`NB=jiWH)6J)eq)-agsY!G^Y$xAboADw>`d z)e>X;-I$lJ(<&9{W1~-xbMMMQe|Xu=dED~EgX{jd)iWe<*u}-g(a{n9@0*xhQj%!L z_fqYeultoYZoI8_ZyQf*WS32VeZqXV#J}CFMMzYnE{E$)6@( zuKN`f6~%I-R&cgZJAZsaLZEcjCSGB+p#8J@sd|2rg-UB*XlCd*8kle|8cyt!i+Ydk zOG1y``#xr+7Az=KyXFyRTlUDn4=JyiuOGWdUzjL558xb~opl^_P1Y=W#j97Z`oz|p zi(h9yIa0G@-5(F5>ihqPvmhyDo!4QsJzs>>^mecB82J`=de_5U%1OE$SRkmJHZtNd zD+y4T_0-jMNl$;A*z=q$!hwqElSW21D}_`B#%K`XIKAEH9JTG%a>n3!mFRQ(i_j6h zT@Pb3oJR6iES`h*TSJMX0haq`J+1oV4~$CaapDwHwMs}u>Bp1@(S*D-At@>U^L@8l zi>B{zd~Hqj9{5`a2L*UqzZfiCGv8FMGha44np zOsZaD&!fNnE%&SDWzPRt&5kt2$Ohd#7uNaXSG~Ue_OEEkRWog@t$^X%qoA0piKYMhAnTV1DNmA;X2%>f zG@O3gg}y^WLjZ1T*4*88ytc0HoZDx)MF6$8hD^4few&#oa&KGwPiRon+@I=l8q*sMS^RdR{L;!RWeNWode zcx@XKSI@DYyQfV|bW@EyH8^18AuOsD<;N|m54a!YB_2{%oNXT$my?qd+dLi4!PUv8 z6VJ}1XSp1<>M!jX7?}QqPe@JVmt*YdHB$W*Ou1S zFnhO7i`DBmF>bd~zqjqGl~pXH1F(cQk+f<~e9>+8?C z=@)V+gs|o6=cm6vjM~$_s)9DlE&zI#a^6DNJGGFu7pmQ;cfA+Nr0H5-@71J2*%be* zESr?E2V2xRVO(-j&B8)y`g{G?$pQbGx;mp?`9q7sx9m>H+=z3cmxlu^n9_LW#mU#% z4&U-7v0T_krI}BTEqYNADSE(PCn2KaL#z84JBPQ1Esm{Rl;q-3v&q+Pznv4}q<|{c zIq#XwIc&jBW87@gj)y1WX}sm3f;0&`zfx||OKk0g?gFWN&+@Eb~jHpbKZLD;-G*)s`IFH z>eN(7TyC!7_*{#F2IyRtA?YVCdmz1wO z?nMc+AXbHl`>IP$pA(_)294uN^YVgvxhfNQdx%;=vaD^ioap+>Fdm&L4|q0u z(X$^dmai_EwW=?f5Kz>%yT8r1U!ri^ka5nAqk)#?mxS6LbDniOZ{Y5(lt+!n^%d*J z<(@j0kEJ~>O}&0Z`!Uw$stCPDnUl9Y+hIac_`!^LmYjDMWv7XBT4_`+$FRr+36_Gh(A@=)d}!t7W^5E9XCvOaePXS_N))1 z`d?P3Q0(R%MCc!Ha~>{uo|S16yu2Yfc!`PNiF|=`CPM1nRlZYl#zKs+eGK9}>t@+D zx5U0Jyle78cXDkrAY;8wNU>k@dg9A9fnfu}?wm**v;T3{0HRiko9=9gJ+W3#-)jkdqG0lSN*tb|E+uj zBr%?|aC^SzQ^}dQo|-^v@skhnSs%RX)V|z!D>Z!EN;tX-7H*D%O+|MyXkTX0<{0>z zp*Svk{9dT%IFEh9Jp;2#W``hu<~f^VrMx(3tStVh02B`3!ST77E81qAe$V$q&V>z_ zwR2c@&!u(##VERzZ-EA}GozvNmaHcd<}-q_9ApX+@cr%E;P`>Lrc06C&>?0Nciv*yb3xLiz`;?Q zl^&d!EqfMJS&6eQOG~xy_pfQJd+3IBrTiz`#Z}vIkC__`Vbh`^C=}x9!PIIq{*LOq zaq(HJK6n>LuIMhVXfP1~5p&;jrQo6$2L@vsdC?ks=hB{%yRN?tbr{s4-anFc*zCgy zjCYc=#(X1?GbMKQHbLFS?$W@MeY54gUrZrrq1Pvf@GNf8++P22%hcMnx6YD0cJ{GS z-6J=w*Fb2tdv9!ZAHA*OlF&^KN)Ud#LJx|xpAXNVHvV-pJ}X0}E_Jf2G4*>Ff86sN z1sL!mfwSxZ0%ERxDgG|xd57R3{Iyb-j&5~cQnpka-Gl!S2dD_YJ;{#~7WBMsW$iZf ztf#L}Gd~)}srNQ^r@3bIqf(XIi;B=$eb^ehWH&jl*{{#{Umw8r&HCKFJy}XIFs;nc zJ#uebnDwO|PF_~qc>(|@>bGtZ8f=Vki>T_RboHkMDe{unLW)|v;o>aEm?B9to!Cc` zEB3d`6JX%*jSXKq$ekKeu!JWk-YrV^YCA{XKd8h}Ns_RZb)dG5O+1ael8+Z_lDS`E ze&|-%z|HwZVe|SHJU@r;_$#BI@};WqSbkDMQebmeWzZ1^FTT3EwS2osZ7MAO+SQk~ zWO>J&jFlOL8d7cI%`mA|owqpjv@k^NDTfM9tpWC`$?NUKQ4o9m1BGKmIa9mz>g+DY ztgIj>;z(Lg$-x_I_*}%Jgyf7pk8C@Buk>ioPL2i)o3gATGeEd0O>R7MS9I{(wB$fV z-pat~oE!*5!*(_Z$5aU@)~qdbyL2e;M}00-nP-M2AIl35oiEreqQMtks+iqX z5oBQNw-lSR<<*a=lM@H*I6J>O0o4VlKFA#Y8s-+U?YJSncsn&saeXlZhi{TOMr4d` zdPWxM1Aiv*QHXKi!6%_^cyjGd273V>i_l{vIU8y6C~O`jT2llyVqA+z!b z=v222Xu9pc(u$RVUIM13i-!&t3yi=CZ$My;tA`&UrEKC+05OOyTyh;Jrx_H)l& zx%n|KgzuA-G6ckZ{br3xa>X-3#zIpb04k?`=YY!G697M=r&V~z&B)v{i1p9w8VO?a zJr4v}TYtPHboL%+@d|st$7fCs-WKiX4KeXIO@+8YmBfgfd*ydn4?L%!Z5Kmv8~xNz z9l0%TADbaF?lsVJn)(HJ(Mi`3$gW3=lbnw;%^HSKwoQ2DV8=6aa(1mRkK#d;%K+j7 zc#hoJyjnnhBUhr4kX>F@k{T_-))9~JMA3OrGhgH0Hggk)%ZYl|t@g>Tthyw$avM9kge|ep#xKp7&vK`Z z*U816-Sv!I^;kvxT(YI#P75ulsa785JbM6%Fm1{F^@Yvp+x4}gPUK_F20|wr2Um1J z0UJ`P!uOFAv729)E4mcJvYA2k5uYVfhhUh$BlB(A0u1k|=H$b&Cz7iLg77xRymofY z8&dZ@S){+E0=#c@jrDW5>^bo20d#yjIR={^qfJ+wObr;afC>?4PMCyEjLO zXyo5b8o4-*Ud$<+_oxckT?woUw)5jP#-l9yiMrmM;$#`$1)wgasrO>36TUAxAUi=q zkOBj9LnMO4Bnx)HARchG^0GUFiq4Dz7Yg0y}?SvWHsF5lMxZ^TTxZGskOB=o~B(H z#V4k_uNWwIZ{zYqk&B+)_3#AsN5n8984~P%?O`=pSwxc>hS9dK*HyD~eFqy>AvuKc8qxgH32Zp@&sC4=>Hnn!Sm;Fqktr zQ1q_08Oq7*jz>aJUZ%z7=uiAM`xoAq#auiiP!yozAk~vpiE3d=Q(2)9HrMlF02HtH zJyokXliOQcPZlg}9y@F8`mL@*Dw+by?*8n%P^@7DVN;km9GmcL3Q|D{|hNpO}!KD62v@Rm$vav>fg^ zmLI+EqQ{JBkAYooeuzg^#hlM}yra*FIzx6j0{t16g2I^+D|zCFnDaj){1cT*{uOYLWQLJp%k z>3)*%!I^z5Yo;WK;XZOs7~9f-rZ0 zja4Hi>FH4cZMGhJGYftk1&L5gAAO+_2)IT8xep~^j|pd;*PMo?MVPK}u(zD8@1y$r z@wASk!G6)?)IG`h19XVPv?zNJd%kp`7m;k+Oc%hbZC{XnnXz1 zC80g9+4)1*@~uN_qWD!^1@+sIa(otO3@^uuhxQGWshY2QlL6>-X>Wf?I0RJYbH z+z<`#b0+?Q8`fbu9o6K|A1h0tXE}c8vS(oH85qxa?z3~-rLPrvB3}sWd~#+W=m_^YwcvfbaT zCA7w~U=`nE_R19z8fqFh1S_S=$STuJ9i5zBkhSF9O%bF>ztBQ~;D{c=Z-Woz+5%0$ zs9G(g{K!o)_Q{qZ!+nyrIYZ0A?*(jq$1x;V9uva9kvx}V8^q-@d_2FR^Sb@$xGu0= zD^o%6ZCo^n>#)<1GQm*;vlx_b08FA>d* z3|Qv+7POj~n-nMF&Xxs8W&`-MImBO99*+4|g5L=0x(EP#vi z?(oqMFOwe~#dwy@UuI%5!K)t-sHAWP0%%8H4sxRFjXy(#EyxK~PHxP-1PvB0hZWFL znm^&_;_`wV4P_l#@5*RdnfsoYc}~M<47pUs(;pO5&0D(`G}y;Afhdop=zU@gd*WX+ zy6l9GF_~PfCuF0miu3r9o~ZC==!xHEICg1FY*3`7ueV_9pOS@Bw&1zdF1B@Gv$hLy zBFIw%dg8f-iJw}uhe%VC;+bL5DA%Ji9*y_1!PNl7SfqheyU3oPCyJWJK~I2o9e2vG zr{~G1UaL%e`KepFae1{id%&BeqXqW!(NfOyH@gg+L`7b5?#w-;iTPw=A@?yR98uHb zU^6&K9VvNXTIQc}_{pi0`B=bWM%*G4w!^cX9Gdog4oo(hlE1;K9=nF5l@2mYP=4zp z$+t4*Mo#A$GK^q%kPTd8zL0Ugr~-g(`;2@}M+a5$yc#QPgBZ5XZ;Sed)d@kH6a^VN zYUIRWuGU|t4=T;oI@FMB?z&;Gyr0arn0k|a ztt$X%WNaxL<3{o3B9Q+em zDqPM(Cm6M{k(2Ap*u+w)H>q176pL(r4;xXfjAA=Er43qzGy1;(<;`O3<%l8uA8LZY z(LV&i#=r3xG@4hKSNS~~?LKUyp&>%Y?BWo^%pvcfO@YhnlY`~R&Gm8gvVzgU$qI^N@pZbI%!8Sgk|qTv#_Ku%E54B|RJ?p$I=Zo!iVXbl-hYgWCA^D*xw89n6MS zH5^un1|(9&b4*OlW_s@&5;0*<>M6y;vNpc;_g|bDCIxN~0CRmua>1B8 z&{)qfd)f9J{s)cu+fH9>k#%vdt*?dB=E7z+A{YHR3icjVbuA zY~Pig3V3`WhP^q9{;WZGY~v~`YwIbckedUWQ|s}cs28xp{3Ix)B2_lo5Vo|}WwrU6 zU~{Ba3jiKB0~-w)?q9&;vQEgdJ*PNx`;!iZ9m87BcGv1dEgbmy63HDm7P)qzvnE_dEIrK7)HA!k^tj{Yx&yIoz6zP_Fve5s$iQ^GLsL1^LC z>LT3r#v9r6N7$#Ixnk0!*dy08ttyzMdR%t$a38>#W^Tq}*DEW@tXENz`7!$AOz-mQ z4I5bPMb+iBRw_5O`;`v0w0quCXO7%#8}#ClxX*zl(^;-^gvv^`1W|aIGd+#-Z0*uZ zb5h$UBeT6r%~*Q(rxOf9jUQXm^T$e7-z?^4sd-vz#|N!g)6Veyo?X_a1$M*6)UP)h zsntaHt@lfxeqIxku!lY1)!)kwdB^3&?kZ4n+%FXo5y8!+Re%+Y#EQ91^hBM&5|T?e z!yrgwqx=gKUj}BWOzwZvXl)9IPNb;T$L$07WcNMv!WcbdBT%}TMny%cZGX^9<1BfJ zy1MOMDS~_VN9kv79?HIQaMvs*M_~!;0EFcW=ix?v$+IbbcEJK#Lr^tDyDEy^I z>cTZr=PI(|;@`?k;af9=V-wT&+wv*zg0aqMEn^+ZxOVGuTI1Kbx#X9I84_Om>1L({ zCeh^6Z!B$G(22p4x47WU%a?GLRz^? z(|vPJXV>%3Tm%zN`ZRsL8%LtN{q*WH?DUu>jJGg~vu<}+ z@Jbe2S;-PhvdF%W`NWy=xT8nUU$HmDUcChCHaW;1aQoge$hGlEF3Q7jC;N$(DdG&l z%QMcA+7jx~FvyHs=S4O%hSU@+S&njTHQr&LRCAI+R;Z%W^>r1IYi=!F3bAPav6mg= zvi7mCH0r_eS2$WnVa6_e|9_~|l;GV#3EnGhM{P0b0_>HZT(yxuBG!B~Q}3<4Rju5< zZC&160&A-ttSkPHy_t6Ja@A(eTTOazYGH#z9yJhYqMF;y-6whkk2nYhHF9bCwX{4w zJN;Yr1ZQ@<3fITsC~ZWAA+KgIyFd( zefDg-6#hfc>C@-*H#Hb3ZiS_L%E^eemmt~lI`Sv22B-JC%pElKIyLV_CElBoqE;Hf zc#9sIu_J~xYy0cwY2(v8-i7kvp%rEQ>qmvc*Q#4+1>cyNf#F`e%!ZR9t^Kak-jfb> zuO{2S6lU$hlQg&~TE+g9R|l3f=ka3(z1gFkxqrK)gb^+4ruC}=1AV8~e7Iebw!K&i zdI%^81$-=!D#GK2?-v%UmsxcXP~^VF3ShH zXNzH-xzoZxn!%$@H(j`qc12zv}h^>0UcW8at?<)x0!el$<>or0#18l+i3 zp1B?b*K(e{5IxuR_4Q3V42FqT8T=hH#s0oi@0Khl-dFD?E*kB!_J~{V2o)NL0H07jEZJuR9C}O77 zggG1XDnd{hYZntVlM0?}d6d$&Hp9+3xTNGcapt4d?IUQk{L%`rypGoFo$08r=rR}- zqFY-MFI2hBoIcja6I>b1BQ4U#4*@~XdT^dqF!A)<_DSp&1psAjn!LQcl-cKe>g0R* znlv>US_xN9aIZX8c2U`NF4E z8P3{30Z7vUx)4-yk+ZM`4N$9UzGCghsd(u&WGqD{`*2?5E2ci5_h#`5n}yX=Y8cE@~q8k3SQ}7;(1R zAUVW)wVLY@9S_%@Yo@Yta-!xc*YHZ27o3^kYs5*i!TK zt1>ksL_O%Fv1xV=Sl<2Of!$#;%3WH~Yg?~7z!t{Lm$OsH`CBtI45mKyeND5&Gr;$$ zqMg5Jh`5iJr`wCqTo^Au_NLISg})h>;cRBzQXm~39>M)n*f3ZU`@LdYBPvQVU9bVV zSL=&mn%leRv_bCe{#_*x+=qNlirhb;hB?NGa$muI+zym!2`Rzb%yT=tN*>4GkFy*K z=rPs{h3Q#}v$N-n1FQnBcf2ljG_E!2lNO(xY}C%3e%}sxrvt}M%5dV~fC$U2EF$%K zNBzr$6s>X-hjAUMV@+&!CvE;73R(u|VeMR%W^T!I4a8J#QSLP59GBqB4$nzw6hNS` z} zEnTgc&8s+XH3iH~z4|5dWn;QbAOA+~QOHJLR1&<;P6db}q_fj<#6Pc)o`!REwei6J zIBS||5j=ES$Rt7Hy%U;$p&j>-iH@?3saY!6iuY*38uJ$6=NP3A0gi&`2 zDI!R%HfGbHqy4bQ*p@ls3QWQ!_)aN&7o87}Ge!$TU=WHN4T^CXY%rZ160*6vzEBp*AuF}yi*ywROV)cAY$r0f1x1=mp z=TXEW|6)Z=Q>5n_Eu;qR`xVxRpkDrs>|L%)xXu&HK-xYVA~vIdDT|4+{9(jXNQ=0 z5dYEO6KG;O?1>HP$wmYY4&&E7OsFs6vcR7#r}ckP6g1f{`kd^ddueajS%rV8>YB4x zPSX?U3YA8{UZM>AE#JxAQ8OhS2cF@{xVEf>W8xWYxzPyW`)o0Vz<|B}6nFaKVd1uljD(7$#QrH-iwjJm9 z$q8oDCq7=<8}Il(7=3oJym`CHCZ%;~gTlhVkaL{;<+VkRP+Pp?UdL>PonItr!47eW zX0$xNWPvd^LV$!HS(di&spPy0fE>4guqbr zu$M!2=&1{zb{s&Hq`Z-eF<`j`-NsuZDxbd5M0b|3CZ#%C7hz8t~ z91(Kc?D>QrE;HX~)E8>&Njf)|Awj*_i2c^2+Ul=-39`0<;T6rX1y7`;u%=(DQTbUC zEP!BjvnS`#5wd7BqwJz;zu->GcN_DexJsMVKcEYXii)CDd&nk%5osg_p)fH8rQ_Rp zQiS`v|s=t ztpy0i46^Ib>P}B!Vg$j?o|!LnrgH734$Z{lPOscpT?lA`8H`{Jq55*2+&fYUmt`D!7ve;fYL#QA4lR4B(8uvKn>x^u>avL?b`@bFEJanAO)1tj-sMO2vaS^ zhHIlwfb70dluT0EpAfAzH8sma9qp6~u4#@9)F?xARY~l!&+&JQs>oo!hgOsdn)4Ca z2#xY!5G=?z`Y!VU(Y)hH)~cz#sBdXm+u!D)_^QFi4@>}XY&P!O6J?mWXQ-gF1cg_C zGq)>)jak^Jl*FI~$L4!Ci4yk3^j*MmVXUMiV+`zl>8Q{qfL${`(e&wSzJ*=F4_d32 zgVI~a1FVQe`m-Z;1>x^_Q$?yX!r!YW%7Z}+K6tnu9X>;3;i$qMt#`;jR0BDmLcQf+ z%25r~^6auepy`*YVXxgeR?xcH*yni6!b^!)QZgk_K*(#;FO*h{6?)oj4*~~aC$$9vTSA(=h-O`=2S|5LPu`L z0%OHlRtAJh+gx`ntI&XLp}Lm!>}DsmAVL4`T?wX8e==}{tHsk@DfN=q81OP=BqoVn zMm_C9$a{70_Sf`|NK0GW-KrrQC1s+I5 z@!lWK5#Jkja+knw7_U{VVZ>+*!jU$lvqt39xEX}y`bC8FMqWC0fv_-zx7g_}f=X0l z4^O8&T4|g9!@|Lmw&G|%-r~AL%fJA}5Xy>K+?}1caU*}6`Ik(+j4KAe@VGG7IH?{| zu{?TC+1Sm~X_022eG8Sje1@qR+OM^Py%yAPWmUBs8+E$sI2ADUgTFZ zk#ZV7FZ_9nnS4bMV~1?={P?O>NSNy7PgPi2TAwTr29r8Ud}k2VjD(a^`w8|U&*=_( z&1B)OO!XlTjcA<`rA)c&nr7Oygmwh*6%8SIA8U!*@soZ1!i@TNlhT9GiqcYFZ=ftx z`nl2i!cZJ0-m?~NQmebt#K%v^%B){e=?Q;eSrf~-lZBnxHuvVb#^dR4CrvYvV(7VX9{E=c#jqSxUBjB0D(?v3I>Rsr z6GAHD{(aPBkQ6l7qqxvyfERyay;vbNt-F$BaxT$#aCq1cc{b=&f|9|RO~SWVG4{L~ zn_41IIXI{%x;vr zlATMLca9^8E+j2tVSeUb=u0%enwfQJS*s;(z{m8tFp=ywhvPNmbAid0*gWCPXw0PK zIv++zvMNrEu@2Jgby&R%z}G;?V-r#gz0wxkqn>o~O}&2BS%9%15^tsN6GF z`9K0_1Nl&z*eivfe$ewMB7*T^w(Hdt4|PFsw^)K1c#8})zCV;FjuwV#;IKI+kn7kCVNev7LJ3QOBRyZi*S2}U8h-!qAJ*(_TgpXd0q>=Qb_1UVYQ->hdgZd4h`xDH% z)qubX!N6KOUlpfL>DzJ>+2@#2)@$4Ufcs>Abq3^shx}Pb*$j5_`0112l%Wx)2eB6J zsda;eJEgcUe7`g0l4+(IZ79{cax7GF{I8D{6{xPmB(alur~FUthS2L(0;n%gljV|v zh;gKhy%zkr*QjS^oW`et!CEb^TsdCe23(Kw&Z!~j7U8pV{qmgnM*d42v@+4$3e_}#rP)Jyr;NCVhvyP?rWEH!=&0~9RK9c#;Y#}t_FKzho}@~hvuW8V6Onbq^APwq zi1Qamj7^}Efn@r3aJ&GDz4{zYGj)Rn8IG4n`y4A|Hf%NN_3UT%N~aGqwoyU8JKBDP zOm=t+tC`|~S^`L{uC8u62VOJ+w`AC|2wpk;ob)sB`_>-)tvH*C+xzj~OijI@CjkEW zQv0?+IaJjV#@K5iHqeUSjJ!%=wczdMqoY4i8Ei%^zjFFcbTn)WO!7(=Y)@`zi&o;1 zJe%Za6g_xFXKu*AHUOO9fP`hMtWlX{=*kN22sg-5)8gB5vCd@^zhW=K#5)#Z&Pgg_ zn*{LZjrm3K`|pPif_0^&fIo*+!T0aq5!DeUKCmDD@Uwb28SSX0B#U<*8>*9LWG|LA z2uD|>9-vkrL$@()sQ++55QgmI#zPU&dm1wFj9J)vjNXt>{mkX&eq6RJ{Dm^aw(^X8Kcwv5ajQ>J=n9HW3`C8WYrbtk9O8RpuF_|d^% zIbIkewxkv~!En5WK|J(Rywk8EUG(u@0n~7~Nh5Dyau%lt*l(HS^Z7!j=QdG z$E(MUwaAtvVel*R0BVP@=DkrhykkxtQKLkX=)SwE9?q+K^*u_fvM^T=1ulc(;CD=gfbSQ5z0`|x&(%c zO{^M70NZOvZ%)(vMIV(1`?`=(uM?B~m>n_ezeOxB&sJ*w$<9>AiLo6YtB@Ow;WTt+ z%tf{4|HLQj^9XrN)6R7c!%-Au-WbYQUO<#Z$YgoJMJe@QcZtc_2G+4C>+dZGOm#hL z1d}>IS$5RVKbrR2GbpP{koqw%OltHmmfwZBvy2sAue(1})*#^6pgFP!ZP1pE956MoxIu&5iv&i~dU2Tj7wn%SJT=b=Np zO$xVPZTl(+jX~e3yA3P-kvk`6?ud3!Og=kxw{CSFY7&ry4X=%Te7t<3w@wTlIWj+4 zAcx90^sq8Zo%K-AF&ku^gB`Km+~N9l(~_s|9bomuLOYBRhY42U8RM_uKIDNw-L4=@ zjM1d|`w1mX^%_=2I!aYkh%-(HT^)R$jq5#QI``_`l8(}6D>{Ie(QyTg<2Du*8hr#K z26b^4tQ*j!yQAdA*H?yabakyffx(Pu=RH{PZgL3!Ym*#PeV4Vqj;8;6lN^H)U?~7q z(FgyqyZ+H6$2cxy4L7pNf-rN939FM4U*%EH zp><}Q>hd;{*&nq_e_dAFWG+fGRST8}Q2m$Zk0~tW78JkJvtW18-UDG-xs^w&Y+pE{ zguy7VY<9xxp8umuj>-9hJ&5mTjEwU1bERZ$+cv-{Gv6ujAJ(9D1Dv^GOd!yfR}xz<~-?#OJm<6V}9W@90rrKmGx@pp?{q03R93re*e&|TMMsdr&^=} zoUY3oo9_EMRWk%_r2u|@bm(a0$)P5s7e?k;d&trP4k($9Kaw-+EJ-@8YZ4t=*wvRn z>5V;NUp73y9o1Y#c-GdiR0CgG)HpHO*GyDX#N6F+SP(h)(DhIQ0}e$PGtbTn#cRK4 zH^ib7N=(w?babvQHA1A7WF!>foW~ED4^dMK3_$qnRr`_gUiPWA_CNk#w8=4dSdrL# z`TyvWV=R?f0es{H?>OOBbeVWD+X(KoxGqu^=|fKewEQF_U= z$kUugzH8Ow)l-wQg-7o9=SwUQ%FtpNY# z=CUz3WfvwyYqM8pj5w3k_88$G{8=>2jqOamRDXyi8e#@nI5l&EAsV2H@y65hpyOa$ zAO$;)59;f$aIgSFaAZGu5LsTPANWt_UUuKNPgbN$Z6*Ik)NGwhHDgTeDN8!F^WwVW zv^qLb$6<_X;anG#v&A3o5Bo2i>%w4qSqN-->;GtzV+dj$^JWc|H}VpPJ%aJ`t&Vc^ z)mv|%)3vpG-et#T|F!$ZKtlD#D>q9Y?;3P)uk3uQqGK6(!tisXrQD~W&Hvs?@jGF9 z>HWG}w;rsE^|5~QMMHAlK`K5z>}2^DmCs!HdBzQG{#Apc?qufiass}+{Ou@}{;=P) z477<#v{s&wyocU{kcTCA4lIEq!mx}+tY-`3o;;C)-lXuWh5|uEj(NjvFI;vT?UNgN zJNpPu&SNm*H<<#d-EM%KD;bpposA$t^*r&N5`L~+T0v7>T7HyR_`V5x)|>TgN`bPo zQdENe1|j@Jh)8RjJ4u}SJ=PTocJns)C}cY8gNZS%3GqpRy2hYQvhsMGoW^}=hnB4h z`0?g5AB-B#w_^y8SeL-k4W>L)$mA)|CVIT0h1f`3TfSApWO3dGsm{OLw}zBmezOLH zv20|X1Xs-+gTo7{iEtVf%r$D}>(`qF1@R_IvKB`jds}wG`F)IPKkN2o)59+o(2n=Z zNF9WBd~}s4+$fh)iZVX4@#gZ?aB~>Gos+{nT1{|%Qt)I;yEG+Gh4>ABQ(Jz0{|>CAQ@#qc-iZ zUAEUXw8k1AZkxY>y48|(*H1M9?lqV-(}j+7esZGDhNbz^lyhDDN!=9z$7!vM?=l3U zSF`TTHvLC(wV>Z+=E;vNfj?H5HT`EfB~|`QtTrhKPTE6d!}@$d^{Yq~cL`&?0tK`x z-$$p2jE|vctApFJWZHr;4%YW+R1?m^Q57p$JAYj{>mYTR3}4!klwP4ieTZ82R5T+o z)47<58B;eknN~;~trP3`=tAPQQ*_$xs|J-=BbPECjA-FuA@;+QUC>+3e52qz+!}(5 zDC;zxX>}n=3Wf2*OyPb4tlb=I?bZ*U(a^|CcROT_vr^l)Zy&UG_d6a#kqbQJeTgyR zLRS9xKZMA^CMp@$O$wH_sM=1Z4K)fsDv##j3d)y;&sT}?{{{{M>uOc{v1p)t?_Lc#1@s6zn2T^#p6=6nc)moD5Op zC1%XhW$3by6osr$66pUYCubTt^*AShFZZeIlv#)^3B|bQt}t9B079j)W|uJZ0qeQG zO45V}I*Vbr=C|4}^pvcwmOtLF^2dr53lAS+POnJEVe(@Q?m4vN2b!Z9VSBIaQp~-= zLM_~GWW7*n&{#hlxnFb@@> z2r{^8`uSTbqp;DqwimipIMa6nd@eKr#

DtPqPJw;qM88cs3T`THpl2THk3YszHs1NJx2foJ>o0B6I)p`f6 zNO``WJ$>pF+*pAjh#g^u!BEN@PDR0R8Lc#Q-%z9tEBmRd%Fos)mytZ}CsGqYdr=+cbjTk!(BuK36iMsz>2<~Dh{K+%3LLSaR0YwJ^bYF6u} zLg<=!y3?*QB6glNSdBA~Sa~_$0#Ty9Oh|yi?zOytcE!hU9~fzKO@@_YhZUWN{Mzz! zL^M6{3e-%41_`RaytHZGq`NReV8EXCtE^iy*dEvlq&Lu!pDB7rY`$^hMySFN8RtPR z@A>>zn=!FuS!Ujhv^|zb$9NM1;TZ1*Kzgdz_mPXIjn8caLV&Le07$8`?itM;I&{b^ zZvu|-=Fg31gX2q?mGPt#KOY%29k7vO08h*_)*#lbNp&ACK=@DqqMVxfG<*L70&51a zh%24-f)2K)*#Y)h_A(c(TC=XU{^)oP9Es|m zc$t#&&yZDbWQHszvb1|Nb@oGWoM~~+ey8b^6i?V;9aK2^@nhDE5jEhgm<;BvBvr*9 zKl9deWgK1!4p*{x3zHPcOoyhwfVYbMQ=lmXEqO-NYJI*@$L@XRQ@Wg*{%quCGNA`D7$ar*}KeV_1^-LfLxW{rJL*z(**n-Ad7!m zU+(uit%V1DQ3#j|W5e3^`l(f1n*tDXb?SNpXRKRa65!hr>p1bDCf0;WFW8m)u3;L3d85wydx|$iF?eQ``Nh7b&R&{=|jxuFW?>W5y zeRiyzIN>qYJB0I^S`fp{ngWU?lrU|xuJ6>EC$IM~W;e*5UG@jKbuRr-2OYj6HXBOt zB36mggJ!AoFnlBkfMagqiD=olYj8$eOkN^Fu z?v6l#VUp0f!u1xFky?4ft!Zix#6tx-h6{w5q=lJuVFlvA-w;^QvFFb;(cs`C(l3sZ z?%iVqZG?3XFJ>v&ICL~UxcY#V>75ITn3wl5Qotq;wxu*?K~9W(U`FB^k5O`hzfOu> z;6wOdQ&|Z2a0-7lHcJ1^{-eR0?xNXY=A@W;X}DczhFV2^|D%rD>U-Ze%Sge+@AG*s z(%A1Eu~4)z!nTbGRjMVc;bOoeowE!(5`DezWX|xA-d_B z{~^4=bhLRGy0#ECD36Y!s9l?FUzl45^B!JIn2fA!$#b~17gBHSbMEzsGk=ijDp0)8%1%x2)I1?>OP-&tT3XE#~J12<9U& zCzzWK^_>vb>hr8oRzQ%+!^&VbZ5hflmm>SdRY{W|9{wz1pN3sYC!DmWquU%`)K8ef zmS$vH`zPk*+ajJHLnOQ(uZa;i2|lipH`w&d0RhBG_mP4fJ9aP%R*Wudyk4<~;9%4| zogzdTh5ILVEB^R{@`O$*=@>OXnw4zC0C?3=CSIzZU^M2Det>q+uZT-^l(`s1!L?t% z^6_WpLuX!&(U~8n(|QF8Juca{K*i4(@@7Tm^d{Fpogq|p_FVBdVKr_$bw7Voa_w;` zeAD+G61zSje8)60XQ#^T;X=7IGttRIt%;t`I8LLrc&X1^UASMwfZ_H&=4gwsr+~V^ zbb(vvjq87)+*Igr$)864j+6lf>`pVELKB(uI1 zG7~6SsIUo@ChU-Xqtc2c!SRrYRAlfR;n5*xVSsn)YMGjBO@Mw7T@k(y_fPeJ5f5HK zHG*>rXs-Igx60@=8CyM|I^U(u4L;omgRp$d9C5l;E^Wx)LM)*J5Oyt!nc257Z_}X% zz5v3$0`Mqv3k}wyle~7u#%pq&hp&8|oi(%d7lr%iWM%h#2+uJ3T&yQgXxP}CO>$SR zxARnl&wFzJLpl)Zne~op?j69ABrcVpPY?SkwY}0H9dZ_=Ln%i(VA55XE8LX#H|cQe z)>5h2cOV_!eu-mAhnR8Z5?7luqyyXswVofj58vnZrNyZQ`Mh|vJE(uz7+j}?F()xU zIrj9o8;4kD0SK}$koYQ~p3D2u^gR2lb_5PP5{^i0%D%f|o>4PmnpQI>Yx7AodUktM zf-#R;f#M@vbG+H{-H%nacbyFTlO-eA$|pwSA2OoF$OUQ&hd2wGEhCp>Y*?dzW%MfE z7mxya^UjCC-TfyXTe5^t`UzlVbg=hqvc8Z-Wt4i}a9y1H?l7#FNQ<-x3y>}8tR+|Y zg^Jh&Dnf{@B4TElU|)R|$q1ysoITPLj?=Pc2cju(<7W>WkgHXg_+|+gJNnGVyX4G@ zOTsT)<+pEub@VUWRk16aoe2j zg7(^HZHcPPRSjH~j3uA3VCItke~^lB$rHlsjq5*F#;Z^Zv{Ir@XI?lLP)M(2ytk;0 ziLvdkn&JB9?u3_q0CUIl#CP=phiUl$haEm{51&bdRBHET)?(RLH6Kr_po|zEo=!hb zGxM5D!(FH5WoP0G8O{VogIQ#5cKBIE{3Bwj+RTW3tc9yB8ztfPZBV4rLtJx)L-&qI zWpPxtty{mIp$sryE15|dwtsB=uHL!RjN6lph)vCw zHu;jJh5WA)^2F#u80wg&%jTM)d^)Of7YbqsQ|SE2(@@&TQ#OAYvcCJ_Rn36ogmWc; zKhJ=_7&j{z_l*)3LZ;4qYkOfl_+OpY&J&2a?M@C(5Kz3q0LQr#4KG^4{+1m~f#Mh9xHZUYgW#QLR>h}q8M{d8?4B)rNdUK$tf zl&GuSMmA|KG*NnMX&dl%!2rX=$S`vv{SYvcFY>?S;1meidG}7=TVI6yl zhPQ@k`qx7KsPa4XjfLT;buy`NiT&3kmcD&qFB4>Alap0Yk%IOI1Wkm@mG>M!ljG>s zqT+Uzfl@KzOnyoKO=xz?q+^PCq#-L(!8rinjF?!;b=3R)`vq7vU|K|$#jAznH=@D{ z9f?LIF@ng+PGM*RGKq_j$^1HC^&gC82LJ@4L;oxP3)8fMIXkg?$p2ClA~O81?n+UH z|Aq7y)un9%OMg{IF`-r87hNz0v5)YL*t}XmftYx_!;G33UjwEmqcpD;WG;$+w)TrE zq67GQt-Cv%+>c0^Z^o(~Qe3)SbXhf?}j-Z0#?Q%b$2sdTMjkWojl zrB9I#I^c`A0F0%3ID@mbTe_6?Z4nHU+RjoE7?$$6G(e0W?#R*+>$r)Xdkf5EyFs83 zzEsdKHuza4J9o>RoKj6Y9_i&@v8pvrR?iaxFF+~(>As_ZeDJ+3c($Fy z48x`Ne66{4AcRGNq8ZGk-i>pdNDrN8XZv56%>vAXkXHDKxv14kXvBMPa0OhTg_(J6 zWIc;+@S~E)ZUBdc&&5+_!Agn+oqv1fM)(XI8p9_hL>L}m`d^eznT2cY4F3zZzOVam z_JXJ@ddST7?1TT15ks}dQ!gx%5!X7IS>_cxtob;g?HnBNRar2=W|fd$ot_w~TL@Vf z^R36?Cw_F|Ix{L#y8>-a>*_}1u$QWfc1Vf^0(UTqeT=0SbAi`^Wxyj@00x*BGQiv$ zlBr)G_ewd<ftE0d9NI^Pz~_d*Ba zS26-)>AHZ{s<|P6BXo3+-OtG$0Fy`;Y|Sn1aIheLr<0DNueu4t-(Ai8hqegLgV1U= zJrB1lfW0U-7cU+FRXaCX+_Hh~<6y*@cBo~DX0$Rd6kZ~k_(}U;b|5g80<3YIfeu7} zW*!gf+kg$l=s@tQgG`db&Yx!>FkAbi^GAD3gdn?l)6|e2#pXrO_S9?Bhome%5qnPQ zEhKQvI8%h$kb&EZ)8HN@7>x`or(-Bb7_1yc2;73%!4^I?^*~*?D-|VQvu)JSg#~gO zm=P$`z)@eoo$Bd@{3Xctr_N6mQh=C!UGm)=gSSH;@;~k+hf&D*QOIN$kdGiMwzHt` zlpde7XdsN^`Oz0a0@BUs%yzoKLej<=FS(=7)lCJw|G_VrZ z!201|;y}CJc9X*Qt6C__nszMYd$sv&;rwVJ*q=s&8{pSf`OjU;fNlo-*vCsn|HMXh z3zP2AukB>+Y4qP`m^6w0`ziaYOK?t=)pdhkzr*>|FJ?2V-h*FPJ+Uw`^k)eV{`(i8 zIKYqphKT*ol>9e~7EVeh@en##Jiab|qfcg8k~R0SLxCl+%+^e4yOAvI1f0<9-*Wv|6gAc_pZ?E6wzmHQRsy^NV@VR zm8}ef{OfST;)Zx*T?a~OC^%nToE0y6oNhRp2<=`9BOvjnn#OUU%H_|`x z8A**-FYT2bB>A2teyMNGB;dJEAl2tm38n0%;m_%OeEMTeb?K3lvmlY~u>kI{(TP0{ z4gt&WiPn{D-UQx|#62BC{?)!cpQTiCg88Acl6CQWKxhhXM$C{=+4&IT{PtZrESBW! zi(N4Y{i{u{%%#1|eL(rw)k`}+C0qF~dTtP;g%<3=gNN{aLr45U?+NhziYs;&_s+ik z9|A?B6MJv2VE3Fu;~)5=(Yo}&j5Hx${){beFZR5ZYLe}i7;AWW;3vM!(RTJyT(}Qo;=9|}ph1dt5T$K) z$I&1h_*QAHITl+q`qz(SRaXzmuw*&h>)tng1-V@{5|IA~q&4w{f;xM-Q*=Y!=h?YtOOg{FANDVNHi0?n_^oc)x{oS!lgzwCq7E9t{==au13U1!qy{k-VB=ZDmin^XJ?sd|| zG`lGGA%6nvAvNgq7S(MT#f!TCGz?1A$Xza!xk>Nb=6E?T09u*%5vM1%mT;^NI%ywf zYX4N8i1i*@UhWB#S$u6&#K-r&owsu*a2=*#uKYv($ZLy^+59raZV&nP9F?0X zG~=zHRlZzELWug&7@w(+j>iT@^LqTjO}kFB!b6re=H8CuO7or5_}QT*t0h%FKDW|k zQ-zRU77Ob0YzA6$h$WOZV4NN^Z9)mR#-lvOniLNcZ-VX5r>_jFMU8H7#yQJWa1E9_ z)}!%DZa#;-KAyz+sl%l%`GRzUeT!3vt3`;o8fhZ@-C1aMN^`Aq9m~$%OM{7w_`qYD z$B!R>rs{0plonZXf(p*zTY;X>y?-aPSG*zYVWjehge04oh)hcxXZRByztql%Dqe75 z-(J}(Rw2kt+)(qj5S{P#w#*t9Q;87_Gj}s#u?7z9QBhIpuZa|j^_jB7Tzw}tS+6Z2 zP(_{ZR;e#^9X=E@IUcf$@K93zNa^~C?_i{(@4vo2l>v6_R65)p ze#E=>VqeJe==1vN+u8U$^C9OJPcYG$*`ELUT8k&I<?C=LGem~m%|y3|}d zi8J5Bz_JE~kA4@Dexyxi-# zNmRklCf4_u=uwA-JHwA9^@0H)9VUqL@mc9KrKTz|zwzUi7FbH`54jJ|yg1w+CSxjo zg5D#(tVIcy6O=obDhc=7F^K60GreYq1d4L6ytOfP9lv^COw_&GQ#*>p_N>n*FdWs3 zv_r;Bqq{y!-aKTQ+oxR&u;M6iWOdklx5)}2&5qpr&a<915k~^0)ANg4XHBvLNN0|J z21ugsHhNx8Wy!q#h*Qmu?aU+27jf*z%C`~*Tu=1Q6-iKBd(!m&fx6QJRe);bUq=S8 z&L$)6t}V;It1o>|i1u;<&N0DtxY;z?x!EBW*Ftn4&rVgz2^G1$T`S~(fA1G8rXpB$ z^j5#=3nCnO53we)BF*zoJjbdF2aMeYwCfeDV1Qdx%$L5E%ga#(2VIV3#eg?z99|iD z?DB}s!)WvQ^)1b*COd!)23E;YcX#{T>euz$*sadoE@5PK9-t;J0yj9w+d6-+4!ik@k4az%$Fh%~jqvIw(LFBY2$Mp?J7f?ZpYBw97~E#HNTGLWB9d zR^9MD+DO4P|1i7-bj0Ub571ZQ%u);zv?wC-`(;aJUgI*(MIKdqc`j1Ct<5z7Y(zr& z*3n)77a{`gb5ZkXE6ple7c{eUdoDZtXl(d z*(5>B>}K~fLT{Ef?Qd`K0MHIW2~YeQ7ML)fX+UVaN(EOts;Y>NyURe&9vg%j_Kalfwlg}a_p_DojTtf z7$eSn%>T#IshB;s-rp4lQ*JWQ?9RlU2|Y-tIbux5vN4kPwnzxpL@M?qGl8R*0D*)9 zSRJ=S_s+{rDdWX@>ps+`8xKL-W?NZZ@Rui&%+Brzlb~Yz{kCB*%%x;d{fi^V{JP(3 zRlJiEl5B?ENn0_64I{)Kd#*rI zJ({`;PXtYl34;>%Do&4vP-JafDI#yy)QM0Cy)?G&f0?FbV2el2BW>*n!}M~;}BUJcgg|$RBzt;yaO0cMemDx=ko6#imv|&`Uokm z#Mrq(FkW7pOI%*^n67z-v1<&f&tiyR?3+{5O6T*ahuGmIVB?K_xz{oF<<6Gidz*H! zzqCI&;9il}Lo7PiGr$PJ2B(`BRW!ab#J|10)~dhwEbuNx=AdL#e{Q7y%DnJr=9I8} zK1spxbACB%c$_F4Hd7Te7^1p$hoa*d#3g1TXN?XfQ8~-wS$xs=tl3u8mTzNFU8+=xotg{p7`yGv%>gRCUe zL^s;V%bG|=DHbbc&fFXf*ElN}%)Ev*q^tssbtLvQF1FK!v%ICeK@V%*TQW}N5J9YC zIpP&4i0ybTmS^0OZVndW`}6yZc6)F7%WdkL;=qU9+fo-80v!GN79p8SznzOvIKV%! zTt(f|{Z!6UJOs-=N%IC&jg)NkYMYpz($SY8RUwZ%Bm^!bUn6$R4GZ*WvD5e&L%%P= zV0Z7zPCJa?Nb=8Va$%era=NGq5t#bDK`@51ud4q4uE`CnMA z-s2@z<({0+ultA<>EGi{$2vVHhf*>$uU@@M8(#yw-vjeJU9+yy`26XR z6Y;K9g8TZhV6%GleXEFl*~y=xnl1_^^UOIr&12EBqua0*q_IUR_RZzj->S}!{>-P} zEMu1c2N=(CLPj2l5)~ZV6@LBoR~#@a$O1?T%$WwgiY&T#c0~(udH4<|sMawIkv_6KshZAwfafY02oFBxc93sgIgUkrS8&s-N0i>mETl zi${|L(xx3pDO=P%r7TP<; z>Hjco%3nKQ1gyif$j!{B{}o|~KtFl$X-^TLh;jK0xsj}jVYyDl1C!u3%Z|^o6a0&@ zN?@CTossRqUK}9K%!XMK_d)c7fj4ck>73&7pf=t3#Xb-&SyzW|m5eoGH5BgN4UyWp zWY$fUy}&O**9YD@1mIP1ImYPoKn2I==VtOx%R1F1^WDsS*3f{0kBxlEw;%D#U!WMq zYt7n;WZP4jvim!yueeA&*b!U(EE1u!uuW{-JC$BPw@Kg@H35@zEL8+^b2e7pF)-w? z%mxU6YqoR>Ei>mk(wR))#m7tLb$5Dv`O9jm*w63ziTmY$|B`1@UA#Qk(b2RX#E2PQ zId+7}XNk1NtUZhmC$`99sJ4TzzboQgHj25M@;nZ?61KyS+olBH-Dbm~m^zmz&vj&I z`Y$fe*>AnGeoH{XEzVXD?p@pscGJa+7dP%Ws?cBkOl-}%nV#h5ZIFgI7ftYv!EJ9pghgWuxx03EEYNTA@MfZMm~ingR~YMV{l?k-((YxjnWQ3vshM=a4C;-Zf69wkMb0`! zWqMpm&PYnYmpm&sTxu%OV67^yS2AO_T|gi-yoaheoj>;|5Z~h)vHvqTKtX<8!Dl}( zxpF}|`DT*t=w*WDz%>4I(p7>+%G1?d-0I(eZ;E(?Rfghh>oKm5*LSI5e-OU<3!AW< zQxZ>jzfL3@emH3~=zFJ%q`2qYT`3uv#mCv;8FDpOAv{QSqb^=JD-tbaUOOgy#J=%E z__EXT5~v}gd{^J4Xk8QY7%|i&KlA}VyQXB?S~0zV>kKU##&OF5#J+^Xv9eIa(0O`j zCA>CL;C_`rwNp`J2-d8AkCXUQe&$%in{pOpS2|0U5|70__8xWU3_k^>og}pF*1;q$ zbtgE^>l#ok+-MGfT~~W7Ey8hFEOb<#N^J0-g*8u8+#|PfKkK|WPw2&Hmv=Fy8I;Y` zz|_=g=MAJHJ6B4N|CDrq(r@#<*uvBY-vH{MHoz0qD=)$!+@xLp;$^$b=vuJZd=f^FoQGu0#@@PY%*tObVSV_Ze$1tbI_zvlMLCQIai z;Qe9Cc(QP4gXElDXHq%K(x!BW`O?M!rUYsKQD@mxNVxK3KR{mibEfg7Yf88e-eRVB zVkF5Nl;4fq3)+Eir_dRX*aed`Z;AcQ;G_-T8MJka=|1U{Gf}R+lNetgV$=VklQ%3(MkqYCQrUmoN; zF0IKLE1F#y#y{L;%ru|tO1$2wDkHgWu5hngk82pE4alG#y?2d)wM2Ogy)foYup2rO z;-k6I&4F-dc_zjP1F4}V+#EQZ&cm~%-#xoNg{!#}aiF~--xV9~@%S&2DIjWgQJJ5~ zx3BiIWe(ptQ!U53Nth8odQhv=$Hu3mw*y)Evf3*vD_^!bTl-EI-ZoYm2V6y#F+*!# zKWDC%S)Vf=mp@Q1iErqySs95KHzz3j&~Yu7s&=LJJ?&?`(WX$ z*v^cSW$ssLa~q*tN&HZmye-k)R>F`TMBxunJB*kxfa>xOrelQ?q>E;stTrX8S*iNOGM19RBfn6@eJ z9Jmwa8{HYy%S!b!#GXH6#?rw9r~6V99!Q`rpyC&hjJLWj%+ z*G$tZX7SEJ`>LKweg@l@T#4G_&4jm3MYOmSFWSQIYZBVJ&z-5JE`OyHPIHFwm3KmD zVDs}2{ugj^ecZmk8U+o7R)OIj??2_g?9ep87C9l1qB;ZajeAiS2R-<1m`ef9jvT;k zqCmcRAoL8RwE*a*5|F%+^t5TW^u_dmdiPENG1d8P)$Qs9StGYw+4XW}%j zchmb`uxoUx>r6BMNUs(X!H-3W0{M5vRs_&1IRyUXVm9W@d|wvudkAJjjDuKbt-9>9 zeLMORZVM&yuP;X5I^w2+-X{zzCu-M-t{}>95KO%`=BsxO!9bZ^nc)JwlmB0f3|#$ZD`dyV;kf%Z?p?cM*bCAyO8djnjg&_!Iw4BG)hFI#vBwjmakRvLzEy;Vz5`+lImm{)=_$ zoZaanOLXBQSI?wgDmaK>_7e$i_+fO0i`geFs42J%TF_zZhC!EN7Oew1JdcTwHu&lO z6(L?fmy7fIuf*E>$?y%|iR@<}8&!j3qiE(^mX!;)hFgLZAPl-^c3_T`UMf~VRKO={+%KEJy1fb$Tb3IZ&FkM3upFT% zy@Dvyg};Nd6zlO_?!zlq+=h0q=2%nvYkHfDkJocvr)PD@&dOVF*bvxTS66~)joBHj zL!Sp-aB5%=OQFrjGuOT{IvA`H?}!M5$_1+e;bh{0`IA2igc@jn3-U(0=A^A%by)eA z6mjwUxyo_nETAlDk6%sL&1v?ZoDFbZ`LaPS3X#(?{~KhdIF|@P^3G(lTpZeqm62uH zi*_i3H(t0 zLzpAb0xVVDx+T?IDDP~MoR@{7f^}VVED}Q_(jRmat$*1WWr&;CDXWc%%I|I$?*yIs z(D@yIsnQE{hW&`g6GOX`xZMU{BYwi$QXIc-KIG*&(XepRa@Q7^2qw%Y=+S^$f~-iH z9@=$JrT(Y1%d~$C-uF)F4rq2A%aONMbnMB8qwex^m_3~z&uxGWbnl)sO36rH9>9R6dSd6T^8Sg9$^0jM1|7Q{ox=4<`wu_Wby zfPigKuGT>Ni^e_K>Duay8*1H3s252*88p-cB4{E4*?0a8vLB!~XFQ1qxUQKfuNU+R zz$1VoaCs35+24PJY%F>uTqPMYRETnn`x`0N-iik>*y&}H`m~-e;Y$;-c*e_fD;`pb zYg$q#z-YJfI}3{%yO#Vh1k!$(BF|gLRVT``5r?-Jl*c~|N6z7f5#+=B0h}D5svLV6 zQWw$?j6Irc^pWMpR_sZq81TO=Z#pr>$gZQFLco-3S^Cy6L!bWLhj>=>h|Ff&rq`>0 ztwQihy_|g%*;S!v|Dz{_bCC+cm^)1RY|C7Ln&?;zCQ>(%vDnh>2Q%~!Z7luXy^BYv zgAsZqiN5X|W=%$Kdi|dGsy49%t=S=w?4C4B3I6fOtzGNC(Nf!PZG$7xZ{zx44dwG` zmz(nA7^h+Myt85M!M5qZr?PWr#jN91(xN-P{*c~lye;69NILZ-_Hm(R)Nkpm|x^J(LGai|ZyA4v* z)@E*#1(-!z@d})*mO!{yR5sZo_N$L}Zq`_v4FYD&!9=}{!`@a3Z3$Nq`xUYzNkjX+ zALAwa>#rM-O`?zXRnu7Ox{$G%@-bmLzN5hAB+3APTVa4yb#OS9fo#Pm?&!Mzb)lv* zU|M$>Y()-z!My1Gp3pN^)pBe*6Eo~wGvwMJFZmQkcjPIwPxQgR%!jP#WQ#5c5LuSf z)*yVYiQ!jUXC~p^$-I%;llePhEPd!DLPonmc1#drPpMi_c{-S7Fv)^6JjoLS$3kVz z&Z0b9N)BC^N2dYLerG@pf*hqyGWs{bRS)+Yr(5tdBzwe4Zcg=rLLFrP^7yRAK0p#{ zz7yV>Uj72UHXZBB)-+Swi*?F(yvf6CE7XjQZlXNfk8Mov_8v39u|uDYpA1vK z(+h**n#c_+%W@GdRNA_g@ZmU>;-7F&Gh{<;KzoiI$iKkUD2TTqo;a6crL!QHw}Lu5 z{Fx{L33~@1PA*JmoE+#@o}8)5 z01~V&-18dO(S~P-!7ag)MQ-=$@WYA?NigGF6K)AJs#{@=EV8oX3k1m?KB? zUg2b7a-kQBF(86wl;eZ_j1Goks3VaAnBIOBm=(;LsH#AwxYdMfVC2|TK(q66y%XW? zXXe>jAc%sbm<}0^2OhC+*$1KViVfOx(=8lL5J8OzrWaQ*d-iimeSw~?>f}3V10$m+ z$Yv2kyO6ei4ZiMu3i6GWTo0hPZli_cy}5&1PKNw-q8DV05%-|i9FWY6etZ21G^44)`oYz@x0Z^S&#>@>X(J#YWJ0oN<$~B-00Q$ zeYz^_)^K%MtnOl0y}^q!{Sp@->4(}1Xw|)%sJLQ}ewcq%x~XLPkk{4DMf&gcfEa=O zSZnzk+`M{^$Ad4}HzU!<6?=5-FJ1zUg=0PV3$rk!lTbfaWQFKna~T=hVd~10t+(Vr z>cIesJBbwT{?Z=`R-NHW;MIlzR)7Q!6;SuiX?-YxXIs}Hq_*rS`WCA{XYHDLd*yZg zA!-}k7c;{V0W-n;K{DGY;%zTulB?k7RFw?q5uL5|3xUL!4Q4S z>w6Zgr`rt)EgM~SsmDCjb}y1zMeT)emPk$A=N-=Ie$+2Or_1W%!O#Gh1ZtoUXw&(F zgMhS%ZNHRt^FpW6*Yy0u?$@dT#e=cEMjuyQ<9p)iYS$7_r4lUxLIgputR^@jKp%qD z*au-1!evxi)aXO2HlOT3k^4b+m^S0yCWNM_a@r$dI1xTsJ#7GvpFksyn?fzWGP*~+ zbN@?9Z6HiAMjWxbR!z(!`kpQ1Jp8VF<5V%Tp0p3@UP*9LRPK}j0U2d-=TFmR!R>fNo5X95T!}!n3A>~V(b|6-7 zWX6Rqjk}pZxxxI7RrGQn-(J*MRU3W?9HkVgQM^sJ_ME!>u@#7w2EWDjket=LcA|6Av_fk?E9+ z86dG=ssi(bKo>&Nn>>a~K9ljE>A01smPzJ7J>$RYxY6DN<;x*h{zye3WLcz4x$caQ zeU3{C>!;skC%C0uMs&u2>+<3uPRr}*JH~y(A(4u6KnLG?8xpX2=5F=cf&Y| zl*5V?W+(mvv+N7NM|5!9rwp+3Xm4yxlWCPx47 zIxhJe>iirMM4M8yTW;xw6wxStxv)@x3c#`6yEW-U(O~d`S4AEYB0oYKW@bju*=Blg z9QE~t1-TJNubbi6v+h{Gbl>$AT_Nfskw=|%p)8qs3;ib6NfcgyUlMY)ZvpUSk?7v**ueyF$ij`ZLY)Ds-3#ce%qot z>EJRdFJ<959gW2KrYNhA+x`#Ohkf}8j4_buF$_`J4>=(|GJ|R^qS&dfoG$)I0!GS+ zBSJHFd}j=RT+&-9D^w2IJ)$v^KndPkk1eE6H+38H|Z)_~?fwr(J>O`Ga;rju`{ zXU}_>RH_DIATqxwz2%d_BPwnT@g}0;sV z#YI`+;$PZ$E-PF~R3m<#V&C;z6BMi4nt6Y$SXFUZGpLID?4fQVLcT&#lB1#g0HmzS z@gWo#gU)OQ)&J7dA)Xgg%>)w0!$p5oaSx(ba*=QT15{j?>-g^~E_?`8ad`xnuTP(+ z;?@bQs<=MB)-Gew{9CZgW~hpL@EAJ7H&aJ5wgh}s+#KRG5F?($#=4ElpBjE=A;F&S zwi-Nla<9~3r4JweAl;k@zZ8$LlgX;MgbNFfw|%W+(q(1x)XMmJk>K_h_;GWb{~=ND zZ-3he@4R;Hw|#zoyP~b;i59H7TQP<=$2xw-=K82-WC*n|hwa*S; z^&}uc|70L7~`NTGg=@TO}pjU4Vg77Ue({)T8Tp+E=YE_++`6 zLvxJ7+$@8Yrl5Pn-eayKzunz)uRM+4iE?7gV9XJ!$KY#WaGOM@FK17dFFhEBxf*x| zdF9;7rw=>3fjOnh_#3=mUrrQjx2YaWPYa?8mF!$I71(>Xr6<7USTyu1wi|bXQc?IL z`WzHnfwFQlnWSXD4Yf)~BKrERtDRYHw~T5mg!cqgG8h8V$jWbuUb8~*H1;$nTU7}Y z+wNk#!QowSFHSQnF*YrDSVx-CuQE`6FDMcTT{b;KAK<^C-y(}CNZM7YZ7HfJV{jWcb+#wX>dRZnlonlDxbU>z;l*&A~->63u>za%upL5^B z&IJc_*iOs(bh@U$UKKA`s7v)|1gGEIi2maa{mu~*LzsF<#j$u z!~yF|C~?1Pf;t3Nt@_z{abrt16RI<`5pbDaZw!zCeg_v3)y#9A!g!!H3^kJvQsDOU zT4v3GthnUE#9O_SDAI?uo+a6!5<$$9McB}zey;hJ&ENd~dlw`3b$tHU_UHAU)L@ZpS6A1` zk*W-OnL)*5HQ@B-=Ex@5^$YqE)-FjgZ=>prWIvrcHTj5vJ|ItYzdm9ukq>(*u)hZXAGQ7yd)(Z0M|id+jR8b<1^k?7DD z>Nk%Rlb-Zj@;3lAZLF)%x`w*Q*2Y|OIW6NeGT2&RZw#&Xit`QbzP%DM2zsJd$CwGW zn0cOlMBC1R~@?rE;h#Zfj7LlS^0PM1^BZ zb`w1tADT?3w4?^rKYmI3J6WZ-YSt2o0ZX^=9%w0OAY#UrQsN8W`~g4Eo;^xkHr*($ zCfl#Zx;E08BMrIfggI)vnRW2S59=<~-_v)vn7ncBIEv2&4n%dPI$rpa{?3fzStpp^ z*u~o&b6^V!fN0$~E3@!0(R=7LxSZSb-O^HI5XQ5=Gr#oBVfAGPSLk}b#1gnm7-s=D zg_+8iN8xG(GVmg?Bb>>AP)vN1>dU&z!XN}hvW+ZvbfOxiyNXuJ^ytkq@OXh;ApVqc4lEkyBN?oNN0KQ{>2;3wPxt zU|bwd%UBf3z(C*&cXw!%god@q$g0g(Lti2(&YVs~;Nx9oveYv-Zx+7G7`m&t>$lJ` zbPqRXo#^x!&CE|rmD;TKk9RZ6J20&L0fvE}yAx6o9IXPw8I6W-=o{`3JThW1*{}Dq zm1Zixe=0Snjf`~_G3o~_D9}}Zw(Jh(;zz`0bQGdb;Os_u_;ebYiws1whr!iZs-BLm z`3GKhsbRIA8kI{*8^aKY{PHd8;MTpmQ1z5BDKvQ8s0Wh25BCXRX45^h zCOeQaiMUDLNRF!{*@uOj8U1FJprw_!X3Ga;a;GB4%gL-AjITg^@5;%6UNnw?LP(r} zQomm;E$UStW+8q${z8?YNOp(&2&G_)8aO%eq`XLCSq)CFf;zf{3ZgYPZ!vmr5&1Wy zI0qO8WA`Izng}^+z+{8X$sZuvRu$b-wl2qVorNGA$X5n3GGo+U_k+6u1y9hQmYdJ3 z?*uPI3TlGxpgTRN`Kp?CIc2I>*taRJHRA-6($?Ny2ufG5^w34ktnWFB+|m{Dy()CN zv<`v%#w)7oQNfGGw7Z~O0-VmM3h$X2?a#NWRf9IEZjp5u$|MSBd4u`okm(!0t6^rp z-AdG@BrMHWMQ~=an+U$wtvX%kBS640gig!WgEx}%#LsHB_lI`Zoiilo`u*zGsWAtSK=HM=oZVM8YjH#B(PR#hXXl zX-Qw#;H<4q!{DZw1w1WtmS4{`xE92Uyi^+~8hDI?vQB52cZCkNy&M9J@#%P^shv%$ca$RTff<7? z`?VWa2A1)EzRdx;K)4bx=F~-M@%+_|q8C8kkbQO}`PIq;!RP}%>tVxcIJ@NnLfRe8 zY4XG&`wh+h$K8VyvcyT?0RT< zRQV$KLTDs=>0HC&D@}y6D{9Kdby*{Z4nSc9)0CH z2tMqm=l5MgIw}L=ZNE)?@4QZ>v=tT>dW?lC;xvvMsLuALfKES%mzxtu9mK*zqHA>> zjy-dl&^BHh(C_Ifl5Lvn6sR)p`Nt0kUDnNei?;?u=(4rcpn`@<#zL&b!y{C$ns#Be z>vm5r^oUrdbB;k%9PvagD|5YAt0zZl@x5R8QKz#m`g;7?^w1H~yLW8|C zt?V|aZ_|_0c63DIpM^2rGgs*xmL<4oY$|_>bt_(Tx*tq$o?}SSnD^d$!H4`Sbi$xi zNghYTOTM|kz#0%1J#FZ$!N&mKNl%Y(D%xEQE|~~066^e6%nYaZ+5o!hO#J~}rskyU z`ve|DcZIOUPtYhK(3^tpBA%6%YF+P6+B0{;Pr=ooGmVBM(j-yTiuiR?_0X9s21oe!- z$A97QzHIg^khOXvq~(H56vH&Zl4kc~O$rV|)Ok}hK&Lq?!f1ocL0u`|&?^wXff`FZ z?oalS$;YzmuOWK-pqw)u!t_jm5Z>L<5yk=$hk2tJ2v&Pd0{w_F>z3K>^&mEnh8vJ-A}z#Bzxv%m-yY#3zJ~7 zAyV50plcZS(;!6Z8#SL+k-GOq6%H^-%rILU511wLz?sztj)8DG+{9$t+V|^D(&t8j z?`>(O;R7uKAW(y-gDbXc;CXYk3HXD629m28WJuF>O8XF^N6H@T2v@hiN|8Dk0&Mdv z2>&$jXh6=l$t>mRAx3f)Q6d}Mt^uwyx>iF1X1?(L??~KKbwSou29jt|xQOn=Pp5V^ z=IB5KnW}H8I1YOFBlFvr=8pfA)a&v6nI;4h=!Js(QCFvMSbKI{2)^KXSd>KC<=pD< zu2Q^BwfDkDVbF%PcsY-x1B&!C@H__*q@Uf{xv*@KNQX$$w}3~IxEv4xVV(~KLqCxU zB6|219%toKz=?I_1!9c11c>xi5H8h;n@od>YT)3X(5k&90@6Bip{d0E&fD?(zW_ML zX?YST1z!3tL#@B#b8~ZLVVDfU%gb> zdf~`C%o0=Dz}<%x@8~hXzvIsUvWGnb=hwFn{iKuN`n@O;4dHsaoF>8w*JBM0OHo~a z1nO1J%D1oua=qJE|2t4uUz*Tx=*m@tK4q4-=o8qTT%dN!x3+cZ&cM?g0Jl>G+9bh> z9RxX__DcS?tdwVttPI_y3Ihx^dAIE1sK`SQ4&&XXpQaI*x0!g9N&~mO%38^k%L>lo zcZi&#a7D-SJH4-QQWpVF^=G~QXh0k`M<=({7@b`5_&4Bo>3_5AK^_NFUt-#lx~SO0 zG2JL51&VS>``timPGBaxuA@s{Hvc(8Zyb_@^n$5g+m4s62$JNF``ZAECrr|cB%pKH zbzt>@r{GTNff%=&GO5WFc|G;tktoyH(%BD?dre~7w@b5&5fDg59C^=dfk3kG{!10U zxrRR;T$c`vH!Q;sMkl5NT|$w04(EUeF6%}kc|MjciX=W=6G~S&y4(W`eL=zxEVt{G zESza&}^dlsp+V(Igy$^sVBj~EgKHl#>1 zq6~E@QBl=~eJwo>l*sWY{vW7x**wqQ_r5$gd=Yc=%L|P6O_Q171{HfY5WVmx4Lr}r z=KR5B(&X{?C{&#?n|CtD0|UXZL-zERt(mL)U&tQWfoE90{rRzCTc=;@2K*%yv*S>N zVqJJwuCI4>A*WvWSnggyIZ$-u9!-BP|M~(5TNybI#Fm-L(TIzy-`G7-5R@aX{5D49_~R7D&z6# zXP|N+c5}($V{e?pFh$<;V+aa@u)laFERRb@cJaPy37k5u5CMnv=Z%a(B|YaDKxw^5 zh|<^H>q34&X;cj18%n!)$duM(Y_|Q@%O~2LQs37+jBYIIui#>|Z9DH3UgJQ)!re4D z{v=3Lq-(S4E~GTN%DI#uikLr;y$D{68Ta;oBzt}OBdZFr8y-9GJdb?A|$1q&l&51C*&K+^98 ziAlJ3&7X4U$=U-ZScAcXTm{?vvm-FJ#x+j-m1TKm8Vpo> z;8VDa<%Dtgv-gKpz}GaVUAC$o0|q6ix@5Fb#BdvF`33<_@Vy$|1UJG7zH1XBxFPvq z?;C#NRxmC+anyJ?A$6(t2aMKuzdH6`AVvf2ng$5663|*x7eR?SePYKMMyg zJ&LS9B#Ur(y_afR`+ysoM`f+N7^2A|IB5?i!-jBgsShxKBOTTti7 z$2oc5&5;puB7^cQbRQIZR&XT6NhYvkphtp>Bbnpyv+jnJSA(1`-|3UbK}`Voxpo6p zXD8dQ)&td!tIoz+hWxZvb8Ky@qBwnd#4mLbDEGAQrw#GFhvXSt0r3At!)|D~*~JlSEW7jXANC}A#xB%rMP%%&BveE-O?aIqgSCDR=h z75GMeLgd+X=7Rr&JX;{i1(hpxJdq_ca$ViMEh#ND8C?=vvH zU+(jK%c)b~a!VYDQ+k))hG{c%9p$aR1OrmV_P)E)M2y%5gNY!nf-@QnkAxfEwKW#igF=oD8ursQGW}o z_X8W_Zs)nNc%sv`Enbs0k~`XgpIZ}BG4bxR2d9S}3lqb6gz3v>Z?gdOaqCs9GzLvx3#?OD+NO*8@~qg!~b2 zol&T&sR`#;H{@Y_n{Nx7oZkxOE)<}OZ8GZg_(VYh8~}G1M;#{OfY|pjf^)4e8UAIs zDnUI?FuGIF$A2#~-0?;{QPtFBg2 zH(3~jowWEYUU;G#yA|cvv;SJnz4FEVHQZWi4tU&+YALzk_g-@!A}ottOg4&{ZgcNq z-rxfFr%SvkR@jCBcV!@c=E5CtOXFsd?3^6e$?^@PVCm^VT)n+BI>q~W-xYKUOfk$n zB8k+xV}~M+*gwTk2RmvARZ-qJ5KQ_MM+4um=)r_b1u zUT$iQ_~F?IsI`-M$ydHO|G`h`jucV#UDg+$mVYhrvaXQ>HHA>!6Wbtx;xKkrkOZtkAxb(spuR%0WWe%VxWQXKepBekc2o7Eg#LY=%o0Aq6*_1Zt zJO_V>TRdXDhp%yUW1WO5;)EtO(6eEGMV9tl9S^e~I~A!kJ1@Yb=xU~xZ$bj*`Obcz z?gw=&{2-lE6TzwSmY~HMR1oSIb>%=H1nG7SUmlw&<9zxz?pFx7U#WBY`1Ye&qi2=07(dA*Ci3*V)`5ZN>$bD?7gIX--|zFQAc!m&s=N#Pq^QRH17c) z$^Vu6>FfW<{T}fa9b{hL)nfw}L7uM<aE1(_-|W`wRt$w0VLYD3G@n@M`-uQ1xkN2_|UoU0P;5$~(ubk#m!B$%A5|_&FR1h0aLNot>5voYejp8CT|L%aq9X1&b{A$*rm6?seJ zD9^A)_#sLw4Td2#0Pag4A4W!czUv05q_ZXVM2gHSKaj;l7I(wK3qGx_&zXR9;^LpTkc5XlkCDZD7BVRWPR7u?26MxLeqYWUF`cxzvX#SMN5LJ;A^x%*@ zET~k}<`d;5?f68CtqTeWUriD#pgubrMn}$Ua)4xk`*SuLDz25GAR zGpPv~qT6|yRM_P1y|Yvh$P`KCI(5W=I8#)J=O09)0g(FvF&EQ6^cLJ>aDOF}I#gi{ zXsm%Mr*g+i$(qJ{UO1>X@mRl{gKD? zG8Lq7$oF`xio9R)Kdi=?jpccWa~A>k+XF&InBd<$-Xw1ij^qdsnu4ql{S@e^Ajj|n zg^l~D0*stsYGTlNWAxMaVict3`daW`fR^9i*8=X}kp%&BBbGPziE-Uyb4lTr7q*7Q zcv~yfRaJ#|6VW8SHV0HXlr^I6vct7=9sZQvg?9G zg)*qq#{si$b>~^)E_f@w()^ppxT_beqFkqbfvG+xOX}Ciq$rGZx?CDX4{Hjm=vG-P zUyngit|KHo^e)9vE#O*#$OUrpTH8bEhi;7ror}x^vN8D@FTgCDZ)ALNGBCd^T+w1K zU_Lkg1Rf{E*Qb#DkAnoxw+$I5SGaU5llNU;)*l0W4c`qCsTH0!+JXH@BGobQ*}VGp zRW5yH98E)k>ua8ST3DD7*vc4^mnLf}36MRWK6}BvoU6}zhwyA<YMdC( zf3L<_nB4XzZ zH=rN7j|XeVdSf7!)**SStWfENfz`Q^fc<)Cpm1NUDU{GXNDc1ntiHttHJP~fu4(+W z)0#f7Z(abtcY#+l!50?;iIDq%<%>F=GKaqDfXKO=NSZ@qE1sr=*hm>?mvS)6ZJ+lN^KJ-vc1dqJ% z*PXb=IiyTCfSt5b3IPMrv07#t0l9aw)4V9jWtcMrqk`?TBN2knM4I8 zPgqk#J38lH9lU9WA~2S?ES_3HUNgm&csF`&bk>*pMBIn)M;^m>LVy(Xsde>}_B@J=x79Y+rkgU^#R?&o0e0=c1{e z@~rr}^&%oC5A5FkLHATT^S*cOvs+^g7GcD@awg&-u|3#gHhI8D9YTYK{Ec?d^&ozz zGJm8v8(e5+Rofv4DW#D5Z||L-ZHKv9$2}T&-hDV^>v-3ciHRoc3sIAHWn`=66&f0lm^2Srn+HiF752It$jz_ zX^F#FJ*z!srQC~B!PsveOB(*kz-!tM&hE@ez1sM4Y`6Kgmf!{Px=(`@Z|ALFnQ=4d2dp$c zV~DR$tyG!^_Z(;jb`HK>k~>OkROzRmv$`<(RXfG7T z63or4_aAt_Z^3V_mFvA{pS}09pIy$mPkeJDm{Aj+!nl;DaBV;{yn@Ap+ZAR?NwF6e z(bmFMv+$18?5TVCU^?BU`#!l4KV1HgpW}M)r`ZlS2i&1!ol?tZu&OB!(vE*j2kCbI zDwggshP~B6*#p++POC<2T4ko!+r=D?hJqqDF@fCrPd(sO^n>*I$IPd$v4hW|S=O!} zCzir#I1imX2jLSrDjQMT57XCs;d7R05cL-Gc7u^m%Jy$v6S(e$SFWt%eu<8f3QSPp z`nKq6^7u-QwT2(d8_AwlZl3Ax*2?(rzD!+l1_BaDdJBJ*;p=TEI#RRX=4Qa6hOQ;HUg z$iL!v_JIwwSmb%QxfZ++(7b9iXpSe_Jo7Zcau|B!@`Hz z|JjgrYGJMQXvQ5auQR`NwQS(=eHD{J!j+nryatSedM_B(w`+(&8?Sc1?`^g{OtG*G z$|cP0<*e&;)(j86-QuY;ld<04H`-gz!I2u5wa~s$tSknXsNFs&oGm2`ehK{BIb2iQ zC7V|V4Wu4wS3|;OUHIel`&sktqp&AptJ7nadb?MKp{1DVf4uzSxSBRkkk*@V$I^=! z6sEQUb&xig#du&c4&L3#-@>Z`ia z`=EZ|ZfG1-;Qi;>k4n!7pylmOq_>%_aBVvq| z*Vx0HirabBgyaBqb8Q0XPUX0{{`gj9Z(Swih@qR`)LE%I2g8QdNhmR*;dHD#UO9Nh z*kC11z=1IuC(lFWHiO4d>(9+#1Mbwdkg)K(SDw%9S)6@ShP@63`jW?~l^#b(Bt_Jt zdsO|??f&vTDTbQi!k1vXari_WVwU!D~G^G0=EjdhD8E(JV&aka{gtzUuoc0PF26NbD zqP>OuyM=Mn_{i(D#4Jr%$a4&R?iNge3HK_DGS2O3Y-cuG9l;Ol_nSaR%Q74KcuKtU z4@*{y{g%Pb$M&z5BOiD0sI`<`wELOkYGDz>(O!kilwG3nv1M^335?qNU?vB}pM?{c zvgh`2JC+?NX@dJD=`DI5Jk+F%0+b?~Kj}^|?1DZEb9N(2=jCfwIFzxF>xLUv^4gdc zCo}q+rlx4#1a2S#c01@?@Y*Am*0txQaMax#J5&F}^)QQ&t&Fg`QHa%WXva6K9uEUItu7?G(>ZB{@Vd*_QQ%Jd+UGd))ia2k8X?|qnF_N ztnSW8;CxE;g;^ruK0__KfF$9abVWC}ukk%U45^B@{fWZa)>p)mi;MT!R6vs;vsQ9E|)-Gt3wFO$D;=ztzUDG4Dp zVcBf`cV4&3jE+@d5k&VYxcxMMH0gP;X}^t}uY7|#kFT?b6X?h`3-Xx9UyTyLWk&DA zF~8V-VhT#QGCNZI&Bone$5Hc7cfAY}FTzHV7506dotmYxtLk690AR*@uazEe{RfKT zG{=P2XX^AtKmM4T5e!78qS1yDS4tUUo-9*Kb|jiGbnWB<=^T5*SYir;tq@%91% z{7ClD;l=8`hkwHtHATQjCSnmt_l#Lop7iU0KuA@-=mK#Iaho~FiWa7z+QMXPsn*t@ z$`bclj#u{+y>vRN9{DZ1Z6gaWtn>h)86u2Wy6XJaZ zV1-rM!Y~9XUs`Xs^X0{h5yK!RxlIGS;Q1v|{gVMV<9jZ5Ox^4ZyHf3w>HK>2Rci{R zJRBmILEi1*$>)syC{QJQ4H-ohMN7@?u9y?E{{g}ELzu<6k)~C$tYym@9$&?!U?Gav zp2kH5HZ(NHJ6-PBC3Y3nesTkm^gw9MC)dGf0_441Il@*T-66}PI$0W%gS~&ffmdKb zxBcP~(`)jOg`MI_;5SrAGGJLufg#uQp(Z{+Z2*;wCs z0rgVQslv1I;I$lql48qVC`yh0E<%;+H)0gREy;aO8%94yd(u^tyRWh_FK_G|N(cXL zK|xGK1ly+9G5OAh_@O@*ZV*E9t@qIP2dmTO3Dd#ra`dmZsI5im;07~$2h1It?tHxMcbcMrkC^;k5o~YYC$ajA2)5TK>Z&0jKW)x$FQD^#sN}w`zfd~Z z_JFgqGXCCLiKYKBV{8~|aVo82i5r54dKv)gauYRsX%ioF+)YkR^hZ+nHU1PFhONV2 z1)+A-XzW2tfR)JedquF4EZF+6$(>F%vpzEn(9B{z5*7leMWnySJWv38V?hz!`vM(;`PZLBq zU?#8|2*{lQ_m}USDeP7W4!C`X($vTrL`5v1GE$e;YwP!h9fB!0FH6oi>i@a3R^9eX zN=LDX18N)>+Z7JxU1t>+lY;!h7P5@06q*M(MWeMvC7I;i%-DcW~q)Wq%s0RGjF-UzHhLeGOarh~nYL_Ve}m{qx8aH>-&8 zSRo1YFNF}IIEh*w7+#jp3N{Ae?UJc$?73Wpd}f(ZT`jgFZErqbQ?S^lskgf6to2!)m_3z^PMY|tqA{ail$Ar^bnYF{vkNa7 z`cdqKaHP_CA$%LvJ0Rb}E~b5R!p6>?cg~I61>_ft+-0dMrP9qZfxx`-7g%$ zs0*EOkGq<6kr?GCuS0#9KEGzEcn6oJp-wi4RazfH%;GJ-rHz@C)GQC9`uVb!mJ8_T z2C77sNDCBeu#d~i&{DWGCQ>dCz+^(*TNc11^acWxLG3xV$6>lA^^BE+&L1wAYNZk% zi%8&?|0aQ(s1{BWXIz!>e@M{TRN`025S%oV#h-{h?bkcYy}~2B;v~1ER+na?84dDCeo~hG%$Kza3dNb+(GLo zAf-cl3SNuQp*s>@S4bu*3=^qfQLCibe$LhzGdQ~-l;z<3}~l$AD~d~=b6 zNjEVGTb@u08!3%fDuIY1r%x%4D8v$y)0o=H3hPBHpg4Z%X5!w)*`zDjGhT?5QTSH+ z&_bca_L<~E7y|ncq?#1;(N(&bwLuFAhXkKZHJ67B7h)%+u|y-tWV8z-PhTy8+zcXL zO~HGNnwFouJ~Ohf3bQWz-$HagH4^Boww$5#fAhfQFu)Y7FX-Wc4hy2O@0uBVV%s)h zYqW?5jtF^Rt>@UG8x?ouA)&zy&HM~&5n#7h8(eyg@Oo%$86p2~D1SAp@c0O?yK-uB zJ{J;gVZ;Vt4%4pcYx11@1LetU{0X(chOCd&X=f%SCNhu}9#u~O8u&H%#mS8Lp8KQN z&R54E8TZdK^AqAVbg77F;Mf`035Ur7!rwW|IixhT%t#F^EWj?;r_oH5lF1!xS=j|F&&` zIV1ll3d2us+rky0rEN@@AFU!IAB=o4^Z>!)KT0gV%ME5^jOHoILVAMhr&j=eI2#V> z#gn9|s@}r-ZJE(sj0@pRS%3Hr1%bwsC;S|_K75@{W>QKDqh)gPrtD^r@aS_#p%xpz zmRL%uc262dv2pq%{hvGAF@pXU{v#d*7b*&{ThV6$+Jq7J@fI$ zv|}ANHh;)(DWw&C;%*`&cpf&%?U{n>ni0%F+Sknebl$*3dCa3cVx#8yp{}UmNd}LJ zzeK!U?8VTR2dDt?O3>MuLz~k{EqAn%wxWboS9P*=Wn*N%1Gi8q${*p$XBWYy%wP>Y z46*J8!&Mu_qjnL}$lGHj ztq4*Ii2IIwh4B|C--4P@Box@`TT<~ayf6F0th1#;ZVnTdJ z<;YonCw$chOnINsUuV9YgpBQ11ayd}^7u!1>;0FJR~J7cMx!>M2kFBbB|Q$V+dg%*|pI`gx_y;BFcw-4Pj-@1l*ZrMOfiK>;kzC{Q}r zHT)~dDJY&=$q<8es25S}=5ZbfON{2`E$=W@VE}%${WlGKQHbfGPs$^pfoKW4T@>ce zl0Ro4#Oe*qp_2%!;jmp%#@6^eCfvSFk!Q;-C{;lLvgi8EW1)}$`L5HA3RL|*dyEBs z#CFi&`=p=eaLeXY`d`U-SiF|47&$x%e$5tAi8m^lx+17fAI4PoJ-(~qgaBpe5&2Kq zaUND-S4yMw)cF$x_oni-$9WRFp-_!#Mv$+aXl+Q0g)|PN!+9KeIJjs#ti%5{=bTD< zy_17ZeFnCUR9}cLH={a(;ae+IcYq5zd$-zwpCWLRuMpDVI0ZN=JTtOe8{3n*=R%sD zT&RlbtB^IRpb4IqS)m_8l6Rw~cdqu$;O@l|59|TUQ&3k53N|*>XSlfOY!oFF;e%#| zC_@F*YnglP+Xq>pZ4w`LJF>5tR}5h}3eR^oY9_gIgk3=TgU|(}Mc^FzV&i}}Ho|s& z?HX05#kV7=`&A>X7RN=NJ1UBsAu0Yq-Gw3MeQlpHkr@Q!o$X!3B_72WMGd~(++7_7 zakHwmG|C9)E1uI3CW_ko$dmCQ}R)|AEpP7#kP@kz> zj1soq6PFe)7Xk@8ugZ3>B=ZZ`k$B57#Qey~c)1Lf-L1fxA#O%MQuIKzmpS|a&HO9l z!__4o_}+K8SBh#9_8U1xaRKB($~<7^UlFE2&io>0C0A82aozzRzCz-G<#EwxJt4yx zgpQ0koaGcYF!XZWk=EKdz2?qGT*c)+oR1L5 Gi~j*CPM6RC literal 0 HcmV?d00001 diff --git a/forui/test/src/widgets/scaffold_golden_test.dart b/forui/test/src/widgets/scaffold_golden_test.dart index 8c33e43eb..93bf1a102 100644 --- a/forui/test/src/widgets/scaffold_golden_test.dart +++ b/forui/test/src/widgets/scaffold_golden_test.dart @@ -43,6 +43,61 @@ void main() { await expectLater(find.byType(TestScaffold), matchesGoldenFile('scaffold/${theme.name}.png')); }); + + testWidgets('${theme.name} - have sheets', (tester) async { + FSheetController? controller; + + await tester.pumpWidget( + TestScaffold( + theme: theme.data, + child: FScaffold( + header: Row( + children: [ + Expanded( + child: Builder( + builder: (context) => FButton.icon( + child: FIcon(FAssets.icons.chevronRight), + onPress: () { + controller = showFSheet( + context: context, + side: Layout.ltr, + draggable: false, + builder: (context, controller) => Container( + height: double.infinity, + width: double.infinity, + decoration: BoxDecoration( + border: Border.all(color: context.theme.colorScheme.primary), + color: context.theme.colorScheme.background, + ), + child: const Center(child: Text('sheet')), + ), + ); + }, + ), + ), + ), + ], + ), + content: const Placeholder(), + footer: Row( + children: [ + Expanded( + child: Container( + decoration: const BoxDecoration(color: Colors.green), + height: 100, + ), + ), + ], + ), + ), + ), + ); + + await tester.tap(find.byType(FButton)); + await tester.pumpAndSettle(const Duration(seconds: 1)); + + await expectLater(find.byType(TestScaffold), matchesGoldenFile('scaffold/${theme.name}-sheets.png')); + }); } }); } diff --git a/forui/test/src/widgets/sheet/sheets_golden_test.dart b/forui/test/src/widgets/sheet/sheets_golden_test.dart index a418e79d2..d3d68039b 100644 --- a/forui/test/src/widgets/sheet/sheets_golden_test.dart +++ b/forui/test/src/widgets/sheet/sheets_golden_test.dart @@ -25,7 +25,7 @@ void main() { controller = showFSheet( context: context, side: side, - builder: (context) => Container( + builder: (context, controller) => Container( height: double.infinity, width: double.infinity, decoration: BoxDecoration( @@ -62,7 +62,7 @@ void main() { context: context, side: side, constraints: const BoxConstraints(maxHeight: 200, maxWidth: 200), - builder: (context) => Container( + builder: (context, controller) => Container( height: double.infinity, width: double.infinity, decoration: BoxDecoration( @@ -99,7 +99,7 @@ void main() { context: context, side: side, mainAxisMaxRatio: null, - builder: (context) => Container( + builder: (context, controller) => Container( height: double.infinity, width: double.infinity, decoration: BoxDecoration( diff --git a/forui/test/src/widgets/sheet/sheets_test.dart b/forui/test/src/widgets/sheet/sheets_test.dart index 8766fb7c5..12c8e99da 100644 --- a/forui/test/src/widgets/sheet/sheets_test.dart +++ b/forui/test/src/widgets/sheet/sheets_test.dart @@ -21,7 +21,7 @@ void main() { controller = showFSheet( context: context, side: Layout.btt, - builder: (context) => Container( + builder: (context, controller) => Container( height: double.infinity, width: double.infinity, color: context.theme.colorScheme.background, @@ -56,7 +56,7 @@ void main() { context: context, side: Layout.btt, keepAliveOffstage: true, - builder: (context) => Container( + builder: (context, controller) => Container( height: double.infinity, width: double.infinity, color: context.theme.colorScheme.background, @@ -89,7 +89,7 @@ void main() { controller = showFSheet( context: context, side: Layout.btt, - builder: (context) => Container( + builder: (context, controller) => Container( height: double.infinity, width: double.infinity, color: context.theme.colorScheme.background, @@ -120,7 +120,7 @@ void main() { key: const Key('test'), context: context, side: Layout.btt, - builder: (context) => Container( + builder: (context, controller) => Container( height: double.infinity, width: double.infinity, color: context.theme.colorScheme.background, @@ -158,7 +158,7 @@ void main() { controller = showFSheet( context: context, side: Layout.btt, - builder: (context) => Container( + builder: (context, controller) => Container( height: double.infinity, width: double.infinity, color: context.theme.colorScheme.background, @@ -197,7 +197,7 @@ void main() { controller = showFSheet( context: context, side: side, - builder: (context) => Container( + builder: (context, controller) => Container( height: double.infinity, width: double.infinity, color: context.theme.colorScheme.background, @@ -232,7 +232,7 @@ void main() { context: context, side: side, draggable: false, - builder: (context) => Container( + builder: (context, controller) => Container( height: double.infinity, width: double.infinity, color: context.theme.colorScheme.background, diff --git a/samples/lib/main.dart b/samples/lib/main.dart index 4d071203e..47203fa3e 100644 --- a/samples/lib/main.dart +++ b/samples/lib/main.dart @@ -93,6 +93,8 @@ class _AppRouter extends RootStackRouter { AutoRoute(path: '/select-tile-group/multi-value', page: SelectTileGroupMultiValueRoute.page), AutoRoute(path: '/select-tile-group/radio', page: SelectTileGroupRadioRoute.page), AutoRoute(path: '/select-tile-group/suffix', page: SelectTileGroupSuffixRoute.page), + AutoRoute(path: '/sheets/default', page: SheetsRoute.page), + AutoRoute(path: '/sheets/draggable', page: DraggableSheetsRoute.page), AutoRoute(path: '/slider/default', page: SliderRoute.page), AutoRoute(path: '/slider/tooltip', page: TooltipSliderRoute.page), AutoRoute(path: '/slider/marks', page: MarksSliderRoute.page), diff --git a/samples/lib/widgets/modal_sheet.dart b/samples/lib/widgets/modal_sheet.dart index a11d90fb5..82590e64e 100644 --- a/samples/lib/widgets/modal_sheet.dart +++ b/samples/lib/widgets/modal_sheet.dart @@ -40,7 +40,7 @@ class ModalSheetPage extends Sample { onPress: () => showFModalSheet( context: context, side: Layout.rtl, - builder: (context) => const Form(side: Layout.btt), + builder: (context) => const Form(side: Layout.rtl), ), ), const SizedBox(height: 5), diff --git a/samples/lib/widgets/sheets.dart b/samples/lib/widgets/sheets.dart new file mode 100644 index 000000000..f12f819bd --- /dev/null +++ b/samples/lib/widgets/sheets.dart @@ -0,0 +1,173 @@ +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; + +import 'package:auto_route/auto_route.dart'; +import 'package:forui/forui.dart'; + +import 'package:forui_samples/sample.dart'; + +@RoutePage() +class SheetsPage extends StatefulSample { + SheetsPage({ + @queryParam super.theme, + }); + + @override + State createState() => _State(); +} + +class _State extends StatefulSampleState { + final Map _controllers = {}; + + @override + Widget sample(BuildContext context) { + VoidCallback onPress(Layout side) => () { + var controller = _controllers[side]; + if (controller == null) { + controller = _controllers[side] ??= showFSheet( + context: context, + side: side, + builder: (context, controller) => Form(side: side, controller: controller), + ); + } else { + controller.toggle(); + } + }; + + return Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + FButton( + label: const Text('Left'), + onPress: onPress(Layout.ltr), + ), + const SizedBox(height: 5), + FButton( + label: const Text('Top'), + onPress: onPress(Layout.ttb), + ), + const SizedBox(height: 5), + FButton( + label: const Text('Right'), + onPress: onPress(Layout.rtl), + ), + const SizedBox(height: 5), + FButton( + label: const Text('Bottom'), + onPress: onPress(Layout.btt), + ), + ], + ); + } + + @override + void dispose() { + for (final controller in _controllers.values) { + controller.dispose(); + } + super.dispose(); + } +} + +class Form extends StatelessWidget { + final Layout side; + final FSheetController controller; + + Form({required this.side, required this.controller, super.key}); + + @override + Widget build(BuildContext context) => Container( + height: double.infinity, + width: double.infinity, + decoration: BoxDecoration( + color: context.theme.colorScheme.background, + border: side.vertical + ? Border.symmetric(horizontal: BorderSide(color: context.theme.colorScheme.border)) + : Border.symmetric(vertical: BorderSide(color: context.theme.colorScheme.border)), + ), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 8.0), + child: Center( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Account', + style: context.theme.typography.xl2.copyWith( + fontWeight: FontWeight.w600, + color: context.theme.colorScheme.foreground, + height: 1.5, + ), + ), + Text( + 'Make changes to your account here. Click save when you are done.', + style: context.theme.typography.sm.copyWith( + color: context.theme.colorScheme.mutedForeground, + ), + ), + const SizedBox(height: 8), + SizedBox( + width: 450, + child: Column( + children: [ + const FTextField( + label: Text('Name'), + hint: 'John Renalo', + ), + const SizedBox(height: 10), + const FTextField( + label: Text('Email'), + hint: 'john@doe.com', + ), + const SizedBox(height: 16), + FButton( + label: const Text('Save'), + onPress: controller.toggle, + ), + ], + ), + ), + ], + ), + ), + ), + ); +} + +@RoutePage() +class DraggableSheetsPage extends Sample { + DraggableSheetsPage({ + @queryParam super.theme, + }); + + @override + Widget sample(BuildContext context) => FButton( + label: const Text('Click me'), + onPress: () => showFSheet( + context: context, + side: Layout.btt, + mainAxisMaxRatio: null, + builder: (context, _) => DraggableScrollableSheet( + expand: false, + builder: (context, controller) => ScrollConfiguration( + // This is required to enable dragging on desktop. + // See https://github.com/flutter/flutter/issues/101903 for more information. + behavior: ScrollConfiguration.of(context).copyWith( + dragDevices: { + PointerDeviceKind.touch, + PointerDeviceKind.mouse, + PointerDeviceKind.trackpad, + }, + ), + child: FTileGroup.builder( + count: 25, + controller: controller, + tileBuilder: (context, index) => FTile(title: Text('Tile $index')), + ), + ), + ), + ), + ); +} From 0cc19b1497d49145452f4a890515f9387f5e9517 Mon Sep 17 00:00:00 2001 From: Matthias Ngeo Date: Thu, 5 Dec 2024 14:48:34 +0800 Subject: [PATCH 18/29] Update sheets documentation --- docs/pages/docs/overlay/modal-sheet.mdx | 3 + docs/pages/docs/overlay/sheet.mdx | 224 +++++++++++++++++++++--- forui/lib/src/widgets/sheet/sheets.dart | 14 +- samples/lib/widgets/sheets.dart | 76 +++++--- 4 files changed, 261 insertions(+), 56 deletions(-) diff --git a/docs/pages/docs/overlay/modal-sheet.mdx b/docs/pages/docs/overlay/modal-sheet.mdx index 464c28041..079da0efb 100644 --- a/docs/pages/docs/overlay/modal-sheet.mdx +++ b/docs/pages/docs/overlay/modal-sheet.mdx @@ -7,6 +7,9 @@ import LinkBadgeGroup from "../../../components/link-badge/link-badge-group.tsx" A modal sheet is an alternative to a menu or a dialog and prevents the user from interacting with the rest of the app. +A closely related widget is a [sheet](/docs/overlay/sheet), which shows information that supplements the primary content +of the app without preventing the user from interacting with the app. + diff --git a/docs/pages/docs/overlay/sheet.mdx b/docs/pages/docs/overlay/sheet.mdx index b310ec2c6..649e19403 100644 --- a/docs/pages/docs/overlay/sheet.mdx +++ b/docs/pages/docs/overlay/sheet.mdx @@ -8,6 +8,9 @@ import LinkBadgeGroup from "../../../components/link-badge/link-badge-group.tsx" A sheet that are displayed above another widget. It is part of [FScaffold](/docs/layout/scaffold), which should be preferred in most cases. +A closely related widget is a [modal sheet](/docs/overlay/modal-sheet) which prevents the user from interacting with the +rest of the app. + @@ -38,7 +41,7 @@ preferred in most cases. controller = _controllers[side] ??= showFSheet( context: context, side: Layout.ltr, - builder: (context) => Form(side: side), + builder: (context, controller) => Form(side: side, controller: controller), ); } else { controller.toggle(); @@ -77,8 +80,9 @@ preferred in most cases. class Form extends StatelessWidget { final Layout side; + final FSheetController controller; - const Form({required this.side, super.key}); + const Form({required this.side, required this.controller, super.key}); @override Widget build(BuildContext context) => Container( @@ -171,6 +175,145 @@ showFSheet( ## Examples +### With `KeepAliveOffstage` + + + + + + + ```dart {17} + class Sheets extends StatefulWidget { + @override + State createState() => _State(); + } + + class _State extends State { + final Map _controllers = {}; + + @override + Widget build(BuildContext context) { + VoidCallback onPress(Layout side) => () { + var controller = _controllers[side]; + if (controller == null) { + controller = _controllers[side] ??= showFSheet( + context: context, + side: Layout.ltr, + keepAliveOffstage: true, + builder: (context, controller) => Form(side: side, controller: controller), + ); + } else { + controller.toggle(); + } + }; + + return FScaffold( // This can be replaced with FSheets + content: Column( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + FButton( + label: const Text('Left'), + onPress: onPress(Layout.ltr), + ), + const SizedBox(height: 5), + FButton( + label: const Text('Top'), + onPress: onPress(Layout.ttb), + ), + const SizedBox(height: 5), + FButton( + label: const Text('Right'), + onPress: onPress(Layout.rtl), + ), + const SizedBox(height: 5), + FButton( + label: const Text('Bottom'), + onPress: onPress(Layout.btt), + ), + ], + ), + ); + } + } + + class Form extends StatelessWidget { + final Layout side; + final FSheetController controller; + + const Form({required this.side, required this.controller, super.key}); + + @override + Widget build(BuildContext context) => Container( + height: double.infinity, + width: double.infinity, + decoration: BoxDecoration( + color: context.theme.colorScheme.background, + border: side.vertical + ? Border.symmetric(horizontal: BorderSide(color: context.theme.colorScheme.border)) + : Border.symmetric(vertical: BorderSide(color: context.theme.colorScheme.border)), + ), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 8.0), + child: Center( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Account', + style: context.theme.typography.xl2.copyWith( + fontWeight: FontWeight.w600, + color: context.theme.colorScheme.foreground, + height: 1.5, + ), + ), + Text( + 'Make changes to your account here. Click save when you are done.', + style: context.theme.typography.sm.copyWith( + color: context.theme.colorScheme.mutedForeground, + ), + ), + const SizedBox(height: 8), + SizedBox( + width: 450, + child: Column( + children: [ + const FTextField( + label: Text('Name'), + hint: 'John Renalo', + ), + const SizedBox(height: 10), + const FTextField( + label: Text('Email'), + hint: 'john@doe.com', + ), + const SizedBox(height: 16), + FButton( + label: const Text('Save'), + onPress: () => Navigator.of(context).pop(), + ), + ], + ), + ), + ], + ), + ), + ), + ); + + @override + void dispose() { + for (final controller in _controllers.values) { + controller.dispose(); + } + super.dispose(); + } + } + ``` + + + ### With `DraggableScrollableSheet` @@ -179,33 +322,58 @@ showFSheet( ```dart - FScaffold( // This can be replaced with FSheets - content: FButton( - label: const Text('Click me'), - onPress: () => showFSheet( - context: context, - side: Layout.btt, - mainAxisMaxRatio: null, - builder: (context) => DraggableScrollableSheet( - expand: false, - builder: (context, controller) => ScrollConfiguration( - // This is required to enable dragging on desktop. - // See https://github.com/flutter/flutter/issues/101903 for more information. - behavior: ScrollConfiguration.of(context).copyWith(dragDevices: { - PointerDeviceKind.touch, - PointerDeviceKind.mouse, - PointerDeviceKind.trackpad, - }), - child: FTileGroup.builder( - count: 25, - controller: controller, - tileBuilder: (context, index) => FTile(title: Text('Tile $index')), - ), + class DraggableSheets extends StatefulWidget { + @override + State createState() => _State(); + } + + class _State extends State { + FSheetController? controller; + + @override + Widget build(BuildContext context) => FScaffold( + content: FButton( + label: const Text('Click me'), + onPress: () { + if (controller != null) { + controller!.toggle(); + return; + } + + controller = showFSheet( + context: context, + side: Layout.btt, + mainAxisMaxRatio: null, + builder: (context, _) => DraggableScrollableSheet( + expand: false, + builder: (context, controller) => ScrollConfiguration( + // This is required to enable dragging on desktop. + // See https://github.com/flutter/flutter/issues/101903 for more information. + behavior: ScrollConfiguration.of(context).copyWith( + dragDevices: { + PointerDeviceKind.touch, + PointerDeviceKind.mouse, + PointerDeviceKind.trackpad, + }, + ), + child: FTileGroup.builder( + count: 25, + controller: controller, + tileBuilder: (context, index) => FTile(title: Text('Tile $index')), + ), + ), + ), + ); + }, ), - ), - ), - ), - ); + ); + + @override + void dispose() { + controller?.dispose(); + super.dispose(); + } + } ``` diff --git a/forui/lib/src/widgets/sheet/sheets.dart b/forui/lib/src/widgets/sheet/sheets.dart index ab6932528..b9009d8c1 100644 --- a/forui/lib/src/widgets/sheet/sheets.dart +++ b/forui/lib/src/widgets/sheet/sheets.dart @@ -1,6 +1,7 @@ import 'dart:math'; import 'package:flutter/foundation.dart'; +import 'package:flutter/scheduler.dart'; import 'package:flutter/widgets.dart'; import 'package:forui/forui.dart'; import 'package:forui/src/widgets/sheet/sheet.dart'; @@ -229,9 +230,18 @@ class FSheetsState extends State with TickerProviderStateMixin { setState(() => sheets[controller.key] = (controller, sheet)); } - void _remove(Key key) { - if (mounted) { + Future _remove(Key key) async { + // This checks if the method was called during the build phase, and schedules the removal for the next frame. + // This done as _remove is called in FSheetController.dispose, and subsequently StatefulWidget.dispose, which is + // part of the build phase. + if (mounted && SchedulerBinding.instance.schedulerPhase == SchedulerPhase.idle) { setState(() => sheets.remove(key)); + } else { + WidgetsBinding.instance.addPostFrameCallback((_) { + if (mounted) { + setState(() => sheets.remove(key)); + } + }); } } diff --git a/samples/lib/widgets/sheets.dart b/samples/lib/widgets/sheets.dart index f12f819bd..9590066a3 100644 --- a/samples/lib/widgets/sheets.dart +++ b/samples/lib/widgets/sheets.dart @@ -8,15 +8,18 @@ import 'package:forui_samples/sample.dart'; @RoutePage() class SheetsPage extends StatefulSample { + final bool keepAliveOffstage; + SheetsPage({ @queryParam super.theme, + @queryParam this.keepAliveOffstage = false, }); @override - State createState() => _State(); + State createState() => _SheetsState(); } -class _State extends StatefulSampleState { +class _SheetsState extends StatefulSampleState { final Map _controllers = {}; @override @@ -27,6 +30,7 @@ class _State extends StatefulSampleState { controller = _controllers[side] ??= showFSheet( context: context, side: side, + keepAliveOffstage: widget.keepAliveOffstage, builder: (context, controller) => Form(side: side, controller: controller), ); } else { @@ -74,7 +78,7 @@ class Form extends StatelessWidget { final Layout side; final FSheetController controller; - Form({required this.side, required this.controller, super.key}); + const Form({required this.side, required this.controller, super.key}); @override Widget build(BuildContext context) => Container( @@ -137,37 +141,57 @@ class Form extends StatelessWidget { } @RoutePage() -class DraggableSheetsPage extends Sample { +class DraggableSheetsPage extends StatefulSample { DraggableSheetsPage({ @queryParam super.theme, }); + @override + State createState() => _DraggableSheetsState(); +} + +class _DraggableSheetsState extends StatefulSampleState { + FSheetController? controller; + @override Widget sample(BuildContext context) => FButton( label: const Text('Click me'), - onPress: () => showFSheet( - context: context, - side: Layout.btt, - mainAxisMaxRatio: null, - builder: (context, _) => DraggableScrollableSheet( - expand: false, - builder: (context, controller) => ScrollConfiguration( - // This is required to enable dragging on desktop. - // See https://github.com/flutter/flutter/issues/101903 for more information. - behavior: ScrollConfiguration.of(context).copyWith( - dragDevices: { - PointerDeviceKind.touch, - PointerDeviceKind.mouse, - PointerDeviceKind.trackpad, - }, - ), - child: FTileGroup.builder( - count: 25, - controller: controller, - tileBuilder: (context, index) => FTile(title: Text('Tile $index')), + onPress: () { + if (controller != null) { + controller!.toggle(); + return; + } + + controller = showFSheet( + context: context, + side: Layout.btt, + mainAxisMaxRatio: null, + builder: (context, _) => DraggableScrollableSheet( + expand: false, + builder: (context, controller) => ScrollConfiguration( + // This is required to enable dragging on desktop. + // See https://github.com/flutter/flutter/issues/101903 for more information. + behavior: ScrollConfiguration.of(context).copyWith( + dragDevices: { + PointerDeviceKind.touch, + PointerDeviceKind.mouse, + PointerDeviceKind.trackpad, + }, + ), + child: FTileGroup.builder( + count: 25, + controller: controller, + tileBuilder: (context, index) => FTile(title: Text('Tile $index')), + ), ), ), - ), - ), + ); + }, ); + + @override + void dispose() { + controller?.dispose(); + super.dispose(); + } } From 644fcf63a05e27cc8a3eab69ab222b598758cf77 Mon Sep 17 00:00:00 2001 From: Matthias Ngeo Date: Thu, 5 Dec 2024 15:00:42 +0800 Subject: [PATCH 19/29] Fix failing analyzer warning --- forui/test/src/widgets/scaffold_golden_test.dart | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/forui/test/src/widgets/scaffold_golden_test.dart b/forui/test/src/widgets/scaffold_golden_test.dart index 93bf1a102..de9c57d99 100644 --- a/forui/test/src/widgets/scaffold_golden_test.dart +++ b/forui/test/src/widgets/scaffold_golden_test.dart @@ -45,8 +45,6 @@ void main() { }); testWidgets('${theme.name} - have sheets', (tester) async { - FSheetController? controller; - await tester.pumpWidget( TestScaffold( theme: theme.data, @@ -58,7 +56,7 @@ void main() { builder: (context) => FButton.icon( child: FIcon(FAssets.icons.chevronRight), onPress: () { - controller = showFSheet( + showFSheet( context: context, side: Layout.ltr, draggable: false, From a13ae0445ee15d68e4b590f2db036814ad1e0ede Mon Sep 17 00:00:00 2001 From: Matthias Ngeo Date: Sat, 7 Dec 2024 15:48:59 +0800 Subject: [PATCH 20/29] Fix PR issues --- docs/pages/docs/overlay/_meta.ts | 2 +- docs/pages/docs/overlay/modal-sheet.mdx | 16 ++++---- .../{sheet.mdx => persistent-sheet.mdx} | 37 ++++++++++++------ forui/example/lib/sandbox.dart | 2 +- forui/example/pubspec.lock | 20 +++++----- forui/lib/src/widgets/sheet/modal_sheet.dart | 10 ++--- .../{sheets.dart => persistent_sheet.dart} | 30 +++++++------- forui/lib/widgets/sheet.dart | 2 +- .../constrained-Layout.btt.png | Bin .../constrained-Layout.ltr.png | Bin .../constrained-Layout.rtl.png | Bin .../constrained-Layout.ttb.png | Bin .../default-Layout.btt.png | Bin .../default-Layout.ltr.png | Bin .../default-Layout.rtl.png | Bin .../default-Layout.ttb.png | Bin .../scrollable-Layout.btt.png | Bin .../scrollable-Layout.ltr.png | Bin .../scrollable-Layout.rtl.png | Bin .../scrollable-Layout.ttb.png | Bin .../src/widgets/scaffold_golden_test.dart | 2 +- .../sheet/modal_sheet_golden_test.dart | 6 +-- .../src/widgets/sheet/modal_sheet_test.dart | 6 +-- ...dart => persistent_sheet_golden_test.dart} | 14 +++---- ...s_test.dart => persistent_sheet_test.dart} | 22 +++++------ samples/lib/main.dart | 4 +- samples/lib/widgets/modal_sheet.dart | 10 ++--- .../{sheets.dart => persistent_sheet.dart} | 32 +++++++++------ 28 files changed, 117 insertions(+), 98 deletions(-) rename docs/pages/docs/overlay/{sheet.mdx => persistent-sheet.mdx} (91%) rename forui/lib/src/widgets/sheet/{sheets.dart => persistent_sheet.dart} (88%) rename forui/test/golden/sheet/{sheets => persistent}/constrained-Layout.btt.png (100%) rename forui/test/golden/sheet/{sheets => persistent}/constrained-Layout.ltr.png (100%) rename forui/test/golden/sheet/{sheets => persistent}/constrained-Layout.rtl.png (100%) rename forui/test/golden/sheet/{sheets => persistent}/constrained-Layout.ttb.png (100%) rename forui/test/golden/sheet/{sheets => persistent}/default-Layout.btt.png (100%) rename forui/test/golden/sheet/{sheets => persistent}/default-Layout.ltr.png (100%) rename forui/test/golden/sheet/{sheets => persistent}/default-Layout.rtl.png (100%) rename forui/test/golden/sheet/{sheets => persistent}/default-Layout.ttb.png (100%) rename forui/test/golden/sheet/{sheets => persistent}/scrollable-Layout.btt.png (100%) rename forui/test/golden/sheet/{sheets => persistent}/scrollable-Layout.ltr.png (100%) rename forui/test/golden/sheet/{sheets => persistent}/scrollable-Layout.rtl.png (100%) rename forui/test/golden/sheet/{sheets => persistent}/scrollable-Layout.ttb.png (100%) rename forui/test/src/widgets/sheet/{sheets_golden_test.dart => persistent_sheet_golden_test.dart} (92%) rename forui/test/src/widgets/sheet/{sheets_test.dart => persistent_sheet_test.dart} (93%) rename samples/lib/widgets/{sheets.dart => persistent_sheet.dart} (85%) diff --git a/docs/pages/docs/overlay/_meta.ts b/docs/pages/docs/overlay/_meta.ts index be3db23bf..9768ee855 100644 --- a/docs/pages/docs/overlay/_meta.ts +++ b/docs/pages/docs/overlay/_meta.ts @@ -2,7 +2,7 @@ export default { dialog: 'Dialog', popover: 'Popover', 'popover-menu': 'Popover Menu', - 'sheet': 'Sheet', 'modal-sheet': 'Modal Sheet', + 'persistent-sheet': 'Persistent Sheet', tooltip: 'Tooltip', }; diff --git a/docs/pages/docs/overlay/modal-sheet.mdx b/docs/pages/docs/overlay/modal-sheet.mdx index 079da0efb..489c2d508 100644 --- a/docs/pages/docs/overlay/modal-sheet.mdx +++ b/docs/pages/docs/overlay/modal-sheet.mdx @@ -7,8 +7,8 @@ import LinkBadgeGroup from "../../../components/link-badge/link-badge-group.tsx" A modal sheet is an alternative to a menu or a dialog and prevents the user from interacting with the rest of the app. -A closely related widget is a [sheet](/docs/overlay/sheet), which shows information that supplements the primary content -of the app without preventing the user from interacting with the app. +A closely related widget is a [persistent sheet](/docs/overlay/persistent-sheet), which shows information that +supplements the primary content of the app without preventing the user from interacting with the app. @@ -28,7 +28,7 @@ of the app without preventing the user from interacting with the app. children: [ FButton( label: const Text('Left'), - onPress: () => showFModalSheet( + onPress: () => showFSheet( context: context, side: Layout.ltr, builder: (context) => const Form(side: Layout.ltr), @@ -37,7 +37,7 @@ of the app without preventing the user from interacting with the app. const SizedBox(height: 5), FButton( label: const Text('Top'), - onPress: () => showFModalSheet( + onPress: () => showFSheet( context: context, side: Layout.ttb, builder: (context) => const Form(side: Layout.ttb), @@ -46,7 +46,7 @@ of the app without preventing the user from interacting with the app. const SizedBox(height: 5), FButton( label: const Text('Right'), - onPress: () => showFModalSheet( + onPress: () => showFSheet( context: context, side: Layout.rtl, builder: (context) => const Form(side: Layout.btt), @@ -55,7 +55,7 @@ of the app without preventing the user from interacting with the app. const SizedBox(height: 5), FButton( label: const Text('Bottom'), - onPress: () => showFModalSheet( + onPress: () => showFSheet( context: context, side: Layout.btt, builder: (context) => const Form(side: Layout.btt), @@ -135,10 +135,10 @@ of the app without preventing the user from interacting with the app. ## Usage -### `showFModalSheet(...)` +### `showFSheet(...)` ```dart -showFModalSheet( +showFSheet( context: context, side: Layout.ltr, useRootNavigator: true, diff --git a/docs/pages/docs/overlay/sheet.mdx b/docs/pages/docs/overlay/persistent-sheet.mdx similarity index 91% rename from docs/pages/docs/overlay/sheet.mdx rename to docs/pages/docs/overlay/persistent-sheet.mdx index 649e19403..291bb268c 100644 --- a/docs/pages/docs/overlay/sheet.mdx +++ b/docs/pages/docs/overlay/persistent-sheet.mdx @@ -3,10 +3,10 @@ import { Widget } from "../../../components/widget.tsx"; import LinkBadge from "../../../components/link-badge/link-badge.tsx"; import LinkBadgeGroup from "../../../components/link-badge/link-badge-group.tsx"; -# Sheet +# Persistent Sheet -A sheet that are displayed above another widget. It is part of [FScaffold](/docs/layout/scaffold), which should be -preferred in most cases. +A persistent sheet that are displayed above another widget. It is part of [FScaffold](/docs/layout/scaffold), which +should be preferred in most cases. A closely related widget is a [modal sheet](/docs/overlay/modal-sheet) which prevents the user from interacting with the rest of the app. @@ -16,12 +16,13 @@ rest of the app. - All calls to `showFSheet(...)` should be made inside widgets that have either `FScaffold` or `Sheets` as their + All calls to `showFPersistentSheet(...)` should be made inside widgets that have either `FScaffold` or `FSheets` as + their ancestor. - + ```dart @@ -36,9 +37,15 @@ rest of the app. @override Widget build(BuildContext context) { VoidCallback onPress(Layout side) => () { + for (final MapEntry(:key, :value) in _controllers.entries) { + if (key != side && value.shown) { + return; + } + } + var controller = _controllers[side]; if (controller == null) { - controller = _controllers[side] ??= showFSheet( + controller = _controllers[side] ??= showFPersistentSheet( context: context, side: Layout.ltr, builder: (context, controller) => Form(side: side, controller: controller), @@ -157,10 +164,10 @@ rest of the app. ## Usage -### `showFSheet(...)` +### `showFPersistentSheet(...)` ```dart -showFSheet( +showFPersistentSheet( context: context, side: Layout.ltr, useRootNavigator: true, @@ -179,7 +186,7 @@ showFSheet( - + ```dart {17} @@ -194,9 +201,15 @@ showFSheet( @override Widget build(BuildContext context) { VoidCallback onPress(Layout side) => () { + for (final MapEntry(:key, :value) in _controllers.entries) { + if (key != side && value.shown) { + return; + } + } + var controller = _controllers[side]; if (controller == null) { - controller = _controllers[side] ??= showFSheet( + controller = _controllers[side] ??= showFPersistentSheet( context: context, side: Layout.ltr, keepAliveOffstage: true, @@ -318,7 +331,7 @@ showFSheet( - + ```dart @@ -340,7 +353,7 @@ showFSheet( return; } - controller = showFSheet( + controller = showFPersistentSheet( context: context, side: Layout.btt, mainAxisMaxRatio: null, diff --git a/forui/example/lib/sandbox.dart b/forui/example/lib/sandbox.dart index 869d2388c..3ec1fba03 100644 --- a/forui/example/lib/sandbox.dart +++ b/forui/example/lib/sandbox.dart @@ -29,7 +29,7 @@ class _SandboxState extends State with SingleTickerProviderStateMixin { children: [ FButton( label: const Text('Click me'), - onPress: () => showFModalSheet( + onPress: () => showFSheet( context: context, side: Layout.ltr, builder: (context) => ListView.builder( diff --git a/forui/example/pubspec.lock b/forui/example/pubspec.lock index 498cffe37..b35981699 100644 --- a/forui/example/pubspec.lock +++ b/forui/example/pubspec.lock @@ -236,10 +236,10 @@ packages: dependency: transitive description: name: flutter_svg - sha256: "936d9c1c010d3e234d1672574636f3352b4941ca3decaddd3cafaeb9ad49c471" + sha256: "54900a1a1243f3c4a5506d853a2b5c2dbc38d5f27e52a52618a8054401431123" url: "https://pub.dev" source: hosted - version: "2.0.15" + version: "2.0.16" flutter_test: dependency: "direct dev" description: flutter @@ -501,18 +501,18 @@ packages: dependency: transitive description: name: path_provider_android - sha256: c464428172cb986b758c6d1724c603097febb8fb855aa265aeecc9280c294d4a + sha256: "8c4967f8b7cb46dc914e178daa29813d83ae502e0529d7b0478330616a691ef7" url: "https://pub.dev" source: hosted - version: "2.2.12" + version: "2.2.14" path_provider_foundation: dependency: transitive description: name: path_provider_foundation - sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16 + sha256: "4843174df4d288f5e29185bd6e72a6fbdf5a4a4602717eed565497429f179942" url: "https://pub.dev" source: hosted - version: "2.4.0" + version: "2.4.1" path_provider_linux: dependency: transitive description: @@ -714,10 +714,10 @@ packages: dependency: transitive description: name: vector_graphics_compiler - sha256: ab9ff38fc771e9ee1139320adbe3d18a60327370c218c60752068ebee4b49ab1 + sha256: "1b4b9e706a10294258727674a340ae0d6e64a7231980f9f9a3d12e4b42407aad" url: "https://pub.dev" source: hosted - version: "1.1.15" + version: "1.1.16" vector_math: dependency: transitive description: @@ -786,10 +786,10 @@ packages: dependency: transitive description: name: win32 - sha256: "84ba388638ed7a8cb3445a320c8273136ab2631cd5f2c57888335504ddab1bc2" + sha256: "8b338d4486ab3fbc0ba0db9f9b4f5239b6697fcee427939a40e720cbb9ee0a69" url: "https://pub.dev" source: hosted - version: "5.8.0" + version: "5.9.0" xdg_directories: dependency: transitive description: diff --git a/forui/lib/src/widgets/sheet/modal_sheet.dart b/forui/lib/src/widgets/sheet/modal_sheet.dart index 660391e93..713a7e748 100644 --- a/forui/lib/src/widgets/sheet/modal_sheet.dart +++ b/forui/lib/src/widgets/sheet/modal_sheet.dart @@ -34,12 +34,12 @@ import 'package:forui/src/widgets/sheet/sheet.dart'; /// /// See: /// * https://forui.dev/docs/overlay/modal-sheet for working examples. -/// * [showFSheet] for displaying a sheet above the current widget. +/// * [showFPersistentSheet] for displaying a sheet above the current widget. /// * [FModalSheetRoute] for more information about the various arguments. /// * [FSheetStyle] for customizing a switch's appearance. /// * [DraggableScrollableSheet], creates a bottom sheet that grows and then becomes scrollable once it reaches its /// maximum size. -Future showFModalSheet({ +Future showFSheet({ required BuildContext context, required WidgetBuilder builder, required Layout side, @@ -87,7 +87,7 @@ Future showFModalSheet({ ); } -/// A route that represents a modal sheet. [showFModalSheet] should be preferred in most cases. +/// A route that represents a modal sheet. [showFSheet] should be preferred in most cases. /// /// A modal sheet is an alternative to a menu or a dialog and prevents the user from interacting with the rest of the /// app. @@ -98,8 +98,8 @@ Future showFModalSheet({ /// See: /// * https://forui.dev/docs/overlay/modal-sheet for working examples. /// * [FSheetStyle] for customizing a switch's appearance. -/// * [showFModalSheet] for displaying a FModalSheetRoute. -/// * [showFSheet] for displaying a sheet above the current widget. +/// * [showFSheet] for displaying a FModalSheetRoute. +/// * [showFPersistentSheet] for displaying a sheet above the current widget. /// * [DraggableScrollableSheet], creates a bottom sheet that grows and then becomes scrollable once it reaches its /// maximum size. /// diff --git a/forui/lib/src/widgets/sheet/sheets.dart b/forui/lib/src/widgets/sheet/persistent_sheet.dart similarity index 88% rename from forui/lib/src/widgets/sheet/sheets.dart rename to forui/lib/src/widgets/sheet/persistent_sheet.dart index b9009d8c1..28905c4e8 100644 --- a/forui/lib/src/widgets/sheet/sheets.dart +++ b/forui/lib/src/widgets/sheet/persistent_sheet.dart @@ -7,9 +7,9 @@ import 'package:forui/forui.dart'; import 'package:forui/src/widgets/sheet/sheet.dart'; import 'package:meta/meta.dart'; -/// Shows a sheet that appears above the current widget. It should have a [FSheets] or [FScaffold] ancestor. +/// Shows a persistent sheet that appears above the current widget. It should have a [FSheets] or [FScaffold] ancestor. /// -/// The returned [FSheetController] should always be disposed after use. Not doing so can lead to the sheets +/// The returned [FPersistentSheetController] should always be disposed after use. Not doing so can lead to the sheets /// accumulating over time, which can negatively impact performance. /// /// A closely related widget is a modal sheet which prevents the user from interacting with the rest of the app. @@ -39,16 +39,16 @@ import 'package:meta/meta.dart'; /// * a sheet with the same [key] already exists. /// /// See: -/// * https://forui.dev/docs/overlay/sheet for working examples. -/// * [showFModalSheet] for showing a sheet in a modal that prevents the user from interacting with the rest of the app. +/// * https://forui.dev/docs/overlay/persistent-sheet for working examples. +/// * [showFSheet] for showing a sheet in a modal that prevents the user from interacting with the rest of the app. /// * [FSheetStyle] for customizing a switch's appearance. /// * [DraggableScrollableSheet], creates a bottom sheet that grows and then becomes scrollable once it reaches its /// maximum size. @useResult -FSheetController showFSheet({ +FPersistentSheetController showFPersistentSheet({ required BuildContext context, required Layout side, - required Widget Function(BuildContext, FSheetController) builder, + required Widget Function(BuildContext, FPersistentSheetController) builder, FSheetStyle? style, double? mainAxisMaxRatio = 9 / 16, BoxConstraints constraints = const BoxConstraints(), @@ -80,7 +80,7 @@ FSheetController showFSheet({ key ??= ValueKey(Random.secure().nextInt(2147483647)); style ??= context.theme.sheetStyle; - final controller = FSheetController._( + final controller = FPersistentSheetController._( vsync: state, style: style, key: key, @@ -115,7 +115,7 @@ FSheetController showFSheet({ } /// A sheet controller. -class FSheetController { +class FPersistentSheetController { /// The sheet's key. final Key key; @@ -130,7 +130,7 @@ class FSheetController { final AnimationController _controller; final VoidCallback _onDispose; - FSheetController._({ + FPersistentSheetController._({ required TickerProvider vsync, required FSheetStyle style, required VoidCallback onDispose, @@ -142,7 +142,7 @@ class FSheetController { if (kFlutterMemoryAllocationsEnabled) { FlutterMemoryAllocations.instance.dispatchObjectCreated( library: 'package:flutter/forui.dart', - className: '$FSheetController', + className: '$FPersistentSheetController', object: this, ); } @@ -180,8 +180,8 @@ class FSheetController { /// See: /// * https://forui.dev/docs/overlay/sheet for working examples. /// * [FSheetStyle] for customizing a switch's appearance. -/// * [showFSheet] for for displaying a sheet above the current widget. -/// * [showFModalSheet] for displaying a modal sheet. +/// * [showFPersistentSheet] for for displaying a sheet above the current widget. +/// * [showFSheet] for displaying a modal sheet. /// * [DraggableScrollableSheet], creates a bottom sheet that grows and then becomes scrollable once it reaches its /// maximum size. class FSheets extends StatefulWidget { @@ -198,7 +198,7 @@ class FSheets extends StatefulWidget { @visibleForTesting @internal class FSheetsState extends State with TickerProviderStateMixin { - final Map sheets = {}; + final Map sheets = {}; @override Widget build(BuildContext context) => Stack( @@ -209,7 +209,7 @@ class FSheetsState extends State with TickerProviderStateMixin { ], ); - void _add(FSheetController controller, Sheet sheet) { + void _add(FPersistentSheetController controller, Sheet sheet) { if (!mounted) { return; } @@ -248,6 +248,6 @@ class FSheetsState extends State with TickerProviderStateMixin { @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); - properties.add(DiagnosticsProperty>('sheets', sheets)); + properties.add(DiagnosticsProperty>('sheets', sheets)); } } diff --git a/forui/lib/widgets/sheet.dart b/forui/lib/widgets/sheet.dart index 2fe60f50d..b75a3496a 100644 --- a/forui/lib/widgets/sheet.dart +++ b/forui/lib/widgets/sheet.dart @@ -7,5 +7,5 @@ library forui.widgets.sheet; export '../src/widgets/sheet/modal_sheet.dart'; -export '../src/widgets/sheet/sheets.dart' hide FSheetsState; +export '../src/widgets/sheet/persistent_sheet.dart' hide FSheetsState; export '../src/widgets/sheet/sheet.dart' show FSheetStyle; diff --git a/forui/test/golden/sheet/sheets/constrained-Layout.btt.png b/forui/test/golden/sheet/persistent/constrained-Layout.btt.png similarity index 100% rename from forui/test/golden/sheet/sheets/constrained-Layout.btt.png rename to forui/test/golden/sheet/persistent/constrained-Layout.btt.png diff --git a/forui/test/golden/sheet/sheets/constrained-Layout.ltr.png b/forui/test/golden/sheet/persistent/constrained-Layout.ltr.png similarity index 100% rename from forui/test/golden/sheet/sheets/constrained-Layout.ltr.png rename to forui/test/golden/sheet/persistent/constrained-Layout.ltr.png diff --git a/forui/test/golden/sheet/sheets/constrained-Layout.rtl.png b/forui/test/golden/sheet/persistent/constrained-Layout.rtl.png similarity index 100% rename from forui/test/golden/sheet/sheets/constrained-Layout.rtl.png rename to forui/test/golden/sheet/persistent/constrained-Layout.rtl.png diff --git a/forui/test/golden/sheet/sheets/constrained-Layout.ttb.png b/forui/test/golden/sheet/persistent/constrained-Layout.ttb.png similarity index 100% rename from forui/test/golden/sheet/sheets/constrained-Layout.ttb.png rename to forui/test/golden/sheet/persistent/constrained-Layout.ttb.png diff --git a/forui/test/golden/sheet/sheets/default-Layout.btt.png b/forui/test/golden/sheet/persistent/default-Layout.btt.png similarity index 100% rename from forui/test/golden/sheet/sheets/default-Layout.btt.png rename to forui/test/golden/sheet/persistent/default-Layout.btt.png diff --git a/forui/test/golden/sheet/sheets/default-Layout.ltr.png b/forui/test/golden/sheet/persistent/default-Layout.ltr.png similarity index 100% rename from forui/test/golden/sheet/sheets/default-Layout.ltr.png rename to forui/test/golden/sheet/persistent/default-Layout.ltr.png diff --git a/forui/test/golden/sheet/sheets/default-Layout.rtl.png b/forui/test/golden/sheet/persistent/default-Layout.rtl.png similarity index 100% rename from forui/test/golden/sheet/sheets/default-Layout.rtl.png rename to forui/test/golden/sheet/persistent/default-Layout.rtl.png diff --git a/forui/test/golden/sheet/sheets/default-Layout.ttb.png b/forui/test/golden/sheet/persistent/default-Layout.ttb.png similarity index 100% rename from forui/test/golden/sheet/sheets/default-Layout.ttb.png rename to forui/test/golden/sheet/persistent/default-Layout.ttb.png diff --git a/forui/test/golden/sheet/sheets/scrollable-Layout.btt.png b/forui/test/golden/sheet/persistent/scrollable-Layout.btt.png similarity index 100% rename from forui/test/golden/sheet/sheets/scrollable-Layout.btt.png rename to forui/test/golden/sheet/persistent/scrollable-Layout.btt.png diff --git a/forui/test/golden/sheet/sheets/scrollable-Layout.ltr.png b/forui/test/golden/sheet/persistent/scrollable-Layout.ltr.png similarity index 100% rename from forui/test/golden/sheet/sheets/scrollable-Layout.ltr.png rename to forui/test/golden/sheet/persistent/scrollable-Layout.ltr.png diff --git a/forui/test/golden/sheet/sheets/scrollable-Layout.rtl.png b/forui/test/golden/sheet/persistent/scrollable-Layout.rtl.png similarity index 100% rename from forui/test/golden/sheet/sheets/scrollable-Layout.rtl.png rename to forui/test/golden/sheet/persistent/scrollable-Layout.rtl.png diff --git a/forui/test/golden/sheet/sheets/scrollable-Layout.ttb.png b/forui/test/golden/sheet/persistent/scrollable-Layout.ttb.png similarity index 100% rename from forui/test/golden/sheet/sheets/scrollable-Layout.ttb.png rename to forui/test/golden/sheet/persistent/scrollable-Layout.ttb.png diff --git a/forui/test/src/widgets/scaffold_golden_test.dart b/forui/test/src/widgets/scaffold_golden_test.dart index de9c57d99..f1109f066 100644 --- a/forui/test/src/widgets/scaffold_golden_test.dart +++ b/forui/test/src/widgets/scaffold_golden_test.dart @@ -56,7 +56,7 @@ void main() { builder: (context) => FButton.icon( child: FIcon(FAssets.icons.chevronRight), onPress: () { - showFSheet( + showFPersistentSheet( context: context, side: Layout.ltr, draggable: false, diff --git a/forui/test/src/widgets/sheet/modal_sheet_golden_test.dart b/forui/test/src/widgets/sheet/modal_sheet_golden_test.dart index 7d9a727f4..e5bf803f7 100644 --- a/forui/test/src/widgets/sheet/modal_sheet_golden_test.dart +++ b/forui/test/src/widgets/sheet/modal_sheet_golden_test.dart @@ -17,7 +17,7 @@ void main() { child: Builder( builder: (context) => FButton.icon( child: FIcon(FAssets.icons.chevronRight), - onPress: () => showFModalSheet( + onPress: () => showFSheet( context: context, side: side, builder: (context) => Container( @@ -44,7 +44,7 @@ void main() { child: Builder( builder: (context) => FButton.icon( child: FIcon(FAssets.icons.chevronRight), - onPress: () => showFModalSheet( + onPress: () => showFSheet( context: context, side: side, constraints: const BoxConstraints(maxHeight: 200, maxWidth: 200), @@ -72,7 +72,7 @@ void main() { child: Builder( builder: (context) => FButton.icon( child: FIcon(FAssets.icons.chevronRight), - onPress: () => showFModalSheet( + onPress: () => showFSheet( context: context, side: side, mainAxisMaxRatio: null, diff --git a/forui/test/src/widgets/sheet/modal_sheet_test.dart b/forui/test/src/widgets/sheet/modal_sheet_test.dart index 1c5590c6d..91606b011 100644 --- a/forui/test/src/widgets/sheet/modal_sheet_test.dart +++ b/forui/test/src/widgets/sheet/modal_sheet_test.dart @@ -13,7 +13,7 @@ void main() { child: Builder( builder: (context) => FButton.icon( child: FIcon(FAssets.icons.chevronRight), - onPress: () => showFModalSheet( + onPress: () => showFSheet( context: context, side: Layout.btt, builder: (context) => Container( @@ -49,7 +49,7 @@ void main() { child: Builder( builder: (context) => FButton.icon( child: FIcon(FAssets.icons.chevronRight), - onPress: () => showFModalSheet( + onPress: () => showFSheet( context: context, side: side, builder: (context) => Container( @@ -79,7 +79,7 @@ void main() { child: Builder( builder: (context) => FButton.icon( child: FIcon(FAssets.icons.chevronRight), - onPress: () => showFModalSheet( + onPress: () => showFSheet( context: context, side: side, draggable: false, diff --git a/forui/test/src/widgets/sheet/sheets_golden_test.dart b/forui/test/src/widgets/sheet/persistent_sheet_golden_test.dart similarity index 92% rename from forui/test/src/widgets/sheet/sheets_golden_test.dart rename to forui/test/src/widgets/sheet/persistent_sheet_golden_test.dart index d3d68039b..7d17ca50a 100644 --- a/forui/test/src/widgets/sheet/sheets_golden_test.dart +++ b/forui/test/src/widgets/sheet/persistent_sheet_golden_test.dart @@ -9,7 +9,7 @@ import 'package:forui/forui.dart'; import '../../test_scaffold.dart'; void main() { - FSheetController? controller; + FPersistentSheetController? controller; group('showFSheet', () { for (final side in Layout.values) { @@ -22,7 +22,7 @@ void main() { child: FButton.icon( child: FIcon(FAssets.icons.chevronRight), onPress: () { - controller = showFSheet( + controller = showFPersistentSheet( context: context, side: side, builder: (context, controller) => Container( @@ -46,7 +46,7 @@ void main() { await tester.tap(find.byType(FButton)); await tester.pumpAndSettle(); - await expectLater(find.byType(TestScaffold), matchesGoldenFile('sheet/sheets/default-$side.png')); + await expectLater(find.byType(TestScaffold), matchesGoldenFile('sheet/persistent/default-$side.png')); }); testWidgets('constrained - $side', (tester) async { @@ -58,7 +58,7 @@ void main() { child: FButton.icon( child: FIcon(FAssets.icons.chevronRight), onPress: () { - controller = showFSheet( + controller = showFPersistentSheet( context: context, side: side, constraints: const BoxConstraints(maxHeight: 200, maxWidth: 200), @@ -83,7 +83,7 @@ void main() { await tester.tap(find.byType(FButton)); await tester.pumpAndSettle(); - await expectLater(find.byType(TestScaffold), matchesGoldenFile('sheet/sheets/constrained-$side.png')); + await expectLater(find.byType(TestScaffold), matchesGoldenFile('sheet/persistent/constrained-$side.png')); }); testWidgets('scrollable - $side', (tester) async { @@ -95,7 +95,7 @@ void main() { child: FButton.icon( child: FIcon(FAssets.icons.chevronRight), onPress: () { - controller = showFSheet( + controller = showFPersistentSheet( context: context, side: side, mainAxisMaxRatio: null, @@ -127,7 +127,7 @@ void main() { await tester.tap(find.byType(FButton)); await tester.pumpAndSettle(); - await expectLater(find.byType(TestScaffold), matchesGoldenFile('sheet/sheets/scrollable-$side.png')); + await expectLater(find.byType(TestScaffold), matchesGoldenFile('sheet/persistent/scrollable-$side.png')); }); } }); diff --git a/forui/test/src/widgets/sheet/sheets_test.dart b/forui/test/src/widgets/sheet/persistent_sheet_test.dart similarity index 93% rename from forui/test/src/widgets/sheet/sheets_test.dart rename to forui/test/src/widgets/sheet/persistent_sheet_test.dart index 12c8e99da..86806ba3e 100644 --- a/forui/test/src/widgets/sheet/sheets_test.dart +++ b/forui/test/src/widgets/sheet/persistent_sheet_test.dart @@ -3,13 +3,13 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:forui/forui.dart'; -import 'package:forui/src/widgets/sheet/sheets.dart'; +import 'package:forui/src/widgets/sheet/persistent_sheet.dart'; import '../../test_scaffold.dart'; void main() { - FSheetController? controller; + FPersistentSheetController? controller; - group('showFSheet', () { + group('showFPersistentSheet', () { testWidgets('shows sheet', (tester) async { await tester.pumpWidget( TestScaffold.app( @@ -18,7 +18,7 @@ void main() { builder: (context) => FButton.icon( child: FIcon(FAssets.icons.chevronRight), onPress: () { - controller = showFSheet( + controller = showFPersistentSheet( context: context, side: Layout.btt, builder: (context, controller) => Container( @@ -52,7 +52,7 @@ void main() { builder: (context) => FButton.icon( child: FIcon(FAssets.icons.chevronRight), onPress: () { - controller = showFSheet( + controller = showFPersistentSheet( context: context, side: Layout.btt, keepAliveOffstage: true, @@ -86,7 +86,7 @@ void main() { builder: (context) => FButton.icon( child: FIcon(FAssets.icons.chevronRight), onPress: () { - controller = showFSheet( + controller = showFPersistentSheet( context: context, side: Layout.btt, builder: (context, controller) => Container( @@ -116,7 +116,7 @@ void main() { builder: (context) => FButton.icon( child: FIcon(FAssets.icons.chevronRight), onPress: () { - controller = showFSheet( + controller = showFPersistentSheet( key: const Key('test'), context: context, side: Layout.btt, @@ -144,7 +144,7 @@ void main() { }); testWidgets('dispose removes sheet', (tester) async { - late FSheetController controller; + late FPersistentSheetController controller; const key = Key('test'); await tester.pumpWidget( @@ -155,7 +155,7 @@ void main() { builder: (context) => FButton.icon( child: FIcon(FAssets.icons.chevronRight), onPress: () { - controller = showFSheet( + controller = showFPersistentSheet( context: context, side: Layout.btt, builder: (context, controller) => Container( @@ -194,7 +194,7 @@ void main() { builder: (context) => FButton.icon( child: FIcon(FAssets.icons.chevronRight), onPress: () { - controller = showFSheet( + controller = showFPersistentSheet( context: context, side: side, builder: (context, controller) => Container( @@ -228,7 +228,7 @@ void main() { builder: (context) => FButton.icon( child: FIcon(FAssets.icons.chevronRight), onPress: () { - controller = showFSheet( + controller = showFPersistentSheet( context: context, side: side, draggable: false, diff --git a/samples/lib/main.dart b/samples/lib/main.dart index 47203fa3e..93db1d8f8 100644 --- a/samples/lib/main.dart +++ b/samples/lib/main.dart @@ -93,8 +93,8 @@ class _AppRouter extends RootStackRouter { AutoRoute(path: '/select-tile-group/multi-value', page: SelectTileGroupMultiValueRoute.page), AutoRoute(path: '/select-tile-group/radio', page: SelectTileGroupRadioRoute.page), AutoRoute(path: '/select-tile-group/suffix', page: SelectTileGroupSuffixRoute.page), - AutoRoute(path: '/sheets/default', page: SheetsRoute.page), - AutoRoute(path: '/sheets/draggable', page: DraggableSheetsRoute.page), + AutoRoute(path: '/persistent-sheet/default', page: SheetsRoute.page), + AutoRoute(path: '/persistent-sheet/draggable', page: DraggableSheetsRoute.page), AutoRoute(path: '/slider/default', page: SliderRoute.page), AutoRoute(path: '/slider/tooltip', page: TooltipSliderRoute.page), AutoRoute(path: '/slider/marks', page: MarksSliderRoute.page), diff --git a/samples/lib/widgets/modal_sheet.dart b/samples/lib/widgets/modal_sheet.dart index 82590e64e..7dd023b30 100644 --- a/samples/lib/widgets/modal_sheet.dart +++ b/samples/lib/widgets/modal_sheet.dart @@ -19,7 +19,7 @@ class ModalSheetPage extends Sample { children: [ FButton( label: const Text('Left'), - onPress: () => showFModalSheet( + onPress: () => showFSheet( context: context, side: Layout.ltr, builder: (context) => const Form(side: Layout.ltr), @@ -28,7 +28,7 @@ class ModalSheetPage extends Sample { const SizedBox(height: 5), FButton( label: const Text('Top'), - onPress: () => showFModalSheet( + onPress: () => showFSheet( context: context, side: Layout.ttb, builder: (context) => const Form(side: Layout.ttb), @@ -37,7 +37,7 @@ class ModalSheetPage extends Sample { const SizedBox(height: 5), FButton( label: const Text('Right'), - onPress: () => showFModalSheet( + onPress: () => showFSheet( context: context, side: Layout.rtl, builder: (context) => const Form(side: Layout.rtl), @@ -46,7 +46,7 @@ class ModalSheetPage extends Sample { const SizedBox(height: 5), FButton( label: const Text('Bottom'), - onPress: () => showFModalSheet( + onPress: () => showFSheet( context: context, side: Layout.btt, builder: (context) => const Form(side: Layout.btt), @@ -130,7 +130,7 @@ class DraggableModalSheetPage extends Sample { @override Widget sample(BuildContext context) => FButton( label: const Text('Click me'), - onPress: () => showFModalSheet( + onPress: () => showFSheet( context: context, side: Layout.btt, mainAxisMaxRatio: null, diff --git a/samples/lib/widgets/sheets.dart b/samples/lib/widgets/persistent_sheet.dart similarity index 85% rename from samples/lib/widgets/sheets.dart rename to samples/lib/widgets/persistent_sheet.dart index 9590066a3..0e5be8da6 100644 --- a/samples/lib/widgets/sheets.dart +++ b/samples/lib/widgets/persistent_sheet.dart @@ -7,27 +7,33 @@ import 'package:forui/forui.dart'; import 'package:forui_samples/sample.dart'; @RoutePage() -class SheetsPage extends StatefulSample { +class PersistentSheetPage extends StatefulSample { final bool keepAliveOffstage; - SheetsPage({ + PersistentSheetPage({ @queryParam super.theme, @queryParam this.keepAliveOffstage = false, }); @override - State createState() => _SheetsState(); + State createState() => _SheetsState(); } -class _SheetsState extends StatefulSampleState { - final Map _controllers = {}; +class _SheetsState extends StatefulSampleState { + final Map _controllers = {}; @override Widget sample(BuildContext context) { VoidCallback onPress(Layout side) => () { + for (final MapEntry(:key, :value) in _controllers.entries) { + if (key != side && value.shown) { + return; + } + } + var controller = _controllers[side]; if (controller == null) { - controller = _controllers[side] ??= showFSheet( + controller = _controllers[side] ??= showFPersistentSheet( context: context, side: side, keepAliveOffstage: widget.keepAliveOffstage, @@ -76,7 +82,7 @@ class _SheetsState extends StatefulSampleState { class Form extends StatelessWidget { final Layout side; - final FSheetController controller; + final FPersistentSheetController controller; const Form({required this.side, required this.controller, super.key}); @@ -141,17 +147,17 @@ class Form extends StatelessWidget { } @RoutePage() -class DraggableSheetsPage extends StatefulSample { - DraggableSheetsPage({ +class DraggablePersistentSheetPage extends StatefulSample { + DraggablePersistentSheetPage({ @queryParam super.theme, }); @override - State createState() => _DraggableSheetsState(); + State createState() => _DraggableState(); } -class _DraggableSheetsState extends StatefulSampleState { - FSheetController? controller; +class _DraggableState extends StatefulSampleState { + FPersistentSheetController? controller; @override Widget sample(BuildContext context) => FButton( @@ -162,7 +168,7 @@ class _DraggableSheetsState extends StatefulSampleState { return; } - controller = showFSheet( + controller = showFPersistentSheet( context: context, side: Layout.btt, mainAxisMaxRatio: null, From 07425047c414b05935d97a29137deb2b426bcefb Mon Sep 17 00:00:00 2001 From: Matthias Ngeo Date: Sat, 7 Dec 2024 15:51:37 +0800 Subject: [PATCH 21/29] Fix outdated routes --- samples/lib/main.dart | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/samples/lib/main.dart b/samples/lib/main.dart index 93db1d8f8..2e33ebb1b 100644 --- a/samples/lib/main.dart +++ b/samples/lib/main.dart @@ -5,6 +5,7 @@ import 'package:flutter_web_plugins/flutter_web_plugins.dart'; import 'package:forui_samples/main.gr.dart'; import 'package:forui_samples/sample.dart'; +import 'package:forui_samples/widgets/persistent_sheet.dart'; void main() { usePathUrlStrategy(); @@ -93,8 +94,8 @@ class _AppRouter extends RootStackRouter { AutoRoute(path: '/select-tile-group/multi-value', page: SelectTileGroupMultiValueRoute.page), AutoRoute(path: '/select-tile-group/radio', page: SelectTileGroupRadioRoute.page), AutoRoute(path: '/select-tile-group/suffix', page: SelectTileGroupSuffixRoute.page), - AutoRoute(path: '/persistent-sheet/default', page: SheetsRoute.page), - AutoRoute(path: '/persistent-sheet/draggable', page: DraggableSheetsRoute.page), + AutoRoute(path: '/persistent-sheet/default', page: PersistentSheetRoute.page), + AutoRoute(path: '/persistent-sheet/draggable', page: DraggablePersistentSheetRoute.page), AutoRoute(path: '/slider/default', page: SliderRoute.page), AutoRoute(path: '/slider/tooltip', page: TooltipSliderRoute.page), AutoRoute(path: '/slider/marks', page: MarksSliderRoute.page), From 1c11cf545190a6486eb1115222bd3b879b68f78e Mon Sep 17 00:00:00 2001 From: Pante Date: Sat, 7 Dec 2024 07:53:00 +0000 Subject: [PATCH 22/29] Commit from GitHub Actions (Forui Samples Presubmit) --- samples/lib/main.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/samples/lib/main.dart b/samples/lib/main.dart index 2e33ebb1b..e6089ab9f 100644 --- a/samples/lib/main.dart +++ b/samples/lib/main.dart @@ -5,7 +5,6 @@ import 'package:flutter_web_plugins/flutter_web_plugins.dart'; import 'package:forui_samples/main.gr.dart'; import 'package:forui_samples/sample.dart'; -import 'package:forui_samples/widgets/persistent_sheet.dart'; void main() { usePathUrlStrategy(); From c2ff06947353dbe6c271f7ac34bff82bfe696624 Mon Sep 17 00:00:00 2001 From: Matthias Ngeo Date: Sun, 8 Dec 2024 18:27:56 +0800 Subject: [PATCH 23/29] Fix PR issues --- docs/pages/docs/overlay/_meta.ts | 4 ++-- docs/pages/docs/overlay/persistent-sheet.mdx | 16 +++++++++------- .../docs/overlay/{modal-sheet.mdx => sheet.mdx} | 15 +++++++++------ forui/lib/src/widgets/sheet/modal_sheet.dart | 4 ++-- .../lib/src/widgets/sheet/persistent_sheet.dart | 2 +- forui/lib/widgets/sheet.dart | 2 +- 6 files changed, 24 insertions(+), 19 deletions(-) rename docs/pages/docs/overlay/{modal-sheet.mdx => sheet.mdx} (94%) diff --git a/docs/pages/docs/overlay/_meta.ts b/docs/pages/docs/overlay/_meta.ts index 9768ee855..1ec888077 100644 --- a/docs/pages/docs/overlay/_meta.ts +++ b/docs/pages/docs/overlay/_meta.ts @@ -1,8 +1,8 @@ export default { dialog: 'Dialog', + sheet: 'Sheet', + 'persistent-sheet': 'Persistent Sheet', popover: 'Popover', 'popover-menu': 'Popover Menu', - 'modal-sheet': 'Modal Sheet', - 'persistent-sheet': 'Persistent Sheet', tooltip: 'Tooltip', }; diff --git a/docs/pages/docs/overlay/persistent-sheet.mdx b/docs/pages/docs/overlay/persistent-sheet.mdx index 291bb268c..fe7ff98cf 100644 --- a/docs/pages/docs/overlay/persistent-sheet.mdx +++ b/docs/pages/docs/overlay/persistent-sheet.mdx @@ -5,17 +5,19 @@ import LinkBadgeGroup from "../../../components/link-badge/link-badge-group.tsx" # Persistent Sheet -A persistent sheet that are displayed above another widget. It is part of [FScaffold](/docs/layout/scaffold), which -should be preferred in most cases. - -A closely related widget is a [modal sheet](/docs/overlay/modal-sheet) which prevents the user from interacting with the -rest of the app. +A persistent sheet is displayed above another widget while still allowing users to interact with the widget below. +It is part of [FScaffold](/docs/layout/scaffold), which should be preferred in most cases. + A closely related widget is a [modal sheet](/docs/overlay/sheet) which prevents the user from interacting with the + rest of the app. + + + All calls to `showFPersistentSheet(...)` should be made inside widgets that have either `FScaffold` or `FSheets` as their ancestor. @@ -189,7 +191,7 @@ showFPersistentSheet( - ```dart {17} + ```dart {23} class Sheets extends StatefulWidget { @override State createState() => _State(); @@ -334,7 +336,7 @@ showFPersistentSheet( - ```dart + ```dart {23-41} class DraggableSheets extends StatefulWidget { @override State createState() => _State(); diff --git a/docs/pages/docs/overlay/modal-sheet.mdx b/docs/pages/docs/overlay/sheet.mdx similarity index 94% rename from docs/pages/docs/overlay/modal-sheet.mdx rename to docs/pages/docs/overlay/sheet.mdx index 489c2d508..1b480ffd4 100644 --- a/docs/pages/docs/overlay/modal-sheet.mdx +++ b/docs/pages/docs/overlay/sheet.mdx @@ -1,19 +1,22 @@ -import { Tabs } from 'nextra/components'; +import { Callout, Tabs } from 'nextra/components'; import { Widget } from "../../../components/widget.tsx"; import LinkBadge from "../../../components/link-badge/link-badge.tsx"; import LinkBadgeGroup from "../../../components/link-badge/link-badge-group.tsx"; -# Modal Sheet +# Sheet A modal sheet is an alternative to a menu or a dialog and prevents the user from interacting with the rest of the app. - -A closely related widget is a [persistent sheet](/docs/overlay/persistent-sheet), which shows information that -supplements the primary content of the app without preventing the user from interacting with the app. +It navigates to a new page each time. + + A closely related widget is a [persistent sheet](/docs/overlay/persistent-sheet), which shows information that + supplements the primary content of the app without preventing the user from interacting with the app. + + @@ -160,7 +163,7 @@ showFSheet( - ```dart + ```dart {9-22} FButton( label: const Text('Click me'), onPress: () => showFModalSheet( diff --git a/forui/lib/src/widgets/sheet/modal_sheet.dart b/forui/lib/src/widgets/sheet/modal_sheet.dart index 713a7e748..66fefec43 100644 --- a/forui/lib/src/widgets/sheet/modal_sheet.dart +++ b/forui/lib/src/widgets/sheet/modal_sheet.dart @@ -33,7 +33,7 @@ import 'package:forui/src/widgets/sheet/sheet.dart'; /// closed. /// /// See: -/// * https://forui.dev/docs/overlay/modal-sheet for working examples. +/// * https://forui.dev/docs/overlay/sheet for working examples. /// * [showFPersistentSheet] for displaying a sheet above the current widget. /// * [FModalSheetRoute] for more information about the various arguments. /// * [FSheetStyle] for customizing a switch's appearance. @@ -96,7 +96,7 @@ Future showFSheet({ /// app without preventing the user from interacting with the app. /// /// See: -/// * https://forui.dev/docs/overlay/modal-sheet for working examples. +/// * https://forui.dev/docs/overlay/sheet for working examples. /// * [FSheetStyle] for customizing a switch's appearance. /// * [showFSheet] for displaying a FModalSheetRoute. /// * [showFPersistentSheet] for displaying a sheet above the current widget. diff --git a/forui/lib/src/widgets/sheet/persistent_sheet.dart b/forui/lib/src/widgets/sheet/persistent_sheet.dart index 28905c4e8..f12f35376 100644 --- a/forui/lib/src/widgets/sheet/persistent_sheet.dart +++ b/forui/lib/src/widgets/sheet/persistent_sheet.dart @@ -77,7 +77,7 @@ FPersistentSheetController showFPersistentSheet({ ]); } - key ??= ValueKey(Random.secure().nextInt(2147483647)); + key ??= ValueKey(Random().nextInt(2147483647)); style ??= context.theme.sheetStyle; final controller = FPersistentSheetController._( diff --git a/forui/lib/widgets/sheet.dart b/forui/lib/widgets/sheet.dart index b75a3496a..e87745a3f 100644 --- a/forui/lib/widgets/sheet.dart +++ b/forui/lib/widgets/sheet.dart @@ -3,7 +3,7 @@ /// A sheet is a panel that slides in from the edge of a screen. /// /// See: -/// * https://forui.dev/docs/overlay/modal-sheet for working examples of a modal sheet. +/// * https://forui.dev/docs/overlay/sheet for working examples of a modal sheet. library forui.widgets.sheet; export '../src/widgets/sheet/modal_sheet.dart'; From 6a04e628fda3b59a2952f117430bd361ded597b7 Mon Sep 17 00:00:00 2001 From: Pante Date: Sun, 8 Dec 2024 10:29:39 +0000 Subject: [PATCH 24/29] Commit from GitHub Actions (Forui Presubmit) --- forui/example/lib/sandbox.dart | 104 +++++++++--------- .../src/widgets/sheet/persistent_sheet.dart | 4 +- 2 files changed, 55 insertions(+), 53 deletions(-) diff --git a/forui/example/lib/sandbox.dart b/forui/example/lib/sandbox.dart index 3ec1fba03..74e9f45f5 100644 --- a/forui/example/lib/sandbox.dart +++ b/forui/example/lib/sandbox.dart @@ -39,7 +39,7 @@ class _SandboxState extends State with SingleTickerProviderStateMixin { ), ], ), - ); + ); @override void dispose() { @@ -55,60 +55,60 @@ class AForm extends StatelessWidget { @override Widget build(BuildContext context) => Container( - height: double.infinity, - width: double.infinity, - decoration: BoxDecoration( - color: context.theme.colorScheme.background, - border: side.vertical - ? Border.symmetric(horizontal: BorderSide(color: context.theme.colorScheme.border)) - : Border.symmetric(vertical: BorderSide(color: context.theme.colorScheme.border)), - ), - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 8.0), - child: Center( - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Account', - style: context.theme.typography.xl2.copyWith( - fontWeight: FontWeight.w600, - color: context.theme.colorScheme.foreground, - height: 1.5, - ), - ), - Text( - 'Make changes to your account here. Click save when you are done.', - style: context.theme.typography.sm.copyWith( - color: context.theme.colorScheme.mutedForeground, - ), - ), - const SizedBox(height: 8), - SizedBox( - width: 450, - child: Column( - children: [ - const FTextField( - label: Text('Name'), - hint: 'John Renalo', + height: double.infinity, + width: double.infinity, + decoration: BoxDecoration( + color: context.theme.colorScheme.background, + border: side.vertical + ? Border.symmetric(horizontal: BorderSide(color: context.theme.colorScheme.border)) + : Border.symmetric(vertical: BorderSide(color: context.theme.colorScheme.border)), + ), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 8.0), + child: Center( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'Account', + style: context.theme.typography.xl2.copyWith( + fontWeight: FontWeight.w600, + color: context.theme.colorScheme.foreground, + height: 1.5, ), - const SizedBox(height: 10), - const FTextField( - label: Text('Email'), - hint: 'john@doe.com', + ), + Text( + 'Make changes to your account here. Click save when you are done.', + style: context.theme.typography.sm.copyWith( + color: context.theme.colorScheme.mutedForeground, ), - const SizedBox(height: 16), - FButton( - label: const Text('Save'), - onPress: () => Navigator.of(context).pop(), + ), + const SizedBox(height: 8), + SizedBox( + width: 450, + child: Column( + children: [ + const FTextField( + label: Text('Name'), + hint: 'John Renalo', + ), + const SizedBox(height: 10), + const FTextField( + label: Text('Email'), + hint: 'john@doe.com', + ), + const SizedBox(height: 16), + FButton( + label: const Text('Save'), + onPress: () => Navigator.of(context).pop(), + ), + ], ), - ], - ), + ), + ], ), - ], + ), ), - ), - ), - ); + ); } diff --git a/forui/lib/src/widgets/sheet/persistent_sheet.dart b/forui/lib/src/widgets/sheet/persistent_sheet.dart index f12f35376..95a60f2db 100644 --- a/forui/lib/src/widgets/sheet/persistent_sheet.dart +++ b/forui/lib/src/widgets/sheet/persistent_sheet.dart @@ -3,9 +3,11 @@ import 'dart:math'; import 'package:flutter/foundation.dart'; import 'package:flutter/scheduler.dart'; import 'package:flutter/widgets.dart'; + +import 'package:meta/meta.dart'; + import 'package:forui/forui.dart'; import 'package:forui/src/widgets/sheet/sheet.dart'; -import 'package:meta/meta.dart'; /// Shows a persistent sheet that appears above the current widget. It should have a [FSheets] or [FScaffold] ancestor. /// From e6ce38b45f515deb254b75005c2ca267407cc191 Mon Sep 17 00:00:00 2001 From: Matthias Ngeo Date: Sun, 8 Dec 2024 21:16:49 +0800 Subject: [PATCH 25/29] Add barrier color --- forui/lib/src/theme/color_scheme.dart | 11 +++++++++++ forui/lib/src/theme/themes.dart | 18 ++++++++++++++++++ forui/lib/src/widgets/sheet/modal_sheet.dart | 8 +------- forui/lib/src/widgets/sheet/sheet.dart | 11 ++++++++++- .../sheet/modal/constrained-Layout.btt.png | Bin 26538 -> 26929 bytes .../sheet/modal/constrained-Layout.ltr.png | Bin 26632 -> 27081 bytes .../sheet/modal/constrained-Layout.rtl.png | Bin 26626 -> 27070 bytes .../sheet/modal/constrained-Layout.ttb.png | Bin 26482 -> 26851 bytes .../golden/sheet/modal/default-Layout.btt.png | Bin 24643 -> 24644 bytes .../golden/sheet/modal/default-Layout.ltr.png | Bin 24507 -> 24507 bytes .../golden/sheet/modal/default-Layout.rtl.png | Bin 24476 -> 24475 bytes .../golden/sheet/modal/default-Layout.ttb.png | Bin 24488 -> 24494 bytes forui/test/src/test_scaffold.dart | 1 + forui/test/src/theme/color_scheme_test.dart | 4 ++++ forui/test/src/theme/typography_test.dart | 1 + 15 files changed, 46 insertions(+), 8 deletions(-) diff --git a/forui/lib/src/theme/color_scheme.dart b/forui/lib/src/theme/color_scheme.dart index 1cae9b34d..c66112239 100644 --- a/forui/lib/src/theme/color_scheme.dart +++ b/forui/lib/src/theme/color_scheme.dart @@ -30,6 +30,11 @@ final class FColorScheme with Diagnosticable { /// This is typically used to determine the appearance of native UI elements such as on-screen keyboards. final Brightness brightness; + /// The barrier color. + /// + /// Typically used as a background for modal/pop-up routes. + final Color barrier; + /// The background color. /// /// Typically used as a background for [foreground] colored widgets. @@ -111,6 +116,7 @@ final class FColorScheme with Diagnosticable { /// Unless you are creating a completely new color scheme, modifying [FThemes]' predefined color schemes is preferred. const FColorScheme({ required this.brightness, + required this.barrier, required this.background, required this.foreground, required this.primary, @@ -165,6 +171,7 @@ final class FColorScheme with Diagnosticable { @useResult FColorScheme copyWith({ Brightness? brightness, + Color? barrier, Color? background, Color? foreground, Color? primary, @@ -183,6 +190,7 @@ final class FColorScheme with Diagnosticable { }) => FColorScheme( brightness: brightness ?? this.brightness, + barrier: barrier ?? this.barrier, background: background ?? this.background, foreground: foreground ?? this.foreground, primary: primary ?? this.primary, @@ -205,6 +213,7 @@ final class FColorScheme with Diagnosticable { super.debugFillProperties(properties); properties ..add(EnumProperty('brightness', brightness)) + ..add(ColorProperty('barrier', barrier)) ..add(ColorProperty('background', background)) ..add(ColorProperty('foreground', foreground)) ..add(ColorProperty('primary', primary)) @@ -227,6 +236,7 @@ final class FColorScheme with Diagnosticable { identical(this, other) || other is FColorScheme && brightness == other.brightness && + barrier == other.barrier && background == other.background && foreground == other.foreground && primary == other.primary && @@ -246,6 +256,7 @@ final class FColorScheme with Diagnosticable { @override int get hashCode => brightness.hashCode ^ + barrier.hashCode ^ background.hashCode ^ foreground.hashCode ^ primary.hashCode ^ diff --git a/forui/lib/src/theme/themes.dart b/forui/lib/src/theme/themes.dart index e5ef2e8cf..ce196fa88 100644 --- a/forui/lib/src/theme/themes.dart +++ b/forui/lib/src/theme/themes.dart @@ -10,6 +10,7 @@ extension FThemes on Never { light: FThemeData.inherit( colorScheme: const FColorScheme( brightness: Brightness.light, + barrier: Color(0x33000000), background: Color(0xFFFFFFFF), foreground: Color(0xFF09090B), primary: Color(0xFF18181B), @@ -28,6 +29,7 @@ extension FThemes on Never { dark: FThemeData.inherit( colorScheme: const FColorScheme( brightness: Brightness.dark, + barrier: Color(0x7A000000), background: Color(0xFF09090B), foreground: Color(0xFFFAFAFA), primary: Color(0xFFFAFAFA), @@ -50,6 +52,7 @@ extension FThemes on Never { light: FThemeData.inherit( colorScheme: const FColorScheme( brightness: Brightness.light, + barrier: Color(0x33000000), background: Color(0xFFFFFFFF), foreground: Color(0xFF020817), primary: Color(0xFF0F172A), @@ -68,6 +71,7 @@ extension FThemes on Never { dark: FThemeData.inherit( colorScheme: const FColorScheme( brightness: Brightness.dark, + barrier: Color(0x7A000000), background: Color(0xFF020817), foreground: Color(0xFFF8FAFC), primary: Color(0xFFF8FAFC), @@ -90,6 +94,7 @@ extension FThemes on Never { light: FThemeData.inherit( colorScheme: const FColorScheme( brightness: Brightness.light, + barrier: Color(0x33000000), background: Color(0xFFFFFFFF), foreground: Color(0xFF09090B), primary: Color(0xFFDC2626), @@ -108,6 +113,7 @@ extension FThemes on Never { dark: FThemeData.inherit( colorScheme: const FColorScheme( brightness: Brightness.dark, + barrier: Color(0x7A000000), background: Color(0xFF0A0A0A), foreground: Color(0xFFFAFAFA), primary: Color(0xFFDC2626), @@ -130,6 +136,7 @@ extension FThemes on Never { light: FThemeData.inherit( colorScheme: const FColorScheme( brightness: Brightness.light, + barrier: Color(0x33000000), background: Color(0xFFFFFFFF), foreground: Color(0xFF09090B), primary: Color(0xFFE11D48), @@ -148,6 +155,7 @@ extension FThemes on Never { dark: FThemeData.inherit( colorScheme: const FColorScheme( brightness: Brightness.dark, + barrier: Color(0x7A000000), background: Color(0xFF0C0A09), foreground: Color(0xFFF2F2F2), primary: Color(0xFFE11D48), @@ -170,6 +178,7 @@ extension FThemes on Never { light: FThemeData.inherit( colorScheme: const FColorScheme( brightness: Brightness.light, + barrier: Color(0x33000000), background: Color(0xFFFFFFFF), foreground: Color(0xFF0C0A09), primary: Color(0xFFF97316), @@ -188,6 +197,7 @@ extension FThemes on Never { dark: FThemeData.inherit( colorScheme: const FColorScheme( brightness: Brightness.dark, + barrier: Color(0x7A000000), background: Color(0xFF0C0A09), foreground: Color(0xFFFAFAF9), primary: Color(0xFFEA580C), @@ -210,6 +220,7 @@ extension FThemes on Never { light: FThemeData.inherit( colorScheme: const FColorScheme( brightness: Brightness.light, + barrier: Color(0x33000000), background: Color(0xFFFFFFFF), foreground: Color(0xFF09090B), primary: Color(0xFF16A34A), @@ -228,6 +239,7 @@ extension FThemes on Never { dark: FThemeData.inherit( colorScheme: const FColorScheme( brightness: Brightness.dark, + barrier: Color(0x7A000000), background: Color(0xFF0C0A09), foreground: Color(0xFFF2F2F2), primary: Color(0xFF22C55E), @@ -250,6 +262,7 @@ extension FThemes on Never { light: FThemeData.inherit( colorScheme: const FColorScheme( brightness: Brightness.light, + barrier: Color(0x33000000), background: Color(0xFFFFFFFF), foreground: Color(0xFF020817), primary: Color(0xFF2563EB), @@ -268,6 +281,7 @@ extension FThemes on Never { dark: FThemeData.inherit( colorScheme: const FColorScheme( brightness: Brightness.dark, + barrier: Color(0x7A000000), background: Color(0xFF020817), foreground: Color(0xFFF8FAFC), primary: Color(0xFF3B82F6), @@ -290,6 +304,7 @@ extension FThemes on Never { light: FThemeData.inherit( colorScheme: const FColorScheme( brightness: Brightness.light, + barrier: Color(0x33000000), background: Color(0xFFFFFFFF), foreground: Color(0xFF0C0A09), primary: Color(0xFFFACC15), @@ -308,6 +323,7 @@ extension FThemes on Never { dark: FThemeData.inherit( colorScheme: const FColorScheme( brightness: Brightness.dark, + barrier: Color(0x7A000000), background: Color(0xFF0C0A09), foreground: Color(0xFFFAFAF9), primary: Color(0xFFFACC15), @@ -330,6 +346,7 @@ extension FThemes on Never { light: FThemeData.inherit( colorScheme: const FColorScheme( brightness: Brightness.light, + barrier: Color(0x33000000), background: Color(0xFFFFFFFF), foreground: Color(0xFF030712), primary: Color(0xFF7C3AED), @@ -348,6 +365,7 @@ extension FThemes on Never { dark: FThemeData.inherit( colorScheme: const FColorScheme( brightness: Brightness.dark, + barrier: Color(0x7A000000), background: Color(0xFF030712), foreground: Color(0xFFF9FAFB), primary: Color(0xFF6D28D9), diff --git a/forui/lib/src/widgets/sheet/modal_sheet.dart b/forui/lib/src/widgets/sheet/modal_sheet.dart index 66fefec43..aafdf1ef8 100644 --- a/forui/lib/src/widgets/sheet/modal_sheet.dart +++ b/forui/lib/src/widgets/sheet/modal_sheet.dart @@ -48,7 +48,6 @@ Future showFSheet({ double? mainAxisMaxRatio = 9 / 16, String? barrierLabel, bool barrierDismissible = true, - Color? barrierColor, BoxConstraints constraints = const BoxConstraints(), bool draggable = true, RouteSettings? routeSettings, @@ -61,11 +60,6 @@ Future showFSheet({ final navigator = Navigator.of(context, rootNavigator: useRootNavigator); final localizations = FLocalizations.of(context); - final platformBarrierColor = switch (defaultTargetPlatform) { - TargetPlatform.iOS || TargetPlatform.macOS => CupertinoDynamicColor.resolve(kCupertinoModalBarrierColor, context), - _ => Colors.black54, - }; - return navigator.push( FModalSheetRoute( style: style ?? context.theme.sheetStyle, @@ -76,7 +70,7 @@ Future showFSheet({ barrierOnTapHint: localizations.barrierOnTapHint(localizations.sheetLabel), barrierLabel: barrierLabel ?? localizations.barrierLabel, barrierDismissible: barrierDismissible, - barrierColor: barrierColor ?? platformBarrierColor, + barrierColor: (style ?? context.theme.sheetStyle).barrierColor, constraints: constraints, draggable: draggable, settings: routeSettings, diff --git a/forui/lib/src/widgets/sheet/sheet.dart b/forui/lib/src/widgets/sheet/sheet.dart index a1a1d159d..194ec447d 100644 --- a/forui/lib/src/widgets/sheet/sheet.dart +++ b/forui/lib/src/widgets/sheet/sheet.dart @@ -254,6 +254,9 @@ extension on GlobalKey { /// A sheet's style. class FSheetStyle with Diagnosticable { + /// The barrier's color. + final Color barrierColor; + /// The sheet's background color. final Color backgroundColor; @@ -277,6 +280,7 @@ class FSheetStyle with Diagnosticable { /// Creates a [FSheetStyle]. const FSheetStyle({ + required this.barrierColor, required this.backgroundColor, this.enterDuration = const Duration(milliseconds: 200), this.exitDuration = const Duration(milliseconds: 200), @@ -285,12 +289,17 @@ class FSheetStyle with Diagnosticable { }); /// Creates a [FSheetStyle] that inherits its colors from the given [FColorScheme]. - FSheetStyle.inherit({required FColorScheme colorScheme}) : this(backgroundColor: colorScheme.background); + FSheetStyle.inherit({required FColorScheme colorScheme}) + : this( + barrierColor: colorScheme.barrier, + backgroundColor: colorScheme.background, + ); @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); properties + ..add(ColorProperty('barrierColor', barrierColor)) ..add(ColorProperty('backgroundColor', backgroundColor)) ..add(DiagnosticsProperty('enterDuration', enterDuration)) ..add(DiagnosticsProperty('exitDuration', exitDuration)) diff --git a/forui/test/golden/sheet/modal/constrained-Layout.btt.png b/forui/test/golden/sheet/modal/constrained-Layout.btt.png index f221474ca5493a038dc70cf7a9d425c934a30ffb..e9a3594a32d9af58c29ee96e584fff9bb85762ac 100644 GIT binary patch literal 26929 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 literal 26538 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 P8t}O@W+uhPF2DUB>V7Sy literal 26626 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 diff --git a/forui/test/golden/sheet/modal/constrained-Layout.ttb.png b/forui/test/golden/sheet/modal/constrained-Layout.ttb.png index 7ae8a55b7bfecc7503550909ffcb69233571b4f0..3a0bff0d4e9ea1252f2fdcd9f3e118166cca5709 100644 GIT binary patch literal 26851 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 diff --git a/forui/test/golden/sheet/modal/default-Layout.btt.png b/forui/test/golden/sheet/modal/default-Layout.btt.png index 4c445b81e980fc37da01824a37c2ca298bf6e5e3..682a8aad4424dfe98cf83bc59f677dbe9767512a 100644 GIT binary patch literal 24644 zcmeHPX;@QNw~kdlXOJpR2w16NMT!Ut%4kIp5h%)x0faI}K#GikKt%y%syVlnGw*ITNcI+mbwI<>bV*6VA@YhZo z*4p}T=W9^>!(jPPhpxBw?-fR;d8btl$afDi!`=b3!=Eg`?b6=E70#e=^FQDh=AKfcWad zu1%8hBhw`R_GjTIoh>)*)@uZC!&V1d9c*{jy2i>(l|;ksY$fuT<&vyBEM{`DW4C*@y_kO>~17=G}##754H0Hd45E2-1zQwBimtuNPGS9Eu8 zU0vQc>q__F!(n7#&LChCz$Ac40DBJvOahn$FbUu|5`@xlOaR9OFbQCH04o9P4*rk2 z1CQ6i5>R%ozKAh7S%kz1e;gPX2>9Iggvk;ZW@z$AUOqm>$;ruS=ltE;)77hzPugB< zZ*P~UqMe-nsI9F;M$o#uEn1V6it?_%NNiAt-tmlV?o!hL+u%j0=ToOC#mIsx+MunB zj5KTPuiqL8zQeD@dOnmrlMNYrbQ4LV(HzU&2GEUm?)2Qy`H$`fTB^{AVbUR+z5$G3Ku*l`)fweUL{eGb)lc6Ba%Re2(`V-IXAti@$p_8cT%RzD;@OwMCfP& zjU3Kf8p`D%tEXHid$~B~#G+-!`2c1#3H%vLa7gRX$9z{Fv^zYS33{Zb4OcZ z3XAM{<&vDP&dzJCDWad=@*l|?j(#Mt3rYz2{`8KXp`oFd6FlOM9Xq1drD})?HEv7%6lVP|Q5VU$ z+QFAN4ndGiT($+59M7r1#dAlX8?G8FYuVdvC>MUGk?Nk6k%wc~`d=kYayS5XcHK?y zu3T$o4L!3+o!0MAU|n*6tm9ADvFoc0xb&fy5H3J9M(+$5e;?CWEBs}%?8}Z06RgLF z*OFOhtmsHWSWT|!5=PC;kw#->qS+7FP{D@N#477IdZ19!uL6havszq}^Yg78m*z@G z0r#Uei>^s%&)&|^;8sayln1a_b8mK=iEBpZ=QA0MJcX=9^SZ@pMS0Agkx88u^cCu% zT1gLtx3`42t$h`nKF4^GH8^i8E~j%t89x;#NedD#-UrrYiLCkA)rL~yD7sdJ6oj1` zCI;NORoKztC@$dlg%92~NmKLe=0Pu>JIw~K80W@uHoN$o|7USqUr*1xpuvwJU7}yl z9Q2vr@>)b5BotqKJ7?B4>_6RK-cs#ze>M z*{rwMHtaj`hvY9BXP+Lq^5+TX?n!Z}9}QpYU-0|dEcNB}w<%svgHt`#P8`e2);sj0 z$Gc~GHhM80ks3DAS0?N>*nefenfv}ypp@&_sq&?3MSVdxQ(Ak1Y$J%ioTYw}|9~KX zt_wb}G2x%z{g@Ju)5e5HjrSV5 zy1JUv�-rQ7pkvGdKe{mh(ifU&6eFl~pq`XvsSVTa3gR&pTmf!JC44d0hf$5*A=Z>UnojXJ&~+Xvf$xTn zb4TT9QX4mm-c6?PFX5p= z)>HFRLf~ZW-CjnyY}k~$7{xG2Rz}gvLgsYz!&r@(Hr1SbuaE{lxhUe{bK?~3lMv|g z70S!+{72^KdwP0WSS}qiNRkbItBu8CRZ!%K)KkN_4>;a;ehp&#nm0;l?N3+t_30^Z zOXppUKNNDITyR2BF(*4a+bO)Sa?*sY8$9LImZ^>VU>6b+()RR={-KCPZhMEcPFV0s z`^rC^!W-`1_jX>^@5!X)B?yL&cb2=8Y$`l1w54)`k^%#8 zKYA{>?S_gu#vBhrgda!jz&xS#1|CvO($qX zQ7nC)*~5yR&kALJCx#O6)RzKZnxvmS!$;cM9&mNdNSeAQ>HgHupn+=dTW2}DGGw|f zdj!xG5n&i0V{tbdqnpBc1Jb^Du0f$~`7x_P8>s@TqVr?gK==~VeQM9Skus%ZGy`vO z3)urWxep(&7#rK;gIW^RrI#=OZRfVsGD9`xBhG^Pw7b~aT7EWZBk28)CCO#KRH5o9 zpi-Qt$No|QE~&Q;9b{oy6dN-0xrslgEH!~Fb-HaI_|E7!5A4CDP}E*y1Vy8 zUj-V5vkD1BB9R~HPyq5?xUeEln&cw;s%myEYP5=olmQ;fb9yE;NmobSA!14Q;m-sT zaCwc&vtQ6Wwi0t?02NjS(E7~+*SbkgRIL&%E@OAwTe$e;(z!180Oo8Hp>XNmZqwsy z$7dae^l)JtV*nQfadC$n#wTZv$+V6O%r*NxIoZJ0mTusidqP<`>B|fq`)(#iLifeX zm7&a98A?YLV1n_$T^N{{w7)Q-f&r9 z-Zv}RzEX1t$8x3fbFbDM4V@i-gmLp^_$6Q{6k-;}3U&U|@7JZp%#{fX0*%{4dUu%J zdC0c^hPj_{^2rBBjg!yXNoxh)z7g_CDvv(dS5;zuXOARzu0&$thWjlgc|(U?V2p*c zyi9Gm=Gp*alJWO7)oVR5ew={1MBEN`&j_$;puWBz*GWoOb@yqYMsDzyuRo~nbEAQ( zjN!I=cz9@J(--*^(SF^92Jf;vj91Vwr#}hO03%>B0EGy8ek)6iP^-&HIyfiqFVmmI ze4D%;FqzD10UNiSY#6`)k&YvZN#V@yKYzy~2TRY2&;bE!*NFQ>Z<#!SSI23&Zl*0o zxuL4UpFMZRAb}s)O`+@yA5^$*ktfg%SIDer(pmQ63`sHe-jO56OrP$7 zv@dL`VY5vnzLR;Xo)$!iC-cBE7DPK+pjL zfOV=X_6fSf=zMO{78g6-`Ml7{8z@m(IBp9RQx18^ulV6n5Q^^7{bDq1UvT7zTYH*J z)W3EA`s|_k0}v{E9E~o5txN*4B)u6nex^88XX%3*Z;m~n zInSZV0nKh_*YTO0=C&thvZwb_u_)`Op-j&NGKSwpjO+6e+>9eF&G-2l5-}SO7MWxT zFZbW+N{GSJ2ZCq`z?-QZh;I@RuqT8|MM=Ctl`Nre__y~M zHn~rlYH{D#RNgWI7dm##B&|0aeasXO7$i~xd%Uc?L75r*F0-V;=;BKSEQkJkcdN@|Dx z-txzVsO%ulV3Q7$Zsq7G*H`Hsm!TQdoG9aK(2^)KTK~&NzfL2COCSy!Ei5M-Xpu!v zm}~li-7;Vti;qkg< zgpB@PjOf>Os}5aWSLyKWxl z4Hg9e0xSvu1XvUxdw?Sa00Jxu00dYR00^)s01#kNfIxsn0e}FD0svvXDAbE8P%Y3y zH$>E85xo?rk+$jY_YRGg(}2*Ah*bFNWgH@5OqOwg39$kL0w%;N5U@h5009%?e;~wH XA4|;NXU1dr&~ZkWO!bR@aJu_%#f5wU literal 24643 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 P=%n*!EsaTMoJ0Q!YGI1A diff --git a/forui/test/golden/sheet/modal/default-Layout.ltr.png b/forui/test/golden/sheet/modal/default-Layout.ltr.png index 99e33aa9eb0687d1f4745d6c9c6cee7c034361c2..c6dec91bcdd4cb32e3f9539e19e111e77115daa7 100644 GIT binary patch literal 24507 zcmeHPX;@Q7+dgi^rHYEkE?QfZ0s=+Z2`F3LKvWECLPG@v0g+9>5Ni7=f`9O%2_!7vBmwKUTvz|RKi;-ye!$5g%$a%SUY?mu=H@9I z>&+YGH$o7!`RKP6ry*#A8w5$LU;i1nQ`*8`3x2H%JZ*gh%CA=(1uxbH9yxk;Jt$Y# ze;*A&yP=~NhtFO~W-?Z7sMdnkRu(tg%^#0`M*JzuIpu>^M&DZX(EL}etH6JXN`-qH z`{N5}=~&ddmA`D=P_S|deX(li%C*^-6{}aSqt`mDTtdG?J&Os;=_W=c?Y{WK^^M=| znp!P4R%653aZN9I?c__H)f>}Yg18B;j#<5sj`C-bRkPubtCT79Y2)6B&=08wG(Cz0 zbo-M%bVongEcfLnTkdXuvbXN&A6u?|{$wlOx1W3f{N*P*_x^&_vraSDKv03Z28yWf z@itt`+uOUp1&NM(dOVTp>`#(237?6cnwlEvAb2VU)-~GM+e?F6UX7hTZTWFGrS|#q zT~43gj$RmxZg)>GDXy|zUihaXe{X1LIK?yvm19XuivsQ7u_9R`u7sVla~E^?`sZ?r z?lhFb4duuy1U4RzPe75jcpX&GW0#fA_WKvl)`T@oFXd?&3X`Tep?(5P+&KDj!cg5cm8!E~X{7?O+%wFHapbaG;=yZ_Q(O4{+Mh z37wst4@@FL?$C{=e#;0LO7f%?U7+-=${McfiSQrrSTYg^>XZwBVN{4Wvt8N3)z!6< z`10j9k#n_11ARYAdQZJRpS5KrEKXr?&T$eHM?#A#%U2;tH2xD#_fc<*7h8UJ$2}&g=H@~c` zg}%JBZKMX!Z)P-8u|{%7-GNfKAjXw}&4pcl<%fLYQcNOhk_{xK>tqhN$l{4p$8wXU zM300*LPQN8`7asN{s*oB)IkkY7LjOd6=#^?wpgb_e@5qiH{SXpwxlOqO_c`uCCqBe59qNwXb}5B5QE@d&S`9ijnq0ckcvAb%%o8DmFx; zotmf}n#6+dn^53=jd*mg{`;TJF?|(31TX^3(=#)_f5i1>E%Zc8kn|U3>?Yae6IK@0 z3jRd9OY{~bPH*wUjk$HxH>GfLjYj0X&3cyC*0qwzRawdEiN0 z?;uv^`Es^18m&wUS8DJI=?*rHIey@^KARkI`PMG%VM40`e1EZzOi=+^*Lxp zk;%P#_o#?pbtg9-0pQ6-QzF+9Oy}QCrYC>(MgPzvTqkq(>n|{i^ZU|qOI4VE-Ij4K zq6<;pULf^I$=uRH-KA8^#&|Mw_MIfIxgWWQJ+dI~omYfVAz7y=k=RWhNS8^?$*Ee+ zi4O!}Ovwu@HRpN8Sc^}8a$tR2oPwV2_+l=8(a$BMqh$NOd9*uiad%BzIk|&3F|zQ` zr_D9gmvcx=oOWaU?zNED4InRI1Tr=a4Gs|oztr>FFX%W;>}Yd# zc6Kypyp0w}H&ISN@V!nX>*xGS;7{V**PpJ#`v<(0P`;{VW8`abr>!0#V9FxqtK0o4 z3+aFm!p71_yhRli+mzqmFEnNKD%jiGTXy5q()KLQ51ab)i5Th|eZYG8?lVBikggn- z6~V8&43L7llfDJ|U^gHX7^s2EV&Zr206VLT&LB}?_KcvWw@|%y3AuDjAr!0bRFrK`|0ZmzTidIl(3ymP{`~9fTa=u%&@bOpRVI2%1Kb$_G^IF? z^XJcNN6!0B7A9aX<_b2;YVBrIaN(6#$C@wrVpblE5IwkPBiaQ($Xw{z_#YnLO%W@z8YX<~1ZgPAS5d z`Fc3zZIAy*Lz?#Yzx7!WfVIMTw(iSjp?&1;v5uS0C5m&DSjWy?V@RYCg9bQLxOS*Qc=GL!BKK9)v zwAZ^0d#!HC+G*wHottOtIk4j za;|l#;fbebR!A)fQRM<2wod|+$^ZtFPvSnjGWs;JzmT>o){)>rV|Ebq1a-*im1! zTNEWTGxMJ9{F1lNCi7?3yTXd>TT!nspZ}xIX&`ctZU@kVfjS+^E{dQ#`GNjqz6u&2 zTB}h~qeC}#zB`R=2f9=|&If6U#@KR%nTkR&J2+a@L{`M{&jim*^iujd@2Z}Ox%^CW zy!nD4GHIMCrU2 zH^KOuc!Qyl5W@e2S`uP`JX?#F$Cb6DT_8U$~*Ls!|KwrG2z7Ka9UqDx9vBKiJpDG zFT%e`&bjuKwT_~6n?Vq5l;X#gI*H*5h;eE{H7?sO45|*rt8~jGRk3>`CuyZ zLMMv1xjnx8Ms*z_b%BY_NJ~qz9G@RUQsVt1r*D@6i*%>PNc(zFL^eNWAO^WpqKHTa z{n2|jdgyr6?VmlDHZ_QUb80#)p(MK?;Q1enn0Ri{l;bltka z(jqyaCcAXz_uBp!B|YA)hLVU`x6hUM35DUDhgQ=sU%u356={}qhLyAoCMKvpzz!(L z(5i3VDdsbu+voPD$CB-|(629B0#|=^k}0#T@s&^FwGM#XeyWV+@)vQaDq!=Um#1OS z$ktu~>Rrh>ON$c^E?Fyvdr=-79Ayi;S<)LB(e&z`8nQ;p)>uwTg|SVTwhGkAh~Ll)$m`kT*CWcQ_By<9o}>n6<@yA1L!TN94*x;9-uhAfW}=szLAP| z*R|1Z$w?_09$d(sitm|N15$x?gdf&O)D&IdRi|6VVj9ye3*9QOY2=IJVm7XJ0c67a zxqBeU3%lZGK#@VVCd@N{fIE|TK4=BG0a`D)!y%hYMuc+=pENSd#v^wmx?Bz*&=LHcp3?vb7zaI?;SPhr9e z2HCmp!K7Ib$ahb&ks^Dnj|RdW8p{jY48jgdMf_Jnund!DshVJvHVs@?h}>?ij6F+8 zRnT%XbHOc?I+T9E2k=MHU8*Rb656ha>II%{LfG`KSi6jRuT~w;0+=ObcPadEMwk9cNL;Cl?@-SRQm^&nME*6X>lcc;3; zRy<{~*A7IA!{IbGG;9S@)<}xrjr5Szx0uW{?AO%PV01AMt@vFkCb5jn*%t2vd zeX+e@k1!DxY8wy-b&%h-Jr1D+kGE2rY)zHGXgURr7ke_x{S);2qSiS1VxcJRld`h1 zc57k(i_-z++O6AF#Ix=v-Ty0<5xxhMzv(Rduf0Y9w;l$jh@EEtthF&1_b~2Z+>0V0 z`~feRgCP9LazA3jmM#cVJ}EpGKp3;Af9@v>uzJGkDWm`dXAQzA!0HKt@F(gijMM*7 z%vt3SmT1An?Pm%{F+@f*odj<@vHIgNDHUIW#e(Gm-xdb~jtLA1m?SHz0J8yR1Iz}P z4Il!r6u?pdO93neuoS?PCJ_tZ8KYPXU}IbsMHmn;ApWUoq8W>Ecmt#bt7(+uwbJ8F)W{mmWGsCZbfBgP<|9L-e?>_U#xaTqR-1l=`-|zRj?)$l( z``R%Z3#rxet04%IvOH{d9D-Jzh9Jq6D_4Lc&wIGvf9JD;K z61-woo=t+Ft&pXe$%)83I`QJFmwTaQ4Li)&25L{^BcjDIw z#*e+!h7#g;)_=3~Dd}6Mr6%+{^xaZ>>-VQ6mfB|D>{)6i98Ori)Ly@;e5na-laN_z z8}EQmzGRE9%q&B-lA@8%zmfA~3lTVyvY*0Sg^q+h`jvVVrs$I6VC8}ZeF+P2oP)#v zA{M@~2o3A`5{F?uhxL333$UKUdJgNk&;qb3!m0?XqR0aO>FZGSiAa6XqM6)Spkd-r zqcjBVUG;e_?#AbZHu&%&q+y$g4FLlJ1_T7bY=GGShm1uffZ4EU2sk#tu>p<^ORDf+ z&IbM0?pe@cEdb1acmlNqdpH`xY=GGSvq5M9c$z52!RJ(9J&LV#KMbi7G_SSwfZ|0n zMYE<>yGLEg2_73CCETa)xt4YAaPrNft1fOXe;BH?sUKhU{(gAZx2h(^#-_`6tc$w1 zG0gK({=s7sDkfO^);l9V%I5QnGQ*<1PLIE=*Gfeb_Rq6o;_$<4UhIr=JBu;BEMdnN z^>Np~sIs&Cyvq067j<)ozo@?3@x?vg>t7V>S$LU*ys+H=jhf|>F7 z@#Dx3_iuVMCTFs^G_-kjz)&F;Yfuw0sno0(ap8o6!y#}erz+gv-~VWy-gz43`t|F2 zqp4>w9Y#F*mB7V2V2vuERxMIFl9C_cLG3=T>D9_Etf{GKK=q>CWvp(hrz9o0^Qi=B zX-%KE^>SL{HG15MqTEVbaMo1$uyeTn@wVL2zpe1kUJftTKe}v3Z~YeX8ND4f-mmxJ zUPJK0oa{b%cWo~wF)ElCyo{WzTBlT1RrQEZqf(D|*tsK-NbGdG{wV>6A}sHOptlEB zf=bDO@|{+<(N77DI-d+)?8JCdp2P<{ zf7j%pyjYGY8bGZ>sgrbOrr>)TA<*Yzw6nAG3}a9?{lH_}P{x3^Th#l^;z{t9nh zPOIrU!!4A&5Vxbbv$@EiXcCQ4UA>Px36_|_D}gLTSEZe2Q;deMukY&dSl(=!`@)oL zFy~#OHivjsD)3cc+%!#2e>M^0+w(Y@;MJD1DP+9$TEk_@$;yyrqO;U9U#YH?fClb( z7a-+tsM!9L?H=0sSLDZr{b@~(($b3hOhsAOAd}Wy_TdvJPHc3=kLUQEn#YQM3zgT3 zhG4=Tig0hB7p5F)O4B8+M=`1#Z}d)(aH!T>)5Z-korUHsa*D>YzxIn=aXLciT%XHX zYNs6b)>0p<=HhIkqM}mef*l&>KRhh3EMVYt0*G>G{6chhPfyif(SyfNol*#_n;W+o ze(1y#pXJyVG4v|2-nXNkktjC#2bwNQDrLL)aX!9d5%B7db!l(!n)*KJDRFEbdu>my z#^)=kI+P~muXKyek z0a8*GQL%YJf8Oz$tg4tDtUPZ|ujr_IG+pY%s_u&y@a;Rkfhx_5EHcz*g~&-@$ms^S zVlv82v6t3EcciF8wGj<;OtX^O8|Q7?0_x_Pt<%xlwvBhh8*pd#@6OVQFLUOJP`+mF z!VS;jq$KkcnMQ8}>X#S+58*RgvOeNdocIbWjewXX=oABsEw3mk<5ow$`&Bl4&RJ%U z)B0gfQ%_r50G}%*WZo;_{G3oh6(LTw>^YfsZNtJ)w&rjO#xr*z-jPn_=lFIQvM;c- z#lH5*b6gLu!Q|x0lbv`0X8H8g)YNkx^Sso;K?f_JiA`4oKAewQ zS6Gd{OH@w3wn0TZQUE;kJs{Go4go7z;Em37C2B`90J~G}nj#b=6+@3z`VrLKz-Yl) zhnoOeq3k36&Ck2F3XN8A(zxd)%yH!<3bNuS;0(=cj*9;m-Sb;X2`irQ?CQcVVc<_J}^Y+d~P1Gzut!!?<4{eTii(P%2HY~UiOv%4d zh+;FPjH=JRzAm?K;))YK&J-7wp_JJC=dXfIC_2WXq;GP_aGgOpmPD@|=G(YNy)Qmg zAOVd`ilWY2E`uqNC9z>}s+n1wLE$F0MTHZ|qRellF zD5c1e2$2@31#HU(eiHp zFj|>b_`OYisMH*+Hl^3OWXFS`ZtB ztY}JClueP<2mfU+PUM3LtsdsJuUHgaWnxPY~t?LBc_K7mB4(I@mY&qZqb|f>-v&mJK$E*#! z!B#Mc3|b?y`^r5;_$>} zldKyjlS7upZ_L&4_noZ+Ob_hkODfObz107}T1s%B+uqjj--I!Y{shkN5 zgv(wOt5G(kZpnVbN{vRK*IKvXy4a$?;kw|Vu;DaHLA;St)Y$LY+J51!w+(AMy~kT` zZP;$%wy}EH=!b#oz~M36>|h|?EB{GlW#wyjnd{s^T*o?tkH%{hqmNX~rX)o&Ur;ag z4^+{T|FY+`(43AOmJ`aX^ zVT!wR=T5a4vcM6El>6BbpjYkbEWqvO(H97zUfxs3V=4dz2%leIhj@@*>C4C9NNUwY zd0Pbks9ihT4MgLIljuT0pYiNn_kGc);6?g#f&1poY*nGanLM+W}*$v*j)2W;xw zGn9pF8VNOt?BxjDX`oR)(R5#7qvDe`*v=o#?OP`@K|(JYi2+UHmIELg`_8ND!BD2#WV-$? znbznTA4Q4YM-Oki?B%_-T`;6lsX0~c=y-lEXMmud0-UYeTk729J3E*)Ffh;^A~tE| z9)NOVg^*Uw=8dght=V=TOPs9j01XIkDE|g*ykOzObk)6=YxVbWXFk{m&W>DO*Q6Lh z>>Sf}D0AHmAZjuXz@MbmVW7J9z{CiU%Pvg7P)*?^yX^Y)Kk?5T9UXO}Y{h+rD~bCe z1~#&ez_ij-OAC1tF#G_`4)5@SzQYpQ08{QVe^aS+v>< zB%}91=5UW;R0}$IK6V`~(@H2qZphb<2-w6kHw$GFADz|#vJ}bOFD-t?#uy`<5e#I9 zGX@%~@kma|NonZ~yNF5_O8xq~tZTGDCQSzERA00|W1xz~8MS?NWmR>vrHWK~m#wnH zdUta(*RY;UI~SK4d%S5#UibiI^bdO*kiW&Sc4~UO>SvAJ5I6_#da6lb(SGt#-Akh@Ngx7(90_p_`K%I^AU~Y#uQH$xe;@^;gWxuIQAO1s6Hww zDN&sT*!GD6Nscu!w5x3phXz@_j{m?$ZEfvA9J|F`NollsxYuV-W%MVi9%saq+E#{N zkPPlWcT;DMsDYa~z9rl#Bf0{_Ld`?z^GAw0uv2eTJ4+lVS6s$$@a~KQt1N?|375>w%wYCV*R#!L3@U%ywp})P8)e;NUh7PL=ziphou9I@JAV9W8<>BP zY!789A?e$No*dK+AU^j{K9k5wpex|5PXc^V!4mGYfdy%V6OGyC_6b>C+y&ZZ2vRG&cW*}kmUT7z=X1aOk(qg)AROt@?7c?J8b4op z6~Rp{x+yCZngJjYu%2ZQA4!n6_k z2jL?;5Y$&CjNkr53PSM02^(og40@SC?(;rVbIr%5i|Wf;=y?0x8DPkeKdw6``-pGoB(2%T7uSYWjUx2Pe~7Wjz%5krvd zw7F~$b(o-Ne;hExk!}h>Hdqr`Z_%Wsdp*TQLWn3*P z;r*s7q9F_4zVZq6*S#D7j~;^lOILbe*TSw9iR?dYg%id-jQf8h?in6u-a(MEwQyem zQMdnqn+Pz)V2b@4DF)L@WC8HD^`CI#lH(rE5IvA_`ZxTiE#a~jOIKgNp<^aBNso1(*#m8(=oTYycL3 zr2v)!SPK4mQeey=nyiArR>qp+?xB=-MxMX@Se#I_Xa{(&VR#GXMJT{KQ-9th2;TVa yU)uQ2d(cf(5hg+s=XXh%Q!uAQ7Wn@*!LLCLoi`a=7AP)UkHH@BD~1pc{N zUZSatPah!OnNZ>NZ@%1`zg~s*3rVimPab@^VZ9!)>Ee17x(#h#ukZcJ@zW^{Hym9* z9Qr+c@^vi!Vz89^iut)Vl?C!GKUE`*X7gzXg%YMU?VNBM5fC&K;0)k*~fV}|@83HAMy+Hs392?-+0LO-P zRrq^*!@jQ{ff?GhwE+K&7Q?Ls2>iWC4VxG?F+2>i>IHBQZ%qvTmj!Pxi=kKFP;TDG z!JPEc-Vmi75q&4kDnmj@_V=j`7wel+U2Maj_-P@}Hkjg5^bR$id0IVVRpBqB_Fcz@ z9TK;6{}8rni%F&(*@V^HI&cNE>1)HXkqP;V=jLP~XT%pvn}bMA{c-eR{}d)$hZ8sa zE{VPoGWl$Q+`-S5+1>eUJ)Oy)%dBpFw*2n<&nA5jezscg&S%T={(`6X`IaSEKIr1s z|LPZ2bghBqxpO=7$SVOyk;H?&{=<_alpOne@$trNM$h0#T3pn#XV3VD@DwB|z&l!A z|MKhMJ9qAAP8MA*;4&((zYst+espzBTJC=I-A44>$oN41Yf)Fq^8EaKOIqDZj5E6Sl6?H7nH)*NF0dMI z+o@G5hNcFtEJzJ-21V-1hEu4ioNxC#u_m-U=2|um%ruZ?vuyIrC&|gYz-9Hc$B*|R zmZo0s2w5U+fP((DMIdTXF8!~DonD3tP0zJ9yR~Se>tgYjUz_9Ey@7e{O{Zsb?B=g| zjlZz)n&|L)RKZewiwIf3!AhLrT?(dsII9e&#n>~*I1;BL!q)s0`5Kf z{&d{R<+k>AiFb;Mii0-faz#i^Su!UcwVxx`a9u&6#d{WVM4uizmCcKuXTwGLC zRM@x;3TKu@kb)qW#PvJaA{R7O71qiBU(&U5RiDl)@y&U$#qCo2n?$@@>HH=0;m}L=l|65jr_UCUD}>;Uh;nQ%QD#WHAJ1uemcV*k2ZsqTT>zi} zcDLnMi?r%w)bjh-GFaktfET0tY8JyDg_73`n4r7(EYIu5nyQcvGRiPc(K7y*3n^M- znFr9XZcaaSapSYM$D3NyYN6kn%?+F%li(A-PEIGYCeS@+nUd?Ur-E5&Jf@46;wiCc zu6b>R;BtD%@3yRhcXktQaqdWh-ohU{jkHV+tCdQYvOA}(4XeA$ER5)tzt*N2sg$@7 z3ea^mxAq-6t`i;=k)R(E{P6m#$muls<9a)~pjfp!~I z&qvGy4Jjvno?%JKYdGp`TW~QerEVA{VIU5x(9>z;{Z1!3 zjveDONvp}qtK7}*VR!M#a+ht99Dq7+Z7tzV4i69K%o2FS{@LeO8U~--HNWO%VQp=F z2{-S%yRqDB^eYJoi6mVe2+3KevOLFWCeUI=`Y;3kNgq5F?0DaDMo%17@r2zQ%HDK9UV)?hSAtGoH#i)Ts! z?jNg-F54%0^y2$xmG5$bWaQ=M#>y}C(KMH) zf?F~y=%te{x(1iobb6|q*I1isxTs!1Cz}v7^FGWLhij#Wp73Ry6V994qqkVzfsWHl zB+>h-ZlK>k`Z>l~4bv3uJx-Cp=|j+$f`#;7+nSh|JoKhKDDWD+Q#$lplE$LlD>8ck zuTqm~X;Z!L*SScOyDNH>JQRTzGV=a$%VUFIo#`O}e93p}tZlEZwr)d>vWHYc%6>T% z4Zyirm7SiRJ_6h;bX{m;Mn3#*dg*%A!gQTJf={YLr(+g}M>=O8H6lv9Mn7osmbMSL zqPPLT1zyx}eVDx@BQ|@a09EBSNlPcoj&))P?sH|&o_(wBJ=XDR=jk9;AwemD1eC#u zE(XHyr>K7TJcvp6@89REORZua@vAuf6~A{0s%p+n56fCG&W(u@2aJ)@zP(z?KsxCY zBv!X)vt)8kQBhGRTiJHz$Fyb;tFM0{8(@WJ;UoMOhG=1(Gee3|m7f`iR%#Kl*y_RR z#MFTslWq7-2|wD3sjiOPiDq!R?YU-&$Dba?ES8GOzF;(5^Z_uWGC&0H z|8$`ee#ine9HBC|$9z0-BIF3|0m918Zg;Y_x7%Ffc@WoCuYRb$U`s}k4@8xNX5SQ; z(UD69nMP)2W(18!+fitPT(Gxnp1X|$iYBQXbnW%*F=@Hx)!G|v&LHvM+6K+>Q|S0kEa^^DymZrz}YL% z=8oEQ^W@#&EOZx2g)dWc=w99vihZH8S=z|q{R3)*(J~{9o6^S3GCK>M8);MiL-p3G zm?rsw(!t6ig9*_1$vK`&I+1;Tw|>b00kf?1M!PM>{2Vj9r- z+_H~}Vg9_8<>V3Qu3SUR3tF#wXW2poG- z{KjUS>V@o!mUGJpD=RCGYY9NunYk5u$ubqB=lLwv6{Xrp0uJ(?vKY+6czF3ESBxEl6_4bJZdt-IyK1tCj6|musQc)!G7gRPLl8} z5KE)srsS^bU~%ze9p7&g%u;l}K?d926o&HCb_#UC4LwOK#xq06Q}$W=_t(Z$sEKMl zvG^h3xz=Sr;-;Td=_i1tLz!1jXc{hoUqvVbOmPC&iF zjZAkE%CMRlQHuiX2G9&o2J3CxdayPoh96=oCZ3ySr4*cy^?Ls^@R|u}UBByi!erZ1bhk&{q^djZM$7M}@#i7KtL!p>GOzYy~8JfZs|x0x|Anxik{ZHOIqq-a?(UAKY=R!SD_#Y8^IL06m=S+k1`8*BV{!MB#Mp9;{)!a$q%r>xBmanA}bgfgW*I zd&Dm<99okrpY!WkD!93SK#%&bJstqxJp}zthk9Vs!lva12x#v=Ylsu(JCIl>x0uI3O zavcabUalbl%Ofn0usp7-0_+X2H^ANidjmk=?=J;yO|thOXydUj(JMy2atyW2kzw03 z`CA~vd$|eL*8wQt&6Yn6G{SpO|M?soyqVMgxS5mJi^=)5hZ2Arh06QGKE;<-eu2sJ c-;yVF`x|HHP=zlQckn?nF)}yIJ>?koZy_}_r~m)} literal 24476 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 U_q?(i5q!$R^n^*_5$CJ_0U0E96aWAK diff --git a/forui/test/golden/sheet/modal/default-Layout.ttb.png b/forui/test/golden/sheet/modal/default-Layout.ttb.png index 0f4b44fdfa460696a1db802938f262f275f71b57..179d6f7036be0512a026a808d9d2a2409d0f9f7a 100644 GIT binary patch literal 24494 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 p.toString()), [ EnumProperty('brightness', Brightness.light), + ColorProperty('barrier', const Color(0xFF03A9F4)), ColorProperty('background', Colors.black), ColorProperty('foreground', Colors.black12), ColorProperty('primary', Colors.black26), diff --git a/forui/test/src/theme/typography_test.dart b/forui/test/src/theme/typography_test.dart index 0474ac7c0..99f6cf615 100644 --- a/forui/test/src/theme/typography_test.dart +++ b/forui/test/src/theme/typography_test.dart @@ -52,6 +52,7 @@ void main() { group('inherit constructor', () { const colorScheme = FColorScheme( brightness: Brightness.light, + barrier: Colors.black12, background: Colors.black, foreground: Colors.black12, primary: Colors.black26, From 13925da76314f84e9a5d4e981bf0a813e484a067 Mon Sep 17 00:00:00 2001 From: Pante Date: Sun, 8 Dec 2024 13:18:33 +0000 Subject: [PATCH 26/29] Commit from GitHub Actions (Forui Presubmit) --- forui/lib/src/widgets/sheet/modal_sheet.dart | 2 -- 1 file changed, 2 deletions(-) diff --git a/forui/lib/src/widgets/sheet/modal_sheet.dart b/forui/lib/src/widgets/sheet/modal_sheet.dart index aafdf1ef8..177288870 100644 --- a/forui/lib/src/widgets/sheet/modal_sheet.dart +++ b/forui/lib/src/widgets/sheet/modal_sheet.dart @@ -1,5 +1,3 @@ -import 'package:flutter/cupertino.dart'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; From cfac58a27155fbaca3a85623d6a73f95ed2fb80a Mon Sep 17 00:00:00 2001 From: Matthias Ngeo Date: Sun, 8 Dec 2024 22:51:26 +0800 Subject: [PATCH 27/29] Fix failing build --- forui/lib/src/widgets/sheet/modal_sheet.dart | 3 --- 1 file changed, 3 deletions(-) diff --git a/forui/lib/src/widgets/sheet/modal_sheet.dart b/forui/lib/src/widgets/sheet/modal_sheet.dart index 177288870..acd34666f 100644 --- a/forui/lib/src/widgets/sheet/modal_sheet.dart +++ b/forui/lib/src/widgets/sheet/modal_sheet.dart @@ -24,9 +24,6 @@ import 'package:forui/src/widgets/sheet/sheet.dart'; /// /// [barrierLabel] defaults to [FLocalizations.barrierLabel]. /// -/// [barrierColor] defaults to the default Cupertino modal barrier color on iOS & macOS, and [Colors.black54] on other -/// platforms. -/// /// Returns a `Future` that resolves to the value (if any) that was passed to [Navigator.pop] when the modal sheet was /// closed. /// From 4b14c28fac67c952414f2bf415465e5152113da6 Mon Sep 17 00:00:00 2001 From: Matthias Ngeo Date: Sun, 8 Dec 2024 22:53:00 +0800 Subject: [PATCH 28/29] Remove material --- forui/lib/src/widgets/sheet/modal_sheet.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/forui/lib/src/widgets/sheet/modal_sheet.dart b/forui/lib/src/widgets/sheet/modal_sheet.dart index acd34666f..46799345e 100644 --- a/forui/lib/src/widgets/sheet/modal_sheet.dart +++ b/forui/lib/src/widgets/sheet/modal_sheet.dart @@ -1,4 +1,4 @@ -import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; import 'package:flutter/rendering.dart'; import 'package:forui/forui.dart'; @@ -181,13 +181,13 @@ class FModalSheetRoute extends PopupRoute { FModalSheetRoute({ required this.style, required this.side, + required this.barrierColor, required this.builder, this.mainAxisMaxRatio = 9 / 16, this.capturedThemes, this.barrierOnTapHint, this.barrierLabel, this.barrierDismissible = true, - this.barrierColor = Colors.black54, this.constraints = const BoxConstraints(), this.draggable = true, this.transitionAnimationController, From 898acdb1570fa03cf87daec154a359f9f75208ab Mon Sep 17 00:00:00 2001 From: Pante Date: Sun, 8 Dec 2024 14:54:41 +0000 Subject: [PATCH 29/29] Commit from GitHub Actions (Forui Presubmit) --- forui/lib/src/widgets/sheet/modal_sheet.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/forui/lib/src/widgets/sheet/modal_sheet.dart b/forui/lib/src/widgets/sheet/modal_sheet.dart index 46799345e..48891d05b 100644 --- a/forui/lib/src/widgets/sheet/modal_sheet.dart +++ b/forui/lib/src/widgets/sheet/modal_sheet.dart @@ -1,5 +1,5 @@ -import 'package:flutter/widgets.dart'; import 'package:flutter/rendering.dart'; +import 'package:flutter/widgets.dart'; import 'package:forui/forui.dart'; import 'package:forui/src/widgets/sheet/sheet.dart';