redesigned payment page + a lot of fixes
This commit is contained in:
@@ -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,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user