diff --git a/analysis_options.yaml b/analysis_options.yaml index c815239..822d53b 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -19,6 +19,9 @@ analyzer: - "**/*.g.dart" - "**/*.mocks.dart" # Mockito @GenerateMocks +formatter: + page_width: 100 + linter: rules: # This list is derived from the list of all available lints located at diff --git a/packages/dropdown_button2/lib/src/dropdown_button2.dart b/packages/dropdown_button2/lib/src/dropdown_button2.dart index 5957935..893c2dd 100644 --- a/packages/dropdown_button2/lib/src/dropdown_button2.dart +++ b/packages/dropdown_button2/lib/src/dropdown_button2.dart @@ -25,13 +25,11 @@ const Duration _kDropdownMenuDuration = Duration(milliseconds: 300); const double _kMenuItemHeight = kMinInteractiveDimension; const double _kDenseButtonHeight = 24.0; const EdgeInsets _kMenuItemPadding = EdgeInsets.symmetric(horizontal: 16.0); -const EdgeInsetsGeometry _kAlignedButtonPadding = - EdgeInsetsDirectional.only(start: 16.0, end: 4.0); +const EdgeInsetsGeometry _kAlignedButtonPadding = EdgeInsetsDirectional.only(start: 16.0, end: 4.0); const EdgeInsets _kUnalignedButtonPadding = EdgeInsets.zero; /// A builder to customize the selected menu item. -typedef SelectedMenuItemBuilder = Widget Function( - BuildContext context, Widget child); +typedef SelectedMenuItemBuilder = Widget Function(BuildContext context, Widget child); /// A builder to customize the dropdown menu. typedef DropdownBuilder = Widget Function(BuildContext context, Widget child); @@ -40,8 +38,7 @@ typedef DropdownBuilder = Widget Function(BuildContext context, Widget child); typedef OnMenuStateChangeFn = void Function(bool isOpen); /// Signature for the callback for the match function used for searchable dropdowns. -typedef SearchMatchFn = bool Function( - DropdownItem item, String searchValue); +typedef SearchMatchFn = bool Function(DropdownItem item, String searchValue); /// A Material Design button for selecting from a list of items. /// @@ -389,8 +386,7 @@ class DropdownButton2 extends StatefulWidget { State> createState() => _DropdownButton2State(); } -class _DropdownButton2State extends State> - with WidgetsBindingObserver { +class _DropdownButton2State extends State> with WidgetsBindingObserver { int? _selectedIndex; _DropdownRoute? _dropdownRoute; Orientation? _lastOrientation; @@ -453,8 +449,7 @@ class _DropdownButton2State extends State> WidgetsBinding.instance.removeObserver(this); widget.valueListenable?.removeListener(_updateSelectedIndex); widget.multiValueListenable?.removeListener(_updateSelectedIndex); - widget.openDropdownListenable - ?.removeListener(_programmaticallyOpenDropdown); + widget.openDropdownListenable?.removeListener(_programmaticallyOpenDropdown); _removeDropdownRoute(); _focusNode.removeListener(_handleFocusChanged); _internalNode?.dispose(); @@ -510,8 +505,7 @@ class _DropdownButton2State extends State> } if (widget.openDropdownListenable != oldWidget.openDropdownListenable) { - oldWidget.openDropdownListenable - ?.removeListener(_programmaticallyOpenDropdown); + oldWidget.openDropdownListenable?.removeListener(_programmaticallyOpenDropdown); widget.openDropdownListenable?.addListener(_programmaticallyOpenDropdown); } } @@ -521,8 +515,7 @@ class _DropdownButton2State extends State> widget.items!.isEmpty || (_currentValue == null && widget.items! - .where((DropdownItem item) => - item.enabled && item.value == _currentValue) + .where((DropdownItem item) => item.enabled && item.value == _currentValue) .isEmpty)) { _selectedIndex = null; return; @@ -551,23 +544,19 @@ class _DropdownButton2State extends State> _buttonRect.value = _getButtonRect(); } - TextStyle? get _textStyle => - widget.style ?? Theme.of(context).textTheme.titleMedium; + TextStyle? get _textStyle => widget.style ?? Theme.of(context).textTheme.titleMedium; Rect _getButtonRect() { // InputDecorator is a parent of _buttonRect (to avoid the dropdown menu opening under the button's error/helper), // so we need to consider its padding in additional to _buttonRect. - final EdgeInsets contentPadding = - _getInputDecorationPadding() ?? EdgeInsets.zero; + final EdgeInsets contentPadding = _getInputDecorationPadding() ?? EdgeInsets.zero; final NavigatorState navigator = Navigator.of(context, - rootNavigator: - _dropdownStyle.isFullScreen ?? _dropdownStyle.useRootNavigator); + rootNavigator: _dropdownStyle.isFullScreen ?? _dropdownStyle.useRootNavigator); - final RenderBox itemBox = - _buttonRectKey.currentContext!.findRenderObject()! as RenderBox; - final Rect itemRect = itemBox.localToGlobal(Offset.zero, - ancestor: navigator.context.findRenderObject()) & - itemBox.size; + final RenderBox itemBox = _buttonRectKey.currentContext!.findRenderObject()! as RenderBox; + final Rect itemRect = + itemBox.localToGlobal(Offset.zero, ancestor: navigator.context.findRenderObject()) & + itemBox.size; return contentPadding.inflateRect(itemRect); } @@ -576,8 +565,7 @@ class _DropdownButton2State extends State> // Return the contentPadding only if inputDecoration is defined. if (widget._inputDecoration case final decoration?) { final TextDirection? textDirection = Directionality.maybeOf(context); - return (decoration.contentPadding ?? - Theme.of(context).inputDecorationTheme.contentPadding) + return (decoration.contentPadding ?? Theme.of(context).inputDecorationTheme.contentPadding) ?.resolve(textDirection); } else { return null; @@ -587,10 +575,9 @@ class _DropdownButton2State extends State> EdgeInsetsGeometry _buttonAdditionalHPadding() { final TextDirection? textDirection = Directionality.maybeOf(context); - final menuItemPadding = - _menuItemStyle.padding?.resolve(textDirection) ?? _kMenuItemPadding; - final removeItemHPadding = _menuItemStyle.useDecorationHorizontalPadding && - _getInputDecorationPadding() != null; + final menuItemPadding = _menuItemStyle.padding?.resolve(textDirection) ?? _kMenuItemPadding; + final removeItemHPadding = + _menuItemStyle.useDecorationHorizontalPadding && _getInputDecorationPadding() != null; final effectiveMenuItemPadding = menuItemPadding.copyWith( left: removeItemHPadding ? 0 : null, right: removeItemHPadding ? 0 : null, @@ -605,8 +592,7 @@ class _DropdownButton2State extends State> void _handleTap() { final NavigatorState navigator = Navigator.of(context, - rootNavigator: - _dropdownStyle.isFullScreen ?? _dropdownStyle.useRootNavigator); + rootNavigator: _dropdownStyle.isFullScreen ?? _dropdownStyle.useRootNavigator); final items = widget.items!; final separator = widget.dropdownSeparator; @@ -619,13 +605,12 @@ class _DropdownButton2State extends State> selectedIndex: _selectedIndex ?? 0, isNoSelectedItem: _selectedIndex == null, onChanged: widget.onChanged, - capturedThemes: - InheritedTheme.capture(from: context, to: navigator.context), + capturedThemes: InheritedTheme.capture(from: context, to: navigator.context), style: _textStyle!, barrierDismissible: widget.barrierDismissible, barrierColor: widget.barrierColor, - barrierLabel: widget.barrierLabel ?? - MaterialLocalizations.of(context).modalBarrierDismissLabel, + barrierLabel: + widget.barrierLabel ?? MaterialLocalizations.of(context).modalBarrierDismissLabel, barrierCoversButton: widget.barrierCoversButton, parentFocusNode: _focusNode, enableFeedback: widget.enableFeedback ?? true, @@ -643,9 +628,7 @@ class _DropdownButton2State extends State> WidgetsBinding.instance.addPostFrameCallback((_) { _dropdownRoute?._childNode.requestFocus(); }); - navigator - .push(_dropdownRoute!) - .then((_DropdownRouteResult? newValue) { + navigator.push(_dropdownRoute!).then((_DropdownRouteResult? newValue) { _removeDropdownRoute(); _isMenuOpen.value = false; widget.onMenuStateChange?.call(false); @@ -659,12 +642,10 @@ class _DropdownButton2State extends State> // Similarly, we don't reduce the height of the button so much that its icon // would be clipped. double get _denseButtonHeight { - final double fontSize = _textStyle!.fontSize ?? - Theme.of(context).textTheme.titleMedium!.fontSize!; - final double scaledFontSize = - MediaQuery.textScalerOf(context).scale(fontSize); - return math.max( - scaledFontSize, math.max(_iconStyle.iconSize, _kDenseButtonHeight)); + final double fontSize = + _textStyle!.fontSize ?? Theme.of(context).textTheme.titleMedium!.fontSize!; + final double scaledFontSize = MediaQuery.textScalerOf(context).scale(fontSize); + return math.max(scaledFontSize, math.max(_iconStyle.iconSize, _kDenseButtonHeight)); } Color get _iconColor { @@ -685,10 +666,7 @@ class _DropdownButton2State extends State> } } - bool get _enabled => - widget.items != null && - widget.items!.isNotEmpty && - widget.onChanged != null; + bool get _enabled => widget.items != null && widget.items!.isNotEmpty && widget.onChanged != null; Orientation _getOrientation(BuildContext context) { Orientation? result = MediaQuery.maybeOrientationOf(context); @@ -696,16 +674,14 @@ class _DropdownButton2State extends State> // If there's no MediaQuery, then use the current FlutterView to determine // orientation. final Size size = View.of(context).physicalSize; - result = size.width > size.height - ? Orientation.landscape - : Orientation.portrait; + result = size.width > size.height ? Orientation.landscape : Orientation.portrait; } return result; } BorderRadius? _getButtonBorderRadius(BuildContext context) { - final buttonRadius = _buttonStyle?.decoration?.borderRadius ?? - _buttonStyle?.foregroundDecoration?.borderRadius; + final buttonRadius = + _buttonStyle?.decoration?.borderRadius ?? _buttonStyle?.foregroundDecoration?.borderRadius; if (buttonRadius != null) { return buttonRadius.resolve(Directionality.maybeOf(context)); } @@ -735,8 +711,7 @@ class _DropdownButton2State extends State> int? hintIndex; if (widget.hint != null || (!_enabled && widget.disabledHint != null)) { - final Widget displayedHint = - _enabled ? widget.hint! : widget.disabledHint ?? widget.hint!; + final Widget displayedHint = _enabled ? widget.hint! : widget.disabledHint ?? widget.hint!; hintIndex = buttonItems.length; buttonItems.add(DefaultTextStyle( @@ -747,19 +722,16 @@ class _DropdownButton2State extends State> )); } - final EdgeInsetsGeometry padding = ButtonTheme.of(context).alignedDropdown - ? _kAlignedButtonPadding - : _kUnalignedButtonPadding; + final EdgeInsetsGeometry padding = + ButtonTheme.of(context).alignedDropdown ? _kAlignedButtonPadding : _kUnalignedButtonPadding; - final buttonHeight = - _buttonStyle?.height ?? (widget.isDense ? _denseButtonHeight : null); + final buttonHeight = _buttonStyle?.height ?? (widget.isDense ? _denseButtonHeight : null); final Widget innerItemsWidget = buttonItems.isEmpty ? const SizedBox.shrink() : ValueListenableBuilder( - valueListenable: widget.valueListenable ?? - widget.multiValueListenable ?? - ValueNotifier(null), + valueListenable: + widget.valueListenable ?? widget.multiValueListenable ?? ValueNotifier(null), builder: (context, _, __) { _uniqueValueAssert( widget.items, @@ -796,9 +768,7 @@ class _DropdownButton2State extends State> ); Widget result = DefaultTextStyle( - style: _enabled - ? _textStyle! - : _textStyle!.copyWith(color: Theme.of(context).disabledColor), + style: _enabled ? _textStyle! : _textStyle!.copyWith(color: Theme.of(context).disabledColor), child: widget.customButton ?? _ConditionalDecoratedBox( decoration: _buttonStyle?.decoration?.copyWith( @@ -824,10 +794,7 @@ class _DropdownButton2State extends State> mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisSize: MainAxisSize.min, children: [ - if (widget.isExpanded) - Expanded(child: innerItemsWidget) - else - innerItemsWidget, + if (widget.isExpanded) Expanded(child: innerItemsWidget) else innerItemsWidget, IconTheme( data: IconThemeData( color: _iconColor, @@ -876,8 +843,7 @@ class _DropdownButton2State extends State> ); } - final MouseCursor effectiveMouseCursor = - MaterialStateProperty.resolveAs( + final MouseCursor effectiveMouseCursor = MaterialStateProperty.resolveAs( MaterialStateMouseCursor.clickable, { if (!_enabled) MaterialState.disabled, @@ -900,8 +866,7 @@ class _DropdownButton2State extends State> final focusColor = effectiveDecoration.focusColor; // For compatibility, override the fill color when focusColor is set. if (focusColor != null) { - effectiveDecoration = - effectiveDecoration.copyWith(fillColor: focusColor); + effectiveDecoration = effectiveDecoration.copyWith(fillColor: focusColor); } } result = Focus( @@ -926,8 +891,7 @@ class _DropdownButton2State extends State> cursor: effectiveMouseCursor, child: GestureDetector( onTap: _enabled && !widget.openWithLongPress ? _handleTap : null, - onLongPress: - _enabled && widget.openWithLongPress ? _handleTap : null, + onLongPress: _enabled && widget.openWithLongPress ? _handleTap : null, behavior: HitTestBehavior.opaque, child: InputDecorator( decoration: effectiveDecoration, @@ -954,8 +918,8 @@ class _DropdownButton2State extends State> ); } - final bool childHasButtonSemantic = hintIndex != null || - (_selectedIndex != null && widget.selectedItemBuilder == null); + final bool childHasButtonSemantic = + hintIndex != null || (_selectedIndex != null && widget.selectedItemBuilder == null); return Semantics( button: !childHasButtonSemantic, child: Actions( @@ -1033,19 +997,14 @@ class DropdownButtonFormField2 extends FormField { builder: (FormFieldState field) { final _DropdownButtonFormFieldState state = field as _DropdownButtonFormFieldState; - final InputDecoration decorationArg = - decoration ?? const InputDecoration(); - final InputDecoration effectiveDecoration = - decorationArg.applyDefaults( + final InputDecoration decorationArg = decoration ?? const InputDecoration(); + final InputDecoration effectiveDecoration = decorationArg.applyDefaults( Theme.of(field.context).inputDecorationTheme, ); final bool showSelectedItem = items != null && - items - .where((DropdownItem item) => item.value == state.value) - .isNotEmpty; - final bool isDropdownEnabled = - onChanged != null && items != null && items.isNotEmpty; + items.where((DropdownItem item) => item.value == state.value).isNotEmpty; + final bool isDropdownEnabled = onChanged != null && items != null && items.isNotEmpty; // If decoration hintText is provided, use it as the default value for both hint and disabledHint. final Widget? decorationHint = effectiveDecoration.hintText != null ? Text( @@ -1060,8 +1019,7 @@ class DropdownButtonFormField2 extends FormField { final bool isHintOrDisabledHintAvailable = isDropdownEnabled ? effectiveHint != null : effectiveHint != null || effectiveDisabledHint != null; - final bool isEmpty = - !showSelectedItem && !isHintOrDisabledHintAvailable; + final bool isEmpty = !showSelectedItem && !isHintOrDisabledHintAvailable; // An unFocusable Focus widget so that this widget can detect if its // descendants have focus or not. @@ -1123,8 +1081,7 @@ class DropdownButtonFormField2 extends FormField { } class _DropdownButtonFormFieldState extends FormFieldState { - DropdownButtonFormField get _dropdownButtonFormField => - widget as DropdownButtonFormField; + DropdownButtonFormField get _dropdownButtonFormField => widget as DropdownButtonFormField; @override void didChange(T? value) { diff --git a/packages/dropdown_button2/lib/src/dropdown_menu.dart b/packages/dropdown_button2/lib/src/dropdown_menu.dart index 12e3441..4bb25a5 100644 --- a/packages/dropdown_button2/lib/src/dropdown_menu.dart +++ b/packages/dropdown_button2/lib/src/dropdown_menu.dart @@ -1,8 +1,7 @@ part of 'dropdown_button2.dart'; -SearchMatchFn _defaultSearchMatchFn() => - (DropdownItem item, String searchValue) => - item.value.toString().toLowerCase().contains(searchValue.toLowerCase()); +SearchMatchFn _defaultSearchMatchFn() => (DropdownItem item, String searchValue) => + item.value.toString().toLowerCase().contains(searchValue.toLowerCase()); class _MenuLimits { const _MenuLimits(this.top, this.bottom, this.height, this.scrollOffset); @@ -49,8 +48,7 @@ class _DropdownMenuState extends State<_DropdownMenu> { DropdownSearchData? get searchData => widget.route.searchData; - _DropdownItemButton dropdownItemButton(int index) => - _DropdownItemButton( + _DropdownItemButton dropdownItemButton(int index) => _DropdownItemButton( route: widget.route, scrollController: widget.scrollController, textDirection: widget.textDirection, @@ -83,8 +81,7 @@ class _DropdownMenuState extends State<_DropdownMenu> { final searchController = searchData?.searchController; if (searchController == null) { _children = [ - for (int index = 0; index < items.length; ++index) - dropdownItemButton(index), + for (int index = 0; index < items.length; ++index) dropdownItemButton(index), ]; } else { _searchMatchFn = searchData?.searchMatchFn ?? _defaultSearchMatchFn(); @@ -103,8 +100,7 @@ class _DropdownMenuState extends State<_DropdownMenu> { final String currentSearch = searchData!.searchController!.text; return [ for (int index = 0; index < items.length; ++index) - if (_searchMatchFn(items[index], currentSearch)) - dropdownItemButton(index), + if (_searchMatchFn(items[index], currentSearch)) dropdownItemButton(index), ]; } @@ -125,13 +121,11 @@ class _DropdownMenuState extends State<_DropdownMenu> { ScrollbarThemeData? get _scrollbarTheme => dropdownStyle.scrollbarTheme; - bool get _iOSThumbVisibility => - _scrollbarTheme?.thumbVisibility?.resolve(_states) ?? true; + bool get _iOSThumbVisibility => _scrollbarTheme?.thumbVisibility?.resolve(_states) ?? true; bool get _hasIntrinsicHeight => widget.route.items.any((item) => item.intrinsicHeight) || - (widget.route.dropdownSeparator != null && - widget.route.dropdownSeparator!.intrinsicHeight); + (widget.route.dropdownSeparator != null && widget.route.dropdownSeparator!.intrinsicHeight); @override Widget build(BuildContext context) { @@ -144,8 +138,7 @@ class _DropdownMenuState extends State<_DropdownMenu> { // When the menu is dismissed we just fade the entire thing out // in the first 0.25s. assert(debugCheckHasMaterialLocalizations(context)); - final MaterialLocalizations localizations = - MaterialLocalizations.of(context); + final MaterialLocalizations localizations = MaterialLocalizations.of(context); final _DropdownRoute route = widget.route; final separator = widget.route.dropdownSeparator; @@ -189,24 +182,20 @@ class _DropdownMenuState extends State<_DropdownMenu> { thumbVisibility: // ignore: avoid_bool_literals_in_conditional_expressions _isIOS ? _iOSThumbVisibility : true, - thickness: _isIOS - ? _scrollbarTheme?.thickness?.resolve(_states) - : null, + thickness: _isIOS ? _scrollbarTheme?.thickness?.resolve(_states) : null, radius: _isIOS ? _scrollbarTheme?.radius : null, child: ListView.custom( // Ensure this always inherits the PrimaryScrollController primary: true, shrinkWrap: true, - padding: - dropdownStyle.padding ?? kMaterialListPadding, + padding: dropdownStyle.padding ?? kMaterialListPadding, itemExtentBuilder: _hasIntrinsicHeight ? null : (index, dimensions) { final childrenLength = separator == null ? _children.length : SeparatedSliverChildBuilderDelegate - .computeActualChildCount( - _children.length); + .computeActualChildCount(_children.length); // TODO(Ahmed): Remove this when https://github.com/flutter/flutter/pull/142428 // is supported by the min version of the package [Flutter>=3.22.0]. if (index >= childrenLength) { @@ -225,13 +214,9 @@ class _DropdownMenuState extends State<_DropdownMenu> { ) : SeparatedSliverChildBuilderDelegate( itemCount: _children.length, - itemBuilder: (context, index) => - _children[index], - separatorBuilder: (context, index) => - SizedBox( - height: separator.intrinsicHeight - ? null - : separator.height, + itemBuilder: (context, index) => _children[index], + separatorBuilder: (context, index) => SizedBox( + height: separator.intrinsicHeight ? null : separator.height, child: separator, ), ), @@ -265,13 +250,10 @@ class _DropdownMenuState extends State<_DropdownMenu> { label: localizations.popupMenuLabel, child: ClipRRect( //Prevent scrollbar, ripple effect & items from going beyond border boundaries when scrolling. - clipBehavior: dropdownStyle.decoration?.borderRadius != null - ? Clip.antiAlias - : Clip.none, - borderRadius: - dropdownStyle.decoration?.borderRadius ?? BorderRadius.zero, - child: dropdownStyle.dropdownBuilder?.call(context, dropdownMenu) ?? - dropdownMenu, + clipBehavior: + dropdownStyle.decoration?.borderRadius != null ? Clip.antiAlias : Clip.none, + borderRadius: dropdownStyle.decoration?.borderRadius ?? BorderRadius.zero, + child: dropdownStyle.dropdownBuilder?.call(context, dropdownMenu) ?? dropdownMenu, ), ), ), @@ -290,8 +272,7 @@ class _DropdownMenuPainter extends CustomPainter { }) : _painter = dropdownDecoration ?.copyWith( color: dropdownDecoration.color ?? color, - boxShadow: dropdownDecoration.boxShadow ?? - kElevationToShadow[elevation], + boxShadow: dropdownDecoration.boxShadow ?? kElevationToShadow[elevation], ) .createBoxPainter(() {}) ?? BoxDecoration( @@ -323,13 +304,11 @@ class _DropdownMenuPainter extends CustomPainter { ); final Tween bottom = Tween( - begin: clampDouble(top.begin! + itemHeight, - math.min(itemHeight, size.height), size.height), + begin: clampDouble(top.begin! + itemHeight, math.min(itemHeight, size.height), size.height), end: size.height, ); - final Rect rect = Rect.fromLTRB( - 0.0, top.evaluate(resize), size.width, bottom.evaluate(resize)); + final Rect rect = Rect.fromLTRB(0.0, top.evaluate(resize), size.width, bottom.evaluate(resize)); _painter.paint(canvas, rect.topLeft, ImageConfiguration(size: rect.size)); } diff --git a/packages/dropdown_button2/lib/src/dropdown_menu_item.dart b/packages/dropdown_button2/lib/src/dropdown_menu_item.dart index 589cbc0..03220e4 100644 --- a/packages/dropdown_button2/lib/src/dropdown_menu_item.dart +++ b/packages/dropdown_button2/lib/src/dropdown_menu_item.dart @@ -180,8 +180,7 @@ class _DropdownItemButtonState extends State<_DropdownItemButton> { void _setOpacityAnimation() { final double menuCurveEnd = widget.route.dropdownStyle.openInterval.end; final double unit = 0.5 / (widget.route.items.length + 1.5); - final double start = - clampDouble(menuCurveEnd + (widget.itemIndex + 1) * unit, 0.0, 1.0); + final double start = clampDouble(menuCurveEnd + (widget.itemIndex + 1) * unit, 0.0, 1.0); final double end = clampDouble(start + 1.5 * unit, 0.0, 1.0); _opacityAnimation = CurvedAnimation( parent: widget.route.animation!, @@ -190,8 +189,7 @@ class _DropdownItemButtonState extends State<_DropdownItemButton> { } void _handleFocusChange(bool focused) { - final bool inTraditionalMode = - switch (FocusManager.instance.highlightMode) { + final bool inTraditionalMode = switch (FocusManager.instance.highlightMode) { FocusHighlightMode.touch => false, FocusHighlightMode.traditional => true, }; @@ -225,29 +223,23 @@ class _DropdownItemButtonState extends State<_DropdownItemButton> { } } - static const Map _webShortcuts = - { + static const Map _webShortcuts = { // On the web, up/down don't change focus, *except* in a