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

Normalize Activity application architecture

parent 5669f4e0
No related branches found
No related tags found
1 merge request!18Resolve "Normalize Activity application architecture"
Pipeline #6665 passed
This commit is part of merge request !18. Comments created here will be created in the context of that merge request.
Showing
with 659 additions and 44 deletions
{ {
"app_name": "Oware", "app_name": "Oware",
"page_home": "Home",
"page_game": "Game",
"settings_title": "Settings", "settings_title": "Settings",
"settings_label_theme": "Theme mode", "settings_label_theme": "Theme mode",
......
{ {
"app_name": "Awalé", "app_name": "Awalé",
"page_home": "Accueil",
"page_game": "Jeu",
"settings_title": "Réglages", "settings_title": "Réglages",
"settings_label_theme": "Thème de couleurs", "settings_label_theme": "Thème de couleurs",
......
Normalize Activity application architecture.
Harmonisation des applications en Activity.
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_custom_toolbox/flutter_toolbox.dart'; import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
import 'package:awale/ui/screens/page_about.dart'; import 'package:awale/common/ui/pages/game.dart';
import 'package:awale/ui/screens/page_game.dart'; import 'package:awale/common/ui/pages/parameters.dart';
import 'package:awale/ui/screens/page_settings.dart';
class MenuItem { class ActivityPageItem {
final String code;
final Icon icon; final Icon icon;
final Widget page; final Widget page;
const MenuItem({ const ActivityPageItem({
required this.code,
required this.icon, required this.icon,
required this.page, required this.page,
}); });
} }
class Menu { class ActivityPage {
static const indexGame = 0; static const bool displayBottomNavBar = false;
static const menuItemGame = MenuItem(
icon: Icon(UniconsLine.home),
page: PageGame(),
);
static const indexSettings = 1; static const indexHome = 0;
static const menuItemSettings = MenuItem( static const pageHome = ActivityPageItem(
icon: Icon(UniconsLine.setting), code: 'page_home',
page: PageSettings(), icon: Icon(UniconsLine.home),
page: PageParameters(),
); );
static const indexAbout = 2; static const indexGame = 1;
static const menuItemAbout = MenuItem( static const pageGame = ActivityPageItem(
icon: Icon(UniconsLine.info_circle), code: 'page_game',
page: PageAbout(), icon: Icon(UniconsLine.star),
page: PageGame(),
); );
static Map<int, MenuItem> items = { static const Map<int, ActivityPageItem> items = {
indexGame: menuItemGame, indexHome: pageHome,
indexSettings: menuItemSettings, indexGame: pageGame,
indexAbout: menuItemAbout,
}; };
static int defaultPageIndex = indexHome;
static bool isIndexAllowed(int pageIndex) { static bool isIndexAllowed(int pageIndex) {
return items.keys.contains(pageIndex); return items.keys.contains(pageIndex);
} }
static Widget getPageWidget(int pageIndex) { static Widget getWidget(int pageIndex) {
return items[pageIndex]?.page ?? menuItemGame.page; 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:awale/common/ui/screens/about.dart';
import 'package:awale/common/ui/screens/activity.dart';
import 'package:awale/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:flutter_custom_toolbox/flutter_toolbox.dart';
import 'package:awale/config/menu.dart'; import 'package:awale/common/config/activity_page.dart';
class NavCubit extends HydratedCubit<int> { class NavCubitPage extends HydratedCubit<int> {
NavCubit() : super(0); NavCubitPage() : super(0);
void updateIndex(int index) { void updateIndex(int index) {
if (Menu.isIndexAllowed(index)) { if (ActivityPage.isIndexAllowed(index)) {
emit(index); emit(index);
} else { } else {
goToGamePage(); emit(ActivityPage.indexHome);
} }
} }
void goToGamePage() { void goToPageHome() {
emit(Menu.indexGame); updateIndex(ActivityPage.indexHome);
} }
void goToSettingsPage() { void goToPageGame() {
emit(Menu.indexSettings); updateIndex(ActivityPage.indexGame);
}
void goToAboutPage() {
emit(Menu.indexAbout);
} }
@override @override
int fromJson(Map<String, dynamic> json) { int fromJson(Map<String, dynamic> json) {
return Menu.indexGame; return ActivityPage.indexHome;
} }
@override @override
Map<String, dynamic>? toJson(int state) { 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:awale/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:awale/common/config/activity_page.dart';
import 'package:awale/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/material.dart';
import 'package:flutter_custom_toolbox/flutter_toolbox.dart'; import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
import 'package:awale/config/menu.dart'; import 'package:awale/common/config/screen.dart';
import 'package:awale/cubit/game_cubit.dart'; import 'package:awale/common/cubit/nav/nav_cubit_pages.dart';
import 'package:awale/cubit/nav_cubit.dart'; import 'package:awale/common/cubit/nav/nav_cubit_screens.dart';
import 'package:awale/models/game/game.dart';
import 'package:awale/cubit/activity/activity_cubit.dart';
import 'package:awale/models/activity/activity.dart';
class GlobalAppBar extends StatelessWidget implements PreferredSizeWidget { class GlobalAppBar extends StatelessWidget implements PreferredSizeWidget {
const GlobalAppBar({super.key}); const GlobalAppBar({super.key});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocBuilder<GameCubit, GameState>( return BlocBuilder<ActivityCubit, ActivityState>(
builder: (BuildContext context, GameState gameState) { builder: (BuildContext context, ActivityState activityState) {
return BlocBuilder<NavCubit, int>( return BlocBuilder<NavCubitScreen, int>(
builder: (BuildContext context, int pageIndex) { builder: (BuildContext context, int pageIndex) {
final Game currentGame = gameState.currentGame; final Activity currentActivity = activityState.currentActivity;
final List<Widget> menuActions = []; final List<Widget> menuActions = [];
if (currentGame.isRunning && !currentGame.isFinished) { if (currentActivity.isRunning && !currentActivity.isFinished) {
menuActions.add(StyledButton( menuActions.add(StyledButton(
color: Colors.red, color: Colors.red,
onPressed: () {}, onPressed: () {},
onLongPress: () { onLongPress: () {
BlocProvider.of<GameCubit>(context).quitGame(); BlocProvider.of<ActivityCubit>(context).quitActivity();
BlocProvider.of<NavCubitPage>(context).goToPageHome();
}, },
child: const Image( child: const Image(
image: AssetImage('assets/ui/button_back.png'), image: AssetImage('assets/ui/button_back.png'),
...@@ -32,38 +35,38 @@ class GlobalAppBar extends StatelessWidget implements PreferredSizeWidget { ...@@ -32,38 +35,38 @@ class GlobalAppBar extends StatelessWidget implements PreferredSizeWidget {
), ),
)); ));
} else { } else {
if (pageIndex == Menu.indexGame) { if (pageIndex == Screen.indexActivity) {
// go to Settings page // go to Settings page
menuActions.add(ElevatedButton( menuActions.add(ElevatedButton(
onPressed: () { onPressed: () {
BlocProvider.of<NavCubit>(context).goToSettingsPage(); BlocProvider.of<NavCubitScreen>(context).goToScreenSettings();
}, },
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
shape: const CircleBorder(), shape: const CircleBorder(),
), ),
child: Menu.menuItemSettings.icon, child: Screen.screenSettings.icon,
)); ));
// go to About page // go to About page
menuActions.add(ElevatedButton( menuActions.add(ElevatedButton(
onPressed: () { onPressed: () {
BlocProvider.of<NavCubit>(context).goToAboutPage(); BlocProvider.of<NavCubitScreen>(context).goToScreenAbout();
}, },
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
shape: const CircleBorder(), shape: const CircleBorder(),
), ),
child: Menu.menuItemAbout.icon, child: Screen.screenAbout.icon,
)); ));
} else { } else {
// back to Home page // back to Home page
menuActions.add(ElevatedButton( menuActions.add(ElevatedButton(
onPressed: () { onPressed: () {
BlocProvider.of<NavCubit>(context).goToGamePage(); BlocProvider.of<NavCubitScreen>(context).goToScreenActivity();
}, },
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
shape: const CircleBorder(), shape: const CircleBorder(),
), ),
child: Menu.menuItemGame.icon, child: Screen.screenActivity.icon,
)); ));
} }
} }
......
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_custom_toolbox/flutter_toolbox.dart'; import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
import 'package:awale/cubit/game_cubit.dart'; import 'package:awale/cubit/activity/activity_cubit.dart';
import 'package:awale/models/game/game.dart'; import 'package:awale/models/activity/activity.dart';
import 'package:awale/ui/widgets/game/game_board.dart'; import 'package:awale/ui/widgets/game/game_board.dart';
import 'package:awale/ui/widgets/game/game_end.dart'; import 'package:awale/ui/widgets/game/game_end.dart';
import 'package:awale/ui/widgets/game/game_player.dart'; import 'package:awale/ui/widgets/game/game_player.dart';
class GameLayout extends StatelessWidget { class PageGame extends StatelessWidget {
const GameLayout({super.key}); const PageGame({super.key});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocBuilder<GameCubit, GameState>( return BlocBuilder<ActivityCubit, ActivityState>(
builder: (BuildContext context, GameState gameState) { builder: (BuildContext context, ActivityState activityState) {
final Game currentGame = gameState.currentGame; final Activity currentActivity = activityState.currentActivity;
var screenSize = MediaQuery.of(context).size; var screenSize = MediaQuery.of(context).size;
...@@ -35,7 +35,7 @@ class GameLayout extends StatelessWidget { ...@@ -35,7 +35,7 @@ class GameLayout extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
currentGame.isFinished currentActivity.isFinished
? GameEndWidget( ? GameEndWidget(
playerIndex: 0, playerIndex: 0,
widgetSize: baseSize, widgetSize: baseSize,
...@@ -45,7 +45,7 @@ class GameLayout extends StatelessWidget { ...@@ -45,7 +45,7 @@ class GameLayout extends StatelessWidget {
widgetSize: baseSize, widgetSize: baseSize,
), ),
GameBoardWidget(houseSize: baseSize), GameBoardWidget(houseSize: baseSize),
currentGame.isFinished currentActivity.isFinished
? GameEndWidget( ? GameEndWidget(
playerIndex: 1, playerIndex: 1,
widgetSize: baseSize, widgetSize: baseSize,
......
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_custom_toolbox/flutter_toolbox.dart'; import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
import 'package:awale/config/default_game_settings.dart'; import 'package:awale/common/ui/parameters/parameter_widget.dart';
import 'package:awale/config/default_activity_settings.dart';
import 'package:awale/config/default_global_settings.dart'; import 'package:awale/config/default_global_settings.dart';
import 'package:awale/cubit/settings_game_cubit.dart'; import 'package:awale/cubit/activity/activity_cubit.dart';
import 'package:awale/cubit/settings_global_cubit.dart'; import 'package:awale/cubit/settings/settings_activity_cubit.dart';
import 'package:awale/cubit/settings/settings_global_cubit.dart';
import 'package:awale/models/activity/activity.dart';
import 'package:awale/ui/widgets/actions/button_delete_saved_game.dart'; import 'package:awale/ui/widgets/actions/button_delete_saved_game.dart';
import 'package:awale/ui/widgets/actions/button_game_start_new.dart'; import 'package:awale/ui/widgets/actions/button_game_start_new.dart';
import 'package:awale/ui/widgets/actions/button_resume_saved_game.dart'; import 'package:awale/ui/widgets/actions/button_resume_saved_game.dart';
import 'package:awale/ui/parameters/parameter_widget.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; final double separatorHeight = 8.0;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocBuilder<ActivityCubit, ActivityState>(
builder: (BuildContext context, ActivityState activityState) {
final Activity currentActivity = activityState.currentActivity;
final List<Widget> lines = []; final List<Widget> lines = [];
// Game settings // Game settings
for (String code in DefaultGameSettings.availableParameters) { for (String code in DefaultActivitySettings.availableParameters) {
lines.add(Row( lines.add(Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: buildParametersLine( children: buildParametersLine(
...@@ -38,7 +43,7 @@ class ParametersLayout extends StatelessWidget { ...@@ -38,7 +43,7 @@ class ParametersLayout extends StatelessWidget {
child: SizedBox(height: separatorHeight), child: SizedBox(height: separatorHeight),
)); ));
if (canResume == false) { if (currentActivity.canBeResumed == false) {
// Start new game // Start new game
lines.add( lines.add(
const AspectRatio( const AspectRatio(
...@@ -77,6 +82,8 @@ class ParametersLayout extends StatelessWidget { ...@@ -77,6 +82,8 @@ class ParametersLayout extends StatelessWidget {
return Column( return Column(
children: lines, children: lines,
); );
},
);
} }
List<Widget> buildParametersLine({ List<Widget> buildParametersLine({
...@@ -87,25 +94,25 @@ class ParametersLayout extends StatelessWidget { ...@@ -87,25 +94,25 @@ class ParametersLayout extends StatelessWidget {
final List<String> availableValues = isGlobal final List<String> availableValues = isGlobal
? DefaultGlobalSettings.getAvailableValues(code) ? DefaultGlobalSettings.getAvailableValues(code)
: DefaultGameSettings.getAvailableValues(code); : DefaultActivitySettings.getAvailableValues(code);
if (availableValues.length <= 1) { if (availableValues.length <= 1) {
return []; return [];
} }
for (String value in availableValues) { for (String value in availableValues) {
final Widget parameterButton = BlocBuilder<GameSettingsCubit, GameSettingsState>( final Widget parameterButton = BlocBuilder<ActivitySettingsCubit, ActivitySettingsState>(
builder: (BuildContext context, GameSettingsState gameSettingsState) { builder: (BuildContext context, ActivitySettingsState activitySettingsState) {
return BlocBuilder<GlobalSettingsCubit, GlobalSettingsState>( return BlocBuilder<GlobalSettingsCubit, GlobalSettingsState>(
builder: (BuildContext context, GlobalSettingsState globalSettingsState) { builder: (BuildContext context, GlobalSettingsState globalSettingsState) {
final GameSettingsCubit gameSettingsCubit = final ActivitySettingsCubit activitySettingsCubit =
BlocProvider.of<GameSettingsCubit>(context); BlocProvider.of<ActivitySettingsCubit>(context);
final GlobalSettingsCubit globalSettingsCubit = final GlobalSettingsCubit globalSettingsCubit =
BlocProvider.of<GlobalSettingsCubit>(context); BlocProvider.of<GlobalSettingsCubit>(context);
final String currentValue = isGlobal final String currentValue = isGlobal
? globalSettingsCubit.getParameterValue(code) ? globalSettingsCubit.getParameterValue(code)
: gameSettingsCubit.getParameterValue(code); : activitySettingsCubit.getParameterValue(code);
final bool isSelected = (value == currentValue); final bool isSelected = (value == currentValue);
...@@ -119,12 +126,12 @@ class ParametersLayout extends StatelessWidget { ...@@ -119,12 +126,12 @@ class ParametersLayout extends StatelessWidget {
value: value, value: value,
isSelected: isSelected, isSelected: isSelected,
size: itemWidth, size: itemWidth,
gameSettings: gameSettingsState.settings, activitySettings: activitySettingsState.settings,
globalSettings: globalSettingsState.settings, globalSettings: globalSettingsState.settings,
onPressed: () { onPressed: () {
isGlobal isGlobal
? globalSettingsCubit.setParameterValue(code, value) ? globalSettingsCubit.setParameterValue(code, value)
: gameSettingsCubit.setParameterValue(code, value); : activitySettingsCubit.setParameterValue(code, value);
}, },
), ),
); );
......
...@@ -3,20 +3,20 @@ import 'dart:math'; ...@@ -3,20 +3,20 @@ import 'dart:math';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_custom_toolbox/flutter_toolbox.dart'; import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
import 'package:awale/models/settings/settings_game.dart'; import 'package:awale/models/settings/settings_activity.dart';
import 'package:awale/models/settings/settings_global.dart'; import 'package:awale/models/settings/settings_global.dart';
class ParameterPainter extends CustomPainter { class ParameterPainter extends CustomPainter {
const ParameterPainter({ const ParameterPainter({
required this.code, required this.code,
required this.value, required this.value,
required this.gameSettings, required this.activitySettings,
required this.globalSettings, required this.globalSettings,
}); });
final String code; final String code;
final String value; final String value;
final GameSettings gameSettings; final ActivitySettings activitySettings;
final GlobalSettings globalSettings; final GlobalSettings globalSettings;
@override @override
......
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_custom_toolbox/flutter_toolbox.dart'; import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
import 'package:awale/config/default_game_settings.dart'; import 'package:awale/config/default_activity_settings.dart';
import 'package:awale/models/settings/settings_game.dart'; import 'package:awale/models/settings/settings_activity.dart';
import 'package:awale/models/settings/settings_global.dart'; import 'package:awale/models/settings/settings_global.dart';
class ParameterWidget extends StatelessWidget { class ParameterWidget extends StatelessWidget {
...@@ -12,7 +12,7 @@ class ParameterWidget extends StatelessWidget { ...@@ -12,7 +12,7 @@ class ParameterWidget extends StatelessWidget {
required this.value, required this.value,
required this.isSelected, required this.isSelected,
required this.size, required this.size,
required this.gameSettings, required this.activitySettings,
required this.globalSettings, required this.globalSettings,
required this.onPressed, required this.onPressed,
}); });
...@@ -21,7 +21,7 @@ class ParameterWidget extends StatelessWidget { ...@@ -21,7 +21,7 @@ class ParameterWidget extends StatelessWidget {
final String value; final String value;
final bool isSelected; final bool isSelected;
final double size; final double size;
final GameSettings gameSettings; final ActivitySettings activitySettings;
final GlobalSettings globalSettings; final GlobalSettings globalSettings;
final VoidCallback onPressed; final VoidCallback onPressed;
...@@ -35,7 +35,7 @@ class ParameterWidget extends StatelessWidget { ...@@ -35,7 +35,7 @@ class ParameterWidget extends StatelessWidget {
Widget content = const SizedBox.shrink(); Widget content = const SizedBox.shrink();
switch (code) { switch (code) {
case DefaultGameSettings.parameterCodeGameMode: case DefaultActivitySettings.parameterCodeGameMode:
content = getGameModeParameterItem(); content = getGameModeParameterItem();
break; break;
default: default:
...@@ -72,19 +72,19 @@ class ParameterWidget extends StatelessWidget { ...@@ -72,19 +72,19 @@ class ParameterWidget extends StatelessWidget {
Color baseColor = Colors.grey; Color baseColor = Colors.grey;
switch (value) { switch (value) {
case DefaultGameSettings.gameModeHumanVsHuman: case DefaultActivitySettings.gameModeHumanVsHuman:
text = '🧑 🧑'; text = '🧑 🧑';
baseColor = Colors.green; baseColor = Colors.green;
break; break;
case DefaultGameSettings.gameModeHumanVsRobot: case DefaultActivitySettings.gameModeHumanVsRobot:
text = '🧑 🤖'; text = '🧑 🤖';
baseColor = Colors.pink; baseColor = Colors.pink;
break; break;
case DefaultGameSettings.gameModeRobotVsHuman: case DefaultActivitySettings.gameModeRobotVsHuman:
text = '🤖 🧑'; text = '🤖 🧑';
baseColor = Colors.pink; baseColor = Colors.pink;
break; break;
case DefaultGameSettings.gameModeRobotVsRobot: case DefaultActivitySettings.gameModeRobotVsRobot:
text = '🤖 🤖'; text = '🤖 🤖';
baseColor = Colors.brown; baseColor = Colors.brown;
break; break;
......
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_custom_toolbox/flutter_toolbox.dart'; import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
class PageAbout extends StatelessWidget { class ScreenAbout extends StatelessWidget {
const PageAbout({super.key}); const ScreenAbout({super.key});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
......
import 'package:flutter/material.dart';
import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
import 'package:awale/common/config/activity_page.dart';
import 'package:awale/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/material.dart';
import 'package:flutter_custom_toolbox/flutter_toolbox.dart'; import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
class PageSettings extends StatelessWidget { class ScreenSettings extends StatelessWidget {
const PageSettings({super.key}); const ScreenSettings({super.key});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
......
class ApplicationConfig {
static const String appTitle = 'Awale';
}
import 'package:flutter_custom_toolbox/flutter_toolbox.dart'; import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
class DefaultGameSettings { class DefaultActivitySettings {
// available game parameters codes // available game parameters codes
static const String parameterCodeGameMode = 'gameMode'; static const String parameterCodeGameMode = 'gameMode';
static const List<String> availableParameters = [ static const List<String> availableParameters = [
...@@ -25,7 +25,7 @@ class DefaultGameSettings { ...@@ -25,7 +25,7 @@ class DefaultGameSettings {
static List<String> getAvailableValues(String parameterCode) { static List<String> getAvailableValues(String parameterCode) {
switch (parameterCode) { switch (parameterCode) {
case parameterCodeGameMode: case parameterCodeGameMode:
return DefaultGameSettings.allowedGameModeValues; return DefaultActivitySettings.allowedGameModeValues;
} }
printlog('Did not find any available value for game parameter "$parameterCode".'); printlog('Did not find any available value for game parameter "$parameterCode".');
......
...@@ -3,91 +3,93 @@ import 'dart:async'; ...@@ -3,91 +3,93 @@ import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_custom_toolbox/flutter_toolbox.dart'; import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
import 'package:awale/models/game/game.dart'; import 'package:awale/models/activity/activity.dart';
import 'package:awale/models/settings/settings_game.dart'; import 'package:awale/models/settings/settings_activity.dart';
import 'package:awale/models/settings/settings_global.dart'; import 'package:awale/models/settings/settings_global.dart';
import 'package:awale/robot/robot_player.dart'; import 'package:awale/robot/robot_player.dart';
part 'game_state.dart'; part 'activity_state.dart';
class GameCubit extends HydratedCubit<GameState> { class ActivityCubit extends HydratedCubit<ActivityState> {
GameCubit() ActivityCubit()
: super(GameState( : super(ActivityState(
currentGame: Game.createNull(), currentActivity: Activity.createNull(),
)); ));
void updateState(Game game) { void updateState(Activity activity) {
emit(GameState( emit(ActivityState(
currentGame: game, currentActivity: activity,
)); ));
} }
void refresh() { void refresh() {
final Game game = Game( final Activity activity = Activity(
// Settings // Settings
gameSettings: state.currentGame.gameSettings, activitySettings: state.currentActivity.activitySettings,
globalSettings: state.currentGame.globalSettings, globalSettings: state.currentActivity.globalSettings,
// State // State
isRunning: state.currentGame.isRunning, isRunning: state.currentActivity.isRunning,
isStarted: state.currentGame.isStarted, isStarted: state.currentActivity.isStarted,
isFinished: state.currentGame.isFinished, isFinished: state.currentActivity.isFinished,
animationInProgress: state.currentGame.animationInProgress, animationInProgress: state.currentActivity.animationInProgress,
// Base data // Base data
board: state.currentGame.board, board: state.currentActivity.board,
// Game data // Game data
currentPlayer: state.currentGame.currentPlayer, currentPlayer: state.currentActivity.currentPlayer,
scores: state.currentGame.scores, scores: state.currentActivity.scores,
currentHand: state.currentGame.currentHand, currentHand: state.currentActivity.currentHand,
); );
// game.dump(); // game.dump();
updateState(game); updateState(activity);
} }
void startNewGame({ void startNewActivity({
required GameSettings gameSettings, required ActivitySettings activitySettings,
required GlobalSettings globalSettings, required GlobalSettings globalSettings,
}) { }) {
final Game newGame = Game.createNew( final Activity newActivity = Activity.createNew(
// Settings // Settings
gameSettings: gameSettings, activitySettings: activitySettings,
globalSettings: globalSettings, globalSettings: globalSettings,
); );
newGame.dump(); newActivity.dump();
updateState(newGame); updateState(newActivity);
refresh(); refresh();
robotPlay(); robotPlay();
} }
void quitGame() { void quitActivity() {
state.currentGame.isRunning = false; state.currentActivity.isRunning = false;
refresh(); refresh();
} }
void resumeSavedGame() { void resumeSavedActivity() {
state.currentGame.isRunning = true; state.currentActivity.isRunning = true;
refresh(); refresh();
} }
void deleteSavedGame() { void deleteSavedActivity() {
state.currentGame.isRunning = false; state.currentActivity.isRunning = false;
state.currentGame.isFinished = true; state.currentActivity.isFinished = true;
refresh(); refresh();
} }
void toggleCurrentPlayer() { void toggleCurrentPlayer() {
state.currentGame.currentPlayer = 1 - state.currentGame.currentPlayer; state.currentActivity.currentPlayer = 1 - state.currentActivity.currentPlayer;
refresh(); refresh();
robotPlay(); robotPlay();
} }
void robotPlay() async { void robotPlay() async {
if (!state.currentGame.isFinished && !state.currentGame.isCurrentPlayerHuman()) { if (state.currentActivity.isRunning &&
final int? pickedCell = RobotPlayer.pickCell(state.currentGame); !state.currentActivity.isFinished &&
!state.currentActivity.isCurrentPlayerHuman()) {
final int? pickedCell = RobotPlayer.pickCell(state.currentActivity);
await Future.delayed(const Duration(milliseconds: 500)); await Future.delayed(const Duration(milliseconds: 500));
if (pickedCell != null) { if (pickedCell != null) {
...@@ -99,25 +101,25 @@ class GameCubit extends HydratedCubit<GameState> { ...@@ -99,25 +101,25 @@ class GameCubit extends HydratedCubit<GameState> {
void tapOnCell(int cellIndex) async { void tapOnCell(int cellIndex) async {
printlog('tapOnCell: $cellIndex'); printlog('tapOnCell: $cellIndex');
if (!state.currentGame.isCurrentPlayerHouse(cellIndex)) { if (!state.currentActivity.isCurrentPlayerHouse(cellIndex)) {
printlog('not allowed'); printlog('not allowed');
return; return;
} }
if (state.currentGame.board.cells[cellIndex] == 0) { if (state.currentActivity.board.cells[cellIndex] == 0) {
printlog('empty cell'); printlog('empty cell');
return; return;
} }
if (!state.currentGame.isMoveAllowed(cellIndex)) { if (!state.currentActivity.isMoveAllowed(cellIndex)) {
printlog('not allowed (need to give at least one seed to other player)'); printlog('not allowed (need to give at least one seed to other player)');
return; return;
} }
state.currentGame.animationInProgress = true; state.currentActivity.animationInProgress = true;
refresh(); refresh();
final int lastCellIndex = await animateSeedsDistribution(cellIndex); final int lastCellIndex = await animateSeedsDistribution(cellIndex);
...@@ -125,34 +127,34 @@ class GameCubit extends HydratedCubit<GameState> { ...@@ -125,34 +127,34 @@ class GameCubit extends HydratedCubit<GameState> {
toggleCurrentPlayer(); toggleCurrentPlayer();
if (!state.currentGame.canPlay()) { if (!state.currentActivity.canPlay()) {
printlog('user has no more move to play'); printlog('user has no more move to play');
state.currentGame.isFinished = true; state.currentActivity.isFinished = true;
refresh(); refresh();
} }
state.currentGame.animationInProgress = false; state.currentActivity.animationInProgress = false;
refresh(); refresh();
} }
Future<int> animateSeedsDistribution(int sourceCellIndex) async { Future<int> animateSeedsDistribution(int sourceCellIndex) async {
printlog('animateSeedsDistribution / sourceCellIndex: $sourceCellIndex'); printlog('animateSeedsDistribution / sourceCellIndex: $sourceCellIndex');
final int seedsCount = state.currentGame.board.cells[sourceCellIndex]; final int seedsCount = state.currentActivity.board.cells[sourceCellIndex];
// empty source cell // empty source cell
printlog('animateSeedsDistribution / empty source cell'); printlog('animateSeedsDistribution / empty source cell');
state.currentGame.board.cells[sourceCellIndex] = 0; state.currentActivity.board.cells[sourceCellIndex] = 0;
state.currentGame.currentHand = seedsCount; state.currentActivity.currentHand = seedsCount;
refresh(); refresh();
await Future.delayed(const Duration(milliseconds: 200)); await Future.delayed(const Duration(milliseconds: 200));
int cellIndex = sourceCellIndex; int cellIndex = sourceCellIndex;
for (int i = 0; i < seedsCount; i++) { for (int i = 0; i < seedsCount; i++) {
cellIndex = state.currentGame.getNextCellIndex(cellIndex, sourceCellIndex); cellIndex = state.currentActivity.getNextCellIndex(cellIndex, sourceCellIndex);
state.currentGame.currentHand--; state.currentActivity.currentHand--;
state.currentGame.board.cells[cellIndex] += 1; state.currentActivity.board.cells[cellIndex] += 1;
refresh(); refresh();
await Future.delayed(const Duration(milliseconds: 300)); await Future.delayed(const Duration(milliseconds: 300));
} }
...@@ -167,15 +169,15 @@ class GameCubit extends HydratedCubit<GameState> { ...@@ -167,15 +169,15 @@ class GameCubit extends HydratedCubit<GameState> {
int earnedSeedsCount = 0; int earnedSeedsCount = 0;
if (state.currentGame.isOpponentHouse(lastCellIndex)) { if (state.currentActivity.isOpponentHouse(lastCellIndex)) {
final int seedsCount = state.currentGame.board.cells[lastCellIndex]; final int seedsCount = state.currentActivity.board.cells[lastCellIndex];
printlog('found $seedsCount seed(s) on final house'); printlog('found $seedsCount seed(s) on final house');
if ([2, 3].contains(seedsCount)) { if ([2, 3].contains(seedsCount)) {
printlog('-> ok will earn these seeds'); printlog('-> ok will earn these seeds');
state.currentGame.board.cells[lastCellIndex] = 0; state.currentActivity.board.cells[lastCellIndex] = 0;
state.currentGame.scores[state.currentGame.currentPlayer] += seedsCount; state.currentActivity.scores[state.currentActivity.currentPlayer] += seedsCount;
earnedSeedsCount += seedsCount; earnedSeedsCount += seedsCount;
refresh(); refresh();
...@@ -183,7 +185,8 @@ class GameCubit extends HydratedCubit<GameState> { ...@@ -183,7 +185,8 @@ class GameCubit extends HydratedCubit<GameState> {
// (recursively) check previous cells // (recursively) check previous cells
printlog('-> dispatch to previous cell'); printlog('-> dispatch to previous cell');
final int previousCellIndex = state.currentGame.getPreviousCellIndex(lastCellIndex); final int previousCellIndex =
state.currentActivity.getPreviousCellIndex(lastCellIndex);
earnedSeedsCount += await animateSeedsEarning(previousCellIndex); earnedSeedsCount += await animateSeedsEarning(previousCellIndex);
} else { } else {
printlog('-> nothing to do'); printlog('-> nothing to do');
...@@ -194,18 +197,18 @@ class GameCubit extends HydratedCubit<GameState> { ...@@ -194,18 +197,18 @@ class GameCubit extends HydratedCubit<GameState> {
} }
@override @override
GameState? fromJson(Map<String, dynamic> json) { ActivityState? fromJson(Map<String, dynamic> json) {
final Game currentGame = json['currentGame'] as Game; final Activity currentActivity = json['currentActivity'] as Activity;
return GameState( return ActivityState(
currentGame: currentGame, currentActivity: currentActivity,
); );
} }
@override @override
Map<String, dynamic>? toJson(GameState state) { Map<String, dynamic>? toJson(ActivityState state) {
return <String, dynamic>{ return <String, dynamic>{
'currentGame': state.currentGame.toJson(), 'currentActivity': state.currentActivity.toJson(),
}; };
} }
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment