Files
submanager/lib/widgets/payment_card/payment_card_selector.dart
2025-11-14 16:53:41 +09:00

143 lines
4.3 KiB
Dart

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../../l10n/app_localizations.dart';
import '../../models/payment_card_model.dart';
import '../../providers/payment_card_provider.dart';
import '../../utils/payment_card_utils.dart';
class PaymentCardSelector extends StatelessWidget {
final String? selectedCardId;
final ValueChanged<String?> onChanged;
final Future<void> Function()? onAddCard;
final VoidCallback? onManageCards;
const PaymentCardSelector({
super.key,
required this.selectedCardId,
required this.onChanged,
this.onAddCard,
this.onManageCards,
});
@override
Widget build(BuildContext context) {
return Consumer<PaymentCardProvider>(
builder: (context, provider, child) {
final loc = AppLocalizations.of(context);
final cards = provider.cards;
final unassignedSelected = selectedCardId == null;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Wrap(
spacing: 8,
runSpacing: 8,
children: [
Semantics(
label: loc.paymentCardUnassigned,
selected: unassignedSelected,
button: true,
child: ChoiceChip(
label: Text(loc.paymentCardUnassigned),
selected: unassignedSelected,
onSelected: (_) => onChanged(null),
avatar: const Icon(Icons.credit_card_off_rounded, size: 18),
),
),
...cards.map((card) => _PaymentCardChip(
card: card,
isSelected: selectedCardId == card.id,
onSelected: () => onChanged(card.id),
)),
],
),
const SizedBox(height: 8),
Row(
children: [
TextButton.icon(
onPressed: cards.isEmpty && onAddCard == null
? null
: () async {
if (onAddCard != null) {
await onAddCard!();
}
},
icon: const Icon(Icons.add),
label: Text(loc.addNewCard),
),
const SizedBox(width: 8),
TextButton(
onPressed: onManageCards,
child: Text(loc.managePaymentCards),
),
],
),
if (cards.isEmpty)
Padding(
padding: const EdgeInsets.only(top: 8),
child: Text(
loc.noPaymentCards,
style: TextStyle(
color: Theme.of(context).colorScheme.onSurfaceVariant,
fontSize: 13,
),
),
),
],
);
},
);
}
}
class _PaymentCardChip extends StatelessWidget {
final PaymentCardModel card;
final bool isSelected;
final VoidCallback onSelected;
const _PaymentCardChip({
required this.card,
required this.isSelected,
required this.onSelected,
});
@override
Widget build(BuildContext context) {
final color = PaymentCardUtils.colorFromHex(card.colorHex);
final icon = PaymentCardUtils.iconForName(card.iconName);
final cs = Theme.of(context).colorScheme;
final labelText = '${card.issuerName} · ****${card.last4}';
return Semantics(
label: labelText,
selected: isSelected,
button: true,
child: ChoiceChip(
avatar: CircleAvatar(
backgroundColor:
isSelected ? cs.onPrimary : color.withValues(alpha: 0.15),
child: Icon(
icon,
color: isSelected ? color : cs.onSurface,
size: 16,
),
),
label: Text(labelText),
selected: isSelected,
onSelected: (_) => onSelected(),
selectedColor: color,
labelStyle: TextStyle(
color: isSelected ? cs.onPrimary : cs.onSurface,
fontWeight: FontWeight.w600,
),
backgroundColor: cs.surface,
side: BorderSide(
color: isSelected
? Colors.transparent
: cs.outline.withValues(alpha: 0.5),
),
),
);
}
}