mirror of
https://github.com/bggRGjQaUbCoE/PiliPlus.git
synced 2026-04-20 11:08:03 +08:00
@@ -15,7 +15,7 @@ import 'dart:math' as math;
|
||||
|
||||
import 'package:PiliPlus/common/widgets/flutter/dyn/ink_well.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart' hide InkWell;
|
||||
import 'package:flutter/material.dart' hide ButtonStyleButton, InkWell;
|
||||
import 'package:flutter/rendering.dart';
|
||||
|
||||
/// The base [StatefulWidget] class for buttons whose style is defined by a [ButtonStyle] object.
|
||||
@@ -121,7 +121,7 @@ abstract class ButtonStyleButton extends StatefulWidget {
|
||||
/// Defaults to true.
|
||||
final bool? isSemanticButton;
|
||||
|
||||
/// {@macro flutter.material.ButtonStyleButton.iconAlignment}
|
||||
/// {@macro flutter.material.ButtonStyle.iconAlignment}
|
||||
@Deprecated(
|
||||
'Remove this parameter as it is now ignored. '
|
||||
'Use ButtonStyle.iconAlignment instead. '
|
||||
@@ -722,9 +722,9 @@ class _RenderInputPadding extends RenderShiftedBox {
|
||||
}) {
|
||||
if (child != null) {
|
||||
final Size childSize = layoutChild(child!, constraints);
|
||||
final double height = math.max(childSize.width, minSize.width);
|
||||
final double width = math.max(childSize.height, minSize.height);
|
||||
return constraints.constrain(Size(height, width));
|
||||
final double width = math.max(childSize.width, minSize.width);
|
||||
final double height = math.max(childSize.height, minSize.height);
|
||||
return constraints.constrain(Size(width, height));
|
||||
}
|
||||
return Size.zero;
|
||||
}
|
||||
@@ -764,7 +764,7 @@ class _RenderInputPadding extends RenderShiftedBox {
|
||||
layoutChild: ChildLayoutHelper.layoutChild,
|
||||
);
|
||||
if (child != null) {
|
||||
final BoxParentData childParentData = child!.parentData! as BoxParentData;
|
||||
final childParentData = child!.parentData! as BoxParentData;
|
||||
childParentData.offset = Alignment.center.alongOffset(
|
||||
size - child!.size as Offset,
|
||||
);
|
||||
|
||||
@@ -18,7 +18,7 @@ import 'dart:collection';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/material.dart' hide InkWell;
|
||||
import 'package:flutter/rendering.dart';
|
||||
|
||||
abstract class _ParentInkResponseState {
|
||||
@@ -265,14 +265,16 @@ class InkResponse extends StatelessWidget {
|
||||
/// The cursor for a mouse pointer when it enters or is hovering over the
|
||||
/// widget.
|
||||
///
|
||||
/// {@template flutter.material.InkWell.mouseCursor}
|
||||
/// If [mouseCursor] is a [WidgetStateMouseCursor],
|
||||
/// [WidgetStateProperty.resolve] is used for the following [WidgetState]s:
|
||||
///
|
||||
/// * [WidgetState.hovered].
|
||||
/// * [WidgetState.focused].
|
||||
/// * [WidgetState.disabled].
|
||||
/// {@endtemplate}
|
||||
///
|
||||
/// If this property is null, [WidgetStateMouseCursor.clickable] will be used.
|
||||
/// If this property is null, [WidgetStateMouseCursor.adaptiveClickable] will be used.
|
||||
final MouseCursor? mouseCursor;
|
||||
|
||||
/// Whether this ink response should be clipped its bounds.
|
||||
@@ -638,7 +640,7 @@ class _InkResponseStateWidget extends StatefulWidget {
|
||||
@override
|
||||
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
||||
super.debugFillProperties(properties);
|
||||
final List<String> gestures = <String>[
|
||||
final gestures = <String>[
|
||||
if (onTap != null) 'tap',
|
||||
if (onDoubleTap != null) 'double tap',
|
||||
if (onLongPress != null) 'long press',
|
||||
@@ -900,7 +902,7 @@ class _InkResponseState extends State<_InkResponseStateWidget>
|
||||
_HighlightType.hover =>
|
||||
widget.hoverColor ?? Theme.of(context).hoverColor,
|
||||
};
|
||||
final RenderBox referenceBox = context.findRenderObject()! as RenderBox;
|
||||
final referenceBox = context.findRenderObject()! as RenderBox;
|
||||
_highlights[type] = InkHighlight(
|
||||
controller: Material.of(context),
|
||||
referenceBox: referenceBox,
|
||||
@@ -951,7 +953,7 @@ class _InkResponseState extends State<_InkResponseStateWidget>
|
||||
|
||||
InteractiveInkFeature _createSplash(Offset globalPosition) {
|
||||
final MaterialInkController inkController = Material.of(context);
|
||||
final RenderBox referenceBox = context.findRenderObject()! as RenderBox;
|
||||
final referenceBox = context.findRenderObject()! as RenderBox;
|
||||
final Offset position = referenceBox.globalToLocal(globalPosition);
|
||||
final Color color =
|
||||
widget.overlayColor?.resolve(statesController.value) ??
|
||||
@@ -1054,7 +1056,7 @@ class _InkResponseState extends State<_InkResponseStateWidget>
|
||||
|
||||
final Offset globalPosition;
|
||||
if (context != null) {
|
||||
final RenderBox referenceBox = context.findRenderObject()! as RenderBox;
|
||||
final referenceBox = context.findRenderObject()! as RenderBox;
|
||||
assert(
|
||||
referenceBox.hasSize,
|
||||
'InkResponse must be done with layout before starting a splash.',
|
||||
@@ -1139,7 +1141,7 @@ class _InkResponseState extends State<_InkResponseStateWidget>
|
||||
if (_splashes != null) {
|
||||
final Set<InteractiveInkFeature> splashes = _splashes!;
|
||||
_splashes = null;
|
||||
for (final InteractiveInkFeature splash in splashes) {
|
||||
for (final splash in splashes) {
|
||||
splash.dispose();
|
||||
}
|
||||
_currentSplash = null;
|
||||
@@ -1205,7 +1207,7 @@ class _InkResponseState extends State<_InkResponseStateWidget>
|
||||
assert(widget.debugCheckContext(context));
|
||||
|
||||
final ThemeData theme = Theme.of(context);
|
||||
const Set<WidgetState> highlightableStates = <WidgetState>{
|
||||
const highlightableStates = <WidgetState>{
|
||||
WidgetState.focused,
|
||||
WidgetState.hovered,
|
||||
WidgetState.pressed,
|
||||
@@ -1216,15 +1218,15 @@ class _InkResponseState extends State<_InkResponseStateWidget>
|
||||
);
|
||||
// Each highlightable state will be resolved separately to get the corresponding color.
|
||||
// For this resolution to be correct, the non-highlightable states should be preserved.
|
||||
final Set<WidgetState> pressed = <WidgetState>{
|
||||
final pressed = <WidgetState>{
|
||||
...nonHighlightableStates,
|
||||
WidgetState.pressed,
|
||||
};
|
||||
final Set<WidgetState> focused = <WidgetState>{
|
||||
final focused = <WidgetState>{
|
||||
...nonHighlightableStates,
|
||||
WidgetState.focused,
|
||||
};
|
||||
final Set<WidgetState> hovered = <WidgetState>{
|
||||
final hovered = <WidgetState>{
|
||||
...nonHighlightableStates,
|
||||
WidgetState.hovered,
|
||||
};
|
||||
@@ -1260,7 +1262,7 @@ class _InkResponseState extends State<_InkResponseStateWidget>
|
||||
|
||||
final MouseCursor effectiveMouseCursor =
|
||||
WidgetStateProperty.resolveAs<MouseCursor>(
|
||||
widget.mouseCursor ?? WidgetStateMouseCursor.clickable,
|
||||
widget.mouseCursor ?? WidgetStateMouseCursor.adaptiveClickable,
|
||||
statesController.value,
|
||||
);
|
||||
|
||||
|
||||
@@ -14,7 +14,8 @@ import 'dart:ui' show lerpDouble;
|
||||
|
||||
import 'package:PiliPlus/common/widgets/flutter/dyn/button.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart' hide InkWell, ButtonStyleButton;
|
||||
import 'package:flutter/material.dart'
|
||||
hide ButtonStyleButton, TextButton, InkWell;
|
||||
|
||||
/// A Material Design "Text Button".
|
||||
///
|
||||
@@ -84,7 +85,7 @@ class TextButton extends ButtonStyleButton {
|
||||
super.statesController,
|
||||
super.isSemanticButton,
|
||||
required Widget super.child,
|
||||
});
|
||||
}) : _addPadding = false;
|
||||
|
||||
/// Create a text button from a pair of widgets that serve as the button's
|
||||
/// [icon] and [label].
|
||||
@@ -92,56 +93,38 @@ class TextButton extends ButtonStyleButton {
|
||||
/// The icon and label are arranged in a row and padded by 8 logical pixels
|
||||
/// at the ends, with an 8 pixel gap in between.
|
||||
///
|
||||
/// If [icon] is null, will create a [TextButton] instead.
|
||||
/// If [icon] is null, this constructor will create a [TextButton]
|
||||
/// that doesn't display an icon.
|
||||
///
|
||||
/// {@macro flutter.material.ButtonStyleButton.iconAlignment}
|
||||
/// {@macro flutter.material.ButtonStyle.iconAlignment}
|
||||
///
|
||||
factory TextButton.icon({
|
||||
Key? key,
|
||||
required VoidCallback? onPressed,
|
||||
VoidCallback? onLongPress,
|
||||
ValueChanged<bool>? onHover,
|
||||
ValueChanged<bool>? onFocusChange,
|
||||
ButtonStyle? style,
|
||||
FocusNode? focusNode,
|
||||
bool? autofocus,
|
||||
Clip? clipBehavior,
|
||||
WidgetStatesController? statesController,
|
||||
TextButton.icon({
|
||||
super.key,
|
||||
required super.onPressed,
|
||||
super.onLongPress,
|
||||
super.onHover,
|
||||
super.onFocusChange,
|
||||
super.style,
|
||||
super.focusNode,
|
||||
super.autofocus = false,
|
||||
super.clipBehavior = Clip.none,
|
||||
super.statesController,
|
||||
Widget? icon,
|
||||
required Widget label,
|
||||
IconAlignment? iconAlignment,
|
||||
}) {
|
||||
if (icon == null) {
|
||||
return TextButton(
|
||||
key: key,
|
||||
onPressed: onPressed,
|
||||
onLongPress: onLongPress,
|
||||
onHover: onHover,
|
||||
onFocusChange: onFocusChange,
|
||||
style: style,
|
||||
focusNode: focusNode,
|
||||
autofocus: autofocus ?? false,
|
||||
clipBehavior: clipBehavior ?? Clip.none,
|
||||
statesController: statesController,
|
||||
child: label,
|
||||
);
|
||||
}
|
||||
return _TextButtonWithIcon(
|
||||
key: key,
|
||||
onPressed: onPressed,
|
||||
onLongPress: onLongPress,
|
||||
onHover: onHover,
|
||||
onFocusChange: onFocusChange,
|
||||
style: style,
|
||||
focusNode: focusNode,
|
||||
autofocus: autofocus ?? false,
|
||||
clipBehavior: clipBehavior ?? Clip.none,
|
||||
statesController: statesController,
|
||||
icon: icon,
|
||||
label: label,
|
||||
iconAlignment: iconAlignment,
|
||||
);
|
||||
}
|
||||
}) : _addPadding = icon != null,
|
||||
super(
|
||||
child: icon != null
|
||||
? _TextButtonWithIconChild(
|
||||
label: label,
|
||||
icon: icon,
|
||||
buttonStyle: style,
|
||||
iconAlignment: iconAlignment,
|
||||
)
|
||||
: label,
|
||||
);
|
||||
|
||||
final bool _addPadding;
|
||||
|
||||
/// A static convenience method that constructs a text button
|
||||
/// [ButtonStyle] given simple values.
|
||||
@@ -339,9 +322,7 @@ class TextButton extends ButtonStyleButton {
|
||||
/// * `maximumSize` - Size.infinite
|
||||
/// * `side` - null
|
||||
/// * `shape` - RoundedRectangleBorder(borderRadius: BorderRadius.circular(4))
|
||||
/// * `mouseCursor`
|
||||
/// * disabled - SystemMouseCursors.basic
|
||||
/// * others - SystemMouseCursors.click
|
||||
/// * `mouseCursor` - WidgetStateMouseCursor.adaptiveClickable
|
||||
/// * `visualDensity` - theme.visualDensity
|
||||
/// * `tapTargetSize` - theme.materialTapTargetSize
|
||||
/// * `animationDuration` - kThemeChangeDuration
|
||||
@@ -389,9 +370,7 @@ class TextButton extends ButtonStyleButton {
|
||||
/// * `maximumSize` - Size.infinite
|
||||
/// * `side` - null
|
||||
/// * `shape` - StadiumBorder()
|
||||
/// * `mouseCursor`
|
||||
/// * disabled - SystemMouseCursors.basic
|
||||
/// * others - SystemMouseCursors.click
|
||||
/// * `mouseCursor` - WidgetStateMouseCursor.adaptiveClickable
|
||||
/// * `visualDensity` - theme.visualDensity
|
||||
/// * `tapTargetSize` - theme.materialTapTargetSize
|
||||
/// * `animationDuration` - kThemeChangeDuration
|
||||
@@ -406,8 +385,7 @@ class TextButton extends ButtonStyleButton {
|
||||
ButtonStyle defaultStyleOf(BuildContext context) {
|
||||
final ThemeData theme = Theme.of(context);
|
||||
final ColorScheme colorScheme = theme.colorScheme;
|
||||
|
||||
return Theme.of(context).useMaterial3
|
||||
final ButtonStyle buttonStyle = theme.useMaterial3
|
||||
? _TextButtonDefaultsM3(context)
|
||||
: styleFrom(
|
||||
foregroundColor: colorScheme.primary,
|
||||
@@ -425,7 +403,9 @@ class TextButton extends ButtonStyleButton {
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(4)),
|
||||
),
|
||||
enabledMouseCursor: SystemMouseCursors.click,
|
||||
enabledMouseCursor: kIsWeb
|
||||
? SystemMouseCursors.click
|
||||
: SystemMouseCursors.basic,
|
||||
disabledMouseCursor: SystemMouseCursors.basic,
|
||||
visualDensity: theme.visualDensity,
|
||||
tapTargetSize: theme.materialTapTargetSize,
|
||||
@@ -434,6 +414,28 @@ class TextButton extends ButtonStyleButton {
|
||||
alignment: Alignment.center,
|
||||
splashFactory: InkRipple.splashFactory,
|
||||
);
|
||||
|
||||
// Only apply padding when TextButton has an Icon.
|
||||
if (_addPadding) {
|
||||
final double defaultFontSize =
|
||||
buttonStyle.textStyle?.resolve(const <WidgetState>{})?.fontSize ??
|
||||
14.0;
|
||||
final double effectiveTextScale =
|
||||
MediaQuery.textScalerOf(context).scale(defaultFontSize) / 14.0;
|
||||
final EdgeInsetsGeometry scaledPadding = ButtonStyleButton.scaledPadding(
|
||||
theme.useMaterial3
|
||||
? const EdgeInsetsDirectional.fromSTEB(12, 8, 16, 8)
|
||||
: const EdgeInsets.all(8),
|
||||
const EdgeInsets.symmetric(horizontal: 4),
|
||||
const EdgeInsets.symmetric(horizontal: 4),
|
||||
effectiveTextScale,
|
||||
);
|
||||
return buttonStyle.copyWith(
|
||||
padding: WidgetStatePropertyAll<EdgeInsetsGeometry>(scaledPadding),
|
||||
);
|
||||
}
|
||||
|
||||
return buttonStyle;
|
||||
}
|
||||
|
||||
/// Returns the [TextButtonThemeData.style] of the closest
|
||||
@@ -459,53 +461,6 @@ EdgeInsetsGeometry _scaledPadding(BuildContext context) {
|
||||
);
|
||||
}
|
||||
|
||||
class _TextButtonWithIcon extends TextButton {
|
||||
_TextButtonWithIcon({
|
||||
super.key,
|
||||
required super.onPressed,
|
||||
super.onLongPress,
|
||||
super.onHover,
|
||||
super.onFocusChange,
|
||||
super.style,
|
||||
super.focusNode,
|
||||
bool? autofocus,
|
||||
super.clipBehavior,
|
||||
super.statesController,
|
||||
required Widget icon,
|
||||
required Widget label,
|
||||
IconAlignment? iconAlignment,
|
||||
}) : super(
|
||||
autofocus: autofocus ?? false,
|
||||
child: _TextButtonWithIconChild(
|
||||
icon: icon,
|
||||
label: label,
|
||||
buttonStyle: style,
|
||||
iconAlignment: iconAlignment,
|
||||
),
|
||||
);
|
||||
|
||||
@override
|
||||
ButtonStyle defaultStyleOf(BuildContext context) {
|
||||
final bool useMaterial3 = Theme.of(context).useMaterial3;
|
||||
final ButtonStyle buttonStyle = super.defaultStyleOf(context);
|
||||
final double defaultFontSize =
|
||||
buttonStyle.textStyle?.resolve(const <WidgetState>{})?.fontSize ?? 14.0;
|
||||
final double effectiveTextScale =
|
||||
MediaQuery.textScalerOf(context).scale(defaultFontSize) / 14.0;
|
||||
final EdgeInsetsGeometry scaledPadding = ButtonStyleButton.scaledPadding(
|
||||
useMaterial3
|
||||
? const EdgeInsetsDirectional.fromSTEB(12, 8, 16, 8)
|
||||
: const EdgeInsets.all(8),
|
||||
const EdgeInsets.symmetric(horizontal: 4),
|
||||
const EdgeInsets.symmetric(horizontal: 4),
|
||||
effectiveTextScale,
|
||||
);
|
||||
return buttonStyle.copyWith(
|
||||
padding: WidgetStatePropertyAll<EdgeInsetsGeometry>(scaledPadding),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _TextButtonWithIconChild extends StatelessWidget {
|
||||
const _TextButtonWithIconChild({
|
||||
required this.label,
|
||||
@@ -557,72 +512,72 @@ class _TextButtonWithIconChild extends StatelessWidget {
|
||||
// dart format off
|
||||
class _TextButtonDefaultsM3 extends ButtonStyle {
|
||||
_TextButtonDefaultsM3(this.context)
|
||||
: super(
|
||||
animationDuration: kThemeChangeDuration,
|
||||
enableFeedback: true,
|
||||
alignment: Alignment.center,
|
||||
);
|
||||
: super(
|
||||
animationDuration: kThemeChangeDuration,
|
||||
enableFeedback: true,
|
||||
alignment: Alignment.center,
|
||||
);
|
||||
|
||||
final BuildContext context;
|
||||
late final ColorScheme _colors = Theme.of(context).colorScheme;
|
||||
|
||||
@override
|
||||
WidgetStateProperty<TextStyle?> get textStyle =>
|
||||
WidgetStatePropertyAll<TextStyle?>(Theme.of(context).textTheme.labelLarge);
|
||||
WidgetStatePropertyAll<TextStyle?>(Theme.of(context).textTheme.labelLarge);
|
||||
|
||||
@override
|
||||
WidgetStateProperty<Color?>? get backgroundColor =>
|
||||
const WidgetStatePropertyAll<Color>(Colors.transparent);
|
||||
const WidgetStatePropertyAll<Color>(Colors.transparent);
|
||||
|
||||
@override
|
||||
WidgetStateProperty<Color?>? get foregroundColor =>
|
||||
WidgetStateProperty.resolveWith((Set<WidgetState> states) {
|
||||
if (states.contains(WidgetState.disabled)) {
|
||||
return _colors.onSurface.withValues(alpha: 0.38);
|
||||
}
|
||||
return _colors.primary;
|
||||
});
|
||||
WidgetStateProperty.resolveWith((Set<WidgetState> states) {
|
||||
if (states.contains(WidgetState.disabled)) {
|
||||
return _colors.onSurface.withValues(alpha: 0.38);
|
||||
}
|
||||
return _colors.primary;
|
||||
});
|
||||
|
||||
@override
|
||||
WidgetStateProperty<Color?>? get overlayColor =>
|
||||
WidgetStateProperty.resolveWith((Set<WidgetState> states) {
|
||||
if (states.contains(WidgetState.pressed)) {
|
||||
return _colors.primary.withValues(alpha: 0.1);
|
||||
}
|
||||
if (states.contains(WidgetState.hovered)) {
|
||||
return _colors.primary.withValues(alpha: 0.08);
|
||||
}
|
||||
if (states.contains(WidgetState.focused)) {
|
||||
return _colors.primary.withValues(alpha: 0.1);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
WidgetStateProperty.resolveWith((Set<WidgetState> states) {
|
||||
if (states.contains(WidgetState.pressed)) {
|
||||
return _colors.primary.withValues(alpha: 0.1);
|
||||
}
|
||||
if (states.contains(WidgetState.hovered)) {
|
||||
return _colors.primary.withValues(alpha: 0.08);
|
||||
}
|
||||
if (states.contains(WidgetState.focused)) {
|
||||
return _colors.primary.withValues(alpha: 0.1);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
|
||||
@override
|
||||
WidgetStateProperty<Color>? get shadowColor =>
|
||||
const WidgetStatePropertyAll<Color>(Colors.transparent);
|
||||
const WidgetStatePropertyAll<Color>(Colors.transparent);
|
||||
|
||||
@override
|
||||
WidgetStateProperty<Color>? get surfaceTintColor =>
|
||||
const WidgetStatePropertyAll<Color>(Colors.transparent);
|
||||
const WidgetStatePropertyAll<Color>(Colors.transparent);
|
||||
|
||||
@override
|
||||
WidgetStateProperty<double>? get elevation =>
|
||||
const WidgetStatePropertyAll<double>(0.0);
|
||||
const WidgetStatePropertyAll<double>(0.0);
|
||||
|
||||
@override
|
||||
WidgetStateProperty<EdgeInsetsGeometry>? get padding =>
|
||||
WidgetStatePropertyAll<EdgeInsetsGeometry>(_scaledPadding(context));
|
||||
WidgetStatePropertyAll<EdgeInsetsGeometry>(_scaledPadding(context));
|
||||
|
||||
@override
|
||||
WidgetStateProperty<Size>? get minimumSize =>
|
||||
const WidgetStatePropertyAll<Size>(Size(64.0, 40.0));
|
||||
const WidgetStatePropertyAll<Size>(Size(64.0, 40.0));
|
||||
|
||||
// No default fixedSize
|
||||
|
||||
@override
|
||||
WidgetStateProperty<double>? get iconSize =>
|
||||
const WidgetStatePropertyAll<double>(18.0);
|
||||
const WidgetStatePropertyAll<double>(18.0);
|
||||
|
||||
@override
|
||||
WidgetStateProperty<Color>? get iconColor {
|
||||
@@ -645,22 +600,16 @@ class _TextButtonDefaultsM3 extends ButtonStyle {
|
||||
|
||||
@override
|
||||
WidgetStateProperty<Size>? get maximumSize =>
|
||||
const WidgetStatePropertyAll<Size>(Size.infinite);
|
||||
const WidgetStatePropertyAll<Size>(Size.infinite);
|
||||
|
||||
// No default side
|
||||
|
||||
@override
|
||||
WidgetStateProperty<OutlinedBorder>? get shape =>
|
||||
const WidgetStatePropertyAll<OutlinedBorder>(StadiumBorder());
|
||||
const WidgetStatePropertyAll<OutlinedBorder>(StadiumBorder());
|
||||
|
||||
@override
|
||||
WidgetStateProperty<MouseCursor?>? get mouseCursor =>
|
||||
WidgetStateProperty.resolveWith((Set<WidgetState> states) {
|
||||
if (states.contains(WidgetState.disabled)) {
|
||||
return SystemMouseCursors.basic;
|
||||
}
|
||||
return SystemMouseCursors.click;
|
||||
});
|
||||
WidgetStateProperty<MouseCursor?>? get mouseCursor => WidgetStateMouseCursor.adaptiveClickable;
|
||||
|
||||
@override
|
||||
VisualDensity? get visualDensity => Theme.of(context).visualDensity;
|
||||
|
||||
Reference in New Issue
Block a user