updating UI inconsistency
This commit is contained in:
@@ -61,6 +61,7 @@ GroupBatchItem _$GroupBatchItemFromJson(Map<String, dynamic> json) =>
|
|||||||
billProductName: json['billProductName'] as String?,
|
billProductName: json['billProductName'] as String?,
|
||||||
providerLabel: json['providerLabel'] as String?,
|
providerLabel: json['providerLabel'] as String?,
|
||||||
providerImage: json['providerImage'] as String?,
|
providerImage: json['providerImage'] as String?,
|
||||||
|
creditAddress: json['creditAddress'] as String?,
|
||||||
);
|
);
|
||||||
|
|
||||||
Map<String, dynamic> _$GroupBatchItemToJson(GroupBatchItem instance) =>
|
Map<String, dynamic> _$GroupBatchItemToJson(GroupBatchItem instance) =>
|
||||||
@@ -79,6 +80,7 @@ Map<String, dynamic> _$GroupBatchItemToJson(GroupBatchItem instance) =>
|
|||||||
'billProductName': instance.billProductName,
|
'billProductName': instance.billProductName,
|
||||||
'providerLabel': instance.providerLabel,
|
'providerLabel': instance.providerLabel,
|
||||||
'providerImage': instance.providerImage,
|
'providerImage': instance.providerImage,
|
||||||
|
'creditAddress': instance.creditAddress,
|
||||||
};
|
};
|
||||||
|
|
||||||
CreateBatchRequest _$CreateBatchRequestFromJson(Map<String, dynamic> json) =>
|
CreateBatchRequest _$CreateBatchRequestFromJson(Map<String, dynamic> json) =>
|
||||||
|
|||||||
@@ -2467,7 +2467,7 @@ class _BatchDetailScreenState extends State<BatchDetailScreen>
|
|||||||
return Container(
|
return Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: isDark ? const Color(0xFF1A1A2E) : Colors.white,
|
color: isDark ? const Color(0xFF1A1A2E) : Colors.white,
|
||||||
borderRadius: BorderRadius.circular(14),
|
borderRadius: BorderRadius.circular(16),
|
||||||
border: Border.all(
|
border: Border.all(
|
||||||
color: isDark
|
color: isDark
|
||||||
? Colors.white.withValues(alpha: 0.06)
|
? Colors.white.withValues(alpha: 0.06)
|
||||||
@@ -2483,24 +2483,31 @@ class _BatchDetailScreenState extends State<BatchDetailScreen>
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
padding: const EdgeInsets.all(10),
|
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 14),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
CircleAvatar(
|
Container(
|
||||||
radius: 18,
|
width: 44,
|
||||||
backgroundColor: theme.colorScheme.primary.withAlpha(25),
|
height: 44,
|
||||||
child: Text(
|
padding: const EdgeInsets.all(10),
|
||||||
item.recipientName?.isNotEmpty == true
|
decoration: BoxDecoration(
|
||||||
? item.recipientName![0].toUpperCase()
|
color: theme.colorScheme.primary.withValues(alpha: 0.1),
|
||||||
: '?',
|
borderRadius: BorderRadius.circular(12),
|
||||||
style: TextStyle(
|
),
|
||||||
fontSize: 14,
|
child: Center(
|
||||||
fontWeight: FontWeight.w600,
|
child: Text(
|
||||||
color: theme.colorScheme.primary,
|
item.recipientName?.isNotEmpty == true
|
||||||
|
? item.recipientName![0].toUpperCase()
|
||||||
|
: '?',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: theme.colorScheme.primary,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 10),
|
const SizedBox(width: 14),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
@@ -2513,16 +2520,38 @@ class _BatchDetailScreenState extends State<BatchDetailScreen>
|
|||||||
color: isDark ? Colors.white : Colors.black87,
|
color: isDark ? Colors.white : Colors.black87,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 2),
|
const SizedBox(height: 4),
|
||||||
Text(
|
Row(
|
||||||
item.recipientAccount ?? '',
|
children: [
|
||||||
style: TextStyle(fontSize: 12, color: Colors.grey.shade500),
|
if (item.billProductName != null &&
|
||||||
|
item.billProductName!.isNotEmpty) ...[
|
||||||
|
Text(
|
||||||
|
item.billProductName!,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
color: isDark ? Colors.white54 : Colors.grey.shade500,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
' • ',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 11,
|
||||||
|
color: isDark ? Colors.white24 : Colors.grey.shade400,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
Text(
|
||||||
|
item.recipientAccount ?? '',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
color: isDark ? Colors.white54 : Colors.grey.shade500,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
if (item.billName != null || item.billProductName != null)
|
Text(item.creditAddress ?? ''),
|
||||||
const SizedBox(height: 4),
|
|
||||||
if (item.billName != null || item.billProductName != null)
|
|
||||||
_buildBillInfoRow(item, isDark),
|
|
||||||
if (item.creditAddress != null) Text(item.creditAddress ?? ''),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -2533,7 +2562,7 @@ class _BatchDetailScreenState extends State<BatchDetailScreen>
|
|||||||
Text(
|
Text(
|
||||||
'${batch.currency ?? 'USD'} ${item.amount?.toStringAsFixed(2) ?? '—'}',
|
'${batch.currency ?? 'USD'} ${item.amount?.toStringAsFixed(2) ?? '—'}',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 14,
|
fontSize: 16,
|
||||||
fontWeight: FontWeight.w700,
|
fontWeight: FontWeight.w700,
|
||||||
color: isDark ? Colors.white : Colors.black87,
|
color: isDark ? Colors.white : Colors.black87,
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -315,6 +315,8 @@ class _GroupDetailScreenState extends State<GroupDetailScreen>
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildMemberCard(RecipientGroupMember member) {
|
Widget _buildMemberCard(RecipientGroupMember member) {
|
||||||
|
final theme = Theme.of(context);
|
||||||
|
final isDark = theme.brightness == Brightness.dark;
|
||||||
final recipient = member.recipient;
|
final recipient = member.recipient;
|
||||||
final name = recipient.name?.isNotEmpty == true
|
final name = recipient.name?.isNotEmpty == true
|
||||||
? recipient.name!
|
? recipient.name!
|
||||||
@@ -329,19 +331,26 @@ class _GroupDetailScreenState extends State<GroupDetailScreen>
|
|||||||
},
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.white,
|
color: isDark ? const Color(0xFF1A1A2E) : Colors.white,
|
||||||
borderRadius: BorderRadius.circular(16),
|
borderRadius: BorderRadius.circular(16),
|
||||||
border: Border.all(color: Colors.grey.shade200, width: 1),
|
border: Border.all(
|
||||||
|
color: isDark
|
||||||
|
? Colors.white.withValues(alpha: 0.06)
|
||||||
|
: Colors.grey.shade200,
|
||||||
|
width: 1,
|
||||||
|
),
|
||||||
boxShadow: [
|
boxShadow: [
|
||||||
BoxShadow(
|
BoxShadow(
|
||||||
color: Colors.black.withValues(alpha: 0.04),
|
color: isDark
|
||||||
|
? Colors.black.withValues(alpha: 0.2)
|
||||||
|
: Colors.black.withValues(alpha: 0.03),
|
||||||
blurRadius: 8,
|
blurRadius: 8,
|
||||||
offset: const Offset(0, 2),
|
offset: const Offset(0, 2),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 14, horizontal: 14),
|
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 14),
|
||||||
child: Row(
|
child: Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
@@ -353,22 +362,27 @@ class _GroupDetailScreenState extends State<GroupDetailScreen>
|
|||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
name,
|
name,
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16,
|
fontSize: 14,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
color: Colors.black87,
|
color: isDark ? Colors.white : Colors.black87,
|
||||||
),
|
),
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 6),
|
const SizedBox(height: 4),
|
||||||
_buildMemberSubtitleRow(recipient, member.account),
|
_buildMemberSubtitleRow(
|
||||||
|
recipient,
|
||||||
|
member.account,
|
||||||
|
isDark,
|
||||||
|
),
|
||||||
if (recipient.phoneNumber != null &&
|
if (recipient.phoneNumber != null &&
|
||||||
recipient.phoneNumber!.isNotEmpty) ...[
|
recipient.phoneNumber!.isNotEmpty) ...[
|
||||||
const SizedBox(height: 6),
|
const SizedBox(height: 4),
|
||||||
_buildContactLine(
|
_buildContactLine(
|
||||||
Icons.phone_outlined,
|
Icons.phone_outlined,
|
||||||
recipient.phoneNumber!,
|
recipient.phoneNumber!,
|
||||||
|
isDark,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
if (recipient.email != null &&
|
if (recipient.email != null &&
|
||||||
@@ -377,6 +391,7 @@ class _GroupDetailScreenState extends State<GroupDetailScreen>
|
|||||||
_buildContactLine(
|
_buildContactLine(
|
||||||
Icons.email_outlined,
|
Icons.email_outlined,
|
||||||
recipient.email!,
|
recipient.email!,
|
||||||
|
isDark,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
@@ -393,42 +408,29 @@ class _GroupDetailScreenState extends State<GroupDetailScreen>
|
|||||||
|
|
||||||
Widget _buildMemberAvatar(String initials) {
|
Widget _buildMemberAvatar(String initials) {
|
||||||
return Container(
|
return Container(
|
||||||
width: 48,
|
width: 44,
|
||||||
height: 48,
|
height: 44,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
gradient: LinearGradient(
|
color: Theme.of(context).colorScheme.primary.withValues(alpha: 0.1),
|
||||||
colors: [
|
borderRadius: BorderRadius.circular(12),
|
||||||
Theme.of(context).colorScheme.primary,
|
|
||||||
Theme.of(context).colorScheme.primary.withValues(alpha: 0.7),
|
|
||||||
],
|
|
||||||
begin: Alignment.topLeft,
|
|
||||||
end: Alignment.bottomRight,
|
|
||||||
),
|
|
||||||
shape: BoxShape.circle,
|
|
||||||
boxShadow: [
|
|
||||||
BoxShadow(
|
|
||||||
color: Theme.of(
|
|
||||||
context,
|
|
||||||
).colorScheme.primary.withValues(alpha: 0.25),
|
|
||||||
blurRadius: 6,
|
|
||||||
offset: const Offset(0, 2),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
child: Text(
|
child: Text(
|
||||||
initials,
|
initials,
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.w600,
|
||||||
color: Colors.white,
|
color: Theme.of(context).colorScheme.primary,
|
||||||
letterSpacing: 0.5,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildMemberSubtitleRow(Recipient recipient, String? memberAccount) {
|
Widget _buildMemberSubtitleRow(
|
||||||
|
Recipient recipient,
|
||||||
|
String? memberAccount,
|
||||||
|
bool isDark,
|
||||||
|
) {
|
||||||
final account = memberAccount?.isNotEmpty == true
|
final account = memberAccount?.isNotEmpty == true
|
||||||
? memberAccount
|
? memberAccount
|
||||||
: recipient.account;
|
: recipient.account;
|
||||||
@@ -463,29 +465,38 @@ class _GroupDetailScreenState extends State<GroupDetailScreen>
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (hasAccount)
|
if (hasAccount)
|
||||||
Text(
|
Flexible(
|
||||||
account!,
|
child: Text(
|
||||||
style: TextStyle(
|
account!,
|
||||||
fontSize: 13,
|
style: TextStyle(
|
||||||
color: Colors.grey.shade700,
|
fontSize: 12,
|
||||||
fontWeight: FontWeight.w500,
|
color: isDark ? Colors.white54 : Colors.grey.shade600,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
),
|
||||||
|
maxLines: 1,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
),
|
),
|
||||||
maxLines: 1,
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildContactLine(IconData icon, String text) {
|
Widget _buildContactLine(IconData icon, String text, bool isDark) {
|
||||||
return Row(
|
return Row(
|
||||||
children: [
|
children: [
|
||||||
Icon(icon, size: 13, color: Colors.grey.shade500),
|
Icon(
|
||||||
|
icon,
|
||||||
|
size: 13,
|
||||||
|
color: isDark ? Colors.white38 : Colors.grey.shade500,
|
||||||
|
),
|
||||||
const SizedBox(width: 4),
|
const SizedBox(width: 4),
|
||||||
Flexible(
|
Flexible(
|
||||||
child: Text(
|
child: Text(
|
||||||
text,
|
text,
|
||||||
style: TextStyle(fontSize: 12, color: Colors.grey.shade600),
|
style: TextStyle(
|
||||||
|
fontSize: 12,
|
||||||
|
color: isDark ? Colors.white54 : Colors.grey.shade600,
|
||||||
|
),
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
),
|
),
|
||||||
@@ -1127,131 +1138,166 @@ class _GroupDetailScreenState extends State<GroupDetailScreen>
|
|||||||
final status = batch.status ?? 'UNKNOWN';
|
final status = batch.status ?? 'UNKNOWN';
|
||||||
final createdAt = batch.createdAt;
|
final createdAt = batch.createdAt;
|
||||||
final parsedDate = createdAt != null ? DateTime.tryParse(createdAt) : null;
|
final parsedDate = createdAt != null ? DateTime.tryParse(createdAt) : null;
|
||||||
return Card(
|
final theme = Theme.of(context);
|
||||||
elevation: 0,
|
final isDark = theme.brightness == Brightness.dark;
|
||||||
shape: RoundedRectangleBorder(
|
return Padding(
|
||||||
borderRadius: BorderRadius.circular(12),
|
padding: const EdgeInsets.only(bottom: 8),
|
||||||
side: BorderSide(
|
child: Material(
|
||||||
color: inSelectMode && isSelected
|
color: Colors.transparent,
|
||||||
? Theme.of(context).colorScheme.primary
|
child: InkWell(
|
||||||
: Colors.black12.withAlpha(30),
|
borderRadius: BorderRadius.circular(16),
|
||||||
width: inSelectMode && isSelected ? 2 : 1,
|
onTap: inSelectMode
|
||||||
),
|
? () => batchController.toggleBatchSelection(batch.id!)
|
||||||
),
|
: () => context.push('/groups/batches/${batch.id}'),
|
||||||
child: InkWell(
|
child: Container(
|
||||||
borderRadius: BorderRadius.circular(12),
|
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 14),
|
||||||
onTap: inSelectMode
|
decoration: BoxDecoration(
|
||||||
? () => batchController.toggleBatchSelection(batch.id!)
|
color: isDark ? const Color(0xFF1A1A2E) : Colors.white,
|
||||||
: () => context.push('/groups/batches/${batch.id}'),
|
borderRadius: BorderRadius.circular(16),
|
||||||
child: Padding(
|
border: Border.all(
|
||||||
padding: const EdgeInsets.all(10),
|
color: inSelectMode && isSelected
|
||||||
child: Row(
|
? theme.colorScheme.primary
|
||||||
children: [
|
: isDark
|
||||||
if (inSelectMode)
|
? Colors.white.withValues(alpha: 0.06)
|
||||||
Padding(
|
: Colors.grey.shade200,
|
||||||
padding: const EdgeInsets.only(right: 8),
|
width: inSelectMode && isSelected ? 2 : 1,
|
||||||
child: Icon(
|
),
|
||||||
isSelected
|
boxShadow: [
|
||||||
? Icons.check_box
|
BoxShadow(
|
||||||
: Icons.check_box_outline_blank,
|
color: isDark
|
||||||
size: 20,
|
? Colors.black.withValues(alpha: 0.2)
|
||||||
color: isSelected
|
: Colors.black.withValues(alpha: 0.03),
|
||||||
? Theme.of(context).colorScheme.primary
|
blurRadius: 8,
|
||||||
: Colors.grey.shade400,
|
offset: const Offset(0, 2),
|
||||||
),
|
|
||||||
),
|
),
|
||||||
Expanded(
|
],
|
||||||
child: Column(
|
),
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Row(
|
if (inSelectMode)
|
||||||
children: [
|
Padding(
|
||||||
if (batch.description != null &&
|
padding: const EdgeInsets.only(right: 12),
|
||||||
batch.description!.isNotEmpty)
|
child: Icon(
|
||||||
Flexible(
|
isSelected
|
||||||
child: Text(
|
? Icons.check_box
|
||||||
batch.description!,
|
: Icons.check_box_outline_blank,
|
||||||
style: const TextStyle(
|
size: 20,
|
||||||
fontSize: 15,
|
color: isSelected
|
||||||
fontWeight: FontWeight.w700,
|
? theme.colorScheme.primary
|
||||||
|
: Colors.grey.shade400,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
if (batch.description != null &&
|
||||||
|
batch.description!.isNotEmpty)
|
||||||
|
Flexible(
|
||||||
|
child: Text(
|
||||||
|
batch.description!,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: isDark
|
||||||
|
? Colors.white
|
||||||
|
: const Color.fromARGB(221, 58, 58, 58),
|
||||||
|
),
|
||||||
|
maxLines: 1,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
),
|
),
|
||||||
maxLines: 1,
|
),
|
||||||
overflow: TextOverflow.ellipsis,
|
const SizedBox(width: 8),
|
||||||
|
StatusChip(status: status),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 4),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'${batch.currency ?? 'USD'} ${batch.value?.toStringAsFixed(2) ?? '—'}',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
color: isDark ? Colors.white : Colors.black87,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 6),
|
if (parsedDate != null) ...[
|
||||||
StatusChip(status: status),
|
Text(
|
||||||
],
|
' • ',
|
||||||
),
|
style: TextStyle(
|
||||||
const SizedBox(height: 4),
|
fontSize: 11,
|
||||||
Text(
|
color: isDark
|
||||||
'${batch.currency ?? 'USD'} ${batch.value?.toStringAsFixed(2) ?? '—'}',
|
? Colors.white24
|
||||||
style: TextStyle(
|
: Colors.grey.shade400,
|
||||||
fontSize: 13,
|
),
|
||||||
color: Colors.grey.shade600,
|
),
|
||||||
),
|
Text(
|
||||||
),
|
|
||||||
Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
if (parsedDate != null)
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.only(top: 6),
|
|
||||||
child: Text(
|
|
||||||
DateFormat.yMMMd().add_jm().format(parsedDate),
|
DateFormat.yMMMd().add_jm().format(parsedDate),
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
color: Colors.grey.shade500,
|
fontWeight: FontWeight.w400,
|
||||||
|
color: isDark
|
||||||
|
? Colors.white54
|
||||||
|
: Colors.grey.shade500,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
if (batch.count != null)
|
const Spacer(),
|
||||||
Padding(
|
if (batch.count != null)
|
||||||
padding: const EdgeInsets.only(top: 4),
|
Row(
|
||||||
child: Row(
|
|
||||||
children: [
|
children: [
|
||||||
_statIcon(
|
_statIcon(
|
||||||
Icons.people_outline,
|
Icons.people_outline,
|
||||||
'${batch.count}',
|
'${batch.count}',
|
||||||
|
isDark,
|
||||||
),
|
),
|
||||||
const SizedBox(width: 4),
|
const SizedBox(width: 6),
|
||||||
_statIcon(
|
_statIcon(
|
||||||
Icons.check_circle_outline,
|
Icons.check_circle_outline,
|
||||||
'${batch.successfulCount ?? 0}',
|
'${batch.successfulCount ?? 0}',
|
||||||
|
isDark,
|
||||||
),
|
),
|
||||||
const SizedBox(width: 4),
|
const SizedBox(width: 6),
|
||||||
_statIcon(
|
_statIcon(
|
||||||
Icons.cancel_outlined,
|
Icons.cancel_outlined,
|
||||||
'${batch.failedCount ?? 0}',
|
'${batch.failedCount ?? 0}',
|
||||||
|
isDark,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
],
|
),
|
||||||
),
|
],
|
||||||
],
|
),
|
||||||
),
|
),
|
||||||
),
|
if (!inSelectMode)
|
||||||
if (!inSelectMode)
|
Icon(Icons.chevron_right, color: Colors.grey.shade400),
|
||||||
Icon(Icons.chevron_right, color: Colors.grey.shade400),
|
],
|
||||||
],
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _statIcon(IconData icon, String label) {
|
Widget _statIcon(IconData icon, String label, bool isDark) {
|
||||||
return Row(
|
return Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
Icon(icon, size: 12, color: Colors.grey.shade500),
|
Icon(
|
||||||
|
icon,
|
||||||
|
size: 12,
|
||||||
|
color: isDark ? Colors.white38 : Colors.grey.shade500,
|
||||||
|
),
|
||||||
const SizedBox(width: 3),
|
const SizedBox(width: 3),
|
||||||
Text(
|
Text(
|
||||||
label,
|
label,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 11,
|
fontSize: 11,
|
||||||
color: Colors.grey.shade600,
|
color: isDark ? Colors.white54 : Colors.grey.shade600,
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -435,86 +435,112 @@ class _GroupsScreenState extends State<GroupsScreen> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildGroupCard(RecipientGroup group) {
|
Widget _buildGroupCard(RecipientGroup group) {
|
||||||
|
final theme = Theme.of(context);
|
||||||
|
final isDark = theme.brightness == Brightness.dark;
|
||||||
final isSelected = controller.model.selectedGroupIds.contains(group.id);
|
final isSelected = controller.model.selectedGroupIds.contains(group.id);
|
||||||
final inSelectMode = controller.model.selectMode;
|
final inSelectMode = controller.model.selectMode;
|
||||||
|
|
||||||
return Card(
|
return Padding(
|
||||||
elevation: 0,
|
padding: const EdgeInsets.only(bottom: 8),
|
||||||
shape: RoundedRectangleBorder(
|
child: Material(
|
||||||
borderRadius: BorderRadius.circular(12),
|
color: Colors.transparent,
|
||||||
side: BorderSide(
|
child: InkWell(
|
||||||
color: inSelectMode && isSelected
|
borderRadius: BorderRadius.circular(16),
|
||||||
? Theme.of(context).colorScheme.primary
|
onTap: inSelectMode
|
||||||
: Colors.black12.withAlpha(30),
|
? () => controller.toggleGroupSelection(group.id!)
|
||||||
width: inSelectMode && isSelected ? 2 : 1,
|
: () => context.push('/groups/${group.id}', extra: group),
|
||||||
),
|
child: Container(
|
||||||
),
|
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 14),
|
||||||
child: InkWell(
|
decoration: BoxDecoration(
|
||||||
borderRadius: BorderRadius.circular(12),
|
color: isDark ? const Color(0xFF1A1A2E) : Colors.white,
|
||||||
onTap: inSelectMode
|
borderRadius: BorderRadius.circular(16),
|
||||||
? () => controller.toggleGroupSelection(group.id!)
|
border: Border.all(
|
||||||
: () => context.push('/groups/${group.id}', extra: group),
|
color: inSelectMode && isSelected
|
||||||
child: Padding(
|
? theme.colorScheme.primary
|
||||||
padding: const EdgeInsets.all(16),
|
: isDark
|
||||||
child: Row(
|
? Colors.white.withValues(alpha: 0.06)
|
||||||
children: [
|
: Colors.grey.shade200,
|
||||||
if (inSelectMode)
|
width: inSelectMode && isSelected ? 2 : 1,
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.only(right: 12),
|
|
||||||
child: Icon(
|
|
||||||
isSelected
|
|
||||||
? Icons.check_box
|
|
||||||
: Icons.check_box_outline_blank,
|
|
||||||
color: isSelected
|
|
||||||
? Theme.of(context).colorScheme.primary
|
|
||||||
: Colors.grey.shade400,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
CircleAvatar(
|
|
||||||
backgroundColor: Theme.of(
|
|
||||||
context,
|
|
||||||
).colorScheme.primary.withAlpha(30),
|
|
||||||
child: Text(
|
|
||||||
_getGroupAbbreviation(group.name),
|
|
||||||
style: TextStyle(
|
|
||||||
color: Theme.of(context).colorScheme.primary,
|
|
||||||
fontWeight: FontWeight.w600,
|
|
||||||
fontSize: 16,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
const SizedBox(width: 16),
|
boxShadow: [
|
||||||
Expanded(
|
BoxShadow(
|
||||||
child: Column(
|
color: isDark
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
? Colors.black.withValues(alpha: 0.2)
|
||||||
children: [
|
: Colors.black.withValues(alpha: 0.03),
|
||||||
Text(
|
blurRadius: 8,
|
||||||
group.name,
|
offset: const Offset(0, 2),
|
||||||
style: const TextStyle(
|
),
|
||||||
fontSize: 16,
|
],
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
if (inSelectMode)
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(right: 12),
|
||||||
|
child: Icon(
|
||||||
|
isSelected
|
||||||
|
? Icons.check_box
|
||||||
|
: Icons.check_box_outline_blank,
|
||||||
|
color: isSelected
|
||||||
|
? theme.colorScheme.primary
|
||||||
|
: Colors.grey.shade400,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
width: 44,
|
||||||
|
height: 44,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: theme.colorScheme.primary.withValues(alpha: 0.1),
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
),
|
||||||
|
child: Center(
|
||||||
|
child: Text(
|
||||||
|
_getGroupAbbreviation(group.name),
|
||||||
|
style: TextStyle(
|
||||||
|
color: theme.colorScheme.primary,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
|
fontSize: 16,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (group.description != null &&
|
),
|
||||||
group.description!.isNotEmpty)
|
),
|
||||||
Padding(
|
const SizedBox(width: 14),
|
||||||
padding: const EdgeInsets.only(top: 4),
|
Expanded(
|
||||||
child: Text(
|
child: Column(
|
||||||
group.description!,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
style: TextStyle(
|
children: [
|
||||||
fontSize: 13,
|
Text(
|
||||||
color: Colors.grey.shade600,
|
group.name,
|
||||||
),
|
style: TextStyle(
|
||||||
maxLines: 1,
|
fontSize: 14,
|
||||||
overflow: TextOverflow.ellipsis,
|
fontWeight: FontWeight.w600,
|
||||||
|
color: isDark ? Colors.white : Colors.black87,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
if (group.description != null &&
|
||||||
|
group.description!.isNotEmpty)
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(top: 4),
|
||||||
|
child: Text(
|
||||||
|
group.description!,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
color: isDark
|
||||||
|
? Colors.white54
|
||||||
|
: Colors.grey.shade500,
|
||||||
|
),
|
||||||
|
maxLines: 1,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
if (!inSelectMode)
|
||||||
if (!inSelectMode)
|
Icon(Icons.chevron_right, color: Colors.grey.shade400),
|
||||||
Icon(Icons.chevron_right, color: Colors.grey.shade400),
|
],
|
||||||
],
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
Reference in New Issue
Block a user