Changed the spelling of the word adress)
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:pweb/utils/initials.dart';
|
||||
|
||||
|
||||
class RecipientAvatar extends StatelessWidget {
|
||||
final String name;
|
||||
final String? avatarUrl;
|
||||
final double avatarRadius;
|
||||
final TextStyle? nameStyle;
|
||||
final bool isVisible;
|
||||
|
||||
static const double _verticalSpacing = 5;
|
||||
|
||||
const RecipientAvatar({
|
||||
super.key,
|
||||
required this.name,
|
||||
this.avatarUrl,
|
||||
required this.avatarRadius,
|
||||
this.nameStyle,
|
||||
required this.isVisible,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final textColor = Theme.of(context).colorScheme.onPrimary;
|
||||
|
||||
return Column(
|
||||
children: [
|
||||
CircleAvatar(
|
||||
radius: avatarRadius,
|
||||
backgroundImage: avatarUrl != null ? NetworkImage(avatarUrl!) : null,
|
||||
backgroundColor: Theme.of(context).colorScheme.primary,
|
||||
child: avatarUrl == null
|
||||
? Text(
|
||||
getInitials(name),
|
||||
style: TextStyle(
|
||||
color: textColor,
|
||||
fontSize: avatarRadius * 0.8,
|
||||
),
|
||||
)
|
||||
: null,
|
||||
),
|
||||
const SizedBox(height: _verticalSpacing),
|
||||
if (isVisible)
|
||||
Text(
|
||||
name,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: nameStyle ?? Theme.of(context).textTheme.bodyMedium?.copyWith(fontSize: 14),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class PaymentInfoRow extends StatelessWidget {
|
||||
final String label;
|
||||
final String value;
|
||||
|
||||
const PaymentInfoRow({
|
||||
super.key,
|
||||
required this.label,
|
||||
required this.value,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => Row(
|
||||
children: [
|
||||
Text(label, style: Theme.of(context).textTheme.bodySmall),
|
||||
const SizedBox(width: 8),
|
||||
Text(value, style: Theme.of(context).textTheme.bodySmall),
|
||||
],
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import 'package:pshared/models/recipient/recipient.dart';
|
||||
import 'package:pshared/provider/organizations.dart';
|
||||
import 'package:pshared/provider/recipient/pmethods.dart';
|
||||
|
||||
import 'package:pweb/pages/dashboard/payouts/single/address_book/avatar.dart';
|
||||
import 'package:pweb/pages/dashboard/payouts/single/address_book/long_list/info_row.dart';
|
||||
import 'package:pweb/utils/payment/label.dart';
|
||||
|
||||
|
||||
class RecipientItem extends StatefulWidget {
|
||||
static const double _horizontalPadding = 16.0;
|
||||
static const double _verticalPadding = 8.0;
|
||||
static const double _avatarRadius = 20;
|
||||
static const double _spacingWidth = 12;
|
||||
|
||||
final Recipient recipient;
|
||||
final VoidCallback onTap;
|
||||
|
||||
const RecipientItem({
|
||||
super.key,
|
||||
required this.recipient,
|
||||
required this.onTap,
|
||||
});
|
||||
|
||||
@override
|
||||
State<RecipientItem> createState() => _RecipientItemState();
|
||||
}
|
||||
|
||||
class _RecipientItemState extends State<RecipientItem> {
|
||||
late PaymentMethodsProvider _methodsProvider;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_methodsProvider = PaymentMethodsProvider()
|
||||
..addListener(_onProviderChanged)
|
||||
..loadMethods(
|
||||
context.read<OrganizationsProvider>(),
|
||||
widget.recipient.id,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_methodsProvider.removeListener(_onProviderChanged);
|
||||
_methodsProvider.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _onProviderChanged() => setState(() {});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (!_methodsProvider.isReady) return const Center(child: CircularProgressIndicator());
|
||||
|
||||
final recipient = widget.recipient;
|
||||
return InkWell(
|
||||
onTap: widget.onTap,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: RecipientItem._horizontalPadding,
|
||||
vertical: RecipientItem._verticalPadding,
|
||||
),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(
|
||||
child: ListTile(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
leading: RecipientAvatar(
|
||||
isVisible: false,
|
||||
name: recipient.name,
|
||||
avatarUrl: recipient.avatarUrl,
|
||||
avatarRadius: RecipientItem._avatarRadius,
|
||||
nameStyle: Theme.of(context).textTheme.bodyMedium,
|
||||
),
|
||||
title: Text(recipient.name),
|
||||
subtitle: Text(recipient.email),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: RecipientItem._spacingWidth),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: _methodsProvider.methods.map((m) => PaymentInfoRow(
|
||||
label: getPaymentTypeLabel(context, m.type),
|
||||
value: getPaymentTypeDescription(context, m),
|
||||
)).toList(),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:pshared/models/recipient/recipient.dart';
|
||||
|
||||
import 'package:pweb/pages/dashboard/payouts/single/address_book/long_list/item.dart';
|
||||
|
||||
|
||||
class LongListAddressBookPayout extends StatelessWidget {
|
||||
final List<Recipient> filteredRecipients;
|
||||
final ValueChanged<Recipient>? onSelected;
|
||||
|
||||
const LongListAddressBookPayout({
|
||||
super.key,
|
||||
required this.filteredRecipients,
|
||||
this.onSelected,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ListView.builder(
|
||||
itemCount: filteredRecipients.length,
|
||||
itemBuilder: (context, index) {
|
||||
final recipient = filteredRecipients[index];
|
||||
return RecipientItem(
|
||||
recipient: recipient,
|
||||
onTap: () => onSelected!(recipient),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
|
||||
class AddressBookPlaceholder extends StatelessWidget {
|
||||
final String text;
|
||||
|
||||
const AddressBookPlaceholder({required this.text});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => Center(
|
||||
child: Text(
|
||||
text,
|
||||
style: Theme.of(context).textTheme.titleMedium,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:pshared/models/recipient/recipient.dart';
|
||||
import 'package:pweb/pages/dashboard/payouts/single/address_book/avatar.dart';
|
||||
|
||||
|
||||
class ShortListAddressBookPayout extends StatelessWidget {
|
||||
final List<Recipient> recipients;
|
||||
final ValueChanged<Recipient> onSelected;
|
||||
|
||||
const ShortListAddressBookPayout({
|
||||
super.key,
|
||||
required this.recipients,
|
||||
required this.onSelected,
|
||||
});
|
||||
|
||||
static const double _avatarRadius = 20;
|
||||
static const double _avatarSize = 80;
|
||||
static const EdgeInsets _padding = EdgeInsets.symmetric(horizontal: 10, vertical: 8);
|
||||
static const TextStyle _nameStyle = TextStyle(fontSize: 12);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: Row(
|
||||
children: recipients.map((recipient) {
|
||||
return Padding(
|
||||
padding: _padding,
|
||||
child: InkWell(
|
||||
borderRadius: BorderRadius.circular(5),
|
||||
hoverColor: Theme.of(context).colorScheme.primaryContainer,
|
||||
onTap: () => onSelected(recipient),
|
||||
child: SizedBox(
|
||||
height: _avatarSize,
|
||||
width: _avatarSize,
|
||||
child: RecipientAvatar(
|
||||
isVisible: true,
|
||||
name: recipient.name,
|
||||
avatarUrl: recipient.avatarUrl,
|
||||
avatarRadius: _avatarRadius,
|
||||
nameStyle: _nameStyle,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import 'package:pshared/models/recipient/recipient.dart';
|
||||
import 'package:pshared/provider/recipient/provider.dart';
|
||||
|
||||
import 'package:pweb/pages/address_book/page/search.dart';
|
||||
import 'package:pweb/pages/dashboard/payouts/single/address_book/long_list/widget.dart';
|
||||
import 'package:pweb/pages/dashboard/payouts/single/address_book/placeholder.dart';
|
||||
import 'package:pweb/pages/dashboard/payouts/single/address_book/short_list.dart';
|
||||
|
||||
import 'package:pweb/generated/i18n/app_localizations.dart';
|
||||
|
||||
|
||||
class AddressBookPayout extends StatefulWidget {
|
||||
final ValueChanged<Recipient> onSelected;
|
||||
|
||||
const AddressBookPayout({
|
||||
super.key,
|
||||
required this.onSelected,
|
||||
});
|
||||
|
||||
@override
|
||||
State<AddressBookPayout> createState() => _AddressBookPayoutState();
|
||||
}
|
||||
|
||||
class _AddressBookPayoutState extends State<AddressBookPayout> {
|
||||
static const double _expandedHeight = 400;
|
||||
static const double _collapsedHeight = 200;
|
||||
static const double _cardMargin = 1;
|
||||
static const double _paddingAll = 16;
|
||||
static const double _spacingBetween = 16;
|
||||
|
||||
final FocusNode _searchFocusNode = FocusNode();
|
||||
late final TextEditingController _searchController;
|
||||
|
||||
bool get _isExpanded => _searchFocusNode.hasFocus;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
final provider = context.read<RecipientsProvider>();
|
||||
_searchController = TextEditingController(text: provider.query);
|
||||
|
||||
_searchController.addListener(() {
|
||||
provider.setQuery(_searchController.text);
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_searchController.dispose();
|
||||
_searchFocusNode.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final loc = AppLocalizations.of(context)!;
|
||||
final provider = context.watch<RecipientsProvider>();
|
||||
final recipients = provider.recipients;
|
||||
final filteredRecipients = provider.filteredRecipients;
|
||||
|
||||
if (provider.isLoading) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
|
||||
if (provider.error != null) {
|
||||
return Center(child: Text(loc.notificationError(provider.error ?? loc.noErrorInformation)));
|
||||
}
|
||||
|
||||
return SizedBox(
|
||||
height: _isExpanded ? _expandedHeight : _collapsedHeight,
|
||||
child: Card(
|
||||
margin: const EdgeInsets.all(_cardMargin),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
elevation: 4,
|
||||
color: Theme.of(context).colorScheme.onSecondary,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(_paddingAll),
|
||||
child: Column(
|
||||
children: [
|
||||
RecipientSearchField(
|
||||
controller: _searchController,
|
||||
focusNode: _searchFocusNode,
|
||||
onChanged: (_) {},
|
||||
),
|
||||
const SizedBox(height: _spacingBetween),
|
||||
Expanded(
|
||||
child: recipients.isEmpty
|
||||
? AddressBookPlaceholder(text: loc.noRecipientsYet)
|
||||
: _isExpanded && filteredRecipients.isEmpty
|
||||
? AddressBookPlaceholder(text: loc.noRecipientsFound)
|
||||
: _isExpanded
|
||||
? LongListAddressBookPayout(
|
||||
filteredRecipients: filteredRecipients,
|
||||
onSelected: widget.onSelected,
|
||||
)
|
||||
: ShortListAddressBookPayout(
|
||||
recipients: recipients,
|
||||
onSelected: widget.onSelected,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user