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

Normalize game architecture

parent 4b944918
Branches
Tags
1 merge request!27Resolve "Normalize game architecture"
Pipeline #5695 passed
Showing
with 212 additions and 182 deletions
...@@ -14,7 +14,7 @@ class SkeletonScreen extends StatelessWidget { ...@@ -14,7 +14,7 @@ class SkeletonScreen extends StatelessWidget {
appBar: const GlobalAppBar(), appBar: const GlobalAppBar(),
extendBodyBehindAppBar: false, extendBodyBehindAppBar: false,
body: Material( body: Material(
color: Theme.of(context).colorScheme.background, color: Theme.of(context).colorScheme.surface,
child: BlocBuilder<NavCubit, int>( child: BlocBuilder<NavCubit, int>(
builder: (BuildContext context, int pageIndex) { builder: (BuildContext context, int pageIndex) {
return Padding( return Padding(
...@@ -28,7 +28,7 @@ class SkeletonScreen extends StatelessWidget { ...@@ -28,7 +28,7 @@ class SkeletonScreen extends StatelessWidget {
}, },
), ),
), ),
backgroundColor: Theme.of(context).colorScheme.background, backgroundColor: Theme.of(context).colorScheme.surface,
); );
} }
} }
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:sortgame/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:sortgame/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();
},
);
}
}
...@@ -14,17 +14,17 @@ class StartNewGameButton extends StatelessWidget { ...@@ -14,17 +14,17 @@ class StartNewGameButton extends StatelessWidget {
builder: (BuildContext context, GameSettingsState gameSettingsState) { builder: (BuildContext context, GameSettingsState gameSettingsState) {
return BlocBuilder<GlobalSettingsCubit, GlobalSettingsState>( return BlocBuilder<GlobalSettingsCubit, GlobalSettingsState>(
builder: (BuildContext context, GlobalSettingsState globalSettingsState) { builder: (BuildContext context, GlobalSettingsState globalSettingsState) {
final GameCubit gameCubit = BlocProvider.of<GameCubit>(context);
return TextButton( return TextButton(
child: const Image( child: const Image(
image: AssetImage('assets/icons/button_start.png'), image: AssetImage('assets/ui/button_start.png'),
fit: BoxFit.fill, fit: BoxFit.fill,
), ),
onPressed: () => gameCubit.startNewGame( onPressed: () {
BlocProvider.of<GameCubit>(context).startNewGame(
gameSettings: gameSettingsState.settings, gameSettings: gameSettingsState.settings,
globalSettings: globalSettingsState.settings, globalSettings: globalSettingsState.settings,
), );
},
); );
}, },
); );
......
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:sortgame/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:sortgame/cubit/game_cubit.dart';
import 'package:sortgame/models/game/game.dart';
import 'package:sortgame/ui/widgets/game/game_question.dart';
class GameBoardWidget extends StatelessWidget {
const GameBoardWidget({super.key});
@override
Widget build(BuildContext context) {
return Center(
child: BlocBuilder<GameCubit, GameState>(
builder: (BuildContext context, GameState gameState) {
final Game currentGame = gameState.currentGame;
return !currentGame.isFinished
? const GameQuestionWidget()
: const SizedBox.shrink();
},
),
);
}
}
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:sortgame/cubit/game_cubit.dart';
class GameBottomButtonsWidget extends StatelessWidget {
const GameBottomButtonsWidget({super.key});
@override
Widget build(BuildContext context) {
const String decorationImageAssetName = 'assets/icons/placeholder.png';
const Widget decorationWidget = TextButton(
onPressed: null,
child: Image(
image: AssetImage(decorationImageAssetName),
fit: BoxFit.fill,
),
);
return Table(
defaultColumnWidth: const IntrinsicColumnWidth(),
children: [
TableRow(
children: [
const Column(
children: [decorationWidget],
),
Column(
children: [
TextButton(
child: const Image(
image: AssetImage('assets/icons/button_back.png'),
fit: BoxFit.fill,
),
onPressed: () {
final GameCubit gameCubit = BlocProvider.of<GameCubit>(context);
gameCubit.quitGame();
},
)
],
),
const Column(
children: [decorationWidget],
),
],
),
],
);
}
}
...@@ -3,9 +3,9 @@ import 'package:flutter_bloc/flutter_bloc.dart'; ...@@ -3,9 +3,9 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:sortgame/cubit/game_cubit.dart'; import 'package:sortgame/cubit/game_cubit.dart';
import 'package:sortgame/models/data/game_item.dart'; import 'package:sortgame/models/data/game_item.dart';
import 'package:sortgame/models/game.dart'; import 'package:sortgame/models/game/game.dart';
import 'package:sortgame/ui/helpers/outlined_text_widget.dart';
import 'package:sortgame/ui/widgets/game/buttons_yes_no.dart'; import 'package:sortgame/ui/widgets/game/buttons_yes_no.dart';
import 'package:sortgame/ui/widgets/helpers/outlined_text_widget.dart';
class GameQuestionWidget extends StatelessWidget { class GameQuestionWidget extends StatelessWidget {
const GameQuestionWidget({super.key}); const GameQuestionWidget({super.key});
......
import 'package:flutter/material.dart';
import 'package:sortgame/models/game.dart';
import 'package:sortgame/ui/widgets/helpers/outlined_text_widget.dart';
import 'package:sortgame/utils/color_extensions.dart';
class PositionIndicator extends StatelessWidget {
const PositionIndicator({super.key, required this.game});
final Game game;
@override
Widget build(BuildContext context) {
// Normalized [0..1] value
final double barValue = game.position / game.gameSettings.itemsCount;
const Color baseColor = Color.fromARGB(255, 215, 1, 133);
const barHeight = 40.0;
const Color textColor = Color.fromARGB(255, 238, 238, 238);
const Color outlineColor = Color.fromARGB(255, 200, 200, 200);
return Stack(
alignment: Alignment.center,
children: [
LinearProgressIndicator(
value: barValue,
color: baseColor,
backgroundColor: baseColor.darken(),
minHeight: barHeight,
borderRadius: const BorderRadius.all(Radius.circular(barHeight / 4)),
),
OutlinedText(
text: '${game.position}/${game.gameSettings.itemsCount}',
fontSize: 0.9 * barHeight,
textColor: textColor,
outlineColor: outlineColor,
),
],
);
}
}
import 'package:flutter/material.dart';
import 'package:sortgame/models/game.dart';
import 'package:sortgame/ui/widgets/helpers/outlined_text_widget.dart';
class ScoreIndicator extends StatelessWidget {
const ScoreIndicator({super.key, required this.game});
final Game game;
@override
Widget build(BuildContext context) {
const Color baseColor = Color.fromARGB(255, 121, 93, 246);
return OutlinedText(
text: game.score.toString(),
fontSize: 70,
textColor: baseColor,
);
}
}
...@@ -4,8 +4,8 @@ import 'package:flutter_bloc/flutter_bloc.dart'; ...@@ -4,8 +4,8 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:sortgame/config/menu.dart'; import 'package:sortgame/config/menu.dart';
import 'package:sortgame/cubit/game_cubit.dart'; import 'package:sortgame/cubit/game_cubit.dart';
import 'package:sortgame/cubit/nav_cubit.dart'; import 'package:sortgame/cubit/nav_cubit.dart';
import 'package:sortgame/models/game.dart'; import 'package:sortgame/models/game/game.dart';
import 'package:sortgame/ui/widgets/helpers/app_title.dart'; import 'package:sortgame/ui/helpers/app_titles.dart';
class GlobalAppBar extends StatelessWidget implements PreferredSizeWidget { class GlobalAppBar extends StatelessWidget implements PreferredSizeWidget {
const GlobalAppBar({super.key}); const GlobalAppBar({super.key});
...@@ -20,16 +20,15 @@ class GlobalAppBar extends StatelessWidget implements PreferredSizeWidget { ...@@ -20,16 +20,15 @@ class GlobalAppBar extends StatelessWidget implements PreferredSizeWidget {
final List<Widget> menuActions = []; final List<Widget> menuActions = [];
if (currentGame.isRunning) { if (currentGame.isRunning && !currentGame.isFinished) {
menuActions.add(TextButton( menuActions.add(TextButton(
child: const Image( child: const Image(
image: AssetImage('assets/icons/button_back.png'), image: AssetImage('assets/ui/button_back.png'),
fit: BoxFit.fill, fit: BoxFit.fill,
), ),
onPressed: () {}, onPressed: () {},
onLongPress: () { onLongPress: () {
final GameCubit gameCubit = BlocProvider.of<GameCubit>(context); BlocProvider.of<GameCubit>(context).quitGame();
gameCubit.quitGame();
}, },
)); ));
} else { } else {
...@@ -70,7 +69,7 @@ class GlobalAppBar extends StatelessWidget implements PreferredSizeWidget { ...@@ -70,7 +69,7 @@ class GlobalAppBar extends StatelessWidget implements PreferredSizeWidget {
} }
return AppBar( return AppBar(
title: const AppTitle(text: 'app_name'), title: const AppHeader(text: 'app_name'),
actions: menuActions, actions: menuActions,
); );
}, },
......
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 Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
tr(text),
textAlign: TextAlign.start,
style: Theme.of(context).textTheme.headlineSmall!.apply(fontWeightDelta: 2),
),
const SizedBox(height: 8),
],
);
}
}
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:sortgame/cubit/game_cubit.dart';
import 'package:sortgame/models/game/game.dart';
import 'package:sortgame/ui/helpers/outlined_text_widget.dart';
import 'package:sortgame/utils/color_extensions.dart';
class PositionIndicator extends StatelessWidget {
const PositionIndicator({super.key});
@override
Widget build(BuildContext context) {
return BlocBuilder<GameCubit, GameState>(
builder: (BuildContext context, GameState gameState) {
final Game currentGame = gameState.currentGame;
// Normalized [0..1] value
final double barValue =
currentGame.position / int.parse(currentGame.gameSettings.itemsCount);
const Color baseColor = Color.fromARGB(255, 215, 1, 133);
const barHeight = 40.0;
const Color textColor = Color.fromARGB(255, 238, 238, 238);
const Color outlineColor = Color.fromARGB(255, 200, 200, 200);
return Stack(
alignment: Alignment.center,
children: [
LinearProgressIndicator(
value: barValue,
color: baseColor,
backgroundColor: baseColor.darken(),
minHeight: barHeight,
borderRadius: const BorderRadius.all(Radius.circular(barHeight / 4)),
),
OutlinedText(
text: '${currentGame.position}/${currentGame.gameSettings.itemsCount}',
fontSize: 0.9 * barHeight,
textColor: textColor,
outlineColor: outlineColor,
),
],
);
},
);
}
}
...@@ -2,24 +2,24 @@ import 'package:flutter/material.dart'; ...@@ -2,24 +2,24 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:sortgame/cubit/game_cubit.dart'; import 'package:sortgame/cubit/game_cubit.dart';
import 'package:sortgame/models/game.dart'; import 'package:sortgame/ui/helpers/outlined_text_widget.dart';
import 'package:sortgame/ui/widgets/game/indicator_position.dart'; import 'package:sortgame/utils/color_extensions.dart';
import 'package:sortgame/ui/widgets/game/indicator_score.dart';
class GameTopIndicatorWidget extends StatelessWidget { class ScoreIndicator extends StatelessWidget {
const GameTopIndicatorWidget({super.key}); const ScoreIndicator({super.key});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocBuilder<GameCubit, GameState>( return BlocBuilder<GameCubit, GameState>(
builder: (BuildContext context, GameState gameState) { builder: (BuildContext context, GameState gameState) {
final Game currentGame = gameState.currentGame; const Color baseColor = Color.fromARGB(255, 218, 218, 218);
final Color outlineColor = baseColor.darken();
return Column( return OutlinedText(
children: [ text: gameState.currentGame.score.toString(),
PositionIndicator(game: currentGame), fontSize: 70,
ScoreIndicator(game: currentGame), textColor: baseColor,
], outlineColor: outlineColor,
); );
}, },
); );
......
...@@ -61,10 +61,10 @@ packages: ...@@ -61,10 +61,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: easy_localization name: easy_localization
sha256: "432698c31a488dd64c56d4759f20d04844baba5e9e4f2cb1abb9676257918b17" sha256: fa59bcdbbb911a764aa6acf96bbb6fa7a5cf8234354fc45ec1a43a0349ef0201
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.6" version: "3.0.7"
easy_logger: easy_logger:
dependency: transitive dependency: transitive
description: description:
...@@ -114,10 +114,10 @@ packages: ...@@ -114,10 +114,10 @@ packages:
dependency: "direct dev" dependency: "direct dev"
description: description:
name: flutter_lints name: flutter_lints
sha256: "9e8c3858111da373efc5aa341de011d9bd23e2c5c5e0c62bccf32438e192d7b1" sha256: "3f41d009ba7172d5ff9be5f6e6e6abb4300e263aab8866d2a0842ed2a70f8f0c"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.2" version: "4.0.0"
flutter_localizations: flutter_localizations:
dependency: transitive dependency: transitive
description: flutter description: flutter
...@@ -164,18 +164,18 @@ packages: ...@@ -164,18 +164,18 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: intl name: intl
sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d" sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.18.1" version: "0.19.0"
lints: lints:
dependency: transitive dependency: transitive
description: description:
name: lints name: lints
sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290 sha256: "976c774dd944a42e83e2467f4cc670daef7eed6295b10b36ae8c85bcbf828235"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.0" version: "4.0.0"
material_color_utilities: material_color_utilities:
dependency: transitive dependency: transitive
description: description:
...@@ -188,10 +188,10 @@ packages: ...@@ -188,10 +188,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: meta name: meta
sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.11.0" version: "1.12.0"
nested: nested:
dependency: transitive dependency: transitive
description: description:
...@@ -236,18 +236,18 @@ packages: ...@@ -236,18 +236,18 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: path_provider_android name: path_provider_android
sha256: a248d8146ee5983446bf03ed5ea8f6533129a12b11f12057ad1b4a67a2b3b41d sha256: "9c96da072b421e98183f9ea7464898428e764bc0ce5567f27ec8693442e72514"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.2.4" version: "2.2.5"
path_provider_foundation: path_provider_foundation:
dependency: transitive dependency: transitive
description: description:
name: path_provider_foundation name: path_provider_foundation
sha256: "5a7999be66e000916500be4f15a3633ebceb8302719b47b9cc49ce924125350f" sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.2" version: "2.4.0"
path_provider_linux: path_provider_linux:
dependency: transitive dependency: transitive
description: description:
...@@ -308,18 +308,18 @@ packages: ...@@ -308,18 +308,18 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: shared_preferences_android name: shared_preferences_android
sha256: "1ee8bf911094a1b592de7ab29add6f826a7331fb854273d55918693d5364a1f2" sha256: "93d0ec9dd902d85f326068e6a899487d1f65ffcd5798721a95330b26c8131577"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.2.2" version: "2.2.3"
shared_preferences_foundation: shared_preferences_foundation:
dependency: transitive dependency: transitive
description: description:
name: shared_preferences_foundation name: shared_preferences_foundation
sha256: "7708d83064f38060c7b39db12aefe449cb8cdc031d6062280087bc4cdb988f5c" sha256: "0a8a893bf4fd1152f93fec03a415d11c27c74454d96e2318a7ac38dd18683ab7"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.5" version: "2.4.0"
shared_preferences_linux: shared_preferences_linux:
dependency: transitive dependency: transitive
description: description:
...@@ -425,10 +425,10 @@ packages: ...@@ -425,10 +425,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: win32 name: win32
sha256: "0eaf06e3446824099858367950a813472af675116bf63f008a4c2a75ae13e9cb" sha256: a79dbe579cb51ecd6d30b17e0cae4e0ea15e2c0e66f69ad4198f22a6789e94f4
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "5.5.0" version: "5.5.1"
xdg_directories: xdg_directories:
dependency: transitive dependency: transitive
description: description:
...@@ -438,5 +438,5 @@ packages: ...@@ -438,5 +438,5 @@ packages:
source: hosted source: hosted
version: "1.0.4" version: "1.0.4"
sdks: sdks:
dart: ">=3.3.0 <4.0.0" dart: ">=3.4.0 <4.0.0"
flutter: ">=3.19.0" flutter: ">=3.22.0"
...@@ -3,7 +3,7 @@ description: A sorting game application. ...@@ -3,7 +3,7 @@ description: A sorting game application.
publish_to: "none" publish_to: "none"
version: 0.0.26+26 version: 0.1.0+27
environment: environment:
sdk: "^3.0.0" sdk: "^3.0.0"
...@@ -12,6 +12,7 @@ dependencies: ...@@ -12,6 +12,7 @@ dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
# base
easy_localization: ^3.0.1 easy_localization: ^3.0.1
equatable: ^2.0.5 equatable: ^2.0.5
flutter_bloc: ^8.1.1 flutter_bloc: ^8.1.1
...@@ -21,13 +22,16 @@ dependencies: ...@@ -21,13 +22,16 @@ dependencies:
path_provider: ^2.0.11 path_provider: ^2.0.11
unicons: ^2.1.1 unicons: ^2.1.1
# specific
# (none)
dev_dependencies: dev_dependencies:
flutter_lints: ^3.0.1 flutter_lints: ^4.0.0
flutter: flutter:
uses-material-design: true uses-material-design: true
assets: assets:
- assets/icons/ - assets/ui/
- assets/translations/ - assets/translations/
fonts: fonts:
...@@ -41,3 +45,4 @@ flutter: ...@@ -41,3 +45,4 @@ flutter:
weight: 400 weight: 400
- asset: assets/fonts/Nunito-Light.ttf - asset: assets/fonts/Nunito-Light.ttf
weight: 300 weight: 300
...@@ -6,7 +6,7 @@ command -v scour >/dev/null 2>&1 || { echo >&2 "I require scour but it's not ins ...@@ -6,7 +6,7 @@ command -v scour >/dev/null 2>&1 || { echo >&2 "I require scour but it's not ins
command -v optipng >/dev/null 2>&1 || { echo >&2 "I require optipng but it's not installed. Aborting."; exit 1; } command -v optipng >/dev/null 2>&1 || { echo >&2 "I require optipng but it's not installed. Aborting."; exit 1; }
CURRENT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)" CURRENT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"
BASE_DIR="$(dirname "${CURRENT_DIR}")" BASE_DIR="$(dirname "$(dirname "${CURRENT_DIR}")")"
SOURCE_ICON="${CURRENT_DIR}/icon.svg" SOURCE_ICON="${CURRENT_DIR}/icon.svg"
SOURCE_FASTLANE="${CURRENT_DIR}/featureGraphic.svg" SOURCE_FASTLANE="${CURRENT_DIR}/featureGraphic.svg"
......
File moved
File moved
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment