🎨 Optimize the null check in list

This commit is contained in:
2026-02-02 15:48:48 +08:00
parent cfd2a47064
commit 583902ad52
5 changed files with 366 additions and 422 deletions

View File

@@ -120,83 +120,73 @@ class _PurchaseGiftSheetState extends State<PurchaseGiftSheet> {
).colorScheme.outline.withOpacity(0.2), ).colorScheme.outline.withOpacity(0.2),
), ),
), ),
child: child: selectedRecipient != null
selectedRecipient != null ? ListTile(
? ListTile( contentPadding: const EdgeInsets.only(
contentPadding: const EdgeInsets.only( left: 20,
left: 20, right: 12,
right: 12, ),
leading: ProfilePictureWidget(
file: selectedRecipient!.profile.picture,
),
title: Text(
selectedRecipient!.nick,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
), ),
leading: ProfilePictureWidget( ),
file: selectedRecipient!.profile.picture, subtitle: Text(
'selectedRecipient'.tr(),
style: Theme.of(context).textTheme.bodySmall
?.copyWith(
color: Theme.of(
context,
).colorScheme.onSurfaceVariant,
),
),
trailing: IconButton(
onPressed: () =>
setState(() => selectedRecipient = null),
icon: Icon(
Icons.clear,
color: Theme.of(context).colorScheme.error,
), ),
title: Text( tooltip: 'Clear selection',
selectedRecipient!.nick, ),
style: const TextStyle( )
fontSize: 16, : Column(
fontWeight: FontWeight.w600, mainAxisAlignment: MainAxisAlignment.center,
), children: [
), Icon(
subtitle: Text( Icons.person_add_outlined,
'selectedRecipient'.tr(), size: 48,
style: Theme.of( color: Theme.of(
context, context,
).textTheme.bodySmall?.copyWith( ).colorScheme.onSurfaceVariant,
color: ),
Theme.of( const Gap(8),
Text(
'noRecipientSelected'.tr(),
style: Theme.of(context).textTheme.bodyMedium
?.copyWith(
color: Theme.of(
context, context,
).colorScheme.onSurfaceVariant, ).colorScheme.onSurfaceVariant,
),
),
trailing: IconButton(
onPressed:
() => setState(
() => selectedRecipient = null,
), ),
icon: Icon(
Icons.clear,
color: Theme.of(context).colorScheme.error,
),
tooltip: 'Clear selection',
), ),
) const Gap(4),
: Column( Text(
mainAxisAlignment: MainAxisAlignment.center, 'thisWillBeAnOpenGift'.tr(),
children: [ style: Theme.of(context).textTheme.bodySmall
Icon( ?.copyWith(
Icons.person_add_outlined, color: Theme.of(
size: 48,
color:
Theme.of(
context, context,
).colorScheme.onSurfaceVariant, ).colorScheme.onSurfaceVariant,
), ),
const Gap(8), ),
Text( ],
'noRecipientSelected'.tr(), ).padding(vertical: 32),
style: Theme.of(
context,
).textTheme.bodyMedium?.copyWith(
color:
Theme.of(
context,
).colorScheme.onSurfaceVariant,
),
),
const Gap(4),
Text(
'thisWillBeAnOpenGift'.tr(),
style: Theme.of(
context,
).textTheme.bodySmall?.copyWith(
color:
Theme.of(
context,
).colorScheme.onSurfaceVariant,
),
),
],
).padding(vertical: 32),
), ),
const Gap(12), const Gap(12),
OutlinedButton.icon( OutlinedButton.icon(
@@ -259,8 +249,8 @@ class _PurchaseGiftSheetState extends State<PurchaseGiftSheet> {
), ),
), ),
maxLines: 3, maxLines: 3,
onTapOutside: onTapOutside: (_) =>
(_) => FocusManager.instance.primaryFocus?.unfocus(), FocusManager.instance.primaryFocus?.unfocus(),
), ),
], ],
), ),
@@ -274,13 +264,12 @@ class _PurchaseGiftSheetState extends State<PurchaseGiftSheet> {
children: [ children: [
Expanded( Expanded(
child: OutlinedButton( child: OutlinedButton(
onPressed: onPressed: () =>
() => Navigator.of(context).pop(<String, dynamic>{ Navigator.of(context).pop(<String, dynamic>{
'recipient': null, 'recipient': null,
'message': 'message': messageController.text.trim().isEmpty
messageController.text.trim().isEmpty ? null
? null : messageController.text.trim(),
: messageController.text.trim(),
}), }),
child: Text('skipRecipient'.tr()), child: Text('skipRecipient'.tr()),
), ),
@@ -288,13 +277,12 @@ class _PurchaseGiftSheetState extends State<PurchaseGiftSheet> {
const Gap(8), const Gap(8),
Expanded( Expanded(
child: FilledButton( child: FilledButton(
onPressed: onPressed: () =>
() => Navigator.of(context).pop(<String, dynamic>{ Navigator.of(context).pop(<String, dynamic>{
'recipient': selectedRecipient, 'recipient': selectedRecipient,
'message': 'message': messageController.text.trim().isEmpty
messageController.text.trim().isEmpty ? null
? null : messageController.text.trim(),
: messageController.text.trim(),
}), }),
child: Text('purchaseGift'.tr()), child: Text('purchaseGift'.tr()),
), ),
@@ -336,40 +324,38 @@ class StellarProgramTab extends HookConsumerWidget {
) { ) {
return stellarSubscriptionAsync.when( return stellarSubscriptionAsync.when(
data: (membership) => _buildMembershipContent(context, ref, membership), data: (membership) => _buildMembershipContent(context, ref, membership),
loading: loading: () => Container(
() => Container( width: double.infinity,
width: double.infinity, padding: const EdgeInsets.all(16),
padding: const EdgeInsets.all(16), decoration: BoxDecoration(
decoration: BoxDecoration( gradient: LinearGradient(
gradient: LinearGradient( colors: [
colors: [ Theme.of(context).colorScheme.primaryContainer,
Theme.of(context).colorScheme.primaryContainer, Theme.of(context).colorScheme.secondaryContainer,
Theme.of(context).colorScheme.secondaryContainer, ],
], begin: Alignment.topLeft,
begin: Alignment.topLeft, end: Alignment.bottomRight,
end: Alignment.bottomRight,
),
borderRadius: BorderRadius.circular(12),
),
child: const Center(child: CircularProgressIndicator()),
), ),
error: borderRadius: BorderRadius.circular(12),
(error, stack) => Container( ),
width: double.infinity, child: const Center(child: CircularProgressIndicator()),
padding: const EdgeInsets.all(16), ),
decoration: BoxDecoration( error: (error, stack) => Container(
gradient: LinearGradient( width: double.infinity,
colors: [ padding: const EdgeInsets.all(16),
Theme.of(context).colorScheme.primaryContainer, decoration: BoxDecoration(
Theme.of(context).colorScheme.secondaryContainer, gradient: LinearGradient(
], colors: [
begin: Alignment.topLeft, Theme.of(context).colorScheme.primaryContainer,
end: Alignment.bottomRight, Theme.of(context).colorScheme.secondaryContainer,
), ],
borderRadius: BorderRadius.circular(12), begin: Alignment.topLeft,
), end: Alignment.bottomRight,
child: Text('Error loading membership: $error'),
), ),
borderRadius: BorderRadius.circular(12),
),
child: Text('Error loading membership: $error'),
),
); );
} }
@@ -544,118 +530,108 @@ class StellarProgramTab extends HookConsumerWidget {
]; ];
return Column( return Column(
children: children: tiers.map((tier) {
tiers.map((tier) { final isCurrentTier = currentMembership?.identifier == tier['id'];
final isCurrentTier = currentMembership?.identifier == tier['id']; final tierColor = tier['color'] as Color;
final tierColor = tier['color'] as Color;
return Container( return Container(
margin: const EdgeInsets.only(bottom: 8), margin: const EdgeInsets.only(bottom: 8),
child: Material( child: Material(
color: Colors.transparent, color: Colors.transparent,
child: InkWell( child: InkWell(
onTap: onTap: isCurrentTier
isCurrentTier ? null
? null : () =>
: () => _purchaseMembership( _purchaseMembership(context, ref, tier['id'] as String),
context, borderRadius: BorderRadius.circular(8),
ref, child: Container(
tier['id'] as String, padding: const EdgeInsets.all(12),
), decoration: BoxDecoration(
color: isCurrentTier
? tierColor.withOpacity(0.1)
: Theme.of(context).colorScheme.surface,
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
child: Container( border: Border.all(
padding: const EdgeInsets.all(12), color: isCurrentTier
decoration: BoxDecoration( ? tierColor
color: : Theme.of(
isCurrentTier context,
? tierColor.withOpacity(0.1) ).colorScheme.outline.withOpacity(0.2),
: Theme.of(context).colorScheme.surface, width: isCurrentTier ? 2 : 1,
borderRadius: BorderRadius.circular(8),
border: Border.all(
color:
isCurrentTier
? tierColor
: Theme.of(
context,
).colorScheme.outline.withOpacity(0.2),
width: isCurrentTier ? 2 : 1,
),
),
child: Row(
children: [
Container(
width: 4,
height: 40,
decoration: BoxDecoration(
color: tierColor,
borderRadius: BorderRadius.circular(2),
),
),
const Gap(12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Text(
tier['name'] as String,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: isCurrentTier ? tierColor : null,
),
),
const Gap(8),
if (isCurrentTier)
Container(
padding: const EdgeInsets.symmetric(
horizontal: 6,
vertical: 2,
),
decoration: BoxDecoration(
color: tierColor,
borderRadius: BorderRadius.circular(4),
),
child: Text(
'membershipCurrentBadge'.tr(),
style: TextStyle(
fontSize: 10,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
),
],
),
Text(
tier['price'] as String,
style: Theme.of(
context,
).textTheme.bodyMedium?.copyWith(
color:
Theme.of(
context,
).colorScheme.onSurfaceVariant,
),
),
],
),
),
if (!isCurrentTier)
Icon(
Icons.arrow_forward_ios,
size: 16,
color:
Theme.of(context).colorScheme.onSurfaceVariant,
),
],
),
), ),
), ),
child: Row(
children: [
Container(
width: 4,
height: 40,
decoration: BoxDecoration(
color: tierColor,
borderRadius: BorderRadius.circular(2),
),
),
const Gap(12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Text(
tier['name'] as String,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: isCurrentTier ? tierColor : null,
),
),
const Gap(8),
if (isCurrentTier)
Container(
padding: const EdgeInsets.symmetric(
horizontal: 6,
vertical: 2,
),
decoration: BoxDecoration(
color: tierColor,
borderRadius: BorderRadius.circular(4),
),
child: Text(
'membershipCurrentBadge'.tr(),
style: TextStyle(
fontSize: 10,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
),
],
),
Text(
tier['price'] as String,
style: Theme.of(context).textTheme.bodyMedium
?.copyWith(
color: Theme.of(
context,
).colorScheme.onSurfaceVariant,
),
),
],
),
),
if (!isCurrentTier)
Icon(
Icons.arrow_forward_ios,
size: 16,
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
],
),
), ),
); ),
}).toList(), ),
);
}).toList(),
); );
} }
@@ -825,82 +801,75 @@ class StellarProgramTab extends HookConsumerWidget {
]; ];
return Column( return Column(
children: children: tiers.map((tier) {
tiers.map((tier) { final tierColor = tier['color'] as Color;
final tierColor = tier['color'] as Color;
return Container( return Container(
margin: const EdgeInsets.only(bottom: 8), margin: const EdgeInsets.only(bottom: 8),
child: Material( child: Material(
color: Colors.transparent, color: Colors.transparent,
child: InkWell( child: InkWell(
onTap: onTap: () =>
() => _showPurchaseGiftDialog( _showPurchaseGiftDialog(context, ref, tier['id'] as String),
context, borderRadius: BorderRadius.circular(8),
ref, child: Container(
tier['id'] as String, padding: const EdgeInsets.all(12),
), decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surface,
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
child: Container( border: Border.all(
padding: const EdgeInsets.all(12), color: Theme.of(
decoration: BoxDecoration( context,
color: Theme.of(context).colorScheme.surface, ).colorScheme.outline.withOpacity(0.2),
borderRadius: BorderRadius.circular(8), width: 1,
border: Border.all(
color: Theme.of(
context,
).colorScheme.outline.withOpacity(0.2),
width: 1,
),
),
child: Row(
children: [
Container(
width: 4,
height: 40,
decoration: BoxDecoration(
color: tierColor,
borderRadius: BorderRadius.circular(2),
),
),
const Gap(12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
tier['name'] as String,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
Text(
tier['price'] as String,
style: Theme.of(
context,
).textTheme.bodyMedium?.copyWith(
color:
Theme.of(
context,
).colorScheme.onSurfaceVariant,
),
),
],
),
),
Icon(
Icons.arrow_forward_ios,
size: 16,
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
],
),
), ),
), ),
child: Row(
children: [
Container(
width: 4,
height: 40,
decoration: BoxDecoration(
color: tierColor,
borderRadius: BorderRadius.circular(2),
),
),
const Gap(12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
tier['name'] as String,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
Text(
tier['price'] as String,
style: Theme.of(context).textTheme.bodyMedium
?.copyWith(
color: Theme.of(
context,
).colorScheme.onSurfaceVariant,
),
),
],
),
),
Icon(
Icons.arrow_forward_ios,
size: 16,
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
],
),
), ),
); ),
}).toList(), ),
);
}).toList(),
); );
} }
@@ -944,8 +913,8 @@ class StellarProgramTab extends HookConsumerWidget {
), ),
suffixIcon: IconButton( suffixIcon: IconButton(
icon: Icon(Icons.redeem), icon: Icon(Icons.redeem),
onPressed: onPressed: () =>
() => _redeemGift(context, ref, codeController.text.trim()), _redeemGift(context, ref, codeController.text.trim()),
), ),
), ),
onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(), onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(),
@@ -966,16 +935,16 @@ class StellarProgramTab extends HookConsumerWidget {
children: [ children: [
Expanded( Expanded(
child: OutlinedButton( child: OutlinedButton(
onPressed: onPressed: () =>
() => _showGiftHistorySheet(context, ref, sentGifts, true), _showGiftHistorySheet(context, ref, sentGifts, true),
child: Text('sentGifts'.tr()), child: Text('sentGifts'.tr()),
), ),
), ),
const Gap(8), const Gap(8),
Expanded( Expanded(
child: OutlinedButton( child: OutlinedButton(
onPressed: onPressed: () =>
() => _showGiftHistorySheet(context, ref, receivedGifts, false), _showGiftHistorySheet(context, ref, receivedGifts, false),
child: Text('receivedGifts'.tr()), child: Text('receivedGifts'.tr()),
), ),
), ),
@@ -993,36 +962,26 @@ class StellarProgramTab extends HookConsumerWidget {
isScrollControlled: true, isScrollControlled: true,
useRootNavigator: true, useRootNavigator: true,
context: context, context: context,
builder: builder: (context) => SheetScaffold(
(context) => SheetScaffold( titleText: isSent ? 'sentGifts'.tr() : 'receivedGifts'.tr(),
titleText: isSent ? 'sentGifts'.tr() : 'receivedGifts'.tr(), child: giftsAsync.when(
child: giftsAsync.when( data: (gifts) => gifts.isEmpty
data: ? Padding(
(gifts) => padding: const EdgeInsets.all(16),
gifts.isEmpty child: Text(
? Padding( isSent ? 'noSentGifts'.tr() : 'noReceivedGifts'.tr(),
padding: const EdgeInsets.all(16), ),
child: Text( )
isSent : ListView.builder(
? 'noSentGifts'.tr() padding: const EdgeInsets.only(top: 16),
: 'noReceivedGifts'.tr(), itemCount: gifts.length,
), itemBuilder: (context, index) =>
) _buildGiftItem(context, ref, gifts[index], isSent),
: ListView.builder( ),
padding: const EdgeInsets.only(top: 16), loading: () => const Center(child: CircularProgressIndicator()),
itemCount: gifts.length, error: (error, stack) => Center(child: Text('Error: $error')),
itemBuilder: ),
(context, index) => _buildGiftItem( ),
context,
ref,
gifts[index],
isSent,
),
),
loading: () => const Center(child: CircularProgressIndicator()),
error: (error, stack) => Center(child: Text('Error: $error')),
),
),
); );
} }
@@ -1232,10 +1191,10 @@ class StellarProgramTab extends HookConsumerWidget {
'/pass/subscriptions/gifts/purchase', '/pass/subscriptions/gifts/purchase',
data: { data: {
'subscription_identifier': subscriptionId, 'subscription_identifier': subscriptionId,
if (recipientId != null) 'recipient_id': recipientId, 'recipient_id': ?recipientId,
'payment_method': 'solian.wallet', 'payment_method': 'solian.wallet',
'payment_details': {'currency': 'golds'}, 'payment_details': {'currency': 'golds'},
if (message != null) 'message': message, 'message': ?message,
'gift_duration_days': 30, 'gift_duration_days': 30,
'subscription_duration_days': 30, 'subscription_duration_days': 30,
}, },
@@ -1277,83 +1236,75 @@ class StellarProgramTab extends HookConsumerWidget {
if (context.mounted) { if (context.mounted) {
await showModalBottomSheet( await showModalBottomSheet(
context: context, context: context,
builder: builder: (context) => SheetScaffold(
(context) => SheetScaffold( titleText: 'giftPurchased'.tr(),
titleText: 'giftPurchased'.tr(), child: Padding(
child: Padding( padding: const EdgeInsets.all(16),
padding: const EdgeInsets.all(16), child: Column(
child: Column( mainAxisSize: MainAxisSize.min,
mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.stretch,
crossAxisAlignment: CrossAxisAlignment.stretch, children: [
children: [ Container(
Container( padding: const EdgeInsets.all(12),
padding: const EdgeInsets.all(12), decoration: BoxDecoration(
decoration: BoxDecoration( color: Theme.of(context).colorScheme.surface,
color: Theme.of(context).colorScheme.surface, borderRadius: BorderRadius.circular(8),
borderRadius: BorderRadius.circular(8), border: Border.all(
border: Border.all( color: Theme.of(
color: Theme.of( context,
context, ).colorScheme.outline.withOpacity(0.2),
).colorScheme.outline.withOpacity(0.2), ),
),
child: Row(
children: [
Expanded(
child: Text(
updatedGift.giftCode,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
fontFamily: 'monospace',
),
), ),
), ),
child: Row( IconButton(
children: [ onPressed: () async {
Expanded( await Clipboard.setData(
child: Text( ClipboardData(text: updatedGift.giftCode),
updatedGift.giftCode, );
style: TextStyle( if (context.mounted) {
fontSize: 16, showSnackBar('giftCodeCopiedToClipboard'.tr());
fontWeight: FontWeight.w600, }
fontFamily: 'monospace', },
), icon: const Icon(Icons.copy),
), tooltip: 'copyGiftCode'.tr(),
),
IconButton(
onPressed: () async {
await Clipboard.setData(
ClipboardData(text: updatedGift.giftCode),
);
if (context.mounted) {
showSnackBar(
'giftCodeCopiedToClipboard'.tr(),
);
}
},
icon: const Icon(Icons.copy),
tooltip: 'copyGiftCode'.tr(),
),
],
),
),
const Gap(16),
Text(
'shareCodeWithRecipient'.tr(),
style: Theme.of(context).textTheme.bodyMedium,
),
if (updatedGift.recipientId == null) ...[
const Gap(8),
Text(
'openGiftAnyoneCanRedeem'.tr(),
style: Theme.of(
context,
).textTheme.bodySmall?.copyWith(
color:
Theme.of(
context,
).colorScheme.onSurfaceVariant,
),
), ),
], ],
const Gap(24), ),
FilledButton(
onPressed: () => Navigator.of(context).pop(),
child: Text('ok'.tr()),
),
],
), ),
), const Gap(16),
Text(
'shareCodeWithRecipient'.tr(),
style: Theme.of(context).textTheme.bodyMedium,
),
if (updatedGift.recipientId == null) ...[
const Gap(8),
Text(
'openGiftAnyoneCanRedeem'.tr(),
style: Theme.of(context).textTheme.bodySmall?.copyWith(
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
),
],
const Gap(24),
FilledButton(
onPressed: () => Navigator.of(context).pop(),
child: Text('ok'.tr()),
),
],
), ),
),
),
); );
} }
} }
@@ -1397,17 +1348,16 @@ class StellarProgramTab extends HookConsumerWidget {
hideLoadingModal(context); hideLoadingModal(context);
await showDialog( await showDialog(
context: context, context: context,
builder: builder: (context) => AlertDialog(
(context) => AlertDialog( title: Text('giftRedeemed'.tr()),
title: Text('giftRedeemed'.tr()), content: Text('giftRedeemedSuccessfully'.tr()),
content: Text('giftRedeemedSuccessfully'.tr()), actions: [
actions: [ FilledButton(
FilledButton( onPressed: () => Navigator.of(context).pop(),
onPressed: () => Navigator.of(context).pop(), child: Text('ok'.tr()),
child: Text('ok'.tr()),
),
],
), ),
],
),
); );
} }

View File

@@ -398,10 +398,7 @@ class CallOverlayBar extends HookConsumerWidget {
layoutBuilder: (currentChild, previousChildren) { layoutBuilder: (currentChild, previousChildren) {
return Stack( return Stack(
alignment: Alignment.topCenter, alignment: Alignment.topCenter,
children: <Widget>[ children: <Widget>[...previousChildren, ?currentChild],
...previousChildren,
if (currentChild != null) currentChild,
],
); );
}, },
child: child, child: child,

View File

@@ -97,7 +97,7 @@ class ChatRoomSubtitle extends StatelessWidget {
duration: const Duration(milliseconds: 300), duration: const Duration(milliseconds: 300),
layoutBuilder: (currentChild, previousChildren) => Stack( layoutBuilder: (currentChild, previousChildren) => Stack(
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,
children: [...previousChildren, if (currentChild != null) currentChild], children: [...previousChildren, ?currentChild],
), ),
child: summary.when( child: summary.when(
data: (data) => Container( data: (data) => Container(

View File

@@ -478,10 +478,7 @@ class PostItem extends HookConsumerWidget {
final translationSection = Column( final translationSection = Column(
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
children: [ children: [?translatedWidget, ?translatableWidget],
if (translatedWidget != null) translatedWidget,
if (translatableWidget != null) translatableWidget,
],
); );
return Column( return Column(

View File

@@ -854,7 +854,7 @@ class PostHeader extends HookConsumerWidget {
], ],
), ),
), ),
if (trailing != null) trailing!, ?trailing,
], ],
), ),
], ],
@@ -1142,7 +1142,7 @@ class PostBody extends ConsumerWidget {
attachments: item.attachments, attachments: item.attachments,
noMentionChip: item.fediverseUri != null, noMentionChip: item.fediverseUri != null,
), ),
if (translationSection != null) translationSection!, ?translationSection,
], ],
), ),
), ),