Created
September 24, 2025 23:29
-
-
Save EsinShadrach/65822e4b44133a4d1f80b760bc65202e to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import 'package:playcope/lib.dart'; | |
| class GamesAddedCounter extends StatefulWidget { | |
| const GamesAddedCounter({ | |
| super.key, | |
| this.isVisible = true, | |
| required this.controller, | |
| this.offsetY = 0, | |
| this.date, | |
| }); | |
| final bool isVisible; | |
| final NewCustomBetBuilder controller; | |
| final double offsetY; | |
| final DateTime? date; | |
| @override | |
| State<GamesAddedCounter> createState() => _GamesAddedCounterState(); | |
| } | |
| class _GamesAddedCounterState extends State<GamesAddedCounter> { | |
| @override | |
| Widget build(BuildContext context) { | |
| return ListenableBuilder( | |
| listenable: widget.controller, | |
| builder: (context, _) { | |
| final slipCount = widget.controller.count; | |
| final isLoading = widget.controller.isLoading; | |
| return TweenAnimationBuilder<double>( | |
| duration: const Duration(milliseconds: 300), | |
| curve: Curves.easeInOut, | |
| tween: Tween(begin: 0, end: widget.isVisible ? 0 : 100), | |
| builder: (context, value, child) { | |
| return Transform.translate( | |
| offset: Offset(0, value + widget.offsetY), | |
| child: child, | |
| ); | |
| }, | |
| child: Focus( | |
| canRequestFocus: widget.isVisible, | |
| child: GestureDetector( | |
| onTap: () { | |
| final viewGamesSheet = ViewCustomGamesSheet(); | |
| if (context.isApple) { | |
| showCupertinoSheet( | |
| context: context, | |
| builder: (context) { | |
| return viewGamesSheet; | |
| }, | |
| ); | |
| } else { | |
| showGradientBottomSheet( | |
| context, | |
| builder: (context) { | |
| return Container( | |
| decoration: BoxDecoration( | |
| color: context.colorScheme.surfaceContainerHighest, | |
| ), | |
| constraints: BoxConstraints( | |
| maxHeight: context.screenHeight * 0.9, | |
| minHeight: context.screenHeight * 0.65, | |
| ), | |
| child: viewGamesSheet, | |
| ); | |
| }, | |
| ); | |
| } | |
| }, | |
| child: | |
| Container( | |
| padding: EdgeInsets.symmetric(horizontal: 10, vertical: 8), | |
| decoration: ShapeDecoration( | |
| color: context.colorScheme.surface, | |
| shape: StadiumBorder( | |
| side: BorderSide( | |
| color: context.colorScheme.outlineVariant.withValues( | |
| alpha: 0.5, | |
| ), | |
| width: 1.5, | |
| ), | |
| ), | |
| ), | |
| child: Row( | |
| spacing: 10, | |
| children: [ | |
| // negate to test code | |
| if (isLoading) ...[ | |
| Stack( | |
| children: [ | |
| CircleAvatar( | |
| radius: 15, | |
| backgroundColor: | |
| slipCount == 0 | |
| ? context.colorScheme.outlineVariant | |
| : context.colorScheme.primary, | |
| child: Transform.translate( | |
| offset: Offset(0, -2.0), | |
| child: SmoothCounter( | |
| curve: Curves.bounceOut, | |
| count: slipCount, | |
| textStyle: GoogleFonts.spaceGrotesk( | |
| fontSize: 16, | |
| color: | |
| slipCount == 0 | |
| ? context | |
| .colorScheme | |
| .onSurfaceVariant | |
| : context.colorScheme.onPrimary, | |
| fontWeight: FontWeight.w900, | |
| ), | |
| ), | |
| ), | |
| ).positionFill(), | |
| CircularProgressIndicator().withSizedBox( | |
| dimension: 35, | |
| ), | |
| ], | |
| ), | |
| ] else ...[ | |
| Container( | |
| decoration: BoxDecoration( | |
| shape: BoxShape.circle, | |
| border: Border.all( | |
| color: | |
| slipCount == 0 | |
| ? context.colorScheme.outlineVariant | |
| : context.colorScheme.primary, | |
| width: 1.5, | |
| ), | |
| ), | |
| padding: const EdgeInsets.all(3), | |
| child: CircleAvatar( | |
| radius: 15, | |
| backgroundColor: | |
| slipCount == 0 | |
| ? context.colorScheme.outlineVariant | |
| : context.colorScheme.primary, | |
| child: Transform.translate( | |
| offset: Offset(0, -2.0), | |
| child: SmoothCounter( | |
| curve: Curves.bounceOut, | |
| count: slipCount, | |
| textStyle: GoogleFonts.spaceGrotesk( | |
| fontSize: 16, | |
| color: | |
| slipCount == 0 | |
| ? context | |
| .colorScheme | |
| .onSurfaceVariant | |
| : context.colorScheme.onPrimary, | |
| fontWeight: FontWeight.w900, | |
| ), | |
| ), | |
| ), | |
| ), | |
| ), | |
| ], | |
| AnimatedDefaultTextStyle( | |
| duration: const Duration(milliseconds: 300), | |
| curve: Curves.bounceOut, | |
| style: GoogleFonts.spaceGrotesk( | |
| fontSize: 14, | |
| color: | |
| slipCount == 0 | |
| ? context.colorScheme.outlineVariant | |
| : context.colorScheme.onSurfaceVariant, | |
| fontWeight: FontWeight.bold, | |
| ), | |
| child: Text( | |
| pluralizeWithFormat( | |
| slipCount, | |
| "Game", | |
| "Added", | |
| displayCount: false, | |
| ), | |
| ), | |
| ).withSizedBox(width: 100), | |
| ], | |
| ), | |
| ).intrinsicWidth, | |
| ), | |
| ), | |
| ); | |
| }, | |
| ); | |
| } | |
| } | |
| class ViewCustomGamesSheet extends StatefulWidget { | |
| const ViewCustomGamesSheet({super.key}); | |
| @override | |
| State<ViewCustomGamesSheet> createState() => _ViewCustomGamesSheetState(); | |
| } | |
| class _ViewCustomGamesSheetState extends State<ViewCustomGamesSheet> | |
| with | |
| ReferralService, | |
| RequestHandlerMixin<ViewCustomGamesSheet, UserReferralStat> { | |
| final GlobalKey _shareKey = GlobalKey(); | |
| @override | |
| void initState() { | |
| super.initState(); | |
| handleRequest( | |
| eventName: "get-referral-stat", | |
| requestFunction: getReferralStat, | |
| ); | |
| } | |
| VoidCallback? get onShare { | |
| final bool hasCode = data?.data?.code != null; | |
| final bool hasBets = betBuilderController.items?.isNotEmpty ?? false; | |
| if (!hasCode && !hasBets) return null; | |
| return () async { | |
| await toImage( | |
| key: _shareKey, | |
| text: | |
| "Locked in my football predictions on Playcope! Think I've got a winner?", | |
| ); | |
| }; | |
| } | |
| @override | |
| Widget build(BuildContext context) { | |
| final customBets = betBuilderController; | |
| return Stack( | |
| children: [ | |
| ClipRect( | |
| clipBehavior: Clip.antiAlias, | |
| child: OverflowBox( | |
| maxWidth: double.infinity, | |
| maxHeight: double.infinity, | |
| child: | |
| RepaintBoundary( | |
| key: _shareKey, | |
| child: ShareGamesCard( | |
| slips: customBets.slips, | |
| risk: "low", | |
| referralCode: data?.data?.code ?? "--", | |
| ), | |
| ).centered, | |
| ), | |
| ), | |
| Material( | |
| child: Visibility( | |
| visible: true, | |
| child: Column( | |
| children: [ | |
| SlipsSheetHeader( | |
| disabled: customBets.count == 0, | |
| title: "Games", | |
| slipCount: customBets.count, | |
| ).withPadding(horizontal: 14, vertical: 10), | |
| ListView.separated( | |
| itemCount: customBets.items?.length ?? 0, | |
| padding: EdgeInsets.symmetric(horizontal: 14, vertical: 10), | |
| separatorBuilder: (_, _) => YBox(10), | |
| itemBuilder: (_, index) { | |
| final slip = customBets.items?[index]; | |
| return SwipeActionWidget( | |
| onSwipeAction: () async { | |
| // | |
| }, | |
| showInstructions: false, | |
| actionIcon: IconsaxPlusBold.trash, | |
| child: AdviceTile( | |
| hasBeenSwiped: false, | |
| slipInfoItem: SlipInfoItem( | |
| matchId: slip?.id, | |
| advice: slip?.advice, | |
| homeScore: slip?.homeScore, | |
| awayScore: slip?.awayScore, | |
| awayTeamFlag: slip?.awayTeamLogo, | |
| awayTeamName: slip?.awayTeamName, | |
| homeTeamFlag: slip?.homeTeamLogo, | |
| homeTeamName: slip?.homeTeamName, | |
| fixtureId: slip?.fixtureId, | |
| leagueName: slip?.leagueName, | |
| startsOn: slip?.fixtureDatetime, | |
| entered: slip?.entered, | |
| ), | |
| ), | |
| ); | |
| }, | |
| ).expanded, | |
| Divider( | |
| height: 0, | |
| color: context.colorScheme.onSurfaceVariant.withValues( | |
| alpha: 0.2, | |
| ), | |
| ), | |
| Padding( | |
| padding: EdgeInsets.symmetric( | |
| vertical: context.isApple ? 0 : 20, | |
| horizontal: 14, | |
| ).copyWith(top: 10), | |
| child: Row( | |
| spacing: 10, | |
| children: [ | |
| OutlinedButton.icon( | |
| style: OutlinedButton.styleFrom( | |
| textStyle: context.textTheme.labelLarge?.copyWith( | |
| fontWeight: FontWeight.bold, | |
| ), | |
| side: BorderSide( | |
| color: | |
| requestState.isLoading | |
| ? context.colorScheme.outlineVariant | |
| : context.colorScheme.primary, | |
| ), | |
| shape: RoundedSuperellipseBorder( | |
| borderRadius: BorderRadius.circular(8), | |
| ), | |
| ), | |
| onPressed: onShare, | |
| icon: Icon(IconsaxPlusBold.receipt_2), | |
| label: Text("Share Prediction"), | |
| ).withSizedBox(height: 50).expanded, | |
| FilledButton( | |
| onPressed: customBets.save, | |
| style: FilledButton.styleFrom( | |
| textStyle: context.textTheme.labelLarge?.copyWith( | |
| fontWeight: FontWeight.bold, | |
| ), | |
| shape: RoundedSuperellipseBorder( | |
| borderRadius: BorderRadius.circular(8), | |
| ), | |
| ), | |
| child: Text("Save"), | |
| ).withSizedBox(height: 50).expanded, | |
| ], | |
| ), | |
| ).withSafeArea(top: false), | |
| ], | |
| ), | |
| ), | |
| ), | |
| ], | |
| ); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment