diff --git a/mnemo_cards_web_v2/lib/di/user_scope/user_scope_container.dart b/mnemo_cards_web_v2/lib/di/user_scope/user_scope_container.dart index c5d2edc..d0c8b5b 100644 --- a/mnemo_cards_web_v2/lib/di/user_scope/user_scope_container.dart +++ b/mnemo_cards_web_v2/lib/di/user_scope/user_scope_container.dart @@ -37,6 +37,11 @@ class UserScopeContainer extends ChildScopeContainer implements UserScope { UserScopeContainer({required super.parent}); + @override + List>> get initializeQueue => [ + {purchaseEventBroadcasterDep}, + ]; + // State Manager for user state late final userStateManagerDep = dep(() => UserStateManager()); diff --git a/mnemo_cards_web_v2/lib/domain/services/game_session_manager.dart b/mnemo_cards_web_v2/lib/domain/services/game_session_manager.dart index 2452c3b..f3495e5 100644 --- a/mnemo_cards_web_v2/lib/domain/services/game_session_manager.dart +++ b/mnemo_cards_web_v2/lib/domain/services/game_session_manager.dart @@ -231,14 +231,31 @@ class GameSessionManager { if (answer is! String) return false; // Remove spaces from answer - final answerNoSpaces = answer.replaceAll(' ', '').toLowerCase(); - final correctNoSpaces = question.correctAnswer.replaceAll(' ', '').toLowerCase(); + final answerNoSpaces = answer.replaceAll(' ', ''); + + final template = question.template; + final expectedAnswer = StringBuffer(); + int answerLetterIndex = 0; + + for (int i = 0; i < template.length && answerLetterIndex < answerNoSpaces.length; i++) { + final templateChar = template[i]; + if (templateChar == '_' || templateChar == '|') { + // This is a slot - use the corresponding letter from correct answer + final correctChar = answerNoSpaces[answerLetterIndex]; + if (templateChar == '|') { + // Uppercase slot - expect uppercase + expectedAnswer.write(correctChar.toUpperCase()); + } else { + // Lowercase slot - expect lowercase + expectedAnswer.write(correctChar.toLowerCase()); + } + answerLetterIndex++; + } + // Skip other characters in template (visible letters, spaces) + } - // If lengths don't match, answer is wrong - if (answerNoSpaces.length != correctNoSpaces.length) return false; - // Compare user answer with expected answer (case-sensitive for uppercase slots) - return answerNoSpaces == question.correctAnswer; + return answerNoSpaces.toLowerCase() == expectedAnswer.toString().toLowerCase(); } bool _validateMatch(MatchQuestion question, dynamic answer) { diff --git a/mnemo_cards_web_v2/lib/presentation/widgets/card_flipper/card_flipper.dart b/mnemo_cards_web_v2/lib/presentation/widgets/card_flipper/card_flipper.dart index 9afbd70..ba4da06 100644 --- a/mnemo_cards_web_v2/lib/presentation/widgets/card_flipper/card_flipper.dart +++ b/mnemo_cards_web_v2/lib/presentation/widgets/card_flipper/card_flipper.dart @@ -825,7 +825,7 @@ class _CardSide extends StatelessWidget { 'Нет мнемоники', style: TextStyle( fontSize: 18, - fontWeight: FontWeight.w400, + fontWeight: FontWeight.w700, color: colorScheme.onSurface.withOpacity(0.38), ), textAlign: TextAlign.center, diff --git a/mnemo_cards_web_v2/lib/presentation/widgets/card_viewer.dart b/mnemo_cards_web_v2/lib/presentation/widgets/card_viewer.dart index b2f5d87..871da52 100644 --- a/mnemo_cards_web_v2/lib/presentation/widgets/card_viewer.dart +++ b/mnemo_cards_web_v2/lib/presentation/widgets/card_viewer.dart @@ -398,24 +398,27 @@ class _CardSide extends StatelessWidget { return Hero( tag: 'card_${card.id}', - child: Container( - width: cardWidth, - height: cardHeight, - decoration: BoxDecoration( - color: colorScheme.surface, - borderRadius: BorderRadius.circular(24), - border: Border.all(color: packColor, width: 3), - boxShadow: [ - BoxShadow( - color: colorScheme.shadow.withOpacity(0.3), - blurRadius: 20, - offset: const Offset(0, 10), - ), - ], - ), - child: ClipRRect( - borderRadius: BorderRadius.circular(21), - child: isFront ? _buildFrontLayout() : _buildBackLayout(), + child: Material( + color: Colors.transparent, + child: Container( + width: cardWidth, + height: cardHeight, + decoration: BoxDecoration( + color: colorScheme.surface, + borderRadius: BorderRadius.circular(24), + border: Border.all(color: packColor, width: 3), + boxShadow: [ + BoxShadow( + color: colorScheme.shadow.withOpacity(0.3), + blurRadius: 20, + offset: const Offset(0, 10), + ), + ], + ), + child: ClipRRect( + borderRadius: BorderRadius.circular(21), + child: isFront ? _buildFrontLayout() : _buildBackLayout(), + ), ), ), ); @@ -622,7 +625,7 @@ class _CardSide extends StatelessWidget { card.original!, style: TextStyle( fontSize: 24, - fontWeight: FontWeight.w400, + fontWeight: FontWeight.w700, color: colorScheme.onSurface, ), textAlign: TextAlign.center, diff --git a/mnemo_cards_web_v2/lib/presentation/widgets/game/answer_options.dart b/mnemo_cards_web_v2/lib/presentation/widgets/game/answer_options.dart index 625c2f7..32cefb6 100644 --- a/mnemo_cards_web_v2/lib/presentation/widgets/game/answer_options.dart +++ b/mnemo_cards_web_v2/lib/presentation/widgets/game/answer_options.dart @@ -301,7 +301,7 @@ class AnswerOptions extends StatelessWidget { duration: const Duration(milliseconds: 300), style: Theme.of(context).textTheme.bodySmall!.copyWith( color: textColor, - fontWeight: isSelected ? FontWeight.w600 : FontWeight.normal, + fontWeight: FontWeight.bold, ), child: Text( text, @@ -320,9 +320,7 @@ class AnswerOptions extends StatelessWidget { duration: const Duration(milliseconds: 300), style: Theme.of(context).textTheme.bodyLarge!.copyWith( color: textColor, - fontWeight: isSelected || (isAnswerSubmitted && isCorrectOption) - ? FontWeight.w600 - : FontWeight.normal, + fontWeight: FontWeight.bold, fontSize: isSelected ? 17 : 16, ), child: Text( diff --git a/mnemo_cards_web_v2/lib/presentation/widgets/game/input_letters_widget.dart b/mnemo_cards_web_v2/lib/presentation/widgets/game/input_letters_widget.dart index 07f27de..dd2154e 100644 --- a/mnemo_cards_web_v2/lib/presentation/widgets/game/input_letters_widget.dart +++ b/mnemo_cards_web_v2/lib/presentation/widgets/game/input_letters_widget.dart @@ -142,7 +142,7 @@ class _InputLettersWidgetState extends State { mainAxisSize: MainAxisSize.min, children: [ // Image display (if available) - if (widget.question.image != null) ...[ + if (widget.question.image != null && false) ...[ SizedBox( height: imageHeight, child: Center( diff --git a/mnemo_cards_web_v2/lib/presentation/widgets/game/matrix_widget.dart b/mnemo_cards_web_v2/lib/presentation/widgets/game/matrix_widget.dart index 0d97b5b..06f17fd 100644 --- a/mnemo_cards_web_v2/lib/presentation/widgets/game/matrix_widget.dart +++ b/mnemo_cards_web_v2/lib/presentation/widgets/game/matrix_widget.dart @@ -192,107 +192,105 @@ class _MatrixWidgetState extends State final targetPaddingH = 20.w; final targetPaddingV = 16.h; - return Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Expanded( - child: LayoutBuilder( - builder: (context, constraints) { - // Calculate the grid size needed - final availableWidth = constraints.maxWidth; - final availableHeight = constraints.maxHeight; + return Column( + mainAxisSize: MainAxisSize.max, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Expanded( + child: LayoutBuilder( + builder: (context, constraints) { + // Calculate the grid size needed + final availableWidth = constraints.maxWidth; + final availableHeight = constraints.maxHeight; - // Calculate grid dimensions including spacing - final totalSpacingWidth = (size - 1) * cellSpacing; - final totalSpacingHeight = (size - 1) * cellSpacing; - final gridWidthNeeded = availableWidth - totalSpacingWidth; - final gridHeightNeeded = availableHeight - totalSpacingHeight; + // Calculate grid dimensions including spacing + final totalSpacingWidth = (size - 1) * cellSpacing; + final totalSpacingHeight = (size - 1) * cellSpacing; + final gridWidthNeeded = availableWidth - totalSpacingWidth; + final gridHeightNeeded = availableHeight - totalSpacingHeight; - // Calculate cell size based on available space - final cellWidthByWidth = gridWidthNeeded / size; - final cellHeightByHeight = gridHeightNeeded / size; + // Calculate cell size based on available space + final cellWidthByWidth = gridWidthNeeded / size; + final cellHeightByHeight = gridHeightNeeded / size; - // Use the smaller dimension to ensure everything fits - final cellSize = - math.min(cellWidthByWidth, cellHeightByHeight); + // Use the smaller dimension to ensure everything fits + final cellSize = + math.min(cellWidthByWidth, cellHeightByHeight); - // Calculate actual grid size - final actualGridWidth = - cellSize * size + totalSpacingWidth; - final actualGridHeight = - cellSize * size + totalSpacingHeight; + // Calculate actual grid size + final actualGridWidth = + cellSize * size + totalSpacingWidth; + final actualGridHeight = + cellSize * size + totalSpacingHeight; - // Calculate scale to fit if needed - final scaleX = availableWidth / actualGridWidth; - final scaleY = availableHeight / actualGridHeight; - final scale = math.min(1.0, math.min(scaleX, scaleY)); + // Calculate scale to fit if needed + final scaleX = availableWidth / actualGridWidth; + final scaleY = availableHeight / actualGridHeight; + final scale = math.min(1.0, math.min(scaleX, scaleY)); - return Center( - child: Transform.scale( - scale: scale, - child: SizedBox( - width: actualGridWidth, - height: actualGridHeight, - child: GridView.builder( - physics: const NeverScrollableScrollPhysics(), - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: size, - crossAxisSpacing: cellSpacing, - mainAxisSpacing: cellSpacing, - childAspectRatio: 1.0, - ), - itemCount: total, - itemBuilder: (context, index) { - final card = slots[index]; - return _buildSlot(context, card); - }, + return Center( + child: Transform.scale( + scale: scale, + child: SizedBox( + width: actualGridWidth, + height: actualGridHeight, + child: GridView.builder( + physics: const NeverScrollableScrollPhysics(), + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: size, + crossAxisSpacing: cellSpacing, + mainAxisSpacing: cellSpacing, + childAspectRatio: 1.0, ), + itemCount: total, + itemBuilder: (context, index) { + final card = slots[index]; + return _buildSlot(context, card); + }, ), ), - ); - }, + ), + ); + }, + ), + ), + SizedBox(height: spacingBetween), + Align( + alignment: Alignment.center, + child: Container( + alignment: Alignment.center, + padding: EdgeInsets.symmetric( + horizontal: targetPaddingH, + vertical: targetPaddingV, + ), + decoration: BoxDecoration( + color: colorScheme.surface, + borderRadius: BorderRadius.circular(24.r), + border: Border.all(color: colorScheme.primary, width: 3), + ), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + if (widget.question.text != null && + widget.question.text!.isNotEmpty) + Text( + widget.question.text!, + style: textTheme.labelLarge?.copyWith( + color: colorScheme.onSurfaceVariant, + ), + textAlign: TextAlign.center, + ), + if (widget.question.text != null && + widget.question.text!.isNotEmpty) + SizedBox(height: 8.h), + _buildTargetContent(context), + ], ), ), - SizedBox(height: spacingBetween), - Align( - alignment: Alignment.center, - child: Container( - alignment: Alignment.center, - padding: EdgeInsets.symmetric( - horizontal: targetPaddingH, - vertical: targetPaddingV, - ), - decoration: BoxDecoration( - color: colorScheme.surface, - borderRadius: BorderRadius.circular(24.r), - border: Border.all(color: colorScheme.primary, width: 3), - - ), - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - if (widget.question.text != null && - widget.question.text!.isNotEmpty) - Text( - widget.question.text!, - style: textTheme.labelLarge?.copyWith( - color: colorScheme.onSurfaceVariant, - ), - textAlign: TextAlign.center, - ), - if (widget.question.text != null && - widget.question.text!.isNotEmpty) - SizedBox(height: 8.h), - _buildTargetContent(context), - ], - ), - ), - ), - ], - ), - ); + ), + ], + ); } Widget _buildTargetContent(BuildContext context) { diff --git a/mnemo_cards_web_v2/lib/presentation/widgets/pack_card_item.dart b/mnemo_cards_web_v2/lib/presentation/widgets/pack_card_item.dart index 31fdd74..57eb91c 100644 --- a/mnemo_cards_web_v2/lib/presentation/widgets/pack_card_item.dart +++ b/mnemo_cards_web_v2/lib/presentation/widgets/pack_card_item.dart @@ -85,35 +85,38 @@ class PackCardItem extends StatelessWidget { }, child: Hero( tag: 'card_${card.id}', - child: Container( - key: ValueKey('$cardRootKeyPrefix${card.id}'), - alignment: Alignment.center, - decoration: BoxDecoration( - color: Theme.of(context).scaffoldBackgroundColor, - border: Border.all(color: color.withOpacity(0.3), width: 1), - borderRadius: BorderRadius.circular(8), - boxShadow: [ - BoxShadow( - color: Theme.of( - context, - ).colorScheme.primary.withOpacity(0.05), - blurRadius: 2.0, - ), - ], - ), - clipBehavior: Clip.antiAlias, - child: Stack( - fit: StackFit.expand, - children: [ - hasImage - ? _buildCardWithImage(context) - : _buildCardTextOnly(context), - Positioned( - top: 4, - right: 4, - child: _buildFavoriteButton(context), - ), - ], + child: Material( + color: Colors.transparent, + child: Container( + key: ValueKey('$cardRootKeyPrefix${card.id}'), + alignment: Alignment.center, + decoration: BoxDecoration( + color: Theme.of(context).scaffoldBackgroundColor, + border: Border.all(color: color.withOpacity(0.3), width: 1), + borderRadius: BorderRadius.circular(8), + boxShadow: [ + BoxShadow( + color: Theme.of( + context, + ).colorScheme.primary.withOpacity(0.05), + blurRadius: 2.0, + ), + ], + ), + clipBehavior: Clip.antiAlias, + child: Stack( + fit: StackFit.expand, + children: [ + hasImage + ? _buildCardWithImage(context) + : _buildCardTextOnly(context), + Positioned( + top: 4, + right: 4, + child: _buildFavoriteButton(context), + ), + ], + ), ), ), ),