import 'package:flutter/material.dart'; import '../../Entities/dialog_type_enum.dart'; import '../../Services/navigation_service.dart'; import '../../Services/theme_service.dart'; import 'dialog_action.dart'; import 'dialog_input_field.dart'; /// Erstellt einen neuen dynamischen Dialog class DynamicDialog { /// Erstellt eine neue Instanz dieser Klasse DynamicDialog({ this.title, this.icon, this.content, final List? inputFields, final List? actions, this.backgroundColor, this.borderRadius = 16, this.barrierDismissible = true, this.dialogType = DialogTypeEnum.info, this.hiddenValues }) : inputFields = inputFields ?? const [], actions = actions ?? [DialogAction(label: 'Schließen')]; /// Der Titel des Dialogs final String? title; /// Der Icon des Dialogs final IconData? icon; /// Der Inhalt des Dialogs final Widget? content; /// Die Hintergrundfarbe des Dialogs, Standard wenn nicht gesetzt final Color? backgroundColor; /// Der BorderRadius des Dialogs final double borderRadius; /// Ob der Dialog bei einem Klick auf die Barriere geschlossen werden kann final bool barrierDismissible; /// Die InputFelder des Dialogs final List inputFields; /// Die Aktionen des Dialogs final List actions; /// Der Typ des Dialogs final DialogTypeEnum dialogType; /// Versteckte Werte, die beim Abschicken mit zurückgegeben werden final Map? hiddenValues; Map? _controllers; Map? _focusNodes; BuildContext? _dialogContext; void _prepareControllers() { _controllers = { for (final field in inputFields) field.id: TextEditingController(text: field.initialValue ?? ''), }; } void _prepareFocusNodes() { _focusNodes = {for (final field in inputFields) field.id: FocusNode()}; } void _disposeControllers() { for (final TextEditingController controller in _controllers!.values) { controller.dispose(); } _controllers = null; } void _disposeFocusNodes() { for (final FocusNode node in _focusNodes!.values) { node.dispose(); } _focusNodes = null; } /// Zeigt den vorher zusammengebauten Dialog an Future show() async { final BuildContext? context = NavigationService.getCurrentBuildContext(); if (context != null) { final ThemeData theme = Theme.of(context); _prepareControllers(); _prepareFocusNodes(); await showDialog( context: context, barrierDismissible: barrierDismissible, builder: (final BuildContext ctx) { _dialogContext = ctx; WidgetsBinding.instance.addPostFrameCallback((_) { final DialogInputField? autoFocusField = inputFields .where((final DialogInputField f) => f.autoFocus) .cast() .firstWhere( (final DialogInputField? f) => f != null, orElse: () => null, ); if (autoFocusField != null) { _focusNodes![autoFocusField.id]!.requestFocus(); } }); final DialogAction primaryAction = actions.firstWhere( (final a) => a.isPrimary, orElse: () => actions.first, ); Color backgroundColor = this.backgroundColor ?? theme.colorScheme.surface; if (dialogType == DialogTypeEnum.error) { backgroundColor = theme.colorScheme.errorContainer; } else if (dialogType == DialogTypeEnum.success) { backgroundColor = ThemeService.getSuccessColor( brightness: theme.brightness, ); } return AlertDialog( backgroundColor: backgroundColor, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(borderRadius), ), title: Column( mainAxisSize: MainAxisSize.min, children: [ if (icon != null) Icon(icon, size: 48, color: theme.colorScheme.primary), if (title != null) Padding( padding: const EdgeInsets.only(top: 8), child: Text( title!, style: theme.textTheme.titleLarge, textAlign: TextAlign.center, ), ), ], ), content: Column( mainAxisSize: MainAxisSize.min, children: [ if (content != null) content!, ...inputFields.map( (final DialogInputField field) => Padding( padding: const EdgeInsets.symmetric(vertical: 6), child: TextField( controller: _controllers![field.id], focusNode: _focusNodes![field.id], keyboardType: field.keyboardType, obscureText: field.obscureText, onChanged: field.onChanged, decoration: InputDecoration( labelText: field.label, border: const OutlineInputBorder(), isDense: true, ), onSubmitted: (_) { final Map values = { for (final entry in _controllers!.entries) entry.key: entry.value.text, }; hiddenValues?.forEach((final key, final value) { values[key] = value; }); close(); primaryAction.onPressed?.call(values); }, ), ), ), ], ), actions: actions .map( (final action) => TextButton( onPressed: () { final Map values = { for (final entry in _controllers!.entries) entry.key: entry.value.text, }; hiddenValues?.forEach((final key, final value) { values[key] = value; }); close(); action.onPressed?.call(values); }, child: Text(action.label), ), ) .toList(), ); }, ); } } /// Schließt den dynamischen Dialog void close() { if (_dialogContext != null) { Navigator.of(_dialogContext!).pop(); } _disposeControllers(); _disposeFocusNodes(); } }