From 8296302211a15e818856fb2da3d8278fdc56ae54 Mon Sep 17 00:00:00 2001 From: chen08209 Date: Tue, 10 Mar 2026 14:25:00 +0800 Subject: [PATCH] cache --- lib/models/common.dart | 8 + lib/models/generated/common.freezed.dart | 260 +++++++++++++++++++++++ lib/views/profiles/overwrite/custom.dart | 175 +++++++++++---- lib/views/profiles/profiles.dart | 21 +- lib/views/proxies/providers.dart | 9 +- lib/widgets/inherited.dart | 28 ++- lib/widgets/list.dart | 3 +- lib/widgets/sheet.dart | 114 ++++++++-- 8 files changed, 519 insertions(+), 99 deletions(-) diff --git a/lib/models/common.dart b/lib/models/common.dart index 5641d35..25e759e 100644 --- a/lib/models/common.dart +++ b/lib/models/common.dart @@ -596,3 +596,11 @@ abstract class UpdatingMessage with _$UpdatingMessage { required String message, }) = _UpdatingMessage; } + +@freezed +abstract class IconButtonData with _$IconButtonData { + const factory IconButtonData({ + required IconData icon, + required VoidCallback onPressed, + }) = _IconButtonData; +} diff --git a/lib/models/generated/common.freezed.dart b/lib/models/generated/common.freezed.dart index 6e65f8b..c5939c9 100644 --- a/lib/models/generated/common.freezed.dart +++ b/lib/models/generated/common.freezed.dart @@ -6019,6 +6019,266 @@ as String, } +} + +/// @nodoc +mixin _$IconButtonData { + + IconData get icon; VoidCallback get onPressed; +/// Create a copy of IconButtonData +/// with the given fields replaced by the non-null parameter values. +@JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +$IconButtonDataCopyWith get copyWith => _$IconButtonDataCopyWithImpl(this as IconButtonData, _$identity); + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is IconButtonData&&(identical(other.icon, icon) || other.icon == icon)&&(identical(other.onPressed, onPressed) || other.onPressed == onPressed)); +} + + +@override +int get hashCode => Object.hash(runtimeType,icon,onPressed); + +@override +String toString() { + return 'IconButtonData(icon: $icon, onPressed: $onPressed)'; +} + + +} + +/// @nodoc +abstract mixin class $IconButtonDataCopyWith<$Res> { + factory $IconButtonDataCopyWith(IconButtonData value, $Res Function(IconButtonData) _then) = _$IconButtonDataCopyWithImpl; +@useResult +$Res call({ + IconData icon, VoidCallback onPressed +}); + + + + +} +/// @nodoc +class _$IconButtonDataCopyWithImpl<$Res> + implements $IconButtonDataCopyWith<$Res> { + _$IconButtonDataCopyWithImpl(this._self, this._then); + + final IconButtonData _self; + final $Res Function(IconButtonData) _then; + +/// Create a copy of IconButtonData +/// with the given fields replaced by the non-null parameter values. +@pragma('vm:prefer-inline') @override $Res call({Object? icon = null,Object? onPressed = null,}) { + return _then(_self.copyWith( +icon: null == icon ? _self.icon : icon // ignore: cast_nullable_to_non_nullable +as IconData,onPressed: null == onPressed ? _self.onPressed : onPressed // ignore: cast_nullable_to_non_nullable +as VoidCallback, + )); +} + +} + + +/// Adds pattern-matching-related methods to [IconButtonData]. +extension IconButtonDataPatterns on IconButtonData { +/// A variant of `map` that fallback to returning `orElse`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeMap(TResult Function( _IconButtonData value)? $default,{required TResult orElse(),}){ +final _that = this; +switch (_that) { +case _IconButtonData() when $default != null: +return $default(_that);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// Callbacks receives the raw object, upcasted. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case final Subclass2 value: +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult map(TResult Function( _IconButtonData value) $default,){ +final _that = this; +switch (_that) { +case _IconButtonData(): +return $default(_that);case _: + throw StateError('Unexpected subclass'); + +} +} +/// A variant of `map` that fallback to returning `null`. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case final Subclass value: +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? mapOrNull(TResult? Function( _IconButtonData value)? $default,){ +final _that = this; +switch (_that) { +case _IconButtonData() when $default != null: +return $default(_that);case _: + return null; + +} +} +/// A variant of `when` that fallback to an `orElse` callback. +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return orElse(); +/// } +/// ``` + +@optionalTypeArgs TResult maybeWhen(TResult Function( IconData icon, VoidCallback onPressed)? $default,{required TResult orElse(),}) {final _that = this; +switch (_that) { +case _IconButtonData() when $default != null: +return $default(_that.icon,_that.onPressed);case _: + return orElse(); + +} +} +/// A `switch`-like method, using callbacks. +/// +/// As opposed to `map`, this offers destructuring. +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case Subclass2(:final field2): +/// return ...; +/// } +/// ``` + +@optionalTypeArgs TResult when(TResult Function( IconData icon, VoidCallback onPressed) $default,) {final _that = this; +switch (_that) { +case _IconButtonData(): +return $default(_that.icon,_that.onPressed);case _: + throw StateError('Unexpected subclass'); + +} +} +/// A variant of `when` that fallback to returning `null` +/// +/// It is equivalent to doing: +/// ```dart +/// switch (sealedClass) { +/// case Subclass(:final field): +/// return ...; +/// case _: +/// return null; +/// } +/// ``` + +@optionalTypeArgs TResult? whenOrNull(TResult? Function( IconData icon, VoidCallback onPressed)? $default,) {final _that = this; +switch (_that) { +case _IconButtonData() when $default != null: +return $default(_that.icon,_that.onPressed);case _: + return null; + +} +} + +} + +/// @nodoc + + +class _IconButtonData implements IconButtonData { + const _IconButtonData({required this.icon, required this.onPressed}); + + +@override final IconData icon; +@override final VoidCallback onPressed; + +/// Create a copy of IconButtonData +/// with the given fields replaced by the non-null parameter values. +@override @JsonKey(includeFromJson: false, includeToJson: false) +@pragma('vm:prefer-inline') +_$IconButtonDataCopyWith<_IconButtonData> get copyWith => __$IconButtonDataCopyWithImpl<_IconButtonData>(this, _$identity); + + + +@override +bool operator ==(Object other) { + return identical(this, other) || (other.runtimeType == runtimeType&&other is _IconButtonData&&(identical(other.icon, icon) || other.icon == icon)&&(identical(other.onPressed, onPressed) || other.onPressed == onPressed)); +} + + +@override +int get hashCode => Object.hash(runtimeType,icon,onPressed); + +@override +String toString() { + return 'IconButtonData(icon: $icon, onPressed: $onPressed)'; +} + + +} + +/// @nodoc +abstract mixin class _$IconButtonDataCopyWith<$Res> implements $IconButtonDataCopyWith<$Res> { + factory _$IconButtonDataCopyWith(_IconButtonData value, $Res Function(_IconButtonData) _then) = __$IconButtonDataCopyWithImpl; +@override @useResult +$Res call({ + IconData icon, VoidCallback onPressed +}); + + + + +} +/// @nodoc +class __$IconButtonDataCopyWithImpl<$Res> + implements _$IconButtonDataCopyWith<$Res> { + __$IconButtonDataCopyWithImpl(this._self, this._then); + + final _IconButtonData _self; + final $Res Function(_IconButtonData) _then; + +/// Create a copy of IconButtonData +/// with the given fields replaced by the non-null parameter values. +@override @pragma('vm:prefer-inline') $Res call({Object? icon = null,Object? onPressed = null,}) { + return _then(_IconButtonData( +icon: null == icon ? _self.icon : icon // ignore: cast_nullable_to_non_nullable +as IconData,onPressed: null == onPressed ? _self.onPressed : onPressed // ignore: cast_nullable_to_non_nullable +as VoidCallback, + )); +} + + } // dart format on diff --git a/lib/views/profiles/overwrite/custom.dart b/lib/views/profiles/overwrite/custom.dart index c6a7cb7..f54e456 100644 --- a/lib/views/profiles/overwrite/custom.dart +++ b/lib/views/profiles/overwrite/custom.dart @@ -156,7 +156,7 @@ class _CustomProxyGroupsView extends ConsumerWidget { backgroundColor: Colors.transparent, maxWidth: 400, ), - builder: (_) { + builder: (context) { return _EditCustomProxyGroupNestedSheet(proxyGroup); }, ); @@ -169,6 +169,7 @@ class _CustomProxyGroupsView extends ConsumerWidget { title: '代理组', body: ReorderableListView.builder( buildDefaultDragHandles: false, + padding: EdgeInsets.only(bottom: 16), itemBuilder: (_, index) { final proxyGroup = proxyGroups[index]; return ReorderableDelayedDragStartListener( @@ -211,9 +212,28 @@ class _EditCustomProxyGroupNestedSheet extends StatelessWidget { const _EditCustomProxyGroupNestedSheet(this.proxyGroup); + Future _handlePop( + BuildContext context, + NavigatorState? navigatorState, + ) async { + if (navigatorState != null && navigatorState.canPop()) { + final res = await globalState.showMessage( + message: TextSpan(text: '确定要退出当前窗口吗?'), + ); + if (res != true) { + return; + } + } + if (context.mounted) { + Navigator.of(context).pop(); + } + } + @override Widget build(BuildContext context) { + final GlobalKey nestedNavigatorKey = GlobalKey(); final nestedNavigator = Navigator( + key: nestedNavigatorKey, onGenerateInitialRoutes: (navigator, initialRoute) { return [ PagedSheetRoute( @@ -224,30 +244,40 @@ class _EditCustomProxyGroupNestedSheet extends StatelessWidget { ]; }, ); - final isBottomSheet = - SheetTypeProvider.of(context)?.type == SheetType.bottomSheet; - return Stack( - children: [ - Positioned.fill( - child: GestureDetector( - onTap: () { - Navigator.of(context).pop(); - }, - ), - ), - SheetViewport( - child: PagedSheet( - decoration: MaterialSheetDecoration( - size: SheetSize.stretch, - borderRadius: isBottomSheet - ? BorderRadius.vertical(top: Radius.circular(28)) - : BorderRadius.zero, - clipBehavior: Clip.antiAlias, + final sheetProvider = SheetProvider.of(context); + return CommonPopScope( + onPop: (_) async { + _handlePop(context, nestedNavigatorKey.currentState); + return false; + }, + child: sheetProvider!.copyWith( + nestedNavigatorPopCallback: () { + Navigator.of(context).pop(); + }, + child: Stack( + children: [ + Positioned.fill( + child: GestureDetector( + onTap: () async { + _handlePop(context, nestedNavigatorKey.currentState); + }, + ), ), - navigator: nestedNavigator, - ), + SheetViewport( + child: PagedSheet( + decoration: MaterialSheetDecoration( + size: SheetSize.stretch, + borderRadius: sheetProvider.type == SheetType.bottomSheet + ? BorderRadius.vertical(top: Radius.circular(28)) + : BorderRadius.zero, + clipBehavior: Clip.antiAlias, + ), + navigator: nestedNavigator, + ), + ), + ], ), - ], + ), ); } } @@ -266,14 +296,29 @@ class _EditCustomProxyGroupViewState final _nameController = TextEditingController(); final _hideController = ValueNotifier(false); final _disableUDPController = ValueNotifier(false); - final _typeUDPController = ValueNotifier(GroupType.Selector); + final _proxiesController = ValueNotifier>([]); + final _useController = ValueNotifier>([]); + final _typeController = ValueNotifier(GroupType.Selector); + final _allProxiesController = ValueNotifier(false); + final _allProviderController = ValueNotifier(false); @override void initState() { super.initState(); - _nameController.text = widget.proxyGroup.name; - _hideController.value = widget.proxyGroup.hidden ?? false; - _disableUDPController.value = widget.proxyGroup.disableUDP ?? false; + final proxyGroup = widget.proxyGroup; + _nameController.text = proxyGroup.name; + _hideController.value = proxyGroup.hidden ?? false; + _disableUDPController.value = proxyGroup.disableUDP ?? false; + _typeController.value = proxyGroup.type; + _proxiesController.value = proxyGroup.proxies ?? []; + _useController.value = proxyGroup.use ?? []; + if (proxyGroup.includeAll == true) { + _allProxiesController.value = true; + _allProviderController.value = true; + } else { + _allProxiesController.value = proxyGroup.includeAllProxies ?? false; + _allProviderController.value = proxyGroup.includeAllProviders ?? false; + } } @override @@ -281,7 +326,11 @@ class _EditCustomProxyGroupViewState _nameController.dispose(); _hideController.dispose(); _disableUDPController.dispose(); - _typeUDPController.dispose(); + _typeController.dispose(); + _proxiesController.dispose(); + _useController.dispose(); + _allProxiesController.dispose(); + _allProviderController.dispose(); super.dispose(); } @@ -291,13 +340,13 @@ class _EditCustomProxyGroupViewState title: '类型', options: GroupType.values, textBuilder: (item) => item.name, - value: _typeUDPController.value, + value: _typeController.value, ), ); if (value == null) { return; } - _typeUDPController.value = value; + _typeController.value = value; } Widget _buildItem({ @@ -314,10 +363,16 @@ class _EditCustomProxyGroupViewState title, if (trailing != null) Flexible( - child: Container( - alignment: Alignment.centerRight, - height: globalState.measure.bodyLargeHeight + 6, - child: trailing, + child: IconTheme( + data: IconThemeData( + size: 16, + color: context.colorScheme.onSurface.opacity60, + ), + child: Container( + alignment: Alignment.centerRight, + height: globalState.measure.bodyLargeHeight + 24, + child: trailing, + ), ), ), ], @@ -327,7 +382,7 @@ class _EditCustomProxyGroupViewState void _handleToProxies() { final isBottomSheet = - SheetTypeProvider.of(context)?.type == SheetType.bottomSheet; + SheetProvider.of(context)?.type == SheetType.bottomSheet; Navigator.of(context).push( PagedSheetRoute( builder: (context) => SizedBox( @@ -346,14 +401,15 @@ class _EditCustomProxyGroupViewState @override Widget build(BuildContext context) { final isBottomSheet = - SheetTypeProvider.of(context)?.type == SheetType.bottomSheet; + SheetProvider.of(context)?.type == SheetType.bottomSheet; return AdaptiveSheetScaffold( + actions: [IconButtonData(icon: Icons.check, onPressed: () {})], body: SizedBox( height: isBottomSheet ? appController.viewSize.height * 0.65 : double.maxFinite, child: ListView( - padding: EdgeInsets.symmetric(horizontal: 16).copyWith(bottom: 24), + padding: EdgeInsets.symmetric(horizontal: 16).copyWith(bottom: 20), children: [ generateSectionV3( title: '通用', @@ -375,7 +431,7 @@ class _EditCustomProxyGroupViewState _showTypeOptions(); }, trailing: ValueListenableBuilder( - valueListenable: _typeUDPController, + valueListenable: _typeController, builder: (_, type, _) { return Text(type.name); }, @@ -421,8 +477,45 @@ class _EditCustomProxyGroupViewState generateSectionV3( title: '节点', items: [ - _buildItem(title: Text('选择代理'), onPressed: _handleToProxies), - _buildItem(title: Text('选择代理集')), + _buildItem( + title: Text('选择代理'), + trailing: ValueListenableBuilder( + valueListenable: _proxiesController, + builder: (_, proxies, _) { + return Row( + mainAxisSize: MainAxisSize.min, + children: [ + Card( + elevation: 0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(14), + ), + child: Container( + constraints: BoxConstraints(minWidth: 32), + child: Padding( + padding: EdgeInsets.symmetric( + horizontal: 4, + vertical: 3, + ), + child: Text( + textAlign: TextAlign.center, + '${proxies.length}', + style: context.textTheme.bodySmall, + ), + ), + ), + ), + Icon(Icons.arrow_forward_ios), + ], + ); + }, + ), + onPressed: _handleToProxies, + ), + _buildItem( + title: Text('选择代理集'), + trailing: Icon(Icons.arrow_forward_ios), + ), _buildItem( title: Text('节点过滤器'), trailing: TextFormField( @@ -518,7 +611,7 @@ class _EditCustomProxyGroupViewState ], ), ), - title: '编辑', + title: '编辑代理组', ); } } diff --git a/lib/views/profiles/profiles.dart b/lib/views/profiles/profiles.dart index 1acea1d..934ffe7 100644 --- a/lib/views/profiles/profiles.dart +++ b/lib/views/profiles/profiles.dart @@ -469,27 +469,8 @@ class _ReorderableProfilesSheetState extends State { @override Widget build(BuildContext context) { - final bottomSheet = - SheetTypeProvider.of(context)?.type == SheetType.bottomSheet; return AdaptiveSheetScaffold( - actions: [ - if (bottomSheet) - IconButton.filledTonal( - onPressed: _handleSave, - style: IconButton.styleFrom( - visualDensity: VisualDensity.comfortable, - tapTargetSize: MaterialTapTargetSize.padded, - padding: EdgeInsets.all(8), - iconSize: 20, - ), - icon: Icon(Icons.check), - ) - else - IconButton.filledTonal( - icon: Icon(Icons.check), - onPressed: _handleSave, - ), - ], + actions: [IconButtonData(icon: Icons.check, onPressed: _handleSave)], body: Padding( padding: EdgeInsets.only(bottom: 32, top: 12), child: ReorderableListView.builder( diff --git a/lib/views/proxies/providers.dart b/lib/views/proxies/providers.dart index 528b48e..3bb6885 100644 --- a/lib/views/proxies/providers.dart +++ b/lib/views/proxies/providers.dart @@ -56,14 +56,7 @@ class _ProvidersViewState extends ConsumerState { items: ruleProviders, ); return AdaptiveSheetScaffold( - actions: [ - IconButton( - onPressed: () { - _updateProviders(); - }, - icon: const Icon(Icons.sync), - ), - ], + actions: [IconButtonData(icon: Icons.sync, onPressed: _updateProviders)], body: generateListView([...proxySection, ...ruleSection]), title: appLocalizations.providers, ); diff --git a/lib/widgets/inherited.dart b/lib/widgets/inherited.dart index 85b7268..d9d82c9 100644 --- a/lib/widgets/inherited.dart +++ b/lib/widgets/inherited.dart @@ -60,20 +60,36 @@ class ItemPositionProvider extends InheritedWidget { position != oldWidget.position; } -class SheetTypeProvider extends InheritedWidget { +class SheetProvider extends InheritedWidget { final SheetType type; + final VoidCallback? nestedNavigatorPopCallback; - const SheetTypeProvider({ + const SheetProvider({ super.key, required super.child, required this.type, + this.nestedNavigatorPopCallback, }); - static SheetTypeProvider? of(BuildContext context) { - return context.dependOnInheritedWidgetOfExactType(); + SheetProvider copyWith({ + SheetType? type, + VoidCallback? nestedNavigatorPopCallback, + required Widget child, + }) { + return SheetProvider( + type: type ?? this.type, + nestedNavigatorPopCallback: + nestedNavigatorPopCallback ?? this.nestedNavigatorPopCallback, + child: child, + ); + } + + static SheetProvider? of(BuildContext context) { + return context.dependOnInheritedWidgetOfExactType(); } @override - bool updateShouldNotify(SheetTypeProvider oldWidget) => - type != oldWidget.type; + bool updateShouldNotify(SheetProvider oldWidget) => + type != oldWidget.type && + nestedNavigatorPopCallback != oldWidget.nestedNavigatorPopCallback; } diff --git a/lib/widgets/list.dart b/lib/widgets/list.dart index 1dd241b..e852a4a 100644 --- a/lib/widgets/list.dart +++ b/lib/widgets/list.dart @@ -706,7 +706,8 @@ class CommonInputListItem extends StatelessWidget { contentPadding: const EdgeInsets.only(right: 16, left: 16), title: title, subtitle: subtitle, - minVerticalPadding: 14, + minVerticalPadding: 0, + minTileHeight: 54, trailing: trailing, ), ), diff --git a/lib/widgets/sheet.dart b/lib/widgets/sheet.dart index 2361417..2efd455 100644 --- a/lib/widgets/sheet.dart +++ b/lib/widgets/sheet.dart @@ -1,6 +1,8 @@ import 'package:fl_clash/common/common.dart'; import 'package:fl_clash/controller.dart'; +import 'package:fl_clash/models/common.dart'; import 'package:fl_clash/widgets/inherited.dart'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'scaffold.dart'; @@ -53,7 +55,7 @@ Future showSheet({ context: context, isScrollControlled: props.isScrollControlled, builder: (_) { - return SheetTypeProvider( + return SheetProvider( type: SheetType.bottomSheet, child: builder(context), ); @@ -70,7 +72,7 @@ Future showSheet({ constraints: BoxConstraints(maxWidth: props.maxWidth ?? 360), filter: props.blur ? commonFilter : null, builder: (_) { - return SheetTypeProvider( + return SheetProvider( type: SheetType.sideSheet, child: builder(context), ); @@ -88,7 +90,7 @@ Future showExtend( return switch (isMobile || props.forceFull) { true => BaseNavigator.push( context, - SheetTypeProvider(type: SheetType.page, child: builder(context)), + SheetProvider(type: SheetType.page, child: builder(context)), ), false => showModalSideSheet( useSafeArea: props.useSafeArea, @@ -96,7 +98,7 @@ Future showExtend( constraints: BoxConstraints(maxWidth: props.maxWidth ?? 360), filter: props.blur ? commonFilter : null, builder: (context) { - return SheetTypeProvider( + return SheetProvider( type: SheetType.sideSheet, child: builder(context), ); @@ -108,7 +110,7 @@ Future showExtend( class AdaptiveSheetScaffold extends StatefulWidget { final Widget body; final String title; - final List actions; + final List actions; const AdaptiveSheetScaffold({ super.key, @@ -125,34 +127,100 @@ class _AdaptiveSheetScaffoldState extends State { @override Widget build(BuildContext context) { final backgroundColor = context.colorScheme.surface; - final type = SheetTypeProvider.of(context)?.type ?? SheetType.bottomSheet; - final bottomSheet = type == SheetType.bottomSheet; - final sideSheet = type == SheetType.sideSheet; + final sheetProvider = SheetProvider.of(context); + final nestedNavigatorPopCallback = + sheetProvider?.nestedNavigatorPopCallback; + final ModalRoute? route = ModalRoute.of(context); + final type = sheetProvider?.type ?? SheetType.page; + final useCloseIcon = + type != SheetType.page && + (nestedNavigatorPopCallback != null && + route?.impliesAppBarDismissal == false || + nestedNavigatorPopCallback == null); + Widget buildIconButton(IconButtonData data) { + if (type == SheetType.bottomSheet) { + return IconButton.filledTonal( + onPressed: data.onPressed, + style: IconButton.styleFrom( + visualDensity: VisualDensity.standard, + tapTargetSize: MaterialTapTargetSize.shrinkWrap, + ), + icon: Icon(data.icon), + ); + } + return IconButton( + onPressed: data.onPressed, + style: IconButton.styleFrom( + visualDensity: VisualDensity.standard, + tapTargetSize: MaterialTapTargetSize.shrinkWrap, + ), + icon: Icon(data.icon), + ); + } + + final actions = widget.actions.map(buildIconButton).toList(); + + IconData getBackIconData() { + if (kIsWeb) { + return Icons.arrow_back; + } + switch (Theme.of(context).platform) { + case TargetPlatform.android: + case TargetPlatform.fuchsia: + case TargetPlatform.linux: + case TargetPlatform.windows: + return Icons.arrow_back; + case TargetPlatform.iOS: + case TargetPlatform.macOS: + return Icons.arrow_back_ios_new_rounded; + } + } + + final popButton = type != SheetType.page + ? (useCloseIcon + ? buildIconButton( + IconButtonData( + icon: Icons.close, + onPressed: () { + if (nestedNavigatorPopCallback != null) { + nestedNavigatorPopCallback(); + } else { + Navigator.of(context).pop(); + } + }, + ), + ) + : buildIconButton( + IconButtonData( + icon: getBackIconData(), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + )) + : null; + + final suffixPop = type != SheetType.page && actions.isEmpty && useCloseIcon; final appBar = AppBar( - forceMaterialTransparency: bottomSheet ? true : false, - automaticallyImplyLeading: bottomSheet - ? false - : widget.actions.isEmpty && sideSheet - ? false - : true, + forceMaterialTransparency: type == SheetType.bottomSheet ? true : false, + leading: suffixPop ? null : popButton, + automaticallyImplyLeading: type == SheetType.page ? true : false, centerTitle: true, backgroundColor: backgroundColor, + toolbarHeight: type == SheetType.bottomSheet ? 48 : null, title: Text(widget.title), - titleTextStyle: bottomSheet + titleTextStyle: type == SheetType.bottomSheet ? context.textTheme.titleLarge?.adjustSize(-4) : null, - actions: genActions([ - if (widget.actions.isEmpty && sideSheet) CloseButton(), - ...widget.actions, - ]), + actions: !suffixPop ? genActions(actions) : genActions([?popButton]), ); - if (bottomSheet) { - final handleSize = Size(32, 4); + if (type == SheetType.bottomSheet) { + final handleSize = Size(28, 4); return Column( mainAxisSize: MainAxisSize.min, children: [ Padding( - padding: EdgeInsets.only(top: 16), + padding: EdgeInsets.only(top: 4), child: Container( alignment: Alignment.center, height: handleSize.height, @@ -165,7 +233,7 @@ class _AdaptiveSheetScaffoldState extends State { ), ), ), - Padding(padding: EdgeInsets.symmetric(horizontal: 8), child: appBar), + Padding(padding: EdgeInsets.symmetric(horizontal: 4), child: appBar), Flexible(flex: 1, child: widget.body), SizedBox(height: MediaQuery.of(context).viewPadding.bottom), ],