redesigned payment page + a lot of fixes
This commit is contained in:
@@ -2,15 +2,14 @@ import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import 'package:pshared/models/payment/methods/data.dart';
|
||||
import 'package:pshared/models/payment/type.dart';
|
||||
|
||||
import 'package:pweb/controllers/organization/address_book_recipient_form.dart';
|
||||
import 'package:pweb/controllers/organization/address_book_recipient_form_selection.dart';
|
||||
import 'package:pweb/pages/address_book/form/view.dart';
|
||||
import 'package:pweb/providers/address_book_recipient_form.dart';
|
||||
import 'package:pweb/utils/payment/availability.dart';
|
||||
|
||||
|
||||
class AddressBookRecipientFormBody extends StatefulWidget {
|
||||
class AddressBookRecipientFormBody extends StatelessWidget {
|
||||
final GlobalKey<FormState> formKey;
|
||||
final TextEditingController nameCtrl;
|
||||
final TextEditingController emailCtrl;
|
||||
@@ -27,94 +26,43 @@ class AddressBookRecipientFormBody extends StatefulWidget {
|
||||
required this.onBack,
|
||||
});
|
||||
|
||||
@override
|
||||
State<AddressBookRecipientFormBody> createState() => _AddressBookRecipientFormBodyState();
|
||||
}
|
||||
|
||||
class _AddressBookRecipientFormBodyState extends State<AddressBookRecipientFormBody> {
|
||||
PaymentType? _selectedType;
|
||||
int? _selectedIndex;
|
||||
|
||||
void _reconcileSelection(AddressBookRecipientFormProvider formState) {
|
||||
final types = formState.supportedTypes;
|
||||
if (types.isEmpty) return;
|
||||
|
||||
var nextType = _selectedType;
|
||||
var nextIndex = _selectedIndex;
|
||||
|
||||
if (nextType == null || !types.contains(nextType)) {
|
||||
nextType = formState.preferredType ?? types.first;
|
||||
nextIndex = null;
|
||||
}
|
||||
|
||||
final entries = formState.methods[nextType] ?? const [];
|
||||
if (entries.isEmpty) {
|
||||
nextIndex = null;
|
||||
} else if (nextIndex == null || nextIndex < 0 || nextIndex >= entries.length) {
|
||||
nextIndex = 0;
|
||||
}
|
||||
|
||||
if (nextType == _selectedType && nextIndex == _selectedIndex) return;
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (!mounted) return;
|
||||
setState(() {
|
||||
_selectedType = nextType;
|
||||
_selectedIndex = nextIndex;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void _onMethodSelected(PaymentType type, int index) {
|
||||
setState(() {
|
||||
_selectedType = type;
|
||||
_selectedIndex = index;
|
||||
});
|
||||
}
|
||||
|
||||
void _onMethodAdd(AddressBookRecipientFormProvider formState, PaymentType type) {
|
||||
final newIndex = formState.addMethod(type);
|
||||
setState(() {
|
||||
_selectedType = type;
|
||||
_selectedIndex = newIndex;
|
||||
});
|
||||
}
|
||||
|
||||
void _onMethodRemove(AddressBookRecipientFormProvider formState, int index) {
|
||||
final type = _selectedType ?? formState.supportedTypes.first;
|
||||
formState.removeMethod(type, index);
|
||||
}
|
||||
|
||||
void _onMethodChanged(
|
||||
AddressBookRecipientFormProvider formState,
|
||||
int index,
|
||||
PaymentMethodData data,
|
||||
) {
|
||||
final type = _selectedType ?? formState.supportedTypes.first;
|
||||
formState.updateMethod(type, index, data);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final formState = context.watch<AddressBookRecipientFormProvider>();
|
||||
_reconcileSelection(formState);
|
||||
final formState = Provider.of<AddressBookRecipientFormProvider>(context, listen: false);
|
||||
final controller = Provider.of<AddressBookRecipientFormController>(context);
|
||||
final selection =
|
||||
Provider.of<AddressBookRecipientFormSelectionController>(context);
|
||||
|
||||
final selectedType = _selectedType ?? formState.supportedTypes.first;
|
||||
if (controller.supportedTypes.isEmpty) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
|
||||
final selectedType = selection.selectedType ?? controller.supportedTypes.first;
|
||||
return FormView(
|
||||
formKey: widget.formKey,
|
||||
nameCtrl: widget.nameCtrl,
|
||||
emailCtrl: widget.emailCtrl,
|
||||
types: formState.supportedTypes,
|
||||
formKey: formKey,
|
||||
nameCtrl: nameCtrl,
|
||||
emailCtrl: emailCtrl,
|
||||
types: controller.supportedTypes,
|
||||
selectedType: selectedType,
|
||||
selectedIndex: _selectedIndex,
|
||||
methods: formState.methods,
|
||||
onMethodSelected: _onMethodSelected,
|
||||
onMethodAdd: (type) => _onMethodAdd(formState, type),
|
||||
selectedIndex: selection.selectedIndex,
|
||||
methods: controller.methods,
|
||||
onMethodSelected: selection.select,
|
||||
onMethodAdd: (type) {
|
||||
final newIndex = controller.addMethod(type);
|
||||
selection.selectAfterAdd(type, newIndex);
|
||||
},
|
||||
disabledTypes: disabledPaymentTypes,
|
||||
onMethodRemove: (index) => _onMethodRemove(formState, index),
|
||||
onMethodChanged: (index, data) => _onMethodChanged(formState, index, data),
|
||||
onSave: () => widget.onSave(formState),
|
||||
isEditing: widget.isEditing,
|
||||
onBack: widget.onBack,
|
||||
onMethodRemove: (index) {
|
||||
final type = selection.selectedType ?? controller.supportedTypes.first;
|
||||
controller.removeMethod(type, index);
|
||||
},
|
||||
onMethodChanged: (index, data) {
|
||||
final type = selection.selectedType ?? controller.supportedTypes.first;
|
||||
controller.updateMethod(type, index, data);
|
||||
},
|
||||
onSave: () => onSave(formState),
|
||||
isEditing: isEditing,
|
||||
onBack: onBack,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,12 +7,11 @@ import 'package:pshared/models/recipient/recipient.dart';
|
||||
import 'package:pshared/provider/recipient/methods_cache.dart';
|
||||
import 'package:pshared/provider/recipient/provider.dart';
|
||||
|
||||
import 'package:pweb/controllers/organization/address_book_recipient_form.dart';
|
||||
import 'package:pweb/controllers/organization/address_book_recipient_form_selection.dart';
|
||||
import 'package:pweb/pages/address_book/form/body.dart';
|
||||
import 'package:pweb/providers/address_book_recipient_form.dart';
|
||||
import 'package:pweb/utils/payment/availability.dart';
|
||||
import 'package:pweb/utils/payment/label.dart';
|
||||
|
||||
import 'package:pweb/generated/i18n/app_localizations.dart';
|
||||
|
||||
|
||||
class AddressBookRecipientForm extends StatefulWidget {
|
||||
@@ -29,6 +28,8 @@ class _AddressBookRecipientFormState extends State<AddressBookRecipientForm> {
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
late TextEditingController _nameCtrl;
|
||||
late TextEditingController _emailCtrl;
|
||||
late final String _initialName;
|
||||
late final String _initialEmail;
|
||||
|
||||
static const List<PaymentType> _supportedTypes = visiblePaymentTypes;
|
||||
|
||||
@@ -36,61 +37,79 @@ class _AddressBookRecipientFormState extends State<AddressBookRecipientForm> {
|
||||
void initState() {
|
||||
super.initState();
|
||||
final r = widget.recipient;
|
||||
_nameCtrl = TextEditingController(text: r?.name ?? '');
|
||||
_emailCtrl = TextEditingController(text: r?.email ?? '');
|
||||
}
|
||||
|
||||
Map<PaymentType, String> _methodNames(BuildContext context) => {
|
||||
for (final type in _supportedTypes) type: getPaymentTypeLabel(context, type),
|
||||
};
|
||||
|
||||
Future<void> _save(AddressBookRecipientFormProvider formState) async {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
if (!_formKey.currentState!.validate() || !formState.hasAnyMethod) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text(l10n.recipientFormRule)),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
final saved = await formState.save(
|
||||
name: _nameCtrl.text,
|
||||
email: _emailCtrl.text,
|
||||
methodNames: _methodNames(context),
|
||||
);
|
||||
widget.onSaved?.call(saved);
|
||||
} catch (_) {
|
||||
if (!mounted) return;
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text(l10n.notificationError(l10n.noErrorInformation))),
|
||||
);
|
||||
}
|
||||
_initialName = r?.name ?? '';
|
||||
_initialEmail = r?.email ?? '';
|
||||
_nameCtrl = TextEditingController(text: _initialName);
|
||||
_emailCtrl = TextEditingController(text: _initialEmail);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ChangeNotifierProxyProvider2<
|
||||
RecipientsProvider,
|
||||
RecipientMethodsCacheProvider,
|
||||
AddressBookRecipientFormProvider
|
||||
>(
|
||||
create: (_) => AddressBookRecipientFormProvider(
|
||||
recipient: widget.recipient,
|
||||
supportedTypes: _supportedTypes,
|
||||
),
|
||||
update: (_, recipientsProvider, methodsCache, formProvider) =>
|
||||
formProvider!..updateProviders(
|
||||
recipientsProvider: recipientsProvider,
|
||||
methodsCache: methodsCache,
|
||||
return MultiProvider(
|
||||
providers: [
|
||||
ChangeNotifierProxyProvider2<
|
||||
RecipientsProvider,
|
||||
RecipientMethodsCacheProvider,
|
||||
AddressBookRecipientFormProvider
|
||||
>(
|
||||
create: (_) => AddressBookRecipientFormProvider(
|
||||
recipient: widget.recipient,
|
||||
),
|
||||
child: AddressBookRecipientFormBody(
|
||||
formKey: _formKey,
|
||||
nameCtrl: _nameCtrl,
|
||||
emailCtrl: _emailCtrl,
|
||||
isEditing: widget.recipient != null,
|
||||
onSave: _save,
|
||||
onBack: () => widget.onSaved?.call(null),
|
||||
update: (_, recipientsProvider, methodsCache, formProvider) =>
|
||||
formProvider!..updateProviders(
|
||||
recipientsProvider: recipientsProvider,
|
||||
methodsCache: methodsCache,
|
||||
),
|
||||
),
|
||||
ChangeNotifierProxyProvider<
|
||||
RecipientMethodsCacheProvider,
|
||||
AddressBookRecipientFormController
|
||||
>(
|
||||
create: (_) => AddressBookRecipientFormController(
|
||||
supportedTypes: _supportedTypes,
|
||||
),
|
||||
update: (_, methodsCache, controller) => controller!
|
||||
..update(
|
||||
recipient: widget.recipient,
|
||||
methodsCache: methodsCache,
|
||||
),
|
||||
),
|
||||
ChangeNotifierProxyProvider<
|
||||
AddressBookRecipientFormController,
|
||||
AddressBookRecipientFormSelectionController
|
||||
>(
|
||||
create: (_) => AddressBookRecipientFormSelectionController(),
|
||||
update: (_, formController, selectionController) =>
|
||||
selectionController!..update(formController),
|
||||
),
|
||||
],
|
||||
child: Builder(
|
||||
builder: (context) {
|
||||
final formState = context.read<AddressBookRecipientFormProvider>();
|
||||
final controller = context.read<AddressBookRecipientFormController>();
|
||||
return AddressBookRecipientFormBody(
|
||||
formKey: _formKey,
|
||||
nameCtrl: _nameCtrl,
|
||||
emailCtrl: _emailCtrl,
|
||||
isEditing: widget.recipient != null,
|
||||
onSave: (form) => controller.saveForm(
|
||||
context: context,
|
||||
formKey: _formKey,
|
||||
formState: form,
|
||||
name: _nameCtrl.text,
|
||||
email: _emailCtrl.text,
|
||||
onSaved: widget.onSaved,
|
||||
),
|
||||
onBack: () => controller.handleBack(
|
||||
context: context,
|
||||
formKey: _formKey,
|
||||
formState: formState,
|
||||
name: _nameCtrl.text,
|
||||
email: _emailCtrl.text,
|
||||
onSaved: widget.onSaved,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -12,7 +12,8 @@ import 'package:pweb/generated/i18n/app_localizations.dart';
|
||||
class AddPaymentMethodButton extends StatelessWidget {
|
||||
final List<PaymentType> types;
|
||||
final Set<PaymentType> disabledTypes;
|
||||
final ValueChanged<PaymentType> onAdd;
|
||||
final ValueChanged<PaymentType>? onAdd;
|
||||
final VoidCallback? onPressed;
|
||||
|
||||
static const double _borderRadius = 14;
|
||||
static const double _iconSize = 18;
|
||||
@@ -20,13 +21,18 @@ class AddPaymentMethodButton extends StatelessWidget {
|
||||
static const double _menuIconSize = 18;
|
||||
static const double _menuIconTextSpacing = 8;
|
||||
static const double _buttonHeight = 70;
|
||||
static const EdgeInsets _buttonPadding = EdgeInsets.symmetric(horizontal: 14, vertical: 10);
|
||||
static const EdgeInsets _buttonPadding = EdgeInsets.symmetric(
|
||||
horizontal: 14,
|
||||
vertical: 10,
|
||||
);
|
||||
static const FontWeight _labelWeight = FontWeight.w600;
|
||||
|
||||
const AddPaymentMethodButton({
|
||||
super.key,
|
||||
required this.types,
|
||||
required this.disabledTypes,
|
||||
required this.onAdd,
|
||||
this.onAdd,
|
||||
this.onPressed,
|
||||
});
|
||||
|
||||
@override
|
||||
@@ -41,6 +47,38 @@ class AddPaymentMethodButton extends StatelessWidget {
|
||||
? theme.colorScheme.primary
|
||||
: theme.colorScheme.onSurface.withValues(alpha: 0.4);
|
||||
|
||||
final buttonChild = Container(
|
||||
height: _buttonHeight,
|
||||
padding: _buttonPadding,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(_borderRadius),
|
||||
border: Border.all(color: borderColor),
|
||||
color: theme.colorScheme.onSecondary,
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(Icons.add, size: _iconSize, color: textColor),
|
||||
const SizedBox(width: _iconTextSpacing),
|
||||
Text(
|
||||
l10n.addPaymentMethod,
|
||||
style: theme.textTheme.titleSmall?.copyWith(
|
||||
color: textColor,
|
||||
fontWeight: _labelWeight,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
final onPressed = this.onPressed;
|
||||
if (onPressed != null) {
|
||||
return GestureDetector(
|
||||
onTap: hasEnabled ? onPressed : null,
|
||||
child: buttonChild,
|
||||
);
|
||||
}
|
||||
|
||||
return PopupMenuButton<PaymentType>(
|
||||
enabled: hasEnabled,
|
||||
onSelected: onAdd,
|
||||
@@ -67,29 +105,7 @@ class AddPaymentMethodButton extends StatelessWidget {
|
||||
);
|
||||
})
|
||||
.toList(),
|
||||
child: Container(
|
||||
height: _buttonHeight,
|
||||
padding: _buttonPadding,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(_borderRadius),
|
||||
border: Border.all(color: borderColor),
|
||||
color: theme.colorScheme.onSecondary,
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(Icons.add, size: _iconSize, color: textColor),
|
||||
const SizedBox(width: _iconTextSpacing),
|
||||
Text(
|
||||
l10n.addPaymentMethod,
|
||||
style: theme.textTheme.titleSmall?.copyWith(
|
||||
color: textColor,
|
||||
fontWeight: _labelWeight,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
child: buttonChild,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,8 @@ import 'package:pshared/models/recipient/payment_method_draft.dart';
|
||||
import 'package:pweb/pages/payment_methods/form.dart';
|
||||
import 'package:pweb/pages/payment_methods/icon.dart';
|
||||
import 'package:pweb/widgets/dialogs/confirmation_dialog.dart';
|
||||
import 'package:pweb/models/state/control_state.dart';
|
||||
import 'package:pweb/models/state/visibility.dart';
|
||||
|
||||
import 'package:pweb/generated/i18n/app_localizations.dart';
|
||||
|
||||
@@ -17,6 +19,8 @@ class PaymentMethodPanel extends StatelessWidget {
|
||||
final List<RecipientMethodDraft> entries;
|
||||
final ValueChanged<int> onRemove;
|
||||
final void Function(int, PaymentMethodData) onChanged;
|
||||
final ControlState editState;
|
||||
final VisibilityState deleteVisibility;
|
||||
|
||||
final double padding;
|
||||
|
||||
@@ -27,6 +31,8 @@ class PaymentMethodPanel extends StatelessWidget {
|
||||
required this.entries,
|
||||
required this.onRemove,
|
||||
required this.onChanged,
|
||||
this.editState = ControlState.enabled,
|
||||
this.deleteVisibility = VisibilityState.visible,
|
||||
this.padding = 16,
|
||||
});
|
||||
|
||||
@@ -79,7 +85,7 @@ class PaymentMethodPanel extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
),
|
||||
if (entry != null)
|
||||
if (entry != null && deleteVisibility == VisibilityState.visible)
|
||||
TextButton.icon(
|
||||
onPressed: () => _confirmDelete(context, () => onRemove(selectedIndex)),
|
||||
icon: Icon(Icons.delete, color: theme.colorScheme.error),
|
||||
@@ -96,6 +102,7 @@ class PaymentMethodPanel extends StatelessWidget {
|
||||
key: ValueKey('${selectedType.name}-${entry.existing?.id ?? selectedIndex}-form'),
|
||||
selectedType: selectedType,
|
||||
initialData: entry.data,
|
||||
isEditable: editState == ControlState.enabled,
|
||||
onChanged: (data) {
|
||||
if (data == null) return;
|
||||
onChanged(selectedIndex, data);
|
||||
|
||||
@@ -3,8 +3,8 @@ import 'package:flutter/material.dart';
|
||||
import 'package:pshared/models/payment/type.dart';
|
||||
import 'package:pshared/models/recipient/payment_method_draft.dart';
|
||||
|
||||
import 'package:pweb/models/payment_method_tile/availability.dart';
|
||||
import 'package:pweb/models/payment_method_tile/selection.dart';
|
||||
import 'package:pweb/models/payment/method_tile/availability.dart';
|
||||
import 'package:pweb/models/payment/method_tile/selection.dart';
|
||||
import 'package:pweb/pages/address_book/form/widgets/payment_methods/add_button.dart';
|
||||
import 'package:pweb/pages/address_book/form/widgets/payment_methods/tile.dart';
|
||||
|
||||
@@ -15,8 +15,10 @@ class PaymentMethodSelectorRow extends StatelessWidget {
|
||||
final int? selectedIndex;
|
||||
final Map<PaymentType, List<RecipientMethodDraft>> methods;
|
||||
final void Function(PaymentType type, int index) onSelected;
|
||||
final ValueChanged<PaymentType> onAdd;
|
||||
final ValueChanged<PaymentType>? onAdd;
|
||||
final VoidCallback? onAddPressed;
|
||||
final Set<PaymentType> disabledTypes;
|
||||
final String? Function(RecipientMethodDraft entry)? detailsBuilder;
|
||||
|
||||
final double spacing;
|
||||
final double tilePadding;
|
||||
@@ -29,8 +31,10 @@ class PaymentMethodSelectorRow extends StatelessWidget {
|
||||
required this.selectedIndex,
|
||||
required this.methods,
|
||||
required this.onSelected,
|
||||
required this.onAdd,
|
||||
this.onAdd,
|
||||
this.onAddPressed,
|
||||
this.disabledTypes = const {},
|
||||
this.detailsBuilder,
|
||||
this.spacing = 12,
|
||||
this.tilePadding = 10,
|
||||
this.runSpacing = 12,
|
||||
@@ -51,12 +55,14 @@ class PaymentMethodSelectorRow extends StatelessWidget {
|
||||
final availability = isAdded
|
||||
? PaymentMethodTileAvailability.added
|
||||
: PaymentMethodTileAvailability.available;
|
||||
final detailsText = detailsBuilder?.call(entry);
|
||||
tiles.add(
|
||||
PaymentMethodTile(
|
||||
type: type,
|
||||
selection: selection,
|
||||
availability: availability,
|
||||
padding: tilePadding,
|
||||
detailsText: detailsText,
|
||||
onTap: () => onSelected(type, index),
|
||||
),
|
||||
);
|
||||
@@ -68,6 +74,7 @@ class PaymentMethodSelectorRow extends StatelessWidget {
|
||||
types: types,
|
||||
disabledTypes: disabledTypes,
|
||||
onAdd: onAdd,
|
||||
onPressed: onAddPressed,
|
||||
),
|
||||
);
|
||||
|
||||
@@ -78,4 +85,4 @@ class PaymentMethodSelectorRow extends StatelessWidget {
|
||||
children: tiles,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@ import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:pshared/models/payment/type.dart';
|
||||
|
||||
import 'package:pweb/models/payment_method_tile/availability.dart';
|
||||
import 'package:pweb/models/payment_method_tile/selection.dart';
|
||||
import 'package:pweb/models/payment/method_tile/availability.dart';
|
||||
import 'package:pweb/models/payment/method_tile/selection.dart';
|
||||
import 'package:pweb/pages/payment_methods/icon.dart';
|
||||
import 'package:pweb/utils/payment/label.dart';
|
||||
|
||||
@@ -15,6 +15,7 @@ class PaymentMethodTile extends StatelessWidget {
|
||||
final PaymentMethodTileSelection selection;
|
||||
final PaymentMethodTileAvailability availability;
|
||||
final double padding;
|
||||
final String? detailsText;
|
||||
final VoidCallback? onTap;
|
||||
|
||||
const PaymentMethodTile({
|
||||
@@ -22,6 +23,7 @@ class PaymentMethodTile extends StatelessWidget {
|
||||
required this.selection,
|
||||
required this.availability,
|
||||
required this.padding,
|
||||
this.detailsText,
|
||||
required this.onTap,
|
||||
});
|
||||
|
||||
@@ -50,6 +52,13 @@ class PaymentMethodTile extends StatelessWidget {
|
||||
final backgroundColor = isSelected
|
||||
? theme.colorScheme.primary.withValues(alpha: 0.08)
|
||||
: theme.colorScheme.onSecondary;
|
||||
final showDetails =
|
||||
availability == PaymentMethodTileAvailability.added &&
|
||||
detailsText != null &&
|
||||
detailsText!.isNotEmpty;
|
||||
final detailsColor = isSelected
|
||||
? theme.colorScheme.primary
|
||||
: theme.colorScheme.onSurfaceVariant;
|
||||
|
||||
return IntrinsicWidth(
|
||||
child: Opacity(
|
||||
@@ -68,9 +77,9 @@ class PaymentMethodTile extends StatelessWidget {
|
||||
border: Border.all(color: borderColor),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Icon(
|
||||
iconForPaymentType(type),
|
||||
@@ -78,30 +87,44 @@ class PaymentMethodTile extends StatelessWidget {
|
||||
color: isSelected ? theme.colorScheme.primary : theme.colorScheme.onSurface,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
label,
|
||||
style: theme.textTheme.titleSmall?.copyWith(
|
||||
fontWeight: FontWeight.w600,
|
||||
color: isSelected ? theme.colorScheme.primary : theme.colorScheme.onSurface,
|
||||
),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
label,
|
||||
style: theme.textTheme.titleSmall?.copyWith(
|
||||
fontWeight: FontWeight.w600,
|
||||
color: isSelected ? theme.colorScheme.primary : theme.colorScheme.onSurface,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
if (showDetails)
|
||||
Text(
|
||||
detailsText!,
|
||||
style: theme.textTheme.labelSmall?.copyWith(
|
||||
color: detailsColor,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
)
|
||||
else
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
|
||||
decoration: BoxDecoration(
|
||||
color: badgeColor,
|
||||
borderRadius: BorderRadius.circular(999),
|
||||
),
|
||||
child: Text(
|
||||
badgeLabel,
|
||||
style: theme.textTheme.labelSmall?.copyWith(
|
||||
color: badgeTextColor,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
|
||||
decoration: BoxDecoration(
|
||||
color: badgeColor,
|
||||
borderRadius: BorderRadius.circular(999),
|
||||
),
|
||||
child: Text(
|
||||
badgeLabel,
|
||||
style: theme.textTheme.labelSmall?.copyWith(
|
||||
color: badgeTextColor,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
@@ -34,6 +34,8 @@ class RecipientAddressBookInfoRow extends StatelessWidget {
|
||||
final style = textStyle ?? Theme.of(context).textTheme.bodySmall!;
|
||||
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Icon(iconForPaymentType(type), size: iconSize),
|
||||
@@ -55,4 +57,4 @@ class RecipientAddressBookInfoRow extends StatelessWidget {
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,6 +59,7 @@ class _RecipientAddressBookItemState extends State<RecipientAddressBookItem> {
|
||||
child: Padding(
|
||||
padding: widget.padding,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
|
||||
@@ -29,12 +29,22 @@ class RecipientPaymentRow extends StatelessWidget {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
|
||||
return Row(
|
||||
spacing: spacing,
|
||||
children: cacheProvider.methodsForRecipient(recipientId).map((m) => RecipientAddressBookInfoRow(
|
||||
type: m.type,
|
||||
value: getPaymentTypeDescription(context, m),
|
||||
)).toList(),
|
||||
return Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Wrap(
|
||||
alignment: WrapAlignment.start,
|
||||
runAlignment: WrapAlignment.start,
|
||||
crossAxisAlignment: WrapCrossAlignment.start,
|
||||
spacing: spacing,
|
||||
runSpacing: spacing,
|
||||
children: cacheProvider
|
||||
.methodsForRecipient(recipientId)
|
||||
.map((m) => RecipientAddressBookInfoRow(
|
||||
type: m.type,
|
||||
value: getPaymentTypeDescription(context, m),
|
||||
))
|
||||
.toList(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user