2022-11-01 08:32:36 +01:00
|
|
|
// SPDX-FileCopyrightText: 2022 Iconica
|
|
|
|
//
|
|
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
|
2022-10-21 12:05:05 +02:00
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
|
|
|
|
class AlertDialogAction {
|
|
|
|
AlertDialogAction({
|
|
|
|
required this.text,
|
2024-02-07 14:57:31 +01:00
|
|
|
required this.onPressed,
|
2022-10-21 12:05:05 +02:00
|
|
|
this.primary = false,
|
|
|
|
this.secondary = false,
|
|
|
|
}) : assert(
|
|
|
|
!(primary && secondary),
|
|
|
|
"AlertDialogAction can't be primary and secondary at the same time",
|
|
|
|
);
|
2024-02-07 14:57:31 +01:00
|
|
|
final String text;
|
|
|
|
final bool primary;
|
|
|
|
final bool secondary;
|
|
|
|
final VoidCallback onPressed;
|
2022-10-21 12:05:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
typedef ButtonCallback = Widget Function(
|
|
|
|
void Function() onPressed,
|
|
|
|
Widget child,
|
|
|
|
BuildContext context,
|
|
|
|
);
|
|
|
|
|
|
|
|
typedef IconButtonCallback = Widget Function(
|
|
|
|
BuildContext context,
|
|
|
|
void Function() onPressed,
|
|
|
|
);
|
|
|
|
|
|
|
|
class IconicaAlertDialog extends StatelessWidget {
|
|
|
|
const IconicaAlertDialog._({
|
|
|
|
required this.buttons,
|
|
|
|
required this.body,
|
|
|
|
this.closeButton = false,
|
|
|
|
this.primaryButton,
|
|
|
|
this.secondaryButton,
|
|
|
|
this.iconButton,
|
|
|
|
});
|
|
|
|
|
|
|
|
factory IconicaAlertDialog.singleButton({
|
|
|
|
required String title,
|
|
|
|
required String body,
|
|
|
|
required String buttonText,
|
|
|
|
required VoidCallback onPressed,
|
|
|
|
bool primary = false,
|
|
|
|
bool? closeButton,
|
|
|
|
ButtonCallback? primaryButton,
|
|
|
|
ButtonCallback? secondaryButton,
|
|
|
|
IconButtonCallback? iconButton,
|
2024-02-07 14:57:31 +01:00
|
|
|
}) =>
|
|
|
|
IconicaAlertDialog.multiButton(
|
|
|
|
primaryButton: primaryButton,
|
|
|
|
secondaryButton: secondaryButton,
|
|
|
|
iconButton: iconButton,
|
|
|
|
closeButton: closeButton,
|
|
|
|
title: title,
|
|
|
|
body: body,
|
|
|
|
buttons: [
|
|
|
|
AlertDialogAction(
|
|
|
|
text: buttonText,
|
|
|
|
onPressed: onPressed,
|
|
|
|
primary: primary,
|
|
|
|
),
|
|
|
|
],
|
|
|
|
);
|
2022-10-21 12:05:05 +02:00
|
|
|
|
|
|
|
factory IconicaAlertDialog.multiButton({
|
|
|
|
required String title,
|
|
|
|
required String body,
|
|
|
|
required List<AlertDialogAction> buttons,
|
|
|
|
bool? closeButton,
|
|
|
|
ButtonCallback? primaryButton,
|
|
|
|
ButtonCallback? secondaryButton,
|
|
|
|
IconButtonCallback? iconButton,
|
2024-02-07 14:57:31 +01:00
|
|
|
}) =>
|
|
|
|
IconicaAlertDialog._(
|
|
|
|
primaryButton: primaryButton,
|
|
|
|
secondaryButton: secondaryButton,
|
|
|
|
iconButton: iconButton,
|
|
|
|
closeButton: closeButton,
|
|
|
|
buttons: buttons,
|
|
|
|
body: (context) => Column(
|
|
|
|
children: [
|
|
|
|
Padding(
|
|
|
|
padding: const EdgeInsets.symmetric(
|
|
|
|
horizontal: 20,
|
|
|
|
),
|
|
|
|
child: Text(
|
|
|
|
title,
|
|
|
|
style: Theme.of(context).textTheme.titleLarge?.copyWith(
|
|
|
|
fontWeight: FontWeight.bold,
|
|
|
|
color: Theme.of(context).textTheme.bodyMedium?.color,
|
|
|
|
),
|
|
|
|
textAlign: TextAlign.center,
|
|
|
|
),
|
2022-10-21 12:05:05 +02:00
|
|
|
),
|
2024-02-07 14:57:31 +01:00
|
|
|
Padding(
|
|
|
|
padding: const EdgeInsets.only(top: 20, left: 20, right: 20),
|
|
|
|
child: Text(
|
|
|
|
body,
|
|
|
|
style: Theme.of(context).textTheme.bodyMedium,
|
|
|
|
textAlign: TextAlign.center,
|
|
|
|
),
|
2022-10-21 12:05:05 +02:00
|
|
|
),
|
2024-02-07 14:57:31 +01:00
|
|
|
],
|
|
|
|
),
|
|
|
|
);
|
2022-10-21 12:05:05 +02:00
|
|
|
|
|
|
|
factory IconicaAlertDialog.icon({
|
|
|
|
required String title,
|
|
|
|
required Widget icon,
|
|
|
|
required String body,
|
|
|
|
required List<AlertDialogAction> buttons,
|
|
|
|
bool? closeButton,
|
|
|
|
ButtonCallback? primaryButton,
|
|
|
|
ButtonCallback? secondaryButton,
|
|
|
|
IconButtonCallback? iconButton,
|
2024-02-07 14:57:31 +01:00
|
|
|
}) =>
|
|
|
|
IconicaAlertDialog._(
|
|
|
|
primaryButton: primaryButton,
|
|
|
|
secondaryButton: secondaryButton,
|
|
|
|
iconButton: iconButton,
|
|
|
|
closeButton: closeButton,
|
|
|
|
buttons: buttons,
|
|
|
|
body: (context) => Column(
|
|
|
|
children: [
|
|
|
|
icon,
|
|
|
|
Padding(
|
|
|
|
padding: const EdgeInsets.symmetric(horizontal: 20),
|
|
|
|
child: Text(
|
|
|
|
title,
|
|
|
|
style: Theme.of(context).textTheme.titleLarge?.copyWith(
|
|
|
|
fontWeight: FontWeight.bold,
|
|
|
|
),
|
|
|
|
textAlign: TextAlign.center,
|
|
|
|
),
|
2022-10-21 12:05:05 +02:00
|
|
|
),
|
2024-02-07 14:57:31 +01:00
|
|
|
Padding(
|
|
|
|
padding: const EdgeInsets.only(top: 20, left: 20, right: 20),
|
|
|
|
child: Text(
|
|
|
|
body,
|
|
|
|
style: Theme.of(context).textTheme.bodyMedium,
|
|
|
|
textAlign: TextAlign.center,
|
|
|
|
),
|
2022-10-21 12:05:05 +02:00
|
|
|
),
|
2024-02-07 14:57:31 +01:00
|
|
|
],
|
|
|
|
),
|
|
|
|
);
|
2022-10-21 12:05:05 +02:00
|
|
|
|
|
|
|
factory IconicaAlertDialog.yesOrNo({
|
|
|
|
required String title,
|
|
|
|
required String body,
|
|
|
|
required VoidCallback onYes,
|
|
|
|
required VoidCallback onNo,
|
|
|
|
bool focusYes = true,
|
|
|
|
bool otherSecondary = false,
|
|
|
|
bool? closeButton,
|
|
|
|
ButtonCallback? primaryButton,
|
|
|
|
ButtonCallback? secondaryButton,
|
|
|
|
IconButtonCallback? iconButton,
|
2024-02-07 14:57:31 +01:00
|
|
|
}) =>
|
|
|
|
IconicaAlertDialog.multiButton(
|
|
|
|
primaryButton: primaryButton,
|
|
|
|
secondaryButton: secondaryButton,
|
|
|
|
iconButton: iconButton,
|
|
|
|
closeButton: closeButton,
|
|
|
|
title: title,
|
|
|
|
body: body,
|
|
|
|
buttons: _getYesNoDialogButtons(focusYes, otherSecondary, onYes, onNo),
|
|
|
|
);
|
2022-10-21 12:05:05 +02:00
|
|
|
|
|
|
|
factory IconicaAlertDialog.yesOrNoIcon({
|
|
|
|
required String title,
|
|
|
|
required String body,
|
|
|
|
required Widget icon,
|
|
|
|
required VoidCallback onYes,
|
|
|
|
required VoidCallback onNo,
|
|
|
|
bool focusYes = true,
|
|
|
|
bool otherSecondary = false,
|
|
|
|
bool? closeButton,
|
|
|
|
ButtonCallback? primaryButton,
|
|
|
|
ButtonCallback? secondaryButton,
|
|
|
|
IconButtonCallback? iconButton,
|
2024-02-07 14:57:31 +01:00
|
|
|
}) =>
|
|
|
|
IconicaAlertDialog.icon(
|
|
|
|
primaryButton: primaryButton,
|
|
|
|
secondaryButton: secondaryButton,
|
|
|
|
iconButton: iconButton,
|
|
|
|
closeButton: closeButton,
|
|
|
|
title: title,
|
|
|
|
body: body,
|
|
|
|
icon: icon,
|
|
|
|
buttons: _getYesNoDialogButtons(focusYes, otherSecondary, onYes, onNo),
|
|
|
|
);
|
2022-10-21 12:05:05 +02:00
|
|
|
|
|
|
|
factory IconicaAlertDialog.singleButtonIcon({
|
|
|
|
required String title,
|
|
|
|
required String body,
|
|
|
|
required Widget icon,
|
|
|
|
required String buttonText,
|
|
|
|
required VoidCallback onPressed,
|
|
|
|
bool primary = false,
|
|
|
|
bool secondary = false,
|
|
|
|
bool? closeButton,
|
|
|
|
ButtonCallback? primaryButton,
|
|
|
|
ButtonCallback? secondaryButton,
|
|
|
|
IconButtonCallback? iconButton,
|
2024-02-07 14:57:31 +01:00
|
|
|
}) =>
|
|
|
|
IconicaAlertDialog.icon(
|
|
|
|
primaryButton: primaryButton,
|
|
|
|
secondaryButton: secondaryButton,
|
|
|
|
iconButton: iconButton,
|
|
|
|
closeButton: closeButton,
|
|
|
|
title: title,
|
|
|
|
icon: icon,
|
|
|
|
body: body,
|
|
|
|
buttons: [
|
|
|
|
AlertDialogAction(
|
|
|
|
text: buttonText,
|
|
|
|
primary: primary,
|
|
|
|
secondary: secondary,
|
|
|
|
onPressed: onPressed,
|
|
|
|
),
|
|
|
|
],
|
|
|
|
);
|
2022-10-21 12:05:05 +02:00
|
|
|
|
|
|
|
factory IconicaAlertDialog.custom({
|
|
|
|
required Widget body,
|
|
|
|
required List<AlertDialogAction> buttons,
|
|
|
|
bool? closeButton,
|
|
|
|
ButtonCallback? primaryButton,
|
|
|
|
ButtonCallback? secondaryButton,
|
|
|
|
IconButtonCallback? iconButton,
|
2024-02-07 14:57:31 +01:00
|
|
|
}) =>
|
|
|
|
IconicaAlertDialog._(
|
|
|
|
closeButton: closeButton,
|
|
|
|
buttons: buttons,
|
|
|
|
body: (_) => body,
|
|
|
|
primaryButton: primaryButton,
|
|
|
|
secondaryButton: secondaryButton,
|
|
|
|
iconButton: iconButton,
|
|
|
|
);
|
|
|
|
final List<AlertDialogAction> buttons;
|
|
|
|
final WidgetBuilder body;
|
|
|
|
final bool? closeButton;
|
|
|
|
final ButtonCallback? primaryButton;
|
|
|
|
final ButtonCallback? secondaryButton;
|
|
|
|
final IconButtonCallback? iconButton;
|
2022-10-21 12:05:05 +02:00
|
|
|
|
|
|
|
static List<AlertDialogAction> _getYesNoDialogButtons(
|
|
|
|
bool focusYes,
|
|
|
|
bool otherSecondary,
|
|
|
|
VoidCallback onYes,
|
|
|
|
VoidCallback onNo, {
|
|
|
|
String no = 'No',
|
|
|
|
String yes = 'Yes',
|
2024-02-07 14:57:31 +01:00
|
|
|
}) =>
|
|
|
|
<AlertDialogAction>[
|
|
|
|
if (focusYes) ...[
|
|
|
|
AlertDialogAction(
|
|
|
|
text: no,
|
|
|
|
primary: !focusYes,
|
|
|
|
secondary: !focusYes && otherSecondary,
|
|
|
|
onPressed: onNo,
|
|
|
|
),
|
|
|
|
],
|
2022-10-21 12:05:05 +02:00
|
|
|
AlertDialogAction(
|
2024-02-07 14:57:31 +01:00
|
|
|
text: yes,
|
|
|
|
primary: focusYes,
|
2022-10-21 12:05:05 +02:00
|
|
|
secondary: !focusYes && otherSecondary,
|
2024-02-07 14:57:31 +01:00
|
|
|
onPressed: onYes,
|
2022-10-21 12:05:05 +02:00
|
|
|
),
|
2024-02-07 14:57:31 +01:00
|
|
|
if (!focusYes) ...[
|
|
|
|
AlertDialogAction(
|
|
|
|
text: no,
|
|
|
|
primary: !focusYes,
|
|
|
|
secondary: focusYes && otherSecondary,
|
|
|
|
onPressed: onNo,
|
|
|
|
),
|
|
|
|
],
|
|
|
|
];
|
2022-10-21 12:05:05 +02:00
|
|
|
|
|
|
|
@override
|
2024-02-07 14:57:31 +01:00
|
|
|
Widget build(BuildContext context) => Column(
|
|
|
|
children: [
|
|
|
|
const Spacer(),
|
|
|
|
AlertDialog(
|
|
|
|
insetPadding: EdgeInsets.zero,
|
|
|
|
contentPadding: EdgeInsets.zero,
|
|
|
|
backgroundColor: Theme.of(context).cardColor,
|
|
|
|
shape: const RoundedRectangleBorder(
|
|
|
|
borderRadius: BorderRadius.only(
|
|
|
|
topLeft: Radius.circular(10),
|
|
|
|
topRight: Radius.circular(10),
|
|
|
|
),
|
2022-10-21 12:05:05 +02:00
|
|
|
),
|
2024-02-07 14:57:31 +01:00
|
|
|
content: SizedBox(
|
2022-10-21 12:05:05 +02:00
|
|
|
width: MediaQuery.of(context).size.width,
|
|
|
|
child: Stack(
|
|
|
|
children: [
|
|
|
|
Padding(
|
|
|
|
padding: const EdgeInsets.only(top: 10),
|
|
|
|
child: Align(
|
|
|
|
alignment: Alignment.center,
|
|
|
|
child: Column(
|
|
|
|
children: [
|
|
|
|
body.call(context),
|
|
|
|
Padding(
|
|
|
|
padding: EdgeInsets.only(
|
2024-02-07 14:57:31 +01:00
|
|
|
top: buttons.isNotEmpty ? 40 : 0,
|
|
|
|
bottom: 20,
|
|
|
|
left: 20,
|
|
|
|
right: 20,
|
|
|
|
),
|
2022-10-21 12:05:05 +02:00
|
|
|
child: Row(
|
|
|
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
|
|
|
children: buttons.map(
|
|
|
|
(e) {
|
|
|
|
if (e.primary) {
|
|
|
|
return primaryButton?.call(
|
|
|
|
e.onPressed,
|
|
|
|
Text(e.text),
|
|
|
|
context,
|
|
|
|
) ??
|
|
|
|
ElevatedButton(
|
|
|
|
onPressed: e.onPressed,
|
|
|
|
child: Text(e.text),
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
return secondaryButton?.call(
|
|
|
|
e.onPressed,
|
|
|
|
Text(e.text),
|
|
|
|
context,
|
|
|
|
) ??
|
|
|
|
TextButton(
|
|
|
|
onPressed: e.onPressed,
|
|
|
|
child: Text(e.text),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
).toList(),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
if (closeButton ?? false) ...[
|
|
|
|
Padding(
|
|
|
|
padding: const EdgeInsets.all(5),
|
|
|
|
child: Align(
|
|
|
|
alignment: Alignment.topRight,
|
|
|
|
child: iconButton?.call(context, () {
|
|
|
|
Navigator.pop(context);
|
|
|
|
}) ??
|
|
|
|
IconButton(
|
|
|
|
onPressed: () => Navigator.pop(context),
|
|
|
|
icon: const Icon(
|
|
|
|
Icons.close,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
],
|
2024-02-07 14:57:31 +01:00
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
);
|
2022-10-21 12:05:05 +02:00
|
|
|
}
|