From 583902ad522e08e8d224452835a8266e881b7f8f Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Mon, 2 Feb 2026 15:48:48 +0800 Subject: [PATCH] :art: Optimize the null check in list --- lib/widgets/account/stellar_program_tab.dart | 772 +++++++++---------- lib/widgets/chat/call_overlay.dart | 5 +- lib/widgets/chat_room_widgets.dart | 2 +- lib/widgets/post/post_item.dart | 5 +- lib/widgets/post/post_shared.dart | 4 +- 5 files changed, 366 insertions(+), 422 deletions(-) diff --git a/lib/widgets/account/stellar_program_tab.dart b/lib/widgets/account/stellar_program_tab.dart index 62f071ee..96415e33 100644 --- a/lib/widgets/account/stellar_program_tab.dart +++ b/lib/widgets/account/stellar_program_tab.dart @@ -120,83 +120,73 @@ class _PurchaseGiftSheetState extends State { ).colorScheme.outline.withOpacity(0.2), ), ), - child: - selectedRecipient != null - ? ListTile( - contentPadding: const EdgeInsets.only( - left: 20, - right: 12, + child: selectedRecipient != null + ? ListTile( + contentPadding: const EdgeInsets.only( + left: 20, + 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( - selectedRecipient!.nick, - style: const TextStyle( - fontSize: 16, - fontWeight: FontWeight.w600, - ), - ), - subtitle: Text( - 'selectedRecipient'.tr(), - style: Theme.of( + tooltip: 'Clear selection', + ), + ) + : Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Icons.person_add_outlined, + size: 48, + color: Theme.of( context, - ).textTheme.bodySmall?.copyWith( - color: - Theme.of( + ).colorScheme.onSurfaceVariant, + ), + const Gap(8), + Text( + 'noRecipientSelected'.tr(), + style: Theme.of(context).textTheme.bodyMedium + ?.copyWith( + color: Theme.of( context, ).colorScheme.onSurfaceVariant, - ), - ), - trailing: IconButton( - onPressed: - () => setState( - () => selectedRecipient = null, ), - icon: Icon( - Icons.clear, - color: Theme.of(context).colorScheme.error, - ), - tooltip: 'Clear selection', ), - ) - : Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon( - Icons.person_add_outlined, - size: 48, - color: - Theme.of( + const Gap(4), + Text( + 'thisWillBeAnOpenGift'.tr(), + style: Theme.of(context).textTheme.bodySmall + ?.copyWith( + color: Theme.of( context, ).colorScheme.onSurfaceVariant, - ), - const Gap(8), - Text( - 'noRecipientSelected'.tr(), - 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), + ), + ), + ], + ).padding(vertical: 32), ), const Gap(12), OutlinedButton.icon( @@ -259,8 +249,8 @@ class _PurchaseGiftSheetState extends State { ), ), maxLines: 3, - onTapOutside: - (_) => FocusManager.instance.primaryFocus?.unfocus(), + onTapOutside: (_) => + FocusManager.instance.primaryFocus?.unfocus(), ), ], ), @@ -274,13 +264,12 @@ class _PurchaseGiftSheetState extends State { children: [ Expanded( child: OutlinedButton( - onPressed: - () => Navigator.of(context).pop({ + onPressed: () => + Navigator.of(context).pop({ 'recipient': null, - 'message': - messageController.text.trim().isEmpty - ? null - : messageController.text.trim(), + 'message': messageController.text.trim().isEmpty + ? null + : messageController.text.trim(), }), child: Text('skipRecipient'.tr()), ), @@ -288,13 +277,12 @@ class _PurchaseGiftSheetState extends State { const Gap(8), Expanded( child: FilledButton( - onPressed: - () => Navigator.of(context).pop({ + onPressed: () => + Navigator.of(context).pop({ 'recipient': selectedRecipient, - 'message': - messageController.text.trim().isEmpty - ? null - : messageController.text.trim(), + 'message': messageController.text.trim().isEmpty + ? null + : messageController.text.trim(), }), child: Text('purchaseGift'.tr()), ), @@ -336,40 +324,38 @@ class StellarProgramTab extends HookConsumerWidget { ) { return stellarSubscriptionAsync.when( data: (membership) => _buildMembershipContent(context, ref, membership), - loading: - () => Container( - width: double.infinity, - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - gradient: LinearGradient( - colors: [ - Theme.of(context).colorScheme.primaryContainer, - Theme.of(context).colorScheme.secondaryContainer, - ], - begin: Alignment.topLeft, - end: Alignment.bottomRight, - ), - borderRadius: BorderRadius.circular(12), - ), - child: const Center(child: CircularProgressIndicator()), + loading: () => Container( + width: double.infinity, + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + gradient: LinearGradient( + colors: [ + Theme.of(context).colorScheme.primaryContainer, + Theme.of(context).colorScheme.secondaryContainer, + ], + begin: Alignment.topLeft, + end: Alignment.bottomRight, ), - error: - (error, stack) => Container( - width: double.infinity, - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - gradient: LinearGradient( - colors: [ - Theme.of(context).colorScheme.primaryContainer, - Theme.of(context).colorScheme.secondaryContainer, - ], - begin: Alignment.topLeft, - end: Alignment.bottomRight, - ), - borderRadius: BorderRadius.circular(12), - ), - child: Text('Error loading membership: $error'), + borderRadius: BorderRadius.circular(12), + ), + child: const Center(child: CircularProgressIndicator()), + ), + error: (error, stack) => Container( + width: double.infinity, + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + gradient: LinearGradient( + colors: [ + Theme.of(context).colorScheme.primaryContainer, + Theme.of(context).colorScheme.secondaryContainer, + ], + begin: Alignment.topLeft, + end: Alignment.bottomRight, ), + borderRadius: BorderRadius.circular(12), + ), + child: Text('Error loading membership: $error'), + ), ); } @@ -544,118 +530,108 @@ class StellarProgramTab extends HookConsumerWidget { ]; return Column( - children: - tiers.map((tier) { - final isCurrentTier = currentMembership?.identifier == tier['id']; - final tierColor = tier['color'] as Color; + children: tiers.map((tier) { + final isCurrentTier = currentMembership?.identifier == tier['id']; + final tierColor = tier['color'] as Color; - return Container( - margin: const EdgeInsets.only(bottom: 8), - child: Material( - color: Colors.transparent, - child: InkWell( - onTap: - isCurrentTier - ? null - : () => _purchaseMembership( - context, - ref, - tier['id'] as String, - ), + return Container( + margin: const EdgeInsets.only(bottom: 8), + child: Material( + color: Colors.transparent, + child: InkWell( + onTap: isCurrentTier + ? null + : () => + _purchaseMembership(context, ref, tier['id'] as String), + borderRadius: BorderRadius.circular(8), + child: Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: isCurrentTier + ? tierColor.withOpacity(0.1) + : Theme.of(context).colorScheme.surface, borderRadius: BorderRadius.circular(8), - child: Container( - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: - isCurrentTier - ? tierColor.withOpacity(0.1) - : Theme.of(context).colorScheme.surface, - 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, - ), - ], - ), + 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, + ), + ], + ), ), - ); - }).toList(), + ), + ), + ); + }).toList(), ); } @@ -825,82 +801,75 @@ class StellarProgramTab extends HookConsumerWidget { ]; return Column( - children: - tiers.map((tier) { - final tierColor = tier['color'] as Color; + children: tiers.map((tier) { + final tierColor = tier['color'] as Color; - return Container( - margin: const EdgeInsets.only(bottom: 8), - child: Material( - color: Colors.transparent, - child: InkWell( - onTap: - () => _showPurchaseGiftDialog( - context, - ref, - tier['id'] as String, - ), + return Container( + margin: const EdgeInsets.only(bottom: 8), + child: Material( + color: Colors.transparent, + child: InkWell( + onTap: () => + _showPurchaseGiftDialog(context, ref, tier['id'] as String), + borderRadius: BorderRadius.circular(8), + child: Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.surface, borderRadius: BorderRadius.circular(8), - child: Container( - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.surface, - borderRadius: BorderRadius.circular(8), - 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, - ), - ], - ), + 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, + ), + ], + ), ), - ); - }).toList(), + ), + ), + ); + }).toList(), ); } @@ -944,8 +913,8 @@ class StellarProgramTab extends HookConsumerWidget { ), suffixIcon: IconButton( icon: Icon(Icons.redeem), - onPressed: - () => _redeemGift(context, ref, codeController.text.trim()), + onPressed: () => + _redeemGift(context, ref, codeController.text.trim()), ), ), onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(), @@ -966,16 +935,16 @@ class StellarProgramTab extends HookConsumerWidget { children: [ Expanded( child: OutlinedButton( - onPressed: - () => _showGiftHistorySheet(context, ref, sentGifts, true), + onPressed: () => + _showGiftHistorySheet(context, ref, sentGifts, true), child: Text('sentGifts'.tr()), ), ), const Gap(8), Expanded( child: OutlinedButton( - onPressed: - () => _showGiftHistorySheet(context, ref, receivedGifts, false), + onPressed: () => + _showGiftHistorySheet(context, ref, receivedGifts, false), child: Text('receivedGifts'.tr()), ), ), @@ -993,36 +962,26 @@ class StellarProgramTab extends HookConsumerWidget { isScrollControlled: true, useRootNavigator: true, context: context, - builder: - (context) => SheetScaffold( - titleText: isSent ? 'sentGifts'.tr() : 'receivedGifts'.tr(), - child: giftsAsync.when( - data: - (gifts) => - gifts.isEmpty - ? Padding( - padding: const EdgeInsets.all(16), - child: Text( - isSent - ? 'noSentGifts'.tr() - : 'noReceivedGifts'.tr(), - ), - ) - : ListView.builder( - padding: const EdgeInsets.only(top: 16), - itemCount: gifts.length, - itemBuilder: - (context, index) => _buildGiftItem( - context, - ref, - gifts[index], - isSent, - ), - ), - loading: () => const Center(child: CircularProgressIndicator()), - error: (error, stack) => Center(child: Text('Error: $error')), - ), - ), + builder: (context) => SheetScaffold( + titleText: isSent ? 'sentGifts'.tr() : 'receivedGifts'.tr(), + child: giftsAsync.when( + data: (gifts) => gifts.isEmpty + ? Padding( + padding: const EdgeInsets.all(16), + child: Text( + isSent ? 'noSentGifts'.tr() : 'noReceivedGifts'.tr(), + ), + ) + : ListView.builder( + padding: const EdgeInsets.only(top: 16), + itemCount: gifts.length, + 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', data: { 'subscription_identifier': subscriptionId, - if (recipientId != null) 'recipient_id': recipientId, + 'recipient_id': ?recipientId, 'payment_method': 'solian.wallet', 'payment_details': {'currency': 'golds'}, - if (message != null) 'message': message, + 'message': ?message, 'gift_duration_days': 30, 'subscription_duration_days': 30, }, @@ -1277,83 +1236,75 @@ class StellarProgramTab extends HookConsumerWidget { if (context.mounted) { await showModalBottomSheet( context: context, - builder: - (context) => SheetScaffold( - titleText: 'giftPurchased'.tr(), - child: Padding( - padding: const EdgeInsets.all(16), - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Container( - padding: const EdgeInsets.all(12), - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.surface, - borderRadius: BorderRadius.circular(8), - border: Border.all( - color: Theme.of( - context, - ).colorScheme.outline.withOpacity(0.2), + builder: (context) => SheetScaffold( + titleText: 'giftPurchased'.tr(), + child: Padding( + padding: const EdgeInsets.all(16), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Container( + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.surface, + borderRadius: BorderRadius.circular(8), + border: Border.all( + color: Theme.of( + context, + ).colorScheme.outline.withOpacity(0.2), + ), + ), + child: Row( + children: [ + Expanded( + child: Text( + updatedGift.giftCode, + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w600, + fontFamily: 'monospace', + ), ), ), - child: Row( - children: [ - Expanded( - child: Text( - updatedGift.giftCode, - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w600, - fontFamily: 'monospace', - ), - ), - ), - 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, - ), + 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(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); await showDialog( context: context, - builder: - (context) => AlertDialog( - title: Text('giftRedeemed'.tr()), - content: Text('giftRedeemedSuccessfully'.tr()), - actions: [ - FilledButton( - onPressed: () => Navigator.of(context).pop(), - child: Text('ok'.tr()), - ), - ], + builder: (context) => AlertDialog( + title: Text('giftRedeemed'.tr()), + content: Text('giftRedeemedSuccessfully'.tr()), + actions: [ + FilledButton( + onPressed: () => Navigator.of(context).pop(), + child: Text('ok'.tr()), ), + ], + ), ); } diff --git a/lib/widgets/chat/call_overlay.dart b/lib/widgets/chat/call_overlay.dart index 0bc69020..f1a4485b 100644 --- a/lib/widgets/chat/call_overlay.dart +++ b/lib/widgets/chat/call_overlay.dart @@ -398,10 +398,7 @@ class CallOverlayBar extends HookConsumerWidget { layoutBuilder: (currentChild, previousChildren) { return Stack( alignment: Alignment.topCenter, - children: [ - ...previousChildren, - if (currentChild != null) currentChild, - ], + children: [...previousChildren, ?currentChild], ); }, child: child, diff --git a/lib/widgets/chat_room_widgets.dart b/lib/widgets/chat_room_widgets.dart index 694d195a..af2264a2 100644 --- a/lib/widgets/chat_room_widgets.dart +++ b/lib/widgets/chat_room_widgets.dart @@ -97,7 +97,7 @@ class ChatRoomSubtitle extends StatelessWidget { duration: const Duration(milliseconds: 300), layoutBuilder: (currentChild, previousChildren) => Stack( alignment: Alignment.centerLeft, - children: [...previousChildren, if (currentChild != null) currentChild], + children: [...previousChildren, ?currentChild], ), child: summary.when( data: (data) => Container( diff --git a/lib/widgets/post/post_item.dart b/lib/widgets/post/post_item.dart index a265d802..13fd75f4 100644 --- a/lib/widgets/post/post_item.dart +++ b/lib/widgets/post/post_item.dart @@ -478,10 +478,7 @@ class PostItem extends HookConsumerWidget { final translationSection = Column( crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - if (translatedWidget != null) translatedWidget, - if (translatableWidget != null) translatableWidget, - ], + children: [?translatedWidget, ?translatableWidget], ); return Column( diff --git a/lib/widgets/post/post_shared.dart b/lib/widgets/post/post_shared.dart index 0cfd48fb..04612d76 100644 --- a/lib/widgets/post/post_shared.dart +++ b/lib/widgets/post/post_shared.dart @@ -854,7 +854,7 @@ class PostHeader extends HookConsumerWidget { ], ), ), - if (trailing != null) trailing!, + ?trailing, ], ), ], @@ -1142,7 +1142,7 @@ class PostBody extends ConsumerWidget { attachments: item.attachments, noMentionChip: item.fediverseUri != null, ), - if (translationSection != null) translationSection!, + ?translationSection, ], ), ),