refactor: dialog boxes

This commit is contained in:
cogwheel0
2025-09-07 23:48:47 +05:30
parent bbb1f081d1
commit adbe3eb85f
13 changed files with 210 additions and 181 deletions

View File

@@ -115,54 +115,7 @@ class UiUtils {
);
}
/// Shows a Conduit-styled confirmation dialog
static Future<bool> showConfirmationDialog(
BuildContext context, {
required String title,
required String message,
String confirmText = 'Confirm',
String cancelText = 'Cancel',
bool isDestructive = false,
}) async {
return await showDialog<bool>(
context: context,
builder: (context) => AlertDialog(
backgroundColor: context.conduitTheme.surfaceBackground,
title: Text(
title,
style: TextStyle(color: context.conduitTheme.textPrimary),
),
content: Text(
message,
style: TextStyle(color: context.conduitTheme.textSecondary),
),
actions: [
TextButton(
onPressed: () => Navigator.pop(context, false),
child: Text(
cancelText.isNotEmpty
? cancelText
: AppLocalizations.of(context)!.cancel,
),
),
TextButton(
onPressed: () => Navigator.pop(context, true),
style: isDestructive
? TextButton.styleFrom(
foregroundColor: context.conduitTheme.error,
)
: null,
child: Text(
confirmText.isNotEmpty
? confirmText
: AppLocalizations.of(context)!.confirm,
),
),
],
),
) ??
false;
}
// Confirmation dialog moved to shared ThemedDialogs.confirm for cohesion
/// Formats dates in a conversational way following Conduit patterns
static String formatDate(DateTime date) {

View File

@@ -96,4 +96,108 @@ class ThemedDialogs {
),
);
}
/// Cohesive text input dialog used for rename/create flows
static Future<String?> promptTextInput(
BuildContext context, {
required String title,
required String hintText,
String? initialValue,
String confirmText = 'Save',
String cancelText = 'Cancel',
bool barrierDismissible = true,
TextInputType? keyboardType,
TextCapitalization textCapitalization = TextCapitalization.sentences,
int? maxLength,
}) async {
final theme = context.conduitTheme;
final controller = TextEditingController(text: initialValue ?? '');
String? result = await showDialog<String>(
context: context,
barrierDismissible: barrierDismissible,
builder: (ctx) {
return buildBase(
context: ctx,
title: title,
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
TextField(
controller: controller,
autofocus: true,
keyboardType: keyboardType,
textCapitalization: textCapitalization,
maxLength: maxLength,
style: TextStyle(color: theme.inputText),
decoration: InputDecoration(
hintText: hintText,
hintStyle: TextStyle(color: theme.inputPlaceholder),
filled: true,
fillColor: theme.inputBackground,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(AppBorderRadius.md),
borderSide: BorderSide.none,
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(AppBorderRadius.md),
borderSide: BorderSide(color: theme.inputBorder, width: 1),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(AppBorderRadius.md),
borderSide:
BorderSide(color: theme.buttonPrimary, width: 1),
),
contentPadding: const EdgeInsets.symmetric(
horizontal: Spacing.md,
vertical: Spacing.md,
),
),
onSubmitted: (v) {
final trimmed = v.trim();
final unchanged = (initialValue != null &&
trimmed == initialValue.trim());
if (trimmed.isEmpty || unchanged) return;
Navigator.of(ctx).pop(trimmed);
},
),
],
),
actions: [
TextButton(
onPressed: () => Navigator.of(ctx).pop(),
child: Text(
cancelText,
style: TextStyle(color: theme.textSecondary),
),
),
ValueListenableBuilder<TextEditingValue>(
valueListenable: controller,
builder: (context, value, _) {
final trimmed = value.text.trim();
final unchanged =
(initialValue != null && trimmed == initialValue.trim());
final enabled = trimmed.isNotEmpty && !unchanged;
return TextButton(
onPressed: enabled
? () => Navigator.of(ctx).pop(trimmed)
: null,
child: Text(
confirmText,
style: TextStyle(
color: enabled
? theme.buttonPrimary
: theme.textSecondary,
),
),
);
},
),
],
);
},
);
return result;
}
}