fix
Some checks are pending
Web App CI / test (push) Waiting to run
Web App CI / build (push) Blocked by required conditions
Deploy Mnemo Cards / Deploy Backend (push) Waiting to run
Deploy Mnemo Cards / Deploy Web App (push) Blocked by required conditions
Deploy Mnemo Cards / Final Verification (push) Blocked by required conditions
Some checks are pending
Web App CI / test (push) Waiting to run
Web App CI / build (push) Blocked by required conditions
Deploy Mnemo Cards / Deploy Backend (push) Waiting to run
Deploy Mnemo Cards / Deploy Web App (push) Blocked by required conditions
Deploy Mnemo Cards / Final Verification (push) Blocked by required conditions
This commit is contained in:
parent
99100deb20
commit
a71f265a8e
8 changed files with 174 additions and 150 deletions
|
|
@ -37,6 +37,11 @@ class UserScopeContainer extends ChildScopeContainer<UserScopeParent>
|
|||
implements UserScope {
|
||||
UserScopeContainer({required super.parent});
|
||||
|
||||
@override
|
||||
List<Set<AsyncDep<dynamic>>> get initializeQueue => [
|
||||
{purchaseEventBroadcasterDep},
|
||||
];
|
||||
|
||||
// State Manager for user state
|
||||
late final userStateManagerDep = dep(() => UserStateManager());
|
||||
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -142,7 +142,7 @@ class _InputLettersWidgetState extends State<InputLettersWidget> {
|
|||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
// Image display (if available)
|
||||
if (widget.question.image != null) ...[
|
||||
if (widget.question.image != null && false) ...[
|
||||
SizedBox(
|
||||
height: imageHeight,
|
||||
child: Center(
|
||||
|
|
|
|||
|
|
@ -192,107 +192,105 @@ class _MatrixWidgetState extends State<MatrixWidget>
|
|||
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) {
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
|||
Loading…
Reference in a new issue