Add cancelButtonStyle
& confirmButtonStyle
to the DatePickerThemeData
(#132847)
fixes [Unable to adjust the color for "Cancel" and "Ok" button in datePicker dialog](https://github.com/flutter/flutter/issues/127739) ### Code sample <details> <summary>expand to view the code sample</summary> ```dart import 'package:flutter/material.dart'; void main() => runApp(const MyApp()); class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( debugShowCheckedModeBanner: false, theme: ThemeData( useMaterial3: true, datePickerTheme: DatePickerThemeData( cancelButtonStyle: TextButton.styleFrom( shape: const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(16)), side: BorderSide(color: Colors.red), ), backgroundColor: Colors.white, foregroundColor: Colors.red, elevation: 3, shadowColor: Colors.red, ), confirmButtonStyle: TextButton.styleFrom( shape: const RoundedRectangleBorder( borderRadius: BorderRadius.all(Radius.circular(16)), ), backgroundColor: Colors.green[700], foregroundColor: Colors.white, elevation: 3, shadowColor: Colors.green[700], ), ), ), home: const Example(), ); } } class Example extends StatelessWidget { const Example({super.key}); @override Widget build(BuildContext context) { return Scaffold( body: Center( child: DatePickerDialog( initialDate: DateTime.now(), firstDate: DateTime(2020), lastDate: DateTime(2030), ), ), ); } } ``` </details> ### Before Not possible to customize action buttons from the `DatePickerThemeData`. ### After 
This commit is contained in:
parent
2f2a10d540
commit
1e770c3808
@ -56,6 +56,16 @@ class _${blockName}DefaultsM3 extends DatePickerThemeData {
|
|||||||
@override
|
@override
|
||||||
Color? get backgroundColor => ${componentColor("md.comp.date-picker.modal.container")};
|
Color? get backgroundColor => ${componentColor("md.comp.date-picker.modal.container")};
|
||||||
|
|
||||||
|
@override
|
||||||
|
ButtonStyle get cancelButtonStyle {
|
||||||
|
return TextButton.styleFrom();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
ButtonStyle get confirmButtonStyle {
|
||||||
|
return TextButton.styleFrom();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Color? get shadowColor => ${colorOrTransparent("md.comp.date-picker.modal.container.shadow-color")};
|
Color? get shadowColor => ${colorOrTransparent("md.comp.date-picker.modal.container.shadow-color")};
|
||||||
|
|
||||||
@ -231,8 +241,6 @@ class _${blockName}DefaultsM3 extends DatePickerThemeData {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
TextStyle? get rangePickerHeaderHelpStyle => ${textStyle("md.comp.date-picker.modal.range-selection.month.subhead")};
|
TextStyle? get rangePickerHeaderHelpStyle => ${textStyle("md.comp.date-picker.modal.range-selection.month.subhead")};
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
''';
|
''';
|
||||||
}
|
}
|
||||||
|
@ -543,6 +543,7 @@ class _DatePickerDialogState extends State<DatePickerDialog> with RestorationMix
|
|||||||
spacing: 8,
|
spacing: 8,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
TextButton(
|
TextButton(
|
||||||
|
style: datePickerTheme.cancelButtonStyle ?? defaults.cancelButtonStyle,
|
||||||
onPressed: _handleCancel,
|
onPressed: _handleCancel,
|
||||||
child: Text(widget.cancelText ?? (
|
child: Text(widget.cancelText ?? (
|
||||||
useMaterial3
|
useMaterial3
|
||||||
@ -551,6 +552,7 @@ class _DatePickerDialogState extends State<DatePickerDialog> with RestorationMix
|
|||||||
)),
|
)),
|
||||||
),
|
),
|
||||||
TextButton(
|
TextButton(
|
||||||
|
style: datePickerTheme.confirmButtonStyle ?? defaults.confirmButtonStyle,
|
||||||
onPressed: _handleOk,
|
onPressed: _handleOk,
|
||||||
child: Text(widget.confirmText ?? localizations.okButtonLabel),
|
child: Text(widget.confirmText ?? localizations.okButtonLabel),
|
||||||
),
|
),
|
||||||
|
@ -7,10 +7,12 @@ import 'dart:ui' show lerpDouble;
|
|||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
|
import 'button_style.dart';
|
||||||
import 'color_scheme.dart';
|
import 'color_scheme.dart';
|
||||||
import 'colors.dart';
|
import 'colors.dart';
|
||||||
import 'input_decorator.dart';
|
import 'input_decorator.dart';
|
||||||
import 'material_state.dart';
|
import 'material_state.dart';
|
||||||
|
import 'text_button.dart';
|
||||||
import 'text_theme.dart';
|
import 'text_theme.dart';
|
||||||
import 'theme.dart';
|
import 'theme.dart';
|
||||||
|
|
||||||
@ -70,6 +72,8 @@ class DatePickerThemeData with Diagnosticable {
|
|||||||
this.rangeSelectionOverlayColor,
|
this.rangeSelectionOverlayColor,
|
||||||
this.dividerColor,
|
this.dividerColor,
|
||||||
this.inputDecorationTheme,
|
this.inputDecorationTheme,
|
||||||
|
this.cancelButtonStyle,
|
||||||
|
this.confirmButtonStyle,
|
||||||
});
|
});
|
||||||
|
|
||||||
/// Overrides the default value of [Dialog.backgroundColor].
|
/// Overrides the default value of [Dialog.backgroundColor].
|
||||||
@ -294,6 +298,12 @@ class DatePickerThemeData with Diagnosticable {
|
|||||||
/// If this is null, [ThemeData.inputDecorationTheme] is used instead.
|
/// If this is null, [ThemeData.inputDecorationTheme] is used instead.
|
||||||
final InputDecorationTheme? inputDecorationTheme;
|
final InputDecorationTheme? inputDecorationTheme;
|
||||||
|
|
||||||
|
/// Overrides the default style of the cancel button of a [DatePickerDialog].
|
||||||
|
final ButtonStyle? cancelButtonStyle;
|
||||||
|
|
||||||
|
/// Overrrides the default style of the confirm (OK) button of a [DatePickerDialog].
|
||||||
|
final ButtonStyle? confirmButtonStyle;
|
||||||
|
|
||||||
/// Creates a copy of this object with the given fields replaced with the
|
/// Creates a copy of this object with the given fields replaced with the
|
||||||
/// new values.
|
/// new values.
|
||||||
DatePickerThemeData copyWith({
|
DatePickerThemeData copyWith({
|
||||||
@ -331,6 +341,8 @@ class DatePickerThemeData with Diagnosticable {
|
|||||||
MaterialStateProperty<Color?>? rangeSelectionOverlayColor,
|
MaterialStateProperty<Color?>? rangeSelectionOverlayColor,
|
||||||
Color? dividerColor,
|
Color? dividerColor,
|
||||||
InputDecorationTheme? inputDecorationTheme,
|
InputDecorationTheme? inputDecorationTheme,
|
||||||
|
ButtonStyle? cancelButtonStyle,
|
||||||
|
ButtonStyle? confirmButtonStyle,
|
||||||
}) {
|
}) {
|
||||||
return DatePickerThemeData(
|
return DatePickerThemeData(
|
||||||
backgroundColor: backgroundColor ?? this.backgroundColor,
|
backgroundColor: backgroundColor ?? this.backgroundColor,
|
||||||
@ -367,6 +379,8 @@ class DatePickerThemeData with Diagnosticable {
|
|||||||
rangeSelectionOverlayColor: rangeSelectionOverlayColor ?? this.rangeSelectionOverlayColor,
|
rangeSelectionOverlayColor: rangeSelectionOverlayColor ?? this.rangeSelectionOverlayColor,
|
||||||
dividerColor: dividerColor ?? this.dividerColor,
|
dividerColor: dividerColor ?? this.dividerColor,
|
||||||
inputDecorationTheme: inputDecorationTheme ?? this.inputDecorationTheme,
|
inputDecorationTheme: inputDecorationTheme ?? this.inputDecorationTheme,
|
||||||
|
cancelButtonStyle: cancelButtonStyle ?? this.cancelButtonStyle,
|
||||||
|
confirmButtonStyle: confirmButtonStyle ?? this.confirmButtonStyle,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -410,6 +424,8 @@ class DatePickerThemeData with Diagnosticable {
|
|||||||
rangeSelectionOverlayColor: MaterialStateProperty.lerp<Color?>(a?.rangeSelectionOverlayColor, b?.rangeSelectionOverlayColor, t, Color.lerp),
|
rangeSelectionOverlayColor: MaterialStateProperty.lerp<Color?>(a?.rangeSelectionOverlayColor, b?.rangeSelectionOverlayColor, t, Color.lerp),
|
||||||
dividerColor: Color.lerp(a?.dividerColor, b?.dividerColor, t),
|
dividerColor: Color.lerp(a?.dividerColor, b?.dividerColor, t),
|
||||||
inputDecorationTheme: t < 0.5 ? a?.inputDecorationTheme : b?.inputDecorationTheme,
|
inputDecorationTheme: t < 0.5 ? a?.inputDecorationTheme : b?.inputDecorationTheme,
|
||||||
|
cancelButtonStyle: ButtonStyle.lerp(a?.cancelButtonStyle, b?.cancelButtonStyle, t),
|
||||||
|
confirmButtonStyle: ButtonStyle.lerp(a?.confirmButtonStyle, b?.confirmButtonStyle, t),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -459,6 +475,8 @@ class DatePickerThemeData with Diagnosticable {
|
|||||||
rangeSelectionOverlayColor,
|
rangeSelectionOverlayColor,
|
||||||
dividerColor,
|
dividerColor,
|
||||||
inputDecorationTheme,
|
inputDecorationTheme,
|
||||||
|
cancelButtonStyle,
|
||||||
|
confirmButtonStyle,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -500,7 +518,9 @@ class DatePickerThemeData with Diagnosticable {
|
|||||||
&& other.rangeSelectionBackgroundColor == rangeSelectionBackgroundColor
|
&& other.rangeSelectionBackgroundColor == rangeSelectionBackgroundColor
|
||||||
&& other.rangeSelectionOverlayColor == rangeSelectionOverlayColor
|
&& other.rangeSelectionOverlayColor == rangeSelectionOverlayColor
|
||||||
&& other.dividerColor == dividerColor
|
&& other.dividerColor == dividerColor
|
||||||
&& other.inputDecorationTheme == inputDecorationTheme;
|
&& other.inputDecorationTheme == inputDecorationTheme
|
||||||
|
&& other.cancelButtonStyle == cancelButtonStyle
|
||||||
|
&& other.confirmButtonStyle == confirmButtonStyle;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -540,6 +560,8 @@ class DatePickerThemeData with Diagnosticable {
|
|||||||
properties.add(DiagnosticsProperty<MaterialStateProperty<Color?>>('rangeSelectionOverlayColor', rangeSelectionOverlayColor, defaultValue: null));
|
properties.add(DiagnosticsProperty<MaterialStateProperty<Color?>>('rangeSelectionOverlayColor', rangeSelectionOverlayColor, defaultValue: null));
|
||||||
properties.add(ColorProperty('dividerColor', dividerColor, defaultValue: null));
|
properties.add(ColorProperty('dividerColor', dividerColor, defaultValue: null));
|
||||||
properties.add(DiagnosticsProperty<InputDecorationTheme>('inputDecorationTheme', inputDecorationTheme, defaultValue: null));
|
properties.add(DiagnosticsProperty<InputDecorationTheme>('inputDecorationTheme', inputDecorationTheme, defaultValue: null));
|
||||||
|
properties.add(DiagnosticsProperty<ButtonStyle>('cancelButtonStyle', cancelButtonStyle, defaultValue: null));
|
||||||
|
properties.add(DiagnosticsProperty<ButtonStyle>('confirmButtonStyle', confirmButtonStyle, defaultValue: null));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -658,6 +680,16 @@ class _DatePickerDefaultsM2 extends DatePickerThemeData {
|
|||||||
@override
|
@override
|
||||||
Color? get headerBackgroundColor => _isDark ? _colors.surface : _colors.primary;
|
Color? get headerBackgroundColor => _isDark ? _colors.surface : _colors.primary;
|
||||||
|
|
||||||
|
@override
|
||||||
|
ButtonStyle get cancelButtonStyle {
|
||||||
|
return TextButton.styleFrom();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
ButtonStyle get confirmButtonStyle {
|
||||||
|
return TextButton.styleFrom();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Color? get headerForegroundColor => _isDark ? _colors.onSurface : _colors.onPrimary;
|
Color? get headerForegroundColor => _isDark ? _colors.onSurface : _colors.onPrimary;
|
||||||
|
|
||||||
@ -818,6 +850,16 @@ class _DatePickerDefaultsM3 extends DatePickerThemeData {
|
|||||||
@override
|
@override
|
||||||
Color? get backgroundColor => _colors.surface;
|
Color? get backgroundColor => _colors.surface;
|
||||||
|
|
||||||
|
@override
|
||||||
|
ButtonStyle get cancelButtonStyle {
|
||||||
|
return TextButton.styleFrom();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
ButtonStyle get confirmButtonStyle {
|
||||||
|
return TextButton.styleFrom();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Color? get shadowColor => Colors.transparent;
|
Color? get shadowColor => Colors.transparent;
|
||||||
|
|
||||||
@ -993,8 +1035,6 @@ class _DatePickerDefaultsM3 extends DatePickerThemeData {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
TextStyle? get rangePickerHeaderHelpStyle => _textTheme.titleSmall;
|
TextStyle? get rangePickerHeaderHelpStyle => _textTheme.titleSmall;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// END GENERATED TOKEN PROPERTIES - DatePicker
|
// END GENERATED TOKEN PROPERTIES - DatePicker
|
||||||
|
@ -46,7 +46,9 @@ void main() {
|
|||||||
inputDecorationTheme: InputDecorationTheme(
|
inputDecorationTheme: InputDecorationTheme(
|
||||||
fillColor: Color(0xffffff5f),
|
fillColor: Color(0xffffff5f),
|
||||||
border: UnderlineInputBorder(),
|
border: UnderlineInputBorder(),
|
||||||
)
|
),
|
||||||
|
cancelButtonStyle: ButtonStyle(foregroundColor: MaterialStatePropertyAll<Color>(Color(0xffffff6f))),
|
||||||
|
confirmButtonStyle: ButtonStyle(foregroundColor: MaterialStatePropertyAll<Color>(Color(0xffffff7f))),
|
||||||
);
|
);
|
||||||
|
|
||||||
Material findDialogMaterial(WidgetTester tester) {
|
Material findDialogMaterial(WidgetTester tester) {
|
||||||
@ -77,6 +79,10 @@ void main() {
|
|||||||
return container.decoration as BoxDecoration?;
|
return container.decoration as BoxDecoration?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ButtonStyle actionButtonStyle(WidgetTester tester, String text) {
|
||||||
|
return tester.widget<TextButton>(find.widgetWithText(TextButton, text)).style!;
|
||||||
|
}
|
||||||
|
|
||||||
const Size wideWindowSize = Size(1920.0, 1080.0);
|
const Size wideWindowSize = Size(1920.0, 1080.0);
|
||||||
const Size narrowWindowSize = Size(1070.0, 1770.0);
|
const Size narrowWindowSize = Size(1070.0, 1770.0);
|
||||||
|
|
||||||
@ -126,6 +132,8 @@ void main() {
|
|||||||
expect(theme.rangeSelectionOverlayColor, null);
|
expect(theme.rangeSelectionOverlayColor, null);
|
||||||
expect(theme.dividerColor, null);
|
expect(theme.dividerColor, null);
|
||||||
expect(theme.inputDecorationTheme, null);
|
expect(theme.inputDecorationTheme, null);
|
||||||
|
expect(theme.cancelButtonStyle, null);
|
||||||
|
expect(theme.confirmButtonStyle, null);
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('DatePickerTheme.defaults M3 defaults', (WidgetTester tester) async {
|
testWidgets('DatePickerTheme.defaults M3 defaults', (WidgetTester tester) async {
|
||||||
@ -201,6 +209,8 @@ void main() {
|
|||||||
expect(m3.rangePickerHeaderHelpStyle, textTheme.titleSmall);
|
expect(m3.rangePickerHeaderHelpStyle, textTheme.titleSmall);
|
||||||
expect(m3.dividerColor, null);
|
expect(m3.dividerColor, null);
|
||||||
expect(m3.inputDecorationTheme, null);
|
expect(m3.inputDecorationTheme, null);
|
||||||
|
expect(m3.cancelButtonStyle.toString(), equalsIgnoringHashCodes(TextButton.styleFrom().toString()));
|
||||||
|
expect(m3.confirmButtonStyle.toString(), equalsIgnoringHashCodes(TextButton.styleFrom().toString()));
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('DatePickerTheme.defaults M2 defaults', (WidgetTester tester) async {
|
testWidgets('DatePickerTheme.defaults M2 defaults', (WidgetTester tester) async {
|
||||||
@ -268,6 +278,8 @@ void main() {
|
|||||||
expect(m2.rangePickerHeaderHelpStyle, textTheme.labelSmall);
|
expect(m2.rangePickerHeaderHelpStyle, textTheme.labelSmall);
|
||||||
expect(m2.dividerColor, null);
|
expect(m2.dividerColor, null);
|
||||||
expect(m2.inputDecorationTheme, null);
|
expect(m2.inputDecorationTheme, null);
|
||||||
|
expect(m2.cancelButtonStyle.toString(), equalsIgnoringHashCodes(TextButton.styleFrom().toString()));
|
||||||
|
expect(m2.confirmButtonStyle.toString(), equalsIgnoringHashCodes(TextButton.styleFrom().toString()));
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('Default DatePickerThemeData debugFillProperties', (WidgetTester tester) async {
|
testWidgets('Default DatePickerThemeData debugFillProperties', (WidgetTester tester) async {
|
||||||
@ -292,9 +304,7 @@ void main() {
|
|||||||
.map((DiagnosticsNode node) => node.toString())
|
.map((DiagnosticsNode node) => node.toString())
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
expect(
|
expect(description, equalsIgnoringHashCodes(<String>[
|
||||||
description,
|
|
||||||
equalsIgnoringHashCodes(<String>[
|
|
||||||
'backgroundColor: Color(0xfffffff0)',
|
'backgroundColor: Color(0xfffffff0)',
|
||||||
'elevation: 6.0',
|
'elevation: 6.0',
|
||||||
'shadowColor: Color(0xfffffff1)',
|
'shadowColor: Color(0xfffffff1)',
|
||||||
@ -328,9 +338,10 @@ void main() {
|
|||||||
'rangeSelectionBackgroundColor: Color(0xffffff2f)',
|
'rangeSelectionBackgroundColor: Color(0xffffff2f)',
|
||||||
'rangeSelectionOverlayColor: MaterialStatePropertyAll(Color(0xffffff3f))',
|
'rangeSelectionOverlayColor: MaterialStatePropertyAll(Color(0xffffff3f))',
|
||||||
'dividerColor: Color(0xffffff4f)',
|
'dividerColor: Color(0xffffff4f)',
|
||||||
'inputDecorationTheme: InputDecorationTheme#00000(fillColor: Color(0xffffff5f), border: UnderlineInputBorder())'
|
'inputDecorationTheme: InputDecorationTheme#00000(fillColor: Color(0xffffff5f), border: UnderlineInputBorder())',
|
||||||
]),
|
'cancelButtonStyle: ButtonStyle#00000(foregroundColor: MaterialStatePropertyAll(Color(0xffffff6f)))',
|
||||||
);
|
'confirmButtonStyle: ButtonStyle#00000(foregroundColor: MaterialStatePropertyAll(Color(0xffffff7f)))'
|
||||||
|
]));
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('DatePickerDialog uses ThemeData datePicker theme (calendar mode)', (WidgetTester tester) async {
|
testWidgets('DatePickerDialog uses ThemeData datePicker theme (calendar mode)', (WidgetTester tester) async {
|
||||||
@ -426,6 +437,12 @@ void main() {
|
|||||||
await gesture.moveTo(tester.getCenter(find.text('2024')));
|
await gesture.moveTo(tester.getCenter(find.text('2024')));
|
||||||
await tester.pumpAndSettle();
|
await tester.pumpAndSettle();
|
||||||
expect(inkFeatures, paints..rect(color: datePickerTheme.yearOverlayColor?.resolve(<MaterialState>{})));
|
expect(inkFeatures, paints..rect(color: datePickerTheme.yearOverlayColor?.resolve(<MaterialState>{})));
|
||||||
|
|
||||||
|
final ButtonStyle cancelButtonStyle = actionButtonStyle(tester, 'Cancel');
|
||||||
|
expect(cancelButtonStyle.toString(), equalsIgnoringHashCodes(datePickerTheme.cancelButtonStyle.toString()));
|
||||||
|
|
||||||
|
final ButtonStyle confirmButtonStyle = actionButtonStyle(tester, 'OK');
|
||||||
|
expect(confirmButtonStyle.toString(), equalsIgnoringHashCodes(datePickerTheme.confirmButtonStyle.toString()));
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('DatePickerDialog uses ThemeData datePicker theme (input mode)', (WidgetTester tester) async {
|
testWidgets('DatePickerDialog uses ThemeData datePicker theme (input mode)', (WidgetTester tester) async {
|
||||||
@ -467,6 +484,12 @@ void main() {
|
|||||||
|
|
||||||
final InputDecoration inputDecoration = tester.widget<TextField>(find.byType(TextField)).decoration!;
|
final InputDecoration inputDecoration = tester.widget<TextField>(find.byType(TextField)).decoration!;
|
||||||
expect(inputDecoration.fillColor, datePickerTheme.inputDecorationTheme?.fillColor);
|
expect(inputDecoration.fillColor, datePickerTheme.inputDecorationTheme?.fillColor);
|
||||||
|
|
||||||
|
final ButtonStyle cancelButtonStyle = actionButtonStyle(tester, 'Cancel');
|
||||||
|
expect(cancelButtonStyle.toString(), equalsIgnoringHashCodes(datePickerTheme.cancelButtonStyle.toString()));
|
||||||
|
|
||||||
|
final ButtonStyle confirmButtonStyle = actionButtonStyle(tester, 'OK');
|
||||||
|
expect(confirmButtonStyle.toString(), equalsIgnoringHashCodes(datePickerTheme.confirmButtonStyle.toString()));
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('DateRangePickerDialog uses ThemeData datePicker theme', (WidgetTester tester) async {
|
testWidgets('DateRangePickerDialog uses ThemeData datePicker theme', (WidgetTester tester) async {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user