From 15702a108dac210ed4548a3a64abca71c95297da Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 19 Apr 2026 15:18:27 +0200 Subject: [PATCH 1/6] Add: custom dialog action --- .../widgets/dialog/custom_dialog_action.dart | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 lib/presentation/widgets/dialog/custom_dialog_action.dart diff --git a/lib/presentation/widgets/dialog/custom_dialog_action.dart b/lib/presentation/widgets/dialog/custom_dialog_action.dart new file mode 100644 index 0000000..dbf47f4 --- /dev/null +++ b/lib/presentation/widgets/dialog/custom_dialog_action.dart @@ -0,0 +1,29 @@ +import 'package:flutter/cupertino.dart'; +import 'package:tallee/core/enums.dart'; +import 'package:tallee/presentation/widgets/dialog/animated_dialog_button.dart'; + +class CustomDialogAction extends StatelessWidget { + const CustomDialogAction({ + super.key, + required this.onPressed, + required this.text, + this.buttonType = ButtonType.primary, + }); + + // The text displaed on the button + final String text; + + // The type of the button, which determines its styling + final ButtonType buttonType; + + final VoidCallback onPressed; + + @override + Widget build(BuildContext context) { + return AnimatedDialogButton( + onPressed: onPressed, + text: text, + buttonType: buttonType, + ); + } +} -- 2.49.1 From 55437d83c4fc6004859deed45cdf3f3867a5ff66 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 19 Apr 2026 15:19:30 +0200 Subject: [PATCH 2/6] Changed popup class structure --- .../buttons/animated_dialog_button.dart | 50 ----------- .../dialog/animated_dialog_button.dart | 84 +++++++++++++++++++ .../{ => dialog}/custom_alert_dialog.dart | 18 ++-- 3 files changed, 95 insertions(+), 57 deletions(-) delete mode 100644 lib/presentation/widgets/buttons/animated_dialog_button.dart create mode 100644 lib/presentation/widgets/dialog/animated_dialog_button.dart rename lib/presentation/widgets/{ => dialog}/custom_alert_dialog.dart (74%) diff --git a/lib/presentation/widgets/buttons/animated_dialog_button.dart b/lib/presentation/widgets/buttons/animated_dialog_button.dart deleted file mode 100644 index 798edfa..0000000 --- a/lib/presentation/widgets/buttons/animated_dialog_button.dart +++ /dev/null @@ -1,50 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:tallee/core/custom_theme.dart'; - -class AnimatedDialogButton extends StatefulWidget { - /// A custom animated button widget that provides a scaling and opacity effect - /// when pressed. - /// - [onPressed]: Callback function that is triggered when the button is pressed. - /// - [child]: The child widget to be displayed inside the button, typically a text or icon. - const AnimatedDialogButton({ - super.key, - required this.onPressed, - required this.child, - }); - - /// Callback function that is triggered when the button is pressed. - final VoidCallback onPressed; - - /// The child widget to be displayed inside the button, typically a text or icon. - final Widget child; - - @override - State createState() => _AnimatedDialogButtonState(); -} - -class _AnimatedDialogButtonState extends State { - bool _isPressed = false; - - @override - Widget build(BuildContext context) { - return GestureDetector( - onTapDown: (_) => setState(() => _isPressed = true), - onTapUp: (_) => setState(() => _isPressed = false), - onTapCancel: () => setState(() => _isPressed = false), - onTap: widget.onPressed, - child: AnimatedScale( - scale: _isPressed ? 0.95 : 1.0, - duration: const Duration(milliseconds: 100), - child: AnimatedOpacity( - opacity: _isPressed ? 0.6 : 1.0, - duration: const Duration(milliseconds: 100), - child: Container( - decoration: CustomTheme.standardBoxDecoration, - padding: const EdgeInsets.symmetric(horizontal: 26, vertical: 6), - child: widget.child, - ), - ), - ), - ); - } -} diff --git a/lib/presentation/widgets/dialog/animated_dialog_button.dart b/lib/presentation/widgets/dialog/animated_dialog_button.dart new file mode 100644 index 0000000..3875995 --- /dev/null +++ b/lib/presentation/widgets/dialog/animated_dialog_button.dart @@ -0,0 +1,84 @@ +import 'package:flutter/material.dart'; +import 'package:tallee/core/enums.dart'; + +class AnimatedDialogButton extends StatefulWidget { + /// A custom animated button widget that provides a scaling and opacity effect + /// when pressed. + /// - [onPressed]: Callback function that is triggered when the button is pressed. + /// - [child]: The child widget to be displayed inside the button, typically a text or icon. + const AnimatedDialogButton({ + super.key, + required this.onPressed, + required this.text, + this.buttonType = ButtonType.primary, + }); + + /// Callback function that is triggered when the button is pressed. + final VoidCallback onPressed; + + /// The text to be displayed on the button. + final String text; + + final ButtonType buttonType; + + @override + State createState() => _AnimatedDialogButtonState(); +} + +class _AnimatedDialogButtonState extends State { + bool _isPressed = false; + + @override + Widget build(BuildContext context) { + final textStyling = TextStyle( + color: widget.buttonType == ButtonType.primary + ? Colors.black + : Colors.white, + fontSize: 16, + fontWeight: FontWeight.bold, + ); + + final buttonDecoration = widget.buttonType == ButtonType.primary + // Primary + ? BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(12), + ) + : widget.buttonType == ButtonType.secondary + // Secondary + ? BoxDecoration( + border: BoxBorder.all(color: Colors.white, width: 2), + borderRadius: BorderRadius.circular(12), + ) + // Tertiary + : const BoxDecoration(); + + return GestureDetector( + onTapDown: (_) => setState(() => _isPressed = true), + onTapUp: (_) => setState(() => _isPressed = false), + onTapCancel: () => setState(() => _isPressed = false), + onTap: widget.onPressed, + child: AnimatedScale( + scale: _isPressed ? 0.95 : 1.0, + duration: const Duration(milliseconds: 100), + child: AnimatedOpacity( + opacity: _isPressed ? 0.6 : 1.0, + duration: const Duration(milliseconds: 100), + child: Center( + child: Container( + constraints: const BoxConstraints(minWidth: 300), + decoration: buttonDecoration, + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), + margin: const EdgeInsets.symmetric(vertical: 8), + child: Text( + widget.text, + style: textStyling, + textAlign: TextAlign.center, + ), + ), + ), + ), + ), + ); + } +} diff --git a/lib/presentation/widgets/custom_alert_dialog.dart b/lib/presentation/widgets/dialog/custom_alert_dialog.dart similarity index 74% rename from lib/presentation/widgets/custom_alert_dialog.dart rename to lib/presentation/widgets/dialog/custom_alert_dialog.dart index bf98f2c..606fc49 100644 --- a/lib/presentation/widgets/custom_alert_dialog.dart +++ b/lib/presentation/widgets/dialog/custom_alert_dialog.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:tallee/core/custom_theme.dart'; +import 'package:tallee/presentation/widgets/dialog/custom_dialog_action.dart'; class CustomAlertDialog extends StatelessWidget { /// A custom alert dialog widget that provides a os unspecific AlertDialog, @@ -16,20 +17,23 @@ class CustomAlertDialog extends StatelessWidget { }); final String title; - final String content; - final List actions; + final Widget content; + final List actions; @override Widget build(BuildContext context) { return AlertDialog( - title: Text(title, style: const TextStyle(color: CustomTheme.textColor)), - content: Text( - content, - style: const TextStyle(color: CustomTheme.textColor), + title: Text( + title, + style: const TextStyle( + fontWeight: FontWeight.bold, + color: CustomTheme.textColor, + ), ), + content: content, actions: actions, backgroundColor: CustomTheme.boxColor, - actionsAlignment: MainAxisAlignment.spaceAround, + actionsAlignment: MainAxisAlignment.center, shape: RoundedRectangleBorder( borderRadius: CustomTheme.standardBorderRadiusAll, side: const BorderSide(color: CustomTheme.boxBorderColor), -- 2.49.1 From 32e1c587d46952ea9101d7d8900d6cadcbfb6b32 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 19 Apr 2026 15:19:38 +0200 Subject: [PATCH 3/6] Updated popups in views --- .../group_view/group_detail_view.dart | 28 +++++++----------- .../match_view/match_detail_view.dart | 28 +++++++----------- .../settings_view/settings_view.dart | 29 +++++++------------ 3 files changed, 32 insertions(+), 53 deletions(-) diff --git a/lib/presentation/views/main_menu/group_view/group_detail_view.dart b/lib/presentation/views/main_menu/group_view/group_detail_view.dart index 1ef89ef..ab70d1a 100644 --- a/lib/presentation/views/main_menu/group_view/group_detail_view.dart +++ b/lib/presentation/views/main_menu/group_view/group_detail_view.dart @@ -3,6 +3,7 @@ import 'package:intl/intl.dart'; import 'package:provider/provider.dart'; import 'package:tallee/core/adaptive_page_route.dart'; import 'package:tallee/core/custom_theme.dart'; +import 'package:tallee/core/enums.dart'; import 'package:tallee/data/db/database.dart'; import 'package:tallee/data/models/group.dart'; import 'package:tallee/data/models/match.dart'; @@ -10,10 +11,10 @@ import 'package:tallee/data/models/player.dart'; import 'package:tallee/l10n/generated/app_localizations.dart'; import 'package:tallee/presentation/views/main_menu/group_view/create_group_view.dart'; import 'package:tallee/presentation/widgets/app_skeleton.dart'; -import 'package:tallee/presentation/widgets/buttons/animated_dialog_button.dart'; import 'package:tallee/presentation/widgets/buttons/main_menu_button.dart'; import 'package:tallee/presentation/widgets/colored_icon_container.dart'; -import 'package:tallee/presentation/widgets/custom_alert_dialog.dart'; +import 'package:tallee/presentation/widgets/dialog/custom_alert_dialog.dart'; +import 'package:tallee/presentation/widgets/dialog/custom_dialog_action.dart'; import 'package:tallee/presentation/widgets/tiles/info_tile.dart'; import 'package:tallee/presentation/widgets/tiles/text_icon_tile.dart'; @@ -70,23 +71,16 @@ class _GroupDetailViewState extends State { context: context, builder: (context) => CustomAlertDialog( title: '${loc.delete_group}?', - content: loc.this_cannot_be_undone, + content: Text(loc.this_cannot_be_undone), actions: [ - AnimatedDialogButton( - onPressed: () => Navigator.of(context).pop(false), - child: Text( - loc.cancel, - style: const TextStyle(color: CustomTheme.textColor), - ), - ), - AnimatedDialogButton( + CustomDialogAction( onPressed: () => Navigator.of(context).pop(true), - child: Text( - loc.delete, - style: const TextStyle( - color: CustomTheme.secondaryColor, - ), - ), + text: loc.delete, + ), + CustomDialogAction( + onPressed: () => Navigator.of(context).pop(false), + buttonType: ButtonType.secondary, + text: loc.cancel, ), ], ), diff --git a/lib/presentation/views/main_menu/match_view/match_detail_view.dart b/lib/presentation/views/main_menu/match_view/match_detail_view.dart index fc53aa8..2ca6925 100644 --- a/lib/presentation/views/main_menu/match_view/match_detail_view.dart +++ b/lib/presentation/views/main_menu/match_view/match_detail_view.dart @@ -4,15 +4,16 @@ import 'package:provider/provider.dart'; import 'package:tallee/core/adaptive_page_route.dart'; import 'package:tallee/core/common.dart'; import 'package:tallee/core/custom_theme.dart'; +import 'package:tallee/core/enums.dart'; import 'package:tallee/data/db/database.dart'; import 'package:tallee/data/models/match.dart'; import 'package:tallee/l10n/generated/app_localizations.dart'; import 'package:tallee/presentation/views/main_menu/match_view/create_match/create_match_view.dart'; import 'package:tallee/presentation/views/main_menu/match_view/match_result_view.dart'; -import 'package:tallee/presentation/widgets/buttons/animated_dialog_button.dart'; import 'package:tallee/presentation/widgets/buttons/main_menu_button.dart'; import 'package:tallee/presentation/widgets/colored_icon_container.dart'; -import 'package:tallee/presentation/widgets/custom_alert_dialog.dart'; +import 'package:tallee/presentation/widgets/dialog/custom_alert_dialog.dart'; +import 'package:tallee/presentation/widgets/dialog/custom_dialog_action.dart'; import 'package:tallee/presentation/widgets/tiles/info_tile.dart'; import 'package:tallee/presentation/widgets/tiles/text_icon_tile.dart'; @@ -64,23 +65,16 @@ class _MatchDetailViewState extends State { context: context, builder: (context) => CustomAlertDialog( title: '${loc.delete_match}?', - content: loc.this_cannot_be_undone, + content: Text(loc.this_cannot_be_undone), actions: [ - AnimatedDialogButton( - onPressed: () => Navigator.of(context).pop(false), - child: Text( - loc.cancel, - style: const TextStyle(color: CustomTheme.textColor), - ), - ), - AnimatedDialogButton( + CustomDialogAction( onPressed: () => Navigator.of(context).pop(true), - child: Text( - loc.delete, - style: const TextStyle( - color: CustomTheme.secondaryColor, - ), - ), + text: loc.delete, + ), + CustomDialogAction( + onPressed: () => Navigator.of(context).pop(false), + buttonType: ButtonType.secondary, + text: loc.cancel, ), ], ), diff --git a/lib/presentation/views/main_menu/settings_view/settings_view.dart b/lib/presentation/views/main_menu/settings_view/settings_view.dart index 6a558ad..8e1cbdc 100644 --- a/lib/presentation/views/main_menu/settings_view/settings_view.dart +++ b/lib/presentation/views/main_menu/settings_view/settings_view.dart @@ -9,8 +9,8 @@ import 'package:tallee/core/custom_theme.dart'; import 'package:tallee/core/enums.dart'; import 'package:tallee/l10n/generated/app_localizations.dart'; import 'package:tallee/presentation/views/main_menu/settings_view/licenses_view.dart'; -import 'package:tallee/presentation/widgets/buttons/animated_dialog_button.dart'; -import 'package:tallee/presentation/widgets/custom_alert_dialog.dart'; +import 'package:tallee/presentation/widgets/dialog/custom_alert_dialog.dart'; +import 'package:tallee/presentation/widgets/dialog/custom_dialog_action.dart'; import 'package:tallee/presentation/widgets/tiles/settings_list_tile.dart'; import 'package:tallee/services/data_transfer_service.dart'; import 'package:url_launcher/url_launcher.dart'; @@ -122,25 +122,16 @@ class _SettingsViewState extends State { context: context, builder: (context) => CustomAlertDialog( title: '${loc.delete_all_data}?', - content: loc.this_cannot_be_undone, + content: Text(loc.this_cannot_be_undone), actions: [ - AnimatedDialogButton( - onPressed: () => Navigator.of(context).pop(false), - child: Text( - loc.cancel, - style: const TextStyle( - color: CustomTheme.textColor, - ), - ), - ), - AnimatedDialogButton( + CustomDialogAction( onPressed: () => Navigator.of(context).pop(true), - child: Text( - loc.delete, - style: const TextStyle( - color: CustomTheme.secondaryColor, - ), - ), + text: loc.delete, + ), + CustomDialogAction( + onPressed: () => Navigator.of(context).pop(false), + buttonType: ButtonType.secondary, + text: loc.cancel, ), ], ), -- 2.49.1 From 2ad369806744105e23c3a93af20167abc0ea9f0d Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 19 Apr 2026 15:25:22 +0200 Subject: [PATCH 4/6] Updated documentation --- .../dialog/animated_dialog_button.dart | 20 ++++++++++--------- .../widgets/dialog/custom_dialog_action.dart | 9 ++++++--- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/lib/presentation/widgets/dialog/animated_dialog_button.dart b/lib/presentation/widgets/dialog/animated_dialog_button.dart index 3875995..624d20a 100644 --- a/lib/presentation/widgets/dialog/animated_dialog_button.dart +++ b/lib/presentation/widgets/dialog/animated_dialog_button.dart @@ -5,22 +5,24 @@ class AnimatedDialogButton extends StatefulWidget { /// A custom animated button widget that provides a scaling and opacity effect /// when pressed. /// - [onPressed]: Callback function that is triggered when the button is pressed. - /// - [child]: The child widget to be displayed inside the button, typically a text or icon. + /// - [buttonText]: The text to be displayed on the button. + /// - [buttonType]: The type of the button, which determines its styling. const AnimatedDialogButton({ super.key, required this.onPressed, - required this.text, + required this.buttonText, + this.constraints, this.buttonType = ButtonType.primary, }); - /// Callback function that is triggered when the button is pressed. - final VoidCallback onPressed; - - /// The text to be displayed on the button. - final String text; + final BoxConstraints? constraints; final ButtonType buttonType; + final String buttonText; + + final VoidCallback onPressed; + @override State createState() => _AnimatedDialogButtonState(); } @@ -66,12 +68,12 @@ class _AnimatedDialogButtonState extends State { duration: const Duration(milliseconds: 100), child: Center( child: Container( - constraints: const BoxConstraints(minWidth: 300), + constraints: widget.constraints, decoration: buttonDecoration, padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), margin: const EdgeInsets.symmetric(vertical: 8), child: Text( - widget.text, + widget.buttonText, style: textStyling, textAlign: TextAlign.center, ), diff --git a/lib/presentation/widgets/dialog/custom_dialog_action.dart b/lib/presentation/widgets/dialog/custom_dialog_action.dart index dbf47f4..2882c76 100644 --- a/lib/presentation/widgets/dialog/custom_dialog_action.dart +++ b/lib/presentation/widgets/dialog/custom_dialog_action.dart @@ -3,6 +3,10 @@ import 'package:tallee/core/enums.dart'; import 'package:tallee/presentation/widgets/dialog/animated_dialog_button.dart'; class CustomDialogAction extends StatelessWidget { + /// A custom dialog action widget that represents a button in a dialog. + /// - [text]: The text to be displayed on the button. + /// - [buttonType]: The type of the button, which determines its styling. + /// - [onPressed]: Callback function that is triggered when the button is pressed. const CustomDialogAction({ super.key, required this.onPressed, @@ -10,10 +14,8 @@ class CustomDialogAction extends StatelessWidget { this.buttonType = ButtonType.primary, }); - // The text displaed on the button final String text; - // The type of the button, which determines its styling final ButtonType buttonType; final VoidCallback onPressed; @@ -22,8 +24,9 @@ class CustomDialogAction extends StatelessWidget { Widget build(BuildContext context) { return AnimatedDialogButton( onPressed: onPressed, - text: text, + buttonText: text, buttonType: buttonType, + constraints: const BoxConstraints(minWidth: 300), ); } } -- 2.49.1 From ad2e4bc398b8e31e71a4e288a8912fb96ced963c Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 19 Apr 2026 15:56:11 +0200 Subject: [PATCH 5/6] Added constraint parameter --- .../widgets/dialog/animated_dialog_button.dart | 15 ++++++++------- .../widgets/dialog/custom_dialog_action.dart | 2 +- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/lib/presentation/widgets/dialog/animated_dialog_button.dart b/lib/presentation/widgets/dialog/animated_dialog_button.dart index 624d20a..70deea6 100644 --- a/lib/presentation/widgets/dialog/animated_dialog_button.dart +++ b/lib/presentation/widgets/dialog/animated_dialog_button.dart @@ -7,22 +7,23 @@ class AnimatedDialogButton extends StatefulWidget { /// - [onPressed]: Callback function that is triggered when the button is pressed. /// - [buttonText]: The text to be displayed on the button. /// - [buttonType]: The type of the button, which determines its styling. + /// - [buttonConstraints]: Optional constraints to control the button's size. const AnimatedDialogButton({ super.key, - required this.onPressed, required this.buttonText, - this.constraints, + required this.onPressed, + this.buttonConstraints, this.buttonType = ButtonType.primary, }); - final BoxConstraints? constraints; - - final ButtonType buttonType; - final String buttonText; final VoidCallback onPressed; + final BoxConstraints? buttonConstraints; + + final ButtonType buttonType; + @override State createState() => _AnimatedDialogButtonState(); } @@ -68,7 +69,7 @@ class _AnimatedDialogButtonState extends State { duration: const Duration(milliseconds: 100), child: Center( child: Container( - constraints: widget.constraints, + constraints: widget.buttonConstraints, decoration: buttonDecoration, padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), margin: const EdgeInsets.symmetric(vertical: 8), diff --git a/lib/presentation/widgets/dialog/custom_dialog_action.dart b/lib/presentation/widgets/dialog/custom_dialog_action.dart index 2882c76..9718a03 100644 --- a/lib/presentation/widgets/dialog/custom_dialog_action.dart +++ b/lib/presentation/widgets/dialog/custom_dialog_action.dart @@ -26,7 +26,7 @@ class CustomDialogAction extends StatelessWidget { onPressed: onPressed, buttonText: text, buttonType: buttonType, - constraints: const BoxConstraints(minWidth: 300), + buttonConstraints: const BoxConstraints(minWidth: 300), ); } } -- 2.49.1 From 9c4eff5056b0595b529f54c9dc3e5cf285f86080 Mon Sep 17 00:00:00 2001 From: Felix Kirchner Date: Sun, 19 Apr 2026 16:02:14 +0200 Subject: [PATCH 6/6] Moved button --- .../widgets/{dialog => buttons}/animated_dialog_button.dart | 0 lib/presentation/widgets/dialog/custom_dialog_action.dart | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename lib/presentation/widgets/{dialog => buttons}/animated_dialog_button.dart (100%) diff --git a/lib/presentation/widgets/dialog/animated_dialog_button.dart b/lib/presentation/widgets/buttons/animated_dialog_button.dart similarity index 100% rename from lib/presentation/widgets/dialog/animated_dialog_button.dart rename to lib/presentation/widgets/buttons/animated_dialog_button.dart diff --git a/lib/presentation/widgets/dialog/custom_dialog_action.dart b/lib/presentation/widgets/dialog/custom_dialog_action.dart index 9718a03..aec0dfa 100644 --- a/lib/presentation/widgets/dialog/custom_dialog_action.dart +++ b/lib/presentation/widgets/dialog/custom_dialog_action.dart @@ -1,6 +1,6 @@ import 'package:flutter/cupertino.dart'; import 'package:tallee/core/enums.dart'; -import 'package:tallee/presentation/widgets/dialog/animated_dialog_button.dart'; +import 'package:tallee/presentation/widgets/buttons/animated_dialog_button.dart'; class CustomDialogAction extends StatelessWidget { /// A custom dialog action widget that represents a button in a dialog. -- 2.49.1