redesigned payment page + a lot of fixes

This commit is contained in:
Arseni
2026-02-21 21:55:20 +03:00
parent a68aa2abff
commit 0c6fa03aba
208 changed files with 4062 additions and 2217 deletions

View File

@@ -0,0 +1,20 @@
import 'package:flutter/material.dart';
import 'package:pweb/generated/i18n/app_localizations.dart';
class PaymentConfigAdvanced extends StatelessWidget {
const PaymentConfigAdvanced({super.key});
@override
Widget build(BuildContext context) {
final l10n = AppLocalizations.of(context)!;
return ExpansionTile(
title: Text(l10n.advanced),
tilePadding: const EdgeInsets.symmetric(horizontal: 16),
childrenPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
children: [Text(l10n.fallbackExplanation)],
);
}
}

View File

@@ -0,0 +1,36 @@
import 'package:flutter/material.dart';
import 'package:pweb/generated/i18n/app_localizations.dart';
class PaymentConfigHeader extends StatelessWidget {
final VoidCallback onAdd;
const PaymentConfigHeader({super.key, required this.onAdd});
@override
Widget build(BuildContext context) {
final l10n = AppLocalizations.of(context)!;
final theme = Theme.of(context);
return Column(
children: [
Text(
l10n.paymentConfigTitle,
style: theme.textTheme.headlineSmall,
textAlign: TextAlign.center,
),
const SizedBox(height: 4),
Text(l10n.paymentConfigSubtitle, textAlign: TextAlign.center),
const SizedBox(height: 12),
SizedBox(
width: double.infinity,
child: OutlinedButton.icon(
icon: const Icon(Icons.add),
label: Text(l10n.addPaymentMethod),
onPressed: onAdd,
),
),
],
);
}
}

View File

@@ -0,0 +1,41 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:pshared/provider/recipient/pmethods.dart';
import 'package:pweb/pages/payment_methods/manage/method_tile.dart';
import 'package:pweb/controllers/payments/payment_config.dart';
class PaymentConfigList extends StatelessWidget {
final PaymentConfigController controller;
const PaymentConfigList({super.key, required this.controller});
@override
Widget build(BuildContext context) {
final provider = context.watch<PaymentMethodsProvider>();
return ReorderableListView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: provider.methods.length,
onReorder: controller.reorder,
itemBuilder: (context, index) {
final method = provider.methods[index];
return ReorderableDragStartListener(
key: Key(method.id),
index: index,
child: PaymentMethodTile(
method: method,
index: index,
makeMain: () => controller.makeMain(method),
toggleEnabled: (v) => controller.toggleEnabled(method, v),
edit: () => controller.editMethod(method),
delete: () => controller.deleteMethod(method),
),
);
},
);
}
}

View File

@@ -0,0 +1,101 @@
import 'package:flutter/material.dart';
import 'package:pshared/models/payment/methods/type.dart';
import 'package:pweb/pages/payment_methods/icon.dart';
import 'package:pweb/generated/i18n/app_localizations.dart';
class PaymentMethodTile extends StatelessWidget {
const PaymentMethodTile({
super.key,
required this.method,
required this.index,
required this.makeMain,
required this.toggleEnabled,
required this.edit,
required this.delete,
});
final PaymentMethod method;
final int index;
final VoidCallback makeMain;
final ValueChanged<bool> toggleEnabled;
final VoidCallback edit;
final VoidCallback delete;
@override
Widget build(BuildContext context) {
final l10n = AppLocalizations.of(context)!;
final theme = Theme.of(context);
return Opacity(
opacity: method.isArchived ? 1 : 0.5,
child: Card(
margin: const EdgeInsets.symmetric(vertical: 4),
elevation: 0,
child: ListTile(
key: ValueKey(method.id),
leading: Icon(iconForPaymentType(method.type)),
onTap: makeMain,
title: Row(
children: [
Expanded(child: Text(method.name)),
if (method.description != null)
Text(
method.description!,
style: theme.textTheme.bodySmall,
),
],
),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
_buildMakeMainButton(context),
_buildEnabledSwitch(),
_buildPopupMenu(l10n),
],
),
),
),
);
}
Widget _buildMakeMainButton(BuildContext context) {
final theme = Theme.of(context);
return IconButton(
tooltip: AppLocalizations.of(context)!.makeMain,
icon: Icon(
method.isMain ? Icons.star : Icons.star_outline,
color: method.isMain ? theme.colorScheme.primary : null,
),
onPressed: makeMain,
);
}
Widget _buildEnabledSwitch() => Switch.adaptive(
value: method.isArchived,
onChanged: toggleEnabled,
);
Widget _buildPopupMenu(AppLocalizations l10n) {
return PopupMenuButton<String>(
tooltip: l10n.moreActions,
onSelected: (value) {
switch (value) {
case 'edit':
edit();
break;
case 'delete':
delete();
break;
}
},
itemBuilder: (_) => [
PopupMenuItem(value: 'edit', child: Text(l10n.edit)),
PopupMenuItem(value: 'delete', child: Text(l10n.delete)),
],
);
}
}

View File

@@ -0,0 +1,49 @@
import 'package:flutter/material.dart';
import 'package:pweb/pages/payment_methods/manage/advanced.dart';
import 'package:pweb/controllers/payments/payment_config.dart';
import 'package:pweb/pages/payment_methods/manage/header.dart';
import 'package:pweb/pages/payment_methods/manage/list.dart';
class MethodsWidget extends StatefulWidget {
const MethodsWidget({super.key});
@override
State<MethodsWidget> createState() => _MethodsWidgetState();
}
class _MethodsWidgetState extends State<MethodsWidget> {
late final PaymentConfigController controller;
@override
void initState() {
super.initState();
controller = PaymentConfigController(context);
}
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
return Card(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
elevation: theme.cardTheme.elevation ?? 4,
color: theme.colorScheme.onSecondary,
child: SafeArea(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
PaymentConfigHeader(onAdd: controller.addMethod),
const SizedBox(height: 12),
PaymentConfigList(controller: controller),
const SizedBox(height: 12),
const PaymentConfigAdvanced(),
],
),
),
),
);
}
}