Files
dragon_ledger/lib/Pages/Dialog/dynamic_dialog.dart

233 lines
7.1 KiB
Dart

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<DialogInputField>? inputFields,
final List<DialogAction>? 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<DialogInputField> inputFields;
/// Die Aktionen des Dialogs
final List<DialogAction> actions;
/// Der Typ des Dialogs
final DialogTypeEnum dialogType;
/// Versteckte Werte, die beim Abschicken mit zurückgegeben werden
final Map<String, dynamic>? hiddenValues;
final Map<String, dynamic> _values;
BuildContext? _dialogContext;
/// Zeigt den vorher zusammengebauten Dialog an
Future<void> 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: 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<DialogInputFieldSelectItem>(
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);
},
);
}
}
}