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

Normalize Activity application architecture

parent d1356cf0
No related branches found
No related tags found
1 merge request!47Resolve "Normalize Activity application architecture"
Pipeline #6668 passed
Showing
with 622 additions and 206 deletions
{
"app_name": "Hangman",
"page_home": "Home",
"page_game": "Game",
"settings_title": "Settings",
"settings_label_theme": "Theme mode",
......
{
"app_name": "Le Pendu",
"page_home": "Accueil",
"page_game": "Jeu",
"settings_title": "Réglages",
"settings_label_theme": "Thème de couleurs",
......
import 'package:flutter/material.dart';
import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
import 'package:hangman/ui/screens/page_about.dart';
import 'package:hangman/ui/screens/page_game.dart';
import 'package:hangman/ui/screens/page_settings.dart';
import 'package:hangman/common/ui/pages/game.dart';
import 'package:hangman/common/ui/pages/parameters.dart';
class MenuItem {
class ActivityPageItem {
final String code;
final Icon icon;
final Widget page;
const MenuItem({
const ActivityPageItem({
required this.code,
required this.icon,
required this.page,
});
}
class Menu {
static const indexGame = 0;
static const menuItemGame = MenuItem(
icon: Icon(UniconsLine.home),
page: PageGame(),
);
class ActivityPage {
static const bool displayBottomNavBar = false;
static const indexSettings = 1;
static const menuItemSettings = MenuItem(
icon: Icon(UniconsLine.setting),
page: PageSettings(),
static const indexHome = 0;
static const pageHome = ActivityPageItem(
code: 'page_home',
icon: Icon(UniconsLine.home),
page: PageParameters(),
);
static const indexAbout = 2;
static const menuItemAbout = MenuItem(
icon: Icon(UniconsLine.info_circle),
page: PageAbout(),
static const indexGame = 1;
static const pageGame = ActivityPageItem(
code: 'page_game',
icon: Icon(UniconsLine.star),
page: PageGame(),
);
static Map<int, MenuItem> items = {
indexGame: menuItemGame,
indexSettings: menuItemSettings,
indexAbout: menuItemAbout,
static const Map<int, ActivityPageItem> items = {
indexHome: pageHome,
indexGame: pageGame,
};
static int defaultPageIndex = indexHome;
static bool isIndexAllowed(int pageIndex) {
return items.keys.contains(pageIndex);
}
static Widget getPageWidget(int pageIndex) {
return items[pageIndex]?.page ?? menuItemGame.page;
static Widget getWidget(int pageIndex) {
return items[pageIndex]?.page ?? pageHome.page;
}
static int itemsCount = Menu.items.length;
}
import 'package:flutter/material.dart';
import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
import 'package:hangman/common/ui/screens/about.dart';
import 'package:hangman/common/ui/screens/activity.dart';
import 'package:hangman/common/ui/screens/settings.dart';
class ScreenItem {
final String code;
final Icon icon;
final Widget screen;
const ScreenItem({
required this.code,
required this.icon,
required this.screen,
});
}
class Screen {
static const indexActivity = 0;
static const screenActivity = ScreenItem(
code: 'screen_activity',
icon: Icon(UniconsLine.home),
screen: ScreenActivity(),
);
static const indexSettings = 1;
static const screenSettings = ScreenItem(
code: 'screen_settings',
icon: Icon(UniconsLine.setting),
screen: ScreenSettings(),
);
static const indexAbout = 2;
static const screenAbout = ScreenItem(
code: 'screen_about',
icon: Icon(UniconsLine.info_circle),
screen: ScreenAbout(),
);
static Map<int, ScreenItem> items = {
indexActivity: screenActivity,
indexSettings: screenSettings,
indexAbout: screenAbout,
};
static bool isIndexAllowed(int screenIndex) {
return items.keys.contains(screenIndex);
}
static Widget getWidget(int screenIndex) {
return items[screenIndex]?.screen ?? screenActivity.screen;
}
}
import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
import 'package:hangman/config/menu.dart';
import 'package:hangman/common/config/activity_page.dart';
class NavCubit extends HydratedCubit<int> {
NavCubit() : super(0);
class NavCubitPage extends HydratedCubit<int> {
NavCubitPage() : super(0);
void updateIndex(int index) {
if (Menu.isIndexAllowed(index)) {
if (ActivityPage.isIndexAllowed(index)) {
emit(index);
} else {
goToGamePage();
emit(ActivityPage.indexHome);
}
}
void goToGamePage() {
emit(Menu.indexGame);
void goToPageHome() {
updateIndex(ActivityPage.indexHome);
}
void goToSettingsPage() {
emit(Menu.indexSettings);
}
void goToAboutPage() {
emit(Menu.indexAbout);
void goToPageGame() {
updateIndex(ActivityPage.indexGame);
}
@override
int fromJson(Map<String, dynamic> json) {
return Menu.indexGame;
return ActivityPage.indexHome;
}
@override
Map<String, dynamic>? toJson(int state) {
return <String, int>{'pageIndex': state};
return <String, int>{'index': state};
}
}
import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
import 'package:hangman/common/config/screen.dart';
class NavCubitScreen extends HydratedCubit<int> {
NavCubitScreen() : super(0);
void updateIndex(int index) {
if (Screen.isIndexAllowed(index)) {
emit(index);
} else {
goToScreenActivity();
}
}
void goToScreenActivity() {
emit(Screen.indexActivity);
}
void goToScreenSettings() {
emit(Screen.indexSettings);
}
void goToScreenAbout() {
emit(Screen.indexAbout);
}
@override
int fromJson(Map<String, dynamic> json) {
return Screen.indexActivity;
}
@override
Map<String, dynamic>? toJson(int state) {
return <String, int>{'index': state};
}
}
import 'package:flutter/material.dart';
import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
import 'package:hangman/common/config/activity_page.dart';
import 'package:hangman/common/cubit/nav/nav_cubit_pages.dart';
class BottomNavBar extends StatelessWidget {
const BottomNavBar({super.key});
@override
Widget build(BuildContext context) {
return Card(
margin: const EdgeInsets.only(top: 1, right: 4, left: 4),
elevation: 4,
shadowColor: Theme.of(context).colorScheme.shadow,
color: Theme.of(context).colorScheme.surfaceContainerHighest,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(16),
topRight: Radius.circular(16),
),
),
child: BlocBuilder<NavCubitPage, int>(builder: (BuildContext context, int state) {
final List<BottomNavigationBarItem> items = [];
ActivityPage.items.forEach((int pageIndex, ActivityPageItem item) {
items.add(BottomNavigationBarItem(
icon: item.icon,
label: tr(item.code),
));
});
return BottomNavigationBar(
currentIndex: state,
onTap: (int index) => BlocProvider.of<NavCubitPage>(context).updateIndex(index),
type: BottomNavigationBarType.fixed,
elevation: 0,
backgroundColor: Colors.transparent,
selectedItemColor: Theme.of(context).colorScheme.primary,
unselectedItemColor: Theme.of(context).textTheme.bodySmall!.color,
items: items,
);
}),
);
}
}
import 'package:flutter/material.dart';
import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
import 'package:hangman/config/menu.dart';
import 'package:hangman/cubit/game_cubit.dart';
import 'package:hangman/cubit/nav_cubit.dart';
import 'package:hangman/models/game/game.dart';
import 'package:hangman/common/config/screen.dart';
import 'package:hangman/common/cubit/nav/nav_cubit_pages.dart';
import 'package:hangman/common/cubit/nav/nav_cubit_screens.dart';
import 'package:hangman/cubit/activity/activity_cubit.dart';
import 'package:hangman/models/activity/activity.dart';
class GlobalAppBar extends StatelessWidget implements PreferredSizeWidget {
const GlobalAppBar({super.key});
@override
Widget build(BuildContext context) {
return BlocBuilder<GameCubit, GameState>(
builder: (BuildContext context, GameState gameState) {
return BlocBuilder<NavCubit, int>(
return BlocBuilder<ActivityCubit, ActivityState>(
builder: (BuildContext context, ActivityState activityState) {
return BlocBuilder<NavCubitScreen, int>(
builder: (BuildContext context, int pageIndex) {
final Game currentGame = gameState.currentGame;
final Activity currentActivity = activityState.currentActivity;
final List<Widget> menuActions = [];
if (currentGame.isRunning && !currentGame.isFinished) {
if (currentActivity.isRunning && !currentActivity.isFinished) {
menuActions.add(StyledButton(
color: Colors.red,
onPressed: () {},
onLongPress: () {
BlocProvider.of<GameCubit>(context).quitGame();
BlocProvider.of<ActivityCubit>(context).quitActivity();
BlocProvider.of<NavCubitPage>(context).goToPageHome();
},
child: const Image(
image: AssetImage('assets/ui/button_back.png'),
......@@ -32,38 +35,38 @@ class GlobalAppBar extends StatelessWidget implements PreferredSizeWidget {
),
));
} else {
if (pageIndex == Menu.indexGame) {
if (pageIndex == Screen.indexActivity) {
// go to Settings page
menuActions.add(ElevatedButton(
onPressed: () {
BlocProvider.of<NavCubit>(context).goToSettingsPage();
BlocProvider.of<NavCubitScreen>(context).goToScreenSettings();
},
style: ElevatedButton.styleFrom(
shape: const CircleBorder(),
),
child: Menu.menuItemSettings.icon,
child: Screen.screenSettings.icon,
));
// go to About page
menuActions.add(ElevatedButton(
onPressed: () {
BlocProvider.of<NavCubit>(context).goToAboutPage();
BlocProvider.of<NavCubitScreen>(context).goToScreenAbout();
},
style: ElevatedButton.styleFrom(
shape: const CircleBorder(),
),
child: Menu.menuItemAbout.icon,
child: Screen.screenAbout.icon,
));
} else {
// back to Home page
menuActions.add(ElevatedButton(
onPressed: () {
BlocProvider.of<NavCubit>(context).goToGamePage();
BlocProvider.of<NavCubitScreen>(context).goToScreenActivity();
},
style: ElevatedButton.styleFrom(
shape: const CircleBorder(),
),
child: Menu.menuItemGame.icon,
child: Screen.screenActivity.icon,
));
}
}
......
......@@ -2,8 +2,8 @@ import 'package:flutter/material.dart';
import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
import 'package:hangman/config/game_colors.dart';
import 'package:hangman/cubit/game_cubit.dart';
import 'package:hangman/models/game/game.dart';
import 'package:hangman/cubit/activity/activity_cubit.dart';
import 'package:hangman/models/activity/activity.dart';
import 'package:hangman/ui/widgets/game/game_answer.dart';
import 'package:hangman/ui/widgets/game/game_clue.dart';
import 'package:hangman/ui/widgets/game/game_hidden_word.dart';
......@@ -13,20 +13,20 @@ import 'package:hangman/ui/widgets/game/game_virtual_keyboard.dart';
import 'package:hangman/ui/widgets/game/game_end.dart';
import 'package:hangman/ui/widgets/game/game_top.dart';
class GameLayout extends StatelessWidget {
const GameLayout({super.key});
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 BlocBuilder<ActivityCubit, ActivityState>(
builder: (BuildContext context, ActivityState activityState) {
final Activity currentActivity = activityState.currentActivity;
if (currentGame.gettingSecretWord) {
if (currentActivity.gettingSecretWord) {
return const GameLoadingIndicatorWidget();
}
if (currentGame.secretWord == '') {
if (currentActivity.secretWord == '') {
return const GameSomethingWentWrongWidget();
}
......@@ -53,12 +53,14 @@ class GameLayout extends StatelessWidget {
],
),
),
currentGame.clue != '' ? const GameDisplayClueWidget() : const SizedBox.shrink(),
currentGame.isFinished && !currentGame.gameWon
currentActivity.clue != ''
? const GameDisplayClueWidget()
: const SizedBox.shrink(),
currentActivity.isFinished && !currentActivity.gameWon
? const GameDisplayAnswerWidget()
: const SizedBox.shrink(),
const Expanded(child: SizedBox.shrink()),
currentGame.isFinished
currentActivity.isFinished
? const GameEndWidget()
: const GameVirtualKeyboardWidget(),
],
......
import 'package:flutter/material.dart';
import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
import 'package:hangman/config/default_game_settings.dart';
import 'package:hangman/common/ui/parameters/parameter_widget.dart';
import 'package:hangman/config/default_activity_settings.dart';
import 'package:hangman/config/default_global_settings.dart';
import 'package:hangman/cubit/settings_game_cubit.dart';
import 'package:hangman/cubit/settings_global_cubit.dart';
import 'package:hangman/ui/parameters/parameter_widget.dart';
import 'package:hangman/cubit/activity/activity_cubit.dart';
import 'package:hangman/cubit/settings/settings_activity_cubit.dart';
import 'package:hangman/cubit/settings/settings_global_cubit.dart';
import 'package:hangman/models/activity/activity.dart';
import 'package:hangman/ui/widgets/actions/button_delete_saved_game.dart';
import 'package:hangman/ui/widgets/actions/button_game_start_new.dart';
import 'package:hangman/ui/widgets/actions/button_resume_saved_game.dart';
class ParametersLayout extends StatelessWidget {
const ParametersLayout({super.key, required this.canResume});
final bool canResume;
class PageParameters extends StatelessWidget {
const PageParameters({super.key});
final double separatorHeight = 8.0;
@override
Widget build(BuildContext context) {
return BlocBuilder<ActivityCubit, ActivityState>(
builder: (BuildContext context, ActivityState activityState) {
final Activity currentActivity = activityState.currentActivity;
final List<Widget> lines = [];
// Game settings
for (String code in DefaultGameSettings.availableParameters) {
for (String code in DefaultActivitySettings.availableParameters) {
lines.add(Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: buildParametersLine(
......@@ -38,7 +43,7 @@ class ParametersLayout extends StatelessWidget {
child: SizedBox(height: separatorHeight),
));
if (canResume == false) {
if (currentActivity.canBeResumed == false) {
// Start new game
lines.add(
const AspectRatio(
......@@ -77,6 +82,8 @@ class ParametersLayout extends StatelessWidget {
return Column(
children: lines,
);
},
);
}
List<Widget> buildParametersLine({
......@@ -87,25 +94,25 @@ class ParametersLayout extends StatelessWidget {
final List<String> availableValues = isGlobal
? DefaultGlobalSettings.getAvailableValues(code)
: DefaultGameSettings.getAvailableValues(code);
: DefaultActivitySettings.getAvailableValues(code);
if (availableValues.length <= 1) {
return [];
}
for (String value in availableValues) {
final Widget parameterButton = BlocBuilder<GameSettingsCubit, GameSettingsState>(
builder: (BuildContext context, GameSettingsState gameSettingsState) {
final Widget parameterButton = BlocBuilder<ActivitySettingsCubit, ActivitySettingsState>(
builder: (BuildContext context, ActivitySettingsState activitySettingsState) {
return BlocBuilder<GlobalSettingsCubit, GlobalSettingsState>(
builder: (BuildContext context, GlobalSettingsState globalSettingsState) {
final GameSettingsCubit gameSettingsCubit =
BlocProvider.of<GameSettingsCubit>(context);
final ActivitySettingsCubit activitySettingsCubit =
BlocProvider.of<ActivitySettingsCubit>(context);
final GlobalSettingsCubit globalSettingsCubit =
BlocProvider.of<GlobalSettingsCubit>(context);
final String currentValue = isGlobal
? globalSettingsCubit.getParameterValue(code)
: gameSettingsCubit.getParameterValue(code);
: activitySettingsCubit.getParameterValue(code);
final bool isSelected = (value == currentValue);
......@@ -119,12 +126,12 @@ class ParametersLayout extends StatelessWidget {
value: value,
isSelected: isSelected,
size: itemWidth,
gameSettings: gameSettingsState.settings,
activitySettings: activitySettingsState.settings,
globalSettings: globalSettingsState.settings,
onPressed: () {
isGlobal
? globalSettingsCubit.setParameterValue(code, value)
: gameSettingsCubit.setParameterValue(code, value);
: activitySettingsCubit.setParameterValue(code, value);
},
),
);
......
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
import 'package:hangman/config/default_game_settings.dart';
import 'package:hangman/models/settings/settings_game.dart';
import 'package:hangman/config/default_activity_settings.dart';
import 'package:hangman/models/settings/settings_activity.dart';
import 'package:hangman/models/settings/settings_global.dart';
class ParameterPainter extends CustomPainter {
const ParameterPainter({
required this.code,
required this.value,
required this.gameSettings,
required this.activitySettings,
required this.globalSettings,
});
final String code;
final String value;
final GameSettings gameSettings;
final ActivitySettings activitySettings;
final GlobalSettings globalSettings;
@override
......@@ -28,10 +27,10 @@ class ParameterPainter extends CustomPainter {
// content
switch (code) {
case DefaultGameSettings.parameterCodeGameMode:
case DefaultActivitySettings.parameterCodeGameMode:
paintGameModeParameterItem(canvas, canvasSize);
break;
case DefaultGameSettings.parameterCodeGameLevel:
case DefaultActivitySettings.parameterCodeGameLevel:
paintGameLevelParameterItem(canvas, canvasSize);
break;
default:
......@@ -84,10 +83,10 @@ class ParameterPainter extends CustomPainter {
String text = '';
switch (value) {
case DefaultGameSettings.gameModeValueOnline:
case DefaultActivitySettings.gameModeValueOnline:
text = '🌐';
break;
case DefaultGameSettings.gameModeValueOffline:
case DefaultActivitySettings.gameModeValueOffline:
text = '📱';
break;
default:
......@@ -129,10 +128,10 @@ class ParameterPainter extends CustomPainter {
String text = '';
switch (value) {
case DefaultGameSettings.gameLevelValueEasy:
case DefaultActivitySettings.gameLevelValueEasy:
text = '🧒';
break;
case DefaultGameSettings.gameLevelValueHard:
case DefaultActivitySettings.gameLevelValueHard:
text = '🧑‍🎓';
break;
default:
......
import 'package:flutter/material.dart';
import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
import 'package:hangman/config/default_game_settings.dart';
import 'package:hangman/common/ui/parameters/parameter_painter.dart';
import 'package:hangman/config/default_activity_settings.dart';
import 'package:hangman/config/default_global_settings.dart';
import 'package:hangman/models/settings/settings_game.dart';
import 'package:hangman/models/settings/settings_activity.dart';
import 'package:hangman/models/settings/settings_global.dart';
import 'package:hangman/ui/parameters/parameter_painter.dart';
class ParameterWidget extends StatelessWidget {
const ParameterWidget({
......@@ -15,7 +15,7 @@ class ParameterWidget extends StatelessWidget {
required this.value,
required this.isSelected,
required this.size,
required this.gameSettings,
required this.activitySettings,
required this.globalSettings,
required this.onPressed,
});
......@@ -24,7 +24,7 @@ class ParameterWidget extends StatelessWidget {
final String value;
final bool isSelected;
final double size;
final GameSettings gameSettings;
final ActivitySettings activitySettings;
final GlobalSettings globalSettings;
final VoidCallback onPressed;
......@@ -38,10 +38,10 @@ class ParameterWidget extends StatelessWidget {
Widget content = const SizedBox.shrink();
switch (code) {
case DefaultGameSettings.parameterCodeGameMode:
case DefaultActivitySettings.parameterCodeGameMode:
content = getGameModeParameterItem();
break;
case DefaultGameSettings.parameterCodeGameLevel:
case DefaultActivitySettings.parameterCodeGameLevel:
content = getGameLevelParameterItem();
break;
case DefaultGlobalSettings.parameterCodeSkin:
......@@ -88,7 +88,7 @@ class ParameterWidget extends StatelessWidget {
painter: ParameterPainter(
code: code,
value: value,
gameSettings: gameSettings,
activitySettings: activitySettings,
globalSettings: globalSettings,
),
isComplex: true,
......@@ -100,10 +100,10 @@ class ParameterWidget extends StatelessWidget {
Color backgroundColor = Colors.grey;
switch (value) {
case DefaultGameSettings.gameLevelValueEasy:
case DefaultActivitySettings.gameLevelValueEasy:
backgroundColor = Colors.green;
break;
case DefaultGameSettings.gameLevelValueHard:
case DefaultActivitySettings.gameLevelValueHard:
backgroundColor = Colors.orange;
break;
default:
......@@ -119,7 +119,7 @@ class ParameterWidget extends StatelessWidget {
painter: ParameterPainter(
code: code,
value: value,
gameSettings: gameSettings,
activitySettings: activitySettings,
globalSettings: globalSettings,
),
isComplex: true,
......
import 'package:flutter/material.dart';
import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
class PageAbout extends StatelessWidget {
const PageAbout({super.key});
class ScreenAbout extends StatelessWidget {
const ScreenAbout({super.key});
@override
Widget build(BuildContext context) {
......
import 'package:flutter/material.dart';
import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
import 'package:hangman/common/config/activity_page.dart';
import 'package:hangman/common/cubit/nav/nav_cubit_pages.dart';
class ScreenActivity extends StatelessWidget {
const ScreenActivity({super.key});
@override
Widget build(BuildContext context) {
return BlocBuilder<NavCubitPage, int>(
builder: (BuildContext context, int pageIndex) {
return ActivityPage.getWidget(pageIndex);
},
);
}
}
import 'package:flutter/material.dart';
import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
class PageSettings extends StatelessWidget {
const PageSettings({super.key});
class ScreenSettings extends StatelessWidget {
const ScreenSettings({super.key});
@override
Widget build(BuildContext context) {
......
class ApplicationConfig {
static const String appTitle = 'Hangman';
}
import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
class DefaultGameSettings {
class DefaultActivitySettings {
// available game parameters codes
static const String parameterCodeGameMode = 'gameMode';
static const String parameterCodeGameLevel = 'gameLevel';
......@@ -33,9 +33,9 @@ class DefaultGameSettings {
static List<String> getAvailableValues(String parameterCode) {
switch (parameterCode) {
case parameterCodeGameMode:
return DefaultGameSettings.allowedGameModeValues;
return DefaultActivitySettings.allowedGameModeValues;
case parameterCodeGameLevel:
return DefaultGameSettings.allowedGameLevelValues;
return DefaultActivitySettings.allowedGameLevelValues;
}
printlog('Did not find any available value for game parameter "$parameterCode".');
......
import 'package:flutter/material.dart';
import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
import 'package:hangman/data/fetch_data_helper.dart';
import 'package:hangman/models/activity/activity.dart';
import 'package:hangman/models/activity/picked_word.dart';
import 'package:hangman/models/settings/settings_activity.dart';
import 'package:hangman/models/settings/settings_global.dart';
part 'activity_state.dart';
class ActivityCubit extends HydratedCubit<ActivityState> {
ActivityCubit()
: super(ActivityState(
currentActivity: Activity.createNull(),
));
void updateState(Activity activity) {
emit(ActivityState(
currentActivity: activity,
));
}
void refresh() {
final Activity activity = Activity(
// Settings
activitySettings: state.currentActivity.activitySettings,
globalSettings: state.currentActivity.globalSettings,
// State
isRunning: state.currentActivity.isRunning,
isStarted: state.currentActivity.isStarted,
isFinished: state.currentActivity.isFinished,
animationInProgress: state.currentActivity.animationInProgress,
gettingSecretWord: state.currentActivity.gettingSecretWord,
// Base data
secretWord: state.currentActivity.secretWord,
clue: state.currentActivity.clue,
// Game data
hiddenWord: state.currentActivity.hiddenWord,
usedLetters: state.currentActivity.usedLetters,
errorsCount: state.currentActivity.errorsCount,
isClueDisplayed: state.currentActivity.isClueDisplayed,
);
// game.dump();
updateState(activity);
}
void startNewActivity({
required ActivitySettings activitySettings,
required GlobalSettings globalSettings,
}) {
final Activity newActivity = Activity.createNew(
// Settings
activitySettings: activitySettings,
globalSettings: globalSettings,
);
updateState(newActivity);
refresh();
FetchDataHelper().pickRandomWord(activitySettings).then((PickedWord pickedWord) {
state.currentActivity.gettingSecretWord = false;
state.currentActivity.secretWord = pickedWord.word;
state.currentActivity.clue = pickedWord.clue;
state.currentActivity.hiddenWord =
List<String>.generate(pickedWord.word.length, (i) => '_');
state.currentActivity.dump();
refresh();
});
}
void quitActivity() {
state.currentActivity.isRunning = false;
refresh();
}
void resumeSavedActivity() {
state.currentActivity.isRunning = true;
refresh();
}
void deleteSavedActivity() {
state.currentActivity.isRunning = false;
state.currentActivity.isFinished = true;
refresh();
}
void submitLetter(String key) {
if (!state.currentActivity.usedLetters.contains(key)) {
updateUsedLetters(key);
if (state.currentActivity.secretWord.contains(key)) {
for (int index = 0; index < state.currentActivity.secretWord.length; index++) {
if (key == state.currentActivity.secretWord[index]) {
updateHiddenWord(index, key);
}
}
} else {
incrementErrorsCount();
}
}
if ((state.currentActivity.hiddenWordAsString == state.currentActivity.secretWord) ||
(state.currentActivity.errorsCount == 8)) {
state.currentActivity.isFinished = true;
}
refresh();
}
void updateUsedLetters(String key) {
state.currentActivity.usedLetters.add(key);
refresh();
}
void updateHiddenWord(int index, String letter) {
state.currentActivity.hiddenWord[index] = letter;
refresh();
}
void incrementErrorsCount() {
state.currentActivity.errorsCount++;
refresh();
}
void toggleClueDisplay() {
state.currentActivity.isClueDisplayed = !state.currentActivity.isClueDisplayed;
refresh();
}
@override
ActivityState? fromJson(Map<String, dynamic> json) {
final Activity currentActivity = json['currentActivity'] as Activity;
return ActivityState(
currentActivity: currentActivity,
);
}
@override
Map<String, dynamic>? toJson(ActivityState state) {
return <String, dynamic>{
'currentActivity': state.currentActivity.toJson(),
};
}
}
part of 'game_cubit.dart';
part of 'activity_cubit.dart';
@immutable
class GameState extends Equatable {
const GameState({
required this.currentGame,
class ActivityState extends Equatable {
const ActivityState({
required this.currentActivity,
});
final Game currentGame;
final Activity currentActivity;
@override
List<dynamic> get props => <dynamic>[
currentGame,
currentActivity,
];
}
import 'package:flutter/material.dart';
import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
import 'package:hangman/data/fetch_data_helper.dart';
import 'package:hangman/models/game/game.dart';
import 'package:hangman/models/game/picked_word.dart';
import 'package:hangman/models/settings/settings_game.dart';
import 'package:hangman/models/settings/settings_global.dart';
part 'game_state.dart';
class GameCubit extends HydratedCubit<GameState> {
GameCubit()
: super(GameState(
currentGame: Game.createNull(),
));
void updateState(Game game) {
emit(GameState(
currentGame: game,
));
}
void refresh() {
final Game game = Game(
// Settings
gameSettings: state.currentGame.gameSettings,
globalSettings: state.currentGame.globalSettings,
// State
isRunning: state.currentGame.isRunning,
isStarted: state.currentGame.isStarted,
isFinished: state.currentGame.isFinished,
animationInProgress: state.currentGame.animationInProgress,
gettingSecretWord: state.currentGame.gettingSecretWord,
// Base data
secretWord: state.currentGame.secretWord,
clue: state.currentGame.clue,
// Game data
hiddenWord: state.currentGame.hiddenWord,
usedLetters: state.currentGame.usedLetters,
errorsCount: state.currentGame.errorsCount,
isClueDisplayed: state.currentGame.isClueDisplayed,
);
// game.dump();
updateState(game);
}
void startNewGame({
required GameSettings gameSettings,
required GlobalSettings globalSettings,
}) {
final Game newGame = Game.createNew(
// Settings
gameSettings: gameSettings,
globalSettings: globalSettings,
);
updateState(newGame);
refresh();
FetchDataHelper().pickRandomWord(gameSettings).then((PickedWord pickedWord) {
state.currentGame.gettingSecretWord = false;
state.currentGame.secretWord = pickedWord.word;
state.currentGame.clue = pickedWord.clue;
state.currentGame.hiddenWord = List<String>.generate(pickedWord.word.length, (i) => '_');
state.currentGame.dump();
refresh();
});
}
void quitGame() {
state.currentGame.isRunning = false;
refresh();
}
void resumeSavedGame() {
state.currentGame.isRunning = true;
refresh();
}
void deleteSavedGame() {
state.currentGame.isRunning = false;
state.currentGame.isFinished = true;
refresh();
}
void submitLetter(String key) {
if (!state.currentGame.usedLetters.contains(key)) {
updateUsedLetters(key);
if (state.currentGame.secretWord.contains(key)) {
for (int index = 0; index < state.currentGame.secretWord.length; index++) {
if (key == state.currentGame.secretWord[index]) {
updateHiddenWord(index, key);
}
}
} else {
incrementErrorsCount();
}
}
if ((state.currentGame.hiddenWordAsString == state.currentGame.secretWord) ||
(state.currentGame.errorsCount == 8)) {
state.currentGame.isFinished = true;
}
refresh();
}
void updateUsedLetters(String key) {
state.currentGame.usedLetters.add(key);
refresh();
}
void updateHiddenWord(int index, String letter) {
state.currentGame.hiddenWord[index] = letter;
refresh();
}
void incrementErrorsCount() {
state.currentGame.errorsCount++;
refresh();
}
void toggleClueDisplay() {
state.currentGame.isClueDisplayed = !state.currentGame.isClueDisplayed;
refresh();
}
@override
GameState? fromJson(Map<String, dynamic> json) {
final Game currentGame = json['currentGame'] as Game;
return GameState(
currentGame: currentGame,
);
}
@override
Map<String, dynamic>? toJson(GameState state) {
return <String, dynamic>{
'currentGame': state.currentGame.toJson(),
};
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment