import 'package:dropdown_search/dropdown_search.dart'; import 'package:flutter/material.dart'; import '../../Services/navigation_service.dart'; import '../../Services/theme_service.dart'; import '../Misc/InputFields/dynamic_date_time_field.dart'; import 'dialog_action.dart'; import 'dialog_input_field.dart'; import 'dialog_input_field_select_item.dart'; import 'dialog_input_field_type_enum.dart'; import 'dialog_type_enum.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')], _values = hiddenValues ?? {}; /// 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; final Map _values; BuildContext? _dialogContext; /// Zeigt den vorher zusammengebauten Dialog an Future show() async { final BuildContext? context = NavigationService.getCurrentBuildContext(); if (context != null) { final ThemeData theme = Theme.of(context); await showDialog( context: context, barrierDismissible: barrierDismissible, builder: (final BuildContext ctx) { _dialogContext = ctx; 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: ConstrainedBox( constraints: BoxConstraints( maxHeight: MediaQuery.of(ctx).size.height * 0.7, ), child: SingleChildScrollView( child: Column( mainAxisSize: MainAxisSize.min, children: [ if (content != null) content!, ...inputFields.map( (final DialogInputField field) => Padding( padding: const EdgeInsets.symmetric(vertical: 6), child: _getInputField(field, primaryAction), ), ), ], ), ), ), actions: actions .map( (final action) => TextButton( onPressed: () { close(); action.onPressed?.call(_values); }, child: Text(action.label), ), ) .toList(), ); }, ); } } /// Schließt den dynamischen Dialog void close() { if (_dialogContext != null) { Navigator.of(_dialogContext!).pop(); } } Widget _getInputField( final DialogInputField inputField, final DialogAction primaryAction, ) { _values[inputField.id] = inputField.initialValue; if (inputField.inputType == DialogInputFieldTypeEnum.date) { return DynamicDateTimeField( initialValue: inputField.initialValue, autofocus: inputField.autoFocus, onChanged: (final value) { inputField.onChanged?.call(value); _values[inputField.id] = value; }, decoration: InputDecoration( labelText: inputField.label, border: const OutlineInputBorder(), isDense: true, ), ); } else if (inputField.inputType == DialogInputFieldTypeEnum.select) { DialogInputFieldSelectItem? initialValue; if (inputField.initialValue is Enum) { final Enum inputFieldInitialValue = inputField.initialValue; for (final DialogInputFieldSelectItem value in inputField.selectItems) { if (value.id == inputFieldInitialValue.index) { initialValue = value; } } } _values[inputField.id] = initialValue; return DropdownSearch( items: (final f, final cs) => inputField.selectItems, itemAsString: (final DialogInputFieldSelectItem value) => value.value, selectedItem: initialValue, onChanged: (final DialogInputFieldSelectItem? value) { inputField.onChanged?.call(value); _values[inputField.id] = value; }, decoratorProps: DropDownDecoratorProps( decoration: InputDecoration( labelText: inputField.label, border: const OutlineInputBorder(), isDense: true, ), ), compareFn: ( final DialogInputFieldSelectItem v1, final DialogInputFieldSelectItem v2, ) => v1.id == v2.id, ); } else { return TextField( controller: TextEditingController( text: inputField.initialValue is String ? inputField.initialValue : '', ), autofocus: inputField.autoFocus, keyboardType: inputField.keyboardType, obscureText: inputField.obscureText, onChanged: (final value) { inputField.onChanged?.call(value); _values[inputField.id] = value; }, decoration: InputDecoration( labelText: inputField.label, border: const OutlineInputBorder(), isDense: true, ), onSubmitted: (_) { close(); primaryAction.onPressed?.call(_values); }, ); } } }