gcx/frontend/genex-mobile/lib/shared/widgets/confirm_sheet.dart

188 lines
5.4 KiB
Dart

import 'package:flutter/material.dart';
import '../../app/theme/app_colors.dart';
import '../../app/theme/app_typography.dart';
import '../../app/theme/app_spacing.dart';
import 'genex_button.dart';
/// 底部确认Sheet组件
///
/// 支付确认、转赠确认等操作确认
/// 使用场景:购买、转赠、出售、提现等需要确认的操作
class ConfirmSheet extends StatelessWidget {
final String title;
final List<ConfirmSheetItem> items;
final String confirmText;
final String? cancelText;
final VoidCallback onConfirm;
final VoidCallback? onCancel;
final Widget? header;
final String? warning;
const ConfirmSheet({
super.key,
required this.title,
required this.items,
required this.confirmText,
this.cancelText,
required this.onConfirm,
this.onCancel,
this.header,
this.warning,
});
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.fromLTRB(20, 0, 20, 24),
decoration: const BoxDecoration(
color: AppColors.surface,
borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Drag Handle
Center(
child: Container(
margin: const EdgeInsets.only(top: 8, bottom: 16),
width: 36,
height: 4,
decoration: BoxDecoration(
color: AppColors.gray300,
borderRadius: AppSpacing.borderRadiusFull,
),
),
),
// Title
Text(title, style: AppTypography.h2),
const SizedBox(height: 20),
// Optional Header (e.g., coupon card preview)
if (header != null) ...[
header!,
const SizedBox(height: 16),
],
// Detail Items
Container(
padding: AppSpacing.cardPadding,
decoration: BoxDecoration(
color: AppColors.gray50,
borderRadius: AppSpacing.borderRadiusMd,
),
child: Column(
children: items.asMap().entries.map((entry) {
final isLast = entry.key == items.length - 1;
final item = entry.value;
return Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(item.label, style: AppTypography.bodyMedium.copyWith(
color: AppColors.textSecondary,
)),
Text(
item.value,
style: item.isHighlight
? AppTypography.labelMedium.copyWith(color: AppColors.primary)
: AppTypography.labelMedium,
),
],
),
if (!isLast) ...[
const SizedBox(height: 12),
const Divider(),
const SizedBox(height: 12),
],
],
);
}).toList(),
),
),
// Warning
if (warning != null) ...[
const SizedBox(height: 12),
Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: AppColors.warningLight,
borderRadius: AppSpacing.borderRadiusSm,
),
child: Row(
children: [
const Icon(Icons.info_outline_rounded, size: 16, color: AppColors.warning),
const SizedBox(width: 8),
Expanded(
child: Text(
warning!,
style: AppTypography.bodySmall.copyWith(color: AppColors.gray700),
),
),
],
),
),
],
const SizedBox(height: 24),
// Buttons
GenexButton(
label: confirmText,
onPressed: onConfirm,
),
if (cancelText != null) ...[
const SizedBox(height: 8),
GenexButton(
label: cancelText!,
variant: GenexButtonVariant.text,
onPressed: onCancel ?? () => Navigator.of(context).pop(),
),
],
],
),
);
}
static Future<bool?> show(
BuildContext context, {
required String title,
required List<ConfirmSheetItem> items,
required String confirmText,
String? cancelText,
Widget? header,
String? warning,
}) {
return showModalBottomSheet<bool>(
context: context,
isScrollControlled: true,
backgroundColor: Colors.transparent,
builder: (ctx) => ConfirmSheet(
title: title,
items: items,
confirmText: confirmText,
cancelText: cancelText,
header: header,
warning: warning,
onConfirm: () => Navigator.of(ctx).pop(true),
onCancel: () => Navigator.of(ctx).pop(false),
),
);
}
}
class ConfirmSheetItem {
final String label;
final String value;
final bool isHighlight;
const ConfirmSheetItem({
required this.label,
required this.value,
this.isHighlight = false,
});
}