import 'dart:math'; import 'package:collection/collection.dart'; import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:mnemo_cards/widgets/fade_in_widget.dart'; import 'package:mnemo_cards_common/mnemo_cards_common.dart'; import 'package:yandex_mobileads/mobile_ads.dart'; import '../../domain/router/app_router.gr.dart'; import '../../features/analytics/analytics.dart'; import '../../features/yandex_ads/yandex_ads.dart'; import '../../di/locator.dart'; import '../../theme/themes.dart'; import 'card_pack_header.dart'; import 'package:mnemo_cards/utils/string_helper.dart'; import 'cards_view.dart'; import 'cards_view_controller.dart'; final _mainScrollController = ScrollController(); class AvailablePack extends StatelessWidget { final CardPackDto cardPack; late final CardsViewController _cardsViewController = CardsViewController(cardPack); AvailablePack(this.cardPack); @override Widget build(BuildContext context) { Analytics.availablePackOpened(cardPack); return Column( children: [ CardPackHeader( cardPack.title, cardPack.subtitle, Colors.transparent, ), Expanded( child: RefreshIndicator( onRefresh: () => locator.packUpdater.updatePackAndSaveImages(cardPack.id), backgroundColor: Colors.white, color: cardPack.color?.asColor ?? Colors.black, child: ListView( physics: BouncingScrollPhysics( decelerationRate: ScrollDecelerationRate.fast, parent: AlwaysScrollableScrollPhysics()), controller: _mainScrollController, children: [ StatefulBuilder(builder: (context, setState) { return Column( children: [ Container( height: 1, color: cardPack.color?.asColor ?? Colors.grey.withOpacity(0.5), ), Container( decoration: BoxDecoration( color: cardPack.color?.asColor?.withOpacity(0.1), ), alignment: Alignment.center, clipBehavior: Clip.antiAlias, child: CardsView(_cardsViewController, cardPack), ), Container( height: 1, color: cardPack.color?.asColor ?? Colors.grey.withOpacity(0.5), ), SizedBox( height: 10.h, ), Padding( padding: EdgeInsets.symmetric( horizontal: 10.w, ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ StreamBuilder( stream: _cardsViewController.asStream, builder: (context, snapshot) { return AnimatedRotation( duration: Duration(milliseconds: 300), turns: (snapshot.data?.expanded ?? false) ? 0.5 : 0.0, child: _Button( 'down.png', () async { if (snapshot.hasData) { _cardsViewController.setExpanded( !snapshot.requireData.expanded, ); } }, ), ); }), _Button('shuffle.png', () async { final cards = _cardsViewController.state.packCards; if (cards.isEmpty) return; final index = (_cardsViewController.offsetCards + Random().nextInt( (cards.length / 2).ceil(), ) + 3) % cards.length; await _cardsViewController.animateTo(index); AutoRouter.of(context).push( PageRouteInfo( CardGamePage.name, args: CardGamePageArgs( cards: cards, color: cardPack.color?.asColor, startCardId: cards[index].id, infinite: true, shuffle: true, // id: cardPack.dto.id.toString(), ), ), ); }), // _Button('chat.png', () {}), StreamBuilder( stream: _cardsViewController.asStream, builder: (context, snapshot) { return _Button( (snapshot.data?.favorite ?? false) ? 'heart_fill.png' : 'heart.png', () { if (snapshot.hasData) { _cardsViewController.setFavorite( !snapshot.requireData.favorite, ); } }); }), ], ), ), ], ); }), _AdTile(), _TestsSection(cardPack.id.toString()), // _TestButton( // title: 'Быстрый тест', // subtitle: 'Лучший результат: 99 / 100', // time: '3', // timeSubtitle: 'мин', // onTap: () {}, // ), // _TestButton( // title: 'Полный тест', // subtitle: 'Лучший результат: 99 / 100', // time: '10', // timeSubtitle: 'мин', // onTap: () {}, // ), ], ), ), ), Hero( tag: 'bottom', child: SizedBox( height: 0, width: 300.w, ), ), ], ); } } class _TestsSection extends StatelessWidget { final String packId; const _TestsSection(this.packId); @override Widget build(BuildContext context) { return StreamBuilder( stream: locator.testManager.loadTestsStream(packId: packId), builder: (context, snapshot) { return Column( children: [ if (snapshot.hasData) ...snapshot.data!.mapIndexed( (int index, TestDto dto) => FadeInWidget( delay: Duration(milliseconds: index * 200), animationDuration: const Duration(milliseconds: 200), child: _TestButton( title: dto.name, subtitle: null, time: dto.time, timeSubtitle: dto.timeSubtitle, onTap: () { AutoRouter.of(context).push( PageRouteInfo(TestPage.name, args: TestPageArgs(testId: dto.id!)), ); }, ), ), ), ], ); }, ); } } class _AdTile extends StatelessWidget { const _AdTile({super.key}); @override Widget build(BuildContext context) { final theme = Theme.of(context).textTheme; return LayoutBuilder(builder: (context, constraints) { final banner = YandexAds.createBanner( BoxConstraints.tight(Size(constraints.maxWidth - 16, 80 - 8))); return FadeInWidget( future: banner.loadAd(), animationDuration: Duration(milliseconds: 1000), child: Container( height: 80, margin: const EdgeInsets.symmetric(vertical: 4.0, horizontal: 8.0), decoration: BoxDecoration( border: Border.all( color: Colors.white, width: 4.0, ), borderRadius: BorderRadius.circular(12.0), ), child: Center( child: AdWidget(bannerAd: banner), ), ), ); }); } } class _Button extends StatelessWidget { final String asset; final VoidCallback onTap; _Button(this.asset, this.onTap, {super.key}); @override Widget build(BuildContext context) { return InkWell( onTap: onTap, child: Container( width: 110.w, height: 60.h, decoration: BoxDecoration( color: Colors.white, border: Border.all(color: borderGray), borderRadius: BorderRadius.circular(16.0), ), alignment: Alignment.center, child: Image.asset( 'icons/$asset', width: 29.w, // height: 29.h, fit: BoxFit.scaleDown, ), ), ); } } class _TestButton extends StatelessWidget { final VoidCallback onTap; final String title; final String? subtitle; final String? time; final String? timeSubtitle; _TestButton({ required this.title, required this.onTap, this.subtitle, this.time, this.timeSubtitle, }); @override Widget build(BuildContext context) { return Padding( padding: EdgeInsets.symmetric( vertical: 5.0.h, horizontal: 10.w, ), child: InkWell( onTap: onTap, child: Container( height: 120.h, decoration: BoxDecoration( color: Colors.white, border: Border.all(color: borderGray), borderRadius: BorderRadius.circular(16.0), ), padding: EdgeInsets.only( top: 12.0.h, left: 10.0.w, right: 10.0.w, bottom: 20.h, ), child: Row( children: [ Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( title, style: TextStyle( fontSize: 25.sp, fontWeight: FontWeight.w500, height: 0.85, ), ), if (subtitle != null) Text( subtitle!, style: TextStyle( fontSize: 16.sp, fontWeight: FontWeight.w300, height: 0.85, ), ), ], ), ), Container( width: 75.w, child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ if (time != null) Text( time!, style: TextStyle( fontSize: 40.sp, fontWeight: FontWeight.w400, height: 0.85), ), if (timeSubtitle != null) Text( timeSubtitle!, style: TextStyle( fontSize: 24.sp, fontWeight: FontWeight.w400, height: 0.85), ), ], ), ), ], ), ), ), ); } }