showNiceModal<T> function

Future<T?> showNiceModal<T>({
  1. required BuildContext context,
  2. required String title,
  3. required Widget body,
  4. List<Widget>? actions,
  5. bool dismissible = true,
  6. double maxWidth = 520,
  7. IconData? icon,
})

Generic modal dialog with header, body, and footer actions.

Implementation

Future<T?> showNiceModal<T>({
  required BuildContext context,
  required String title,
  required Widget body,
  List<Widget>? actions,
  bool dismissible = true,
  double maxWidth = 520,
  IconData? icon,
}) {
  final theme = NiceTheme.of(context);

  return showDialog<T>(
    context: context,
    barrierDismissible: dismissible,
    builder: (ctx) => Dialog(
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.circular(theme.borderRadius * 2),
      ),
      child: ConstrainedBox(
        constraints: BoxConstraints(maxWidth: maxWidth),
        child: Column(
          mainAxisSize: MainAxisSize.min,
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            // Header
            Container(
              padding: EdgeInsets.all(theme.spacing * 2),
              decoration: BoxDecoration(
                border: Border(
                  bottom: BorderSide(color: theme.colors.border, width: 0.5),
                ),
              ),
              child: Row(
                children: [
                  if (icon != null) ...[
                    Icon(icon, color: theme.colors.primary, size: 22),
                    const SizedBox(width: 8),
                  ],
                  Expanded(
                    child: Text(title, style: theme.typography.label),
                  ),
                  if (dismissible)
                    IconButton(
                      onPressed: () => Navigator.of(ctx).pop(),
                      icon: const Icon(Icons.close, size: 20),
                      padding: EdgeInsets.zero,
                      constraints: const BoxConstraints(),
                    ),
                ],
              ),
            ),
            // Body
            Flexible(
              child: SingleChildScrollView(
                padding: EdgeInsets.all(theme.spacing * 2),
                child: body,
              ),
            ),
            // Footer
            if (actions != null && actions.isNotEmpty)
              Container(
                padding: EdgeInsets.all(theme.spacing * 1.5),
                decoration: BoxDecoration(
                  border: Border(
                    top: BorderSide(color: theme.colors.border, width: 0.5),
                  ),
                ),
                child: Row(
                  mainAxisAlignment: MainAxisAlignment.end,
                  children: [
                    for (int i = 0; i < actions.length; i++) ...[
                      if (i > 0) const SizedBox(width: 8),
                      actions[i],
                    ],
                  ],
                ),
              ),
          ],
        ),
      ),
    ),
  );
}