Skip to content
Snippets Groups Projects
Commit b3636fde authored by Benoît Harrault's avatar Benoît Harrault
Browse files

Normalize game architecture

parent 4ea0fb08
Branches
Tags
1 merge request!33Resolve "Normalize game architecture"
Pipeline #5696 passed
Showing
with 1219 additions and 0 deletions
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
class AppHeader extends StatelessWidget {
const AppHeader({super.key, required this.text});
final String text;
@override
Widget build(BuildContext context) {
return Text(
tr(text),
textAlign: TextAlign.start,
style: Theme.of(context).textTheme.headlineMedium!.apply(fontWeightDelta: 2),
);
}
}
class AppTitle extends StatelessWidget {
const AppTitle({super.key, required this.text});
final String text;
@override
Widget build(BuildContext context) {
return Text(
tr(text),
textAlign: TextAlign.start,
style: Theme.of(context).textTheme.titleLarge!.apply(fontWeightDelta: 2),
);
}
}
import 'package:flutter/material.dart';
import 'package:momomotus/utils/color_extensions.dart';
class OutlinedText extends StatelessWidget {
const OutlinedText({
super.key,
required this.text,
required this.fontSize,
required this.textColor,
this.outlineColor,
});
final String text;
final double fontSize;
final Color textColor;
final Color? outlineColor;
@override
Widget build(BuildContext context) {
final double delta = fontSize / 30;
return Text(
text,
style: TextStyle(
inherit: true,
fontSize: fontSize,
fontWeight: FontWeight.w600,
color: textColor,
shadows: [
Shadow(
offset: Offset(-delta, -delta),
color: outlineColor ?? textColor.darken(),
),
Shadow(
offset: Offset(delta, -delta),
color: outlineColor ?? textColor.darken(),
),
Shadow(
offset: Offset(delta, delta),
color: outlineColor ?? textColor.darken(),
),
Shadow(
offset: Offset(-delta, delta),
color: outlineColor ?? textColor.darken(),
),
],
),
);
}
}
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:momomotus/cubit/game_cubit.dart';
import 'package:momomotus/models/game/game.dart';
import 'package:momomotus/ui/game/game_end.dart';
import 'package:momomotus/ui/widgets/game/game_board.dart';
import 'package:momomotus/ui/widgets/game/keyboard.dart';
class GameLayout extends StatelessWidget {
const GameLayout({super.key});
@override
Widget build(BuildContext context) {
return BlocBuilder<GameCubit, GameState>(
builder: (BuildContext context, GameState gameState) {
final Game currentGame = gameState.currentGame;
return Container(
alignment: AlignmentDirectional.topCenter,
padding: const EdgeInsets.all(4),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const GameBoardWidget(),
const Expanded(child: SizedBox.shrink()),
currentGame.isFinished ? const GameEndWidget() : const KeyboardWidget(),
],
),
);
},
);
}
}
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:momomotus/config/default_game_settings.dart';
import 'package:momomotus/config/default_global_settings.dart';
import 'package:momomotus/cubit/settings_game_cubit.dart';
import 'package:momomotus/cubit/settings_global_cubit.dart';
import 'package:momomotus/ui/parameters/parameter_image.dart';
import 'package:momomotus/ui/parameters/parameter_painter.dart';
import 'package:momomotus/ui/widgets/actions/button_delete_saved_game.dart';
import 'package:momomotus/ui/widgets/actions/button_game_start_new.dart';
import 'package:momomotus/ui/widgets/actions/button_resume_saved_game.dart';
class ParametersLayout extends StatelessWidget {
const ParametersLayout({super.key, required this.canResume});
final bool canResume;
final double separatorHeight = 8.0;
@override
Widget build(BuildContext context) {
final List<Widget> lines = [];
// Game settings
for (String code in DefaultGameSettings.availableParameters) {
lines.add(Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: buildParametersLine(
code: code,
isGlobal: false,
),
));
lines.add(SizedBox(height: separatorHeight));
}
lines.add(SizedBox(height: separatorHeight));
if (canResume == false) {
// Start new game
lines.add(const Expanded(
child: StartNewGameButton(),
));
} else {
// Resume game
lines.add(const Expanded(
child: ResumeSavedGameButton(),
));
// Delete saved game
lines.add(SizedBox.square(
dimension: MediaQuery.of(context).size.width / 4,
child: const DeleteSavedGameButton(),
));
}
lines.add(SizedBox(height: separatorHeight));
// Global settings
for (String code in DefaultGlobalSettings.availableParameters) {
lines.add(Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: buildParametersLine(
code: code,
isGlobal: true,
),
));
lines.add(SizedBox(height: separatorHeight));
}
return Column(
children: lines,
);
}
List<Widget> buildParametersLine({
required String code,
required bool isGlobal,
}) {
final List<Widget> parameterButtons = [];
final List<String> availableValues = isGlobal
? DefaultGlobalSettings.getAvailableValues(code)
: DefaultGameSettings.getAvailableValues(code);
if (availableValues.length <= 1) {
return [];
}
for (String value in availableValues) {
final Widget parameterButton = BlocBuilder<GameSettingsCubit, GameSettingsState>(
builder: (BuildContext context, GameSettingsState gameSettingsState) {
return BlocBuilder<GlobalSettingsCubit, GlobalSettingsState>(
builder: (BuildContext context, GlobalSettingsState globalSettingsState) {
final GameSettingsCubit gameSettingsCubit =
BlocProvider.of<GameSettingsCubit>(context);
final GlobalSettingsCubit globalSettingsCubit =
BlocProvider.of<GlobalSettingsCubit>(context);
final String currentValue = isGlobal
? globalSettingsCubit.getParameterValue(code)
: gameSettingsCubit.getParameterValue(code);
final bool isActive = (value == currentValue);
final double displayWidth = MediaQuery.of(context).size.width;
final double itemWidth = displayWidth / availableValues.length - 26;
final bool displayedWithAssets =
DefaultGlobalSettings.displayedWithAssets.contains(code) ||
DefaultGameSettings.displayedWithAssets.contains(code);
return TextButton(
child: Container(
child: displayedWithAssets
? SizedBox.square(
dimension: itemWidth,
child: ParameterImage(
code: code,
value: value,
isSelected: isActive,
),
)
: CustomPaint(
size: Size(itemWidth, itemWidth),
willChange: false,
painter: ParameterPainter(
code: code,
value: value,
isSelected: isActive,
gameSettings: gameSettingsState.settings,
globalSettings: globalSettingsState.settings,
),
isComplex: true,
),
),
onPressed: () {
isGlobal
? globalSettingsCubit.setParameterValue(code, value)
: gameSettingsCubit.setParameterValue(code, value);
},
);
},
);
},
);
parameterButtons.add(parameterButton);
}
return parameterButtons;
}
}
import 'package:flutter/material.dart';
class ParameterImage extends StatelessWidget {
const ParameterImage({
super.key,
required this.code,
required this.value,
required this.isSelected,
});
final String code;
final String value;
final bool isSelected;
static const Color buttonBackgroundColor = Colors.white;
static const Color buttonBorderColorActive = Colors.blue;
static const Color buttonBorderColorInactive = Colors.white;
static const double buttonBorderWidth = 8.0;
static const double buttonBorderRadius = 8.0;
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
color: buttonBackgroundColor,
borderRadius: BorderRadius.circular(buttonBorderRadius),
border: Border.all(
color: isSelected ? buttonBorderColorActive : buttonBorderColorInactive,
width: buttonBorderWidth,
),
),
child: Image(
image: AssetImage('assets/ui/${code}_$value.png'),
fit: BoxFit.fill,
),
);
}
}
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:momomotus/config/default_game_settings.dart';
import 'package:momomotus/models/settings/settings_game.dart';
import 'package:momomotus/models/settings/settings_global.dart';
import 'package:momomotus/utils/tools.dart';
class ParameterPainter extends CustomPainter {
const ParameterPainter({
required this.code,
required this.value,
required this.isSelected,
required this.gameSettings,
required this.globalSettings,
});
final String code;
final String value;
final bool isSelected;
final GameSettings gameSettings;
final GlobalSettings globalSettings;
@override
void paint(Canvas canvas, Size size) {
// force square
final double canvasSize = min(size.width, size.height);
const Color borderColorEnabled = Colors.blue;
const Color borderColorDisabled = Colors.white;
// "enabled/disabled" border
final paint = Paint();
paint.style = PaintingStyle.stroke;
paint.color = isSelected ? borderColorEnabled : borderColorDisabled;
paint.strokeJoin = StrokeJoin.round;
paint.strokeWidth = 10;
canvas.drawRect(
Rect.fromPoints(const Offset(0, 0), Offset(canvasSize, canvasSize)), paint);
// content
switch (code) {
case DefaultGameSettings.parameterCodeLang:
paintLangParameterItem(value, canvas, canvasSize);
break;
case DefaultGameSettings.parameterCodeLength:
paintLengthParameterItem(value, canvas, canvasSize);
break;
case DefaultGameSettings.parameterCodeLevel:
paintLevelParameterItem(value, canvas, canvasSize);
break;
default:
printlog('Unknown parameter: $code/$value');
paintUnknownParameterItem(value, canvas, canvasSize);
}
}
@override
bool shouldRepaint(CustomPainter oldDelegate) {
return false;
}
// "unknown" parameter -> simple block with text
void paintUnknownParameterItem(
final String value,
final Canvas canvas,
final double size,
) {
final paint = Paint();
paint.strokeJoin = StrokeJoin.round;
paint.strokeWidth = 3;
paint.color = Colors.grey;
paint.style = PaintingStyle.fill;
canvas.drawRect(Rect.fromPoints(const Offset(0, 0), Offset(size, size)), paint);
final textSpan = TextSpan(
text: '?\n$value',
style: const TextStyle(
color: Colors.black,
fontSize: 18,
fontWeight: FontWeight.bold,
),
);
final textPainter = TextPainter(
text: textSpan,
textDirection: TextDirection.ltr,
textAlign: TextAlign.center,
);
textPainter.layout();
textPainter.paint(
canvas,
Offset(
(size - textPainter.width) * 0.5,
(size - textPainter.height) * 0.5,
),
);
}
void paintLangParameterItem(
final String value,
final Canvas canvas,
final double size,
) {
const itemCountEmoji = '💬\n';
Color backgroundColor = Colors.grey;
String text = '';
switch (value) {
case DefaultGameSettings.lengthValue4:
backgroundColor = Colors.grey;
text = '⭐';
break;
case DefaultGameSettings.lengthValue5:
backgroundColor = Colors.green;
text = itemCountEmoji + DefaultGameSettings.lengthValue5.toString();
break;
case DefaultGameSettings.lengthValue6:
backgroundColor = Colors.orange;
text = itemCountEmoji + DefaultGameSettings.lengthValue6.toString();
break;
case DefaultGameSettings.lengthValue7:
backgroundColor = Colors.red;
text = itemCountEmoji + DefaultGameSettings.lengthValue7.toString();
break;
default:
printlog('Wrong value for lang parameter value: $value');
return;
}
final paint = Paint();
paint.strokeJoin = StrokeJoin.round;
paint.strokeWidth = 3 / 100 * size;
// Colored background
paint.color = backgroundColor;
paint.style = PaintingStyle.fill;
canvas.drawRect(Rect.fromPoints(const Offset(0, 0), Offset(size, size)), paint);
// centered text value
final textSpan = TextSpan(
text: text,
style: TextStyle(
color: Colors.black,
fontSize: size / 2.6,
fontWeight: FontWeight.bold,
),
);
final textPainter = TextPainter(
text: textSpan,
textDirection: TextDirection.ltr,
textAlign: TextAlign.center,
);
textPainter.layout();
textPainter.paint(
canvas,
Offset(
(size - textPainter.width) * 0.5,
(size - textPainter.height) * 0.5,
),
);
}
void paintLengthParameterItem(
final String value,
final Canvas canvas,
final double size,
) {
const itemCountEmoji = '💬\n';
Color backgroundColor = Colors.grey;
final String text = itemCountEmoji + value.toString();
switch (value) {
case DefaultGameSettings.lengthValue4:
backgroundColor = Colors.green;
break;
case DefaultGameSettings.lengthValue5:
backgroundColor = Colors.yellow;
break;
case DefaultGameSettings.lengthValue6:
backgroundColor = Colors.orange;
break;
case DefaultGameSettings.lengthValue7:
backgroundColor = Colors.red;
break;
case DefaultGameSettings.lengthValue8:
backgroundColor = Colors.purple;
break;
default:
printlog('Wrong value for length parameter value: $value');
return;
}
final paint = Paint();
paint.strokeJoin = StrokeJoin.round;
paint.strokeWidth = 3 / 100 * size;
// Colored background
paint.color = backgroundColor;
paint.style = PaintingStyle.fill;
canvas.drawRect(Rect.fromPoints(const Offset(0, 0), Offset(size, size)), paint);
// centered text value
final textSpan = TextSpan(
text: text,
style: TextStyle(
color: Colors.black,
fontSize: size / 2.6,
fontWeight: FontWeight.bold,
),
);
final textPainter = TextPainter(
text: textSpan,
textDirection: TextDirection.ltr,
textAlign: TextAlign.center,
);
textPainter.layout();
textPainter.paint(
canvas,
Offset(
(size - textPainter.width) * 0.5,
(size - textPainter.height) * 0.5,
),
);
}
void paintLevelParameterItem(
final String value,
final Canvas canvas,
final double size,
) {
Color backgroundColor = Colors.grey;
String text = '';
switch (value) {
case DefaultGameSettings.levelValueEasy:
backgroundColor = Colors.green;
text = '🧒';
break;
case DefaultGameSettings.levelValueNormal:
backgroundColor = Colors.orange;
text = '🤯';
break;
default:
printlog('Wrong value for level parameter value: $value');
return;
}
final paint = Paint();
paint.strokeJoin = StrokeJoin.round;
paint.strokeWidth = 3;
// Colored background
paint.color = backgroundColor;
paint.style = PaintingStyle.fill;
canvas.drawRect(Rect.fromPoints(const Offset(0, 0), Offset(size, size)), paint);
// centered text value
final textSpan = TextSpan(
text: text,
style: TextStyle(
color: Colors.black,
fontSize: size / 2.6,
fontWeight: FontWeight.bold,
),
);
final textPainter = TextPainter(
text: textSpan,
textDirection: TextDirection.ltr,
textAlign: TextAlign.center,
);
textPainter.layout();
textPainter.paint(
canvas,
Offset(
(size - textPainter.width) * 0.5,
(size - textPainter.height) * 0.5,
),
);
}
}
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:momomotus/ui/helpers/app_titles.dart';
class PageAbout extends StatelessWidget {
const PageAbout({super.key});
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
const SizedBox(height: 8),
const AppTitle(text: 'about_title'),
const Text('about_content').tr(),
FutureBuilder<PackageInfo>(
future: PackageInfo.fromPlatform(),
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.done:
return const Text('about_version').tr(
namedArgs: {
'version': snapshot.data!.version,
},
);
default:
return const SizedBox();
}
},
),
],
),
);
}
}
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:momomotus/cubit/game_cubit.dart';
import 'package:momomotus/models/game/game.dart';
import 'package:momomotus/ui/layouts/game_layout.dart';
import 'package:momomotus/ui/layouts/parameters_layout.dart';
class PageGame extends StatelessWidget {
const PageGame({super.key});
@override
Widget build(BuildContext context) {
return BlocBuilder<GameCubit, GameState>(
builder: (BuildContext context, GameState gameState) {
final Game currentGame = gameState.currentGame;
return currentGame.isRunning
? const GameLayout()
: ParametersLayout(canResume: currentGame.canBeResumed);
},
);
}
}
import 'package:flutter/material.dart';
import 'package:momomotus/ui/helpers/app_titles.dart';
import 'package:momomotus/ui/settings/settings_form.dart';
class PageSettings extends StatelessWidget {
const PageSettings({super.key});
@override
Widget build(BuildContext context) {
return const Padding(
padding: EdgeInsets.symmetric(horizontal: 8),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
SizedBox(height: 8),
AppTitle(text: 'settings_title'),
SizedBox(height: 8),
SettingsForm(),
],
),
);
}
}
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:unicons/unicons.dart';
import 'package:momomotus/ui/settings/theme_card.dart';
class SettingsForm extends StatefulWidget {
const SettingsForm({super.key});
@override
State<SettingsForm> createState() => _SettingsFormState();
}
class _SettingsFormState extends State<SettingsForm> {
@override
void dispose() {
super.dispose();
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
}
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
// Light/dark theme
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
const Text('settings_label_theme').tr(),
const Row(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
ThemeCard(
mode: ThemeMode.system,
icon: UniconsLine.cog,
),
ThemeCard(
mode: ThemeMode.light,
icon: UniconsLine.sun,
),
ThemeCard(
mode: ThemeMode.dark,
icon: UniconsLine.moon,
)
],
),
],
),
const SizedBox(height: 16),
],
);
}
}
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:momomotus/cubit/theme_cubit.dart';
class ThemeCard extends StatelessWidget {
const ThemeCard({
super.key,
required this.mode,
required this.icon,
});
final IconData icon;
final ThemeMode mode;
@override
Widget build(BuildContext context) {
return BlocBuilder<ThemeCubit, ThemeModeState>(
builder: (BuildContext context, ThemeModeState state) {
return Card(
elevation: 2,
shadowColor: Theme.of(context).colorScheme.shadow,
color: state.themeMode == mode
? Theme.of(context).colorScheme.primary
: Theme.of(context).colorScheme.surface,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(12)),
),
margin: const EdgeInsets.all(5),
child: InkWell(
onTap: () => BlocProvider.of<ThemeCubit>(context).getTheme(
ThemeModeState(themeMode: mode),
),
borderRadius: const BorderRadius.all(Radius.circular(12)),
child: Icon(
icon,
size: 32,
color: state.themeMode != mode
? Theme.of(context).colorScheme.primary
: Colors.white,
),
),
);
},
);
}
}
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:momomotus/config/menu.dart';
import 'package:momomotus/cubit/nav_cubit.dart';
import 'package:momomotus/ui/widgets/global_app_bar.dart';
class SkeletonScreen extends StatelessWidget {
const SkeletonScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: const GlobalAppBar(),
extendBodyBehindAppBar: false,
body: Material(
color: Theme.of(context).colorScheme.surface,
child: BlocBuilder<NavCubit, int>(
builder: (BuildContext context, int pageIndex) {
return Padding(
padding: const EdgeInsets.only(
top: 8,
left: 2,
right: 2,
),
child: Menu.getPageWidget(pageIndex),
);
},
),
),
backgroundColor: Theme.of(context).colorScheme.surface,
);
}
}
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:momomotus/cubit/game_cubit.dart';
class DeleteSavedGameButton extends StatelessWidget {
const DeleteSavedGameButton({super.key});
@override
Widget build(BuildContext context) {
return TextButton(
child: const Image(
image: AssetImage('assets/ui/button_delete_saved_game.png'),
fit: BoxFit.fill,
),
onPressed: () {
BlocProvider.of<GameCubit>(context).deleteSavedGame();
},
);
}
}
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:momomotus/cubit/game_cubit.dart';
class QuitGameButton extends StatelessWidget {
const QuitGameButton({super.key});
@override
Widget build(BuildContext context) {
return TextButton(
child: const Image(
image: AssetImage('assets/ui/button_back.png'),
fit: BoxFit.fill,
),
onPressed: () {
BlocProvider.of<GameCubit>(context).quitGame();
},
);
}
}
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:momomotus/cubit/game_cubit.dart';
import 'package:momomotus/cubit/settings_game_cubit.dart';
import 'package:momomotus/cubit/settings_global_cubit.dart';
class StartNewGameButton extends StatelessWidget {
const StartNewGameButton({super.key});
@override
Widget build(BuildContext context) {
return BlocBuilder<GameSettingsCubit, GameSettingsState>(
builder: (BuildContext context, GameSettingsState gameSettingsState) {
return BlocBuilder<GlobalSettingsCubit, GlobalSettingsState>(
builder: (BuildContext context, GlobalSettingsState globalSettingsState) {
return TextButton(
child: const Image(
image: AssetImage('assets/ui/button_start.png'),
fit: BoxFit.fill,
),
onPressed: () {
BlocProvider.of<GameCubit>(context).startNewGame(
gameSettings: gameSettingsState.settings,
globalSettings: globalSettingsState.settings,
);
},
);
},
);
},
);
}
}
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:momomotus/cubit/game_cubit.dart';
class ResumeSavedGameButton extends StatelessWidget {
const ResumeSavedGameButton({super.key});
@override
Widget build(BuildContext context) {
return TextButton(
child: const Image(
image: AssetImage('assets/ui/button_resume_game.png'),
fit: BoxFit.fill,
),
onPressed: () {
BlocProvider.of<GameCubit>(context).resumeSavedGame();
},
);
}
}
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:momomotus/config/default_game_settings.dart';
import 'package:momomotus/cubit/game_cubit.dart';
import 'package:momomotus/models/game/game.dart';
import 'package:momomotus/ui/widgets/game/game_cell.dart';
class GameBoardWidget extends StatelessWidget {
const GameBoardWidget({super.key});
@override
Widget build(BuildContext context) {
return BlocBuilder<GameCubit, GameState>(
builder: (BuildContext context, GameState gameState) {
final Game currentGame = gameState.currentGame;
final GameCubit gameCubit = BlocProvider.of<GameCubit>(context);
const int maxGuessesCount = DefaultGameSettings.maxGuessesCount;
final int wordLength = int.parse(currentGame.gameSettings.length);
final List<String> guesses = currentGame.guesses;
List<TableRow> tableRows = [];
for (int lineIndex = 0; lineIndex < maxGuessesCount; lineIndex++) {
String word = '';
if (lineIndex < guesses.length) {
word = guesses[lineIndex];
} else if (lineIndex == guesses.length) {
word = currentGame.currentGuess;
}
final List<String> tips = gameCubit.getTips(word);
List<TableCell> tableCells = [];
for (int colIndex = 0; colIndex < wordLength; colIndex++) {
String cellValue = ' ';
if (word.length > colIndex) {
cellValue = word[colIndex];
}
String cellTip = '';
if (lineIndex < guesses.length) {
cellTip = tips[colIndex];
}
final bool hasFocus = (!currentGame.gameWon) &&
(lineIndex == guesses.length) &&
(colIndex == word.length);
final String foundLetter =
((!currentGame.gameWon) && (lineIndex == guesses.length))
? currentGame.foundLetters.substring(colIndex, colIndex + 1)
: ' ';
tableCells.add(TableCell(
child: GameCellWidget(
cellValue: cellValue,
cellTip: cellTip,
hasFocus: hasFocus,
foundLetter: foundLetter,
),
));
}
tableRows.add(TableRow(children: tableCells));
}
List<Widget> gameBoard = [
Table(
defaultVerticalAlignment: TableCellVerticalAlignment.middle,
border: TableBorder.all(
color: Colors.white,
style: BorderStyle.none,
),
children: tableRows,
),
];
double horizontalMargins = 10;
if (wordLength < 6) {
horizontalMargins = 40;
if (wordLength < 5) {
horizontalMargins = 60;
}
}
if (gameCubit.isGameFinished() && !currentGame.gameWon) {
gameBoard.add(Text(
currentGame.word,
style: const TextStyle(
fontSize: 40,
fontWeight: FontWeight.bold,
),
));
}
return Container(
margin: EdgeInsets.symmetric(horizontal: horizontalMargins),
padding: const EdgeInsets.all(2),
child: Column(
children: gameBoard,
),
);
},
);
}
}
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:momomotus/cubit/game_cubit.dart';
import 'package:momomotus/models/game/game.dart';
class GameCellWidget extends StatelessWidget {
const GameCellWidget({
super.key,
required this.cellValue,
required this.cellTip,
required this.hasFocus,
required this.foundLetter,
});
final String cellValue;
final String cellTip;
final bool hasFocus;
final String foundLetter;
@override
Widget build(BuildContext context) {
return BlocBuilder<GameCubit, GameState>(
builder: (BuildContext context, GameState gameState) {
final Game currentGame = gameState.currentGame;
final String skin = currentGame.globalSettings.skin;
const Color textColor = Colors.white;
final Color focusBorderColor = Colors.yellow.shade700;
const Color defaultBorderColor = Colors.white;
String cellImage = 'empty';
if (cellTip != '') {
cellImage = cellTip;
}
String displayedCellValue = cellValue;
if ((foundLetter != ' ') && (cellValue == ' ')) {
displayedCellValue = foundLetter;
cellImage = 'good';
}
final Image imageWidget = Image(
image: AssetImage('assets/skins/${skin}_$cellImage.png'),
fit: BoxFit.fill,
);
final Widget cellBackground = Container(
decoration: BoxDecoration(
border: Border.all(
width: 4.0,
color: hasFocus ? focusBorderColor : defaultBorderColor,
style: BorderStyle.solid,
),
),
child: imageWidget,
);
Text textWidget = Text(
displayedCellValue,
style: const TextStyle(
color: textColor,
fontSize: 40.0,
fontWeight: FontWeight.w900,
),
textAlign: TextAlign.center,
);
return Stack(
alignment: Alignment.center,
children: <Widget>[
cellBackground,
Center(child: textWidget),
],
);
},
);
}
}
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:momomotus/cubit/game_cubit.dart';
class KeyWidget extends StatelessWidget {
const KeyWidget({
super.key,
required this.caption,
});
final String caption;
@override
Widget build(BuildContext context) {
String keyText = caption;
if (caption == '<') {
keyText = '⬅️';
} else if (caption == '!') {
keyText = '☑️';
}
const Color keyColor = Colors.black;
if (caption == ' ') {
return const SizedBox();
}
return Stack(
alignment: Alignment.center,
children: <Widget>[
const Image(
image: AssetImage('assets/ui/key.png'),
fit: BoxFit.fill,
),
Center(
child: TextButton(
style: TextButton.styleFrom(
padding: const EdgeInsets.all(0),
),
child: Text(
keyText,
style: const TextStyle(
color: keyColor,
fontSize: 30.0,
fontWeight: FontWeight.w800,
),
textAlign: TextAlign.center,
),
onPressed: () {
if (caption == '<') {
BlocProvider.of<GameCubit>(context).currentGuessRemoveLetter();
} else if (caption == '!') {
BlocProvider.of<GameCubit>(context).submitWord();
} else if (caption != ' ') {
BlocProvider.of<GameCubit>(context).currentGuessAddLetter(caption);
}
},
),
),
],
);
}
}
import 'package:flutter/material.dart';
import 'package:momomotus/ui/widgets/game/key.dart';
class KeyboardWidget extends StatelessWidget {
const KeyboardWidget({super.key});
@override
Widget build(BuildContext context) {
final List<List<String>> keys = [
['A', 'Z', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P'],
['Q', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', 'M'],
['<', ' ', 'W', 'X', 'C', 'V', 'B', 'N', ' ', '!'],
];
List<TableRow> tableRows = [];
for (var row in keys) {
List<TableCell> tableCells = [];
for (var key in row) {
tableCells.add(TableCell(
child: KeyWidget(caption: key),
));
}
tableRows.add(TableRow(children: tableCells));
}
return SizedBox(
height: 150,
width: double.maxFinite,
child: Container(
margin: const EdgeInsets.symmetric(horizontal: 2),
padding: const EdgeInsets.all(2),
child: Table(
defaultVerticalAlignment: TableCellVerticalAlignment.middle,
children: tableRows,
),
),
);
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment