9dfa06ffee
Docker image / Build (linux/amd64) (push) Has been cancelled
Docker image / Build (linux/arm64) (push) Has been cancelled
Docker image / Merge release multi-arch manifest (push) Has been cancelled
Docker image / Merge debug multi-arch manifest (push) Has been cancelled
Docker image / Build public push gateway (linux/amd64) (push) Has been cancelled
Docker image / Build public push gateway (linux/arm64) (push) Has been cancelled
Docker image / Publish public push gateway image (push) Has been cancelled
Sprig image / Build (linux/amd64) (push) Has been cancelled
Sprig image / Build (linux/arm64) (push) Has been cancelled
Sprig image / Merge multi-arch manifest (push) Has been cancelled
Harbor Buzz Orchestra / Python tests and lint (push) Has been cancelled
CI / Detect Changed Paths (push) Has been cancelled
CI / Rust Lint (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Desktop Core (push) Has been cancelled
CI / Desktop Smoke E2E (1) (push) Has been cancelled
CI / Desktop Smoke E2E (2) (push) Has been cancelled
CI / Desktop Smoke E2E (3) (push) Has been cancelled
CI / Desktop Smoke E2E (4) (push) Has been cancelled
CI / Desktop (push) Has been cancelled
CI / Desktop E2E Relay (push) Has been cancelled
CI / Desktop E2E Integration (1/2) (push) Has been cancelled
CI / Desktop E2E Integration (2/2) (push) Has been cancelled
CI / Desktop E2E Integration (push) Has been cancelled
CI / Backend Integration (relay e2e) (push) Has been cancelled
CI / Relay E2E (push) Has been cancelled
CI / Web (push) Has been cancelled
CI / Mobile (push) Has been cancelled
CI / Security (push) Has been cancelled
CI / Dead Token Reference Guard (push) Has been cancelled
CI / Server Cross-Compile (aarch64-unknown-linux-musl) (push) Has been cancelled
CI / Server Cross-Compile (x86_64-unknown-linux-musl) (push) Has been cancelled
CI / Windows Rust (x86_64-pc-windows-msvc) (push) Has been cancelled
CI / Desktop Build (macOS) (push) Has been cancelled
helm chart / lint + unittest + render matrix (push) Has been cancelled
helm chart / install on kind (gated) (push) Has been cancelled
helm chart / publish chart to GHCR (push) Has been cancelled
Mesh Lifecycle / Relay-Driven Mesh Lifecycle Smoke (push) Has been cancelled
Sprig / Build (aarch64-unknown-linux-musl) (push) Has been cancelled
Sprig / Build (x86_64-unknown-linux-musl) (push) Has been cancelled
Sprig / Publish rolling release (push) Has been cancelled
Sprig / Publish tagged release (push) Has been cancelled
Signed-off-by: cls_宁波本机 <908705107@qq.com>
222 lines
7.1 KiB
Dart
222 lines
7.1 KiB
Dart
import 'dart:async';
|
|
|
|
import 'package:flutter/foundation.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter/services.dart';
|
|
import 'package:lucide_icons_flutter/lucide_icons.dart';
|
|
|
|
import '../l10n/l10n.dart';
|
|
import '../theme/theme.dart';
|
|
import 'concentric_sheet_surface.dart';
|
|
|
|
/// Shared motion for occasional modal UI.
|
|
///
|
|
/// The strong ease-out makes entrances respond immediately, while the shorter
|
|
/// exit keeps dismissals from feeling sluggish.
|
|
const buzzModalAnimationStyle = AnimationStyle(
|
|
curve: Cubic(0.23, 1, 0.32, 1),
|
|
duration: Duration(milliseconds: 280),
|
|
reverseCurve: Cubic(0.77, 0, 0.175, 1),
|
|
reverseDuration: Duration(milliseconds: 220),
|
|
);
|
|
|
|
/// Shows a bottom sheet with Buzz's shared motion and sheet chrome.
|
|
///
|
|
/// Sheets include the shared close control by default. On iOS, the surface
|
|
/// uses native concentric corners when available and paints a requested drag
|
|
/// handle inside that inset surface; other platforms retain Flutter's handle.
|
|
Future<T?> showBuzzModalBottomSheet<T>({
|
|
required BuildContext context,
|
|
required WidgetBuilder builder,
|
|
Color? backgroundColor,
|
|
String? barrierLabel,
|
|
double? elevation,
|
|
ShapeBorder? shape,
|
|
Clip? clipBehavior,
|
|
BoxConstraints? constraints,
|
|
Color? barrierColor,
|
|
bool isScrollControlled = false,
|
|
double scrollControlDisabledMaxHeightRatio = 9.0 / 16.0,
|
|
bool useRootNavigator = false,
|
|
bool isDismissible = true,
|
|
bool enableDrag = true,
|
|
bool? showDragHandle,
|
|
bool showCloseButton = true,
|
|
bool useSafeArea = false,
|
|
RouteSettings? routeSettings,
|
|
AnimationController? transitionAnimationController,
|
|
Offset? anchorPoint,
|
|
AnimationStyle? sheetAnimationStyle,
|
|
bool? requestFocus,
|
|
}) {
|
|
final isIos = defaultTargetPlatform == TargetPlatform.iOS;
|
|
final theme = Theme.of(context);
|
|
final surfaceColor =
|
|
backgroundColor ??
|
|
theme.bottomSheetTheme.modalBackgroundColor ??
|
|
theme.bottomSheetTheme.backgroundColor ??
|
|
context.colors.surface;
|
|
final reduceMotion = MediaQuery.disableAnimationsOf(context);
|
|
|
|
return showModalBottomSheet<T>(
|
|
context: context,
|
|
builder: (sheetContext) => ConcentricSheetSurface(
|
|
enabled: isIos,
|
|
color: surfaceColor,
|
|
child: _SheetContent(
|
|
showCloseButton: showCloseButton,
|
|
showDragHandle: isIos && showDragHandle == true,
|
|
child: builder(sheetContext),
|
|
),
|
|
),
|
|
backgroundColor: isIos ? Colors.transparent : backgroundColor,
|
|
barrierLabel: barrierLabel,
|
|
elevation: elevation,
|
|
shape: shape,
|
|
clipBehavior: clipBehavior,
|
|
constraints: constraints,
|
|
barrierColor: barrierColor,
|
|
isScrollControlled: isScrollControlled,
|
|
scrollControlDisabledMaxHeightRatio: scrollControlDisabledMaxHeightRatio,
|
|
useRootNavigator: useRootNavigator,
|
|
isDismissible: isDismissible,
|
|
enableDrag: enableDrag,
|
|
// The iOS route is transparent so its stock handle sits outside the inset
|
|
// concentric surface. Paint it inside the surface above instead.
|
|
showDragHandle: isIos ? false : showDragHandle,
|
|
useSafeArea: useSafeArea,
|
|
routeSettings: routeSettings,
|
|
transitionAnimationController: transitionAnimationController,
|
|
anchorPoint: anchorPoint,
|
|
sheetAnimationStyle: reduceMotion
|
|
? AnimationStyle.noAnimation
|
|
: (sheetAnimationStyle ?? buzzModalAnimationStyle),
|
|
requestFocus: requestFocus,
|
|
);
|
|
}
|
|
|
|
class _SheetContent extends StatelessWidget {
|
|
const _SheetContent({
|
|
required this.child,
|
|
required this.showCloseButton,
|
|
required this.showDragHandle,
|
|
});
|
|
|
|
final Widget child;
|
|
final bool showCloseButton;
|
|
final bool showDragHandle;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
if (showCloseButton)
|
|
Padding(
|
|
padding: const EdgeInsets.only(
|
|
top: Grid.xxs,
|
|
left: Grid.gutter,
|
|
right: Grid.gutter,
|
|
bottom: Grid.xs,
|
|
),
|
|
child: SizedBox(
|
|
height: 56,
|
|
child: Stack(
|
|
alignment: Alignment.topCenter,
|
|
children: [
|
|
if (showDragHandle) const _SheetDragHandle(),
|
|
Align(
|
|
alignment: Alignment.bottomRight,
|
|
child: SizedBox.square(
|
|
dimension: 44,
|
|
child: IconButton(
|
|
tooltip: context.l10n.closeSheet,
|
|
onPressed: () {
|
|
unawaited(HapticFeedback.lightImpact());
|
|
Navigator.of(context).pop();
|
|
},
|
|
style: IconButton.styleFrom(
|
|
padding: EdgeInsets.zero,
|
|
backgroundColor:
|
|
context.colors.surfaceContainerHighest,
|
|
foregroundColor: context.colors.onSurface,
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(Radii.dialog),
|
|
),
|
|
),
|
|
icon: const Icon(LucideIcons.x, size: 22),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
)
|
|
else if (showDragHandle)
|
|
const Padding(
|
|
padding: EdgeInsets.only(top: Grid.xxs, bottom: Grid.xs),
|
|
child: _SheetDragHandle(),
|
|
),
|
|
Flexible(child: child),
|
|
],
|
|
);
|
|
}
|
|
}
|
|
|
|
class _SheetDragHandle extends StatelessWidget {
|
|
const _SheetDragHandle();
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Semantics(
|
|
label: context.l10n.dragHandle,
|
|
child: Container(
|
|
key: const ValueKey('buzz-sheet-drag-handle'),
|
|
width: 32,
|
|
height: 4,
|
|
decoration: BoxDecoration(
|
|
color: context.colors.onSurfaceVariant.withValues(alpha: 0.4),
|
|
borderRadius: BorderRadius.circular(Radii.full),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
/// Shows a dialog with Buzz's shared motion, respecting reduced-motion settings.
|
|
Future<T?> showBuzzDialog<T>({
|
|
required BuildContext context,
|
|
required WidgetBuilder builder,
|
|
bool barrierDismissible = true,
|
|
Color? barrierColor,
|
|
String? barrierLabel,
|
|
bool useSafeArea = true,
|
|
bool useRootNavigator = true,
|
|
RouteSettings? routeSettings,
|
|
Offset? anchorPoint,
|
|
TraversalEdgeBehavior? traversalEdgeBehavior,
|
|
bool fullscreenDialog = false,
|
|
bool? requestFocus,
|
|
AnimationStyle? animationStyle,
|
|
}) {
|
|
final reduceMotion = MediaQuery.disableAnimationsOf(context);
|
|
|
|
return showDialog<T>(
|
|
context: context,
|
|
builder: builder,
|
|
barrierDismissible: barrierDismissible,
|
|
barrierColor: barrierColor,
|
|
barrierLabel: barrierLabel,
|
|
useSafeArea: useSafeArea,
|
|
useRootNavigator: useRootNavigator,
|
|
routeSettings: routeSettings,
|
|
anchorPoint: anchorPoint,
|
|
traversalEdgeBehavior: traversalEdgeBehavior,
|
|
fullscreenDialog: fullscreenDialog,
|
|
requestFocus: requestFocus,
|
|
animationStyle: reduceMotion
|
|
? AnimationStyle.noAnimation
|
|
: (animationStyle ?? buzzModalAnimationStyle),
|
|
);
|
|
}
|