import 'dart:async'; import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:mnemo_cards/features/tests/progress_widget.dart'; import 'package:mnemo_cards/main.dart'; import 'package:mnemo_cards/managers/audio_player.dart'; import 'package:mnemo_cards/theme/themes.dart'; import 'package:mnemo_cards/utils/color_helper.dart'; import 'package:mnemo_cards_common/mnemo_cards_common.dart'; import 'package:rxdart/rxdart.dart'; import '../../di/locator.dart'; import '../../features/card_flipper/flip_card_controllers.dart'; import '../../features/card_swiper/flutter_card_swiper.dart'; import 'card_game_main.dart'; @RoutePage() class CardGamePage extends StatefulWidget { final int? startCardId; final List cards; final Color? color; final bool infinite; final bool shuffle; const CardGamePage({ required this.cards, required this.color, this.startCardId, this.infinite = false, this.shuffle = true, super.key, }); @override State createState() => _CardGamePageState(); } class _CardGamePageState extends State { final CardSwiperController cardSwiperController = CardSwiperController(); final FlipCardController flipCardController = FlipCardController(); StreamSubscription? _sub; List shuffledCards = []; GameCardDto? get activeCard { final index = cardSwiperController.currentIndex; if (index >= 0) { return shuffledCards[index % shuffledCards.length]; } return null; } int get gameLength => widget.infinite ? 10000000 : shuffledCards.length; void playSound(int index) { if (globalSharedPreferences.getBool('auto_play_sound_view') == true) { final text = activeCard?.original; if (text != null) { AudioPlayer.playAudio(text, lang: 'es-ES'); } } } @override Widget build(BuildContext context) { // todo move to controller // final timer = Stream.periodic(Duration(seconds: 1), (tick) { // return Duration(seconds: tick + 1); // }).asBroadcastStream().take(3600).startWith(Duration.zero); return Scaffold( body: PopScope( child: SafeArea( child: LayoutBuilder(builder: (context, constraints) { return Column( children: [ Expanded( child: LayoutBuilder( builder: (context, constraints) { final aspectRatio = constraints.maxHeight / constraints.maxWidth; return Column( children: [ if (aspectRatio > 14 / 9) SizedBox( height: (64.h - 20.h - MediaQuery.of(context).padding.top) / 2, ), if (aspectRatio > 14 / 9) Padding( padding: EdgeInsets.symmetric(horizontal: 10.w), child: StreamBuilder( stream: cardSwiperController.asStream, builder: (context, snapshot) { if (!snapshot.hasData) { return SizedBox( height: 30, ); } return ProgressWidget( widget.infinite ? null : List.filled( cardSwiperController.progress, Result.correct, ), shuffledCards.length, widget.color ?? borderGray, popText: widget.infinite ? 'к теме' : null, key: ValueKey('CARDS PROGRESS'), ); }, ), ), if (aspectRatio > 14 / 9) SizedBox( height: (64.h - 20.h - MediaQuery.of(context).padding.top) / 2, ), Expanded( child: Stack( children: [ CardGameMainWidget( shuffledCards, widget.color, widget.startCardId, cardSwiperController, flipCardController, gameLength, ), if (aspectRatio <= 14 / 9) Align( alignment: Alignment.topLeft, child: IconButton( onPressed: AutoRouter.of(context).maybePop, icon: Icon( Icons.arrow_back_ios, color: Colors.grey[400], ), ), ) ], ), ), ], ); }, ), ), if (constraints.maxHeight / constraints.maxWidth > 17 / 9) Hero( tag: 'bottom', createRectTween: (a, b) => RectTween(begin: a, end: b), child: Material( color: Colors.transparent, child: StreamBuilder( stream: cardSwiperController.asStream, builder: (context, snapshot) { return AnimatedContainer( duration: Duration(milliseconds: 200), height: activeCard == null ? 0 : 90.h, padding: EdgeInsets.only( left: 10.0.w, right: 10.0.w, bottom: 10.0.h, top: 10.0.h, ), child: Row( children: [ Expanded( flex: 1, child: GestureDetector( onTap: () async { if (activeCard != null) await locator.favoriteCardsController .switchFavoriteCard(activeCard!); }, child: StreamBuilder( stream: locator .favoriteCardsController.asStream, initialData: locator .favoriteCardsController.state, builder: (context, snapshot) { return Container( alignment: Alignment.center, decoration: BoxDecoration( color: Theme.of(context) .scaffoldBackgroundColor .lighten(0.05), border: Border.all( color: borderGray), borderRadius: BorderRadius.circular(16.0), ), padding: EdgeInsets.all(10.0.w), child: Image.asset( locator.favoriteCardsController .isFavoriteCard( activeCard?.id, ) ? "icons/heart_fill.png" : "icons/heart.png", width: 29.w, height: 29.h, color: locator .favoriteCardsController .isFavoriteCard( activeCard?.id, ) ? Colors.red : Colors.grey, ), ); }), ), ), SizedBox( width: 10.0.w, ), Expanded( flex: 3, child: InkWell( onTap: () async { cardSwiperController.swipe( direction: CardSwiperState.swipeLeft, ); }, child: Container( alignment: Alignment.center, decoration: BoxDecoration( color: Theme.of(context) .scaffoldBackgroundColor .lighten(0.05), border: Border.all(color: borderGray), borderRadius: BorderRadius.circular(16.0), ), padding: EdgeInsets.all(10.0.w), child: Text( 'Дальше', style: TextStyle( fontSize: 25.sp, fontWeight: FontWeight.w700, height: 0.85, ), ), ), ), ), ], ), ); }), ), ) ], ); }), ), ), ); } @override void initState() { super.initState(); shuffledCards = widget.cards.toList(); if (widget.shuffle) { shuffledCards..shuffle(); } if (widget.startCardId != null) { final startCardIndex = shuffledCards.indexWhere( (card) => card.id == widget.startCardId, ); if (startCardIndex >= 0) { shuffledCards = [ ...shuffledCards.sublist(startCardIndex), ...shuffledCards.sublist(0, startCardIndex), ]; } else { shuffledCards = []; } } else { shuffledCards = widget.cards.toList(); } _sub = cardSwiperController.asStream.distinct().listen(playSound); } @override void dispose() { _sub?.cancel().then((_) => _sub = null); // cardSwiperController.removeListener(cardSwiperListener); cardSwiperController.dispose(); super.dispose(); } }