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

Merge branch '23-normalize-activity-application-architecture' into 'master'

Resolve "Normalize Activity application architecture"

Closes #23

See merge request !20
parents 982507c3 ecf1b256
No related branches found
No related tags found
1 merge request!20Resolve "Normalize Activity application architecture"
Pipeline #6777 passed
Showing
with 250 additions and 112 deletions
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:tetrisdual/config/default_game_settings.dart';
import 'package:tetrisdual/models/settings/settings_game.dart';
import 'package:tetrisdual/config/default_activity_settings.dart';
import 'package:tetrisdual/models/settings/settings_activity.dart';
part 'settings_game_state.dart';
part 'settings_activity_state.dart';
class GameSettingsCubit extends HydratedCubit<GameSettingsState> {
GameSettingsCubit() : super(GameSettingsState(settings: GameSettings.createDefault()));
class ActivitySettingsCubit extends HydratedCubit<ActivitySettingsState> {
ActivitySettingsCubit()
: super(ActivitySettingsState(settings: ActivitySettings.createDefault()));
void setValues({
String? gameType,
}) {
emit(
GameSettingsState(
settings: GameSettings(
ActivitySettingsState(
settings: ActivitySettings(
gameType: gameType ?? state.settings.gameType,
),
),
......@@ -23,17 +24,17 @@ class GameSettingsCubit extends HydratedCubit<GameSettingsState> {
String getParameterValue(String code) {
switch (code) {
case DefaultGameSettings.parameterCodeGameType:
return GameSettings.getGameTypeValueFromUnsafe(state.settings.gameType);
case DefaultActivitySettings.parameterCodeGameType:
return ActivitySettings.getGameTypeValueFromUnsafe(state.settings.gameType);
}
return '';
}
void setParameterValue(String code, String value) {
final String gameType = code == DefaultGameSettings.parameterCodeGameType
final String gameType = code == DefaultActivitySettings.parameterCodeGameType
? value
: getParameterValue(DefaultGameSettings.parameterCodeGameType);
: getParameterValue(DefaultActivitySettings.parameterCodeGameType);
setValues(
gameType: gameType,
......@@ -41,20 +42,20 @@ class GameSettingsCubit extends HydratedCubit<GameSettingsState> {
}
@override
GameSettingsState? fromJson(Map<String, dynamic> json) {
final String gameType = json[DefaultGameSettings.parameterCodeGameType] as String;
ActivitySettingsState? fromJson(Map<String, dynamic> json) {
final String gameType = json[DefaultActivitySettings.parameterCodeGameType] as String;
return GameSettingsState(
settings: GameSettings(
return ActivitySettingsState(
settings: ActivitySettings(
gameType: gameType,
),
);
}
@override
Map<String, dynamic>? toJson(GameSettingsState state) {
Map<String, dynamic>? toJson(ActivitySettingsState state) {
return <String, dynamic>{
DefaultGameSettings.parameterCodeGameType: state.settings.gameType,
DefaultActivitySettings.parameterCodeGameType: state.settings.gameType,
};
}
}
part of 'settings_game_cubit.dart';
part of 'settings_activity_cubit.dart';
@immutable
class GameSettingsState extends Equatable {
const GameSettingsState({
class ActivitySettingsState extends Equatable {
const ActivitySettingsState({
required this.settings,
});
final GameSettings settings;
final ActivitySettings settings;
@override
List<dynamic> get props => <dynamic>[
......
......@@ -4,10 +4,13 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
import 'package:tetrisdual/cubit/game_cubit.dart';
import 'package:tetrisdual/cubit/nav_cubit.dart';
import 'package:tetrisdual/cubit/settings_game_cubit.dart';
import 'package:tetrisdual/cubit/settings_global_cubit.dart';
import 'package:tetrisdual/common/cubit/nav/nav_cubit_pages.dart';
import 'package:tetrisdual/common/cubit/nav/nav_cubit_screens.dart';
import 'package:tetrisdual/config/application_config.dart';
import 'package:tetrisdual/cubit/activity/activity_cubit.dart';
import 'package:tetrisdual/cubit/settings/settings_activity_cubit.dart';
import 'package:tetrisdual/cubit/settings/settings_global_cubit.dart';
import 'package:tetrisdual/ui/skeleton.dart';
void main() async {
......@@ -45,17 +48,30 @@ class MyApp extends StatelessWidget {
return MultiBlocProvider(
providers: [
BlocProvider<NavCubit>(create: (context) => NavCubit()),
// default providers
BlocProvider<NavCubitPage>(
create: (context) => NavCubitPage(),
),
BlocProvider<NavCubitScreen>(
create: (context) => NavCubitScreen(),
),
BlocProvider<ApplicationThemeModeCubit>(
create: (context) => ApplicationThemeModeCubit()),
BlocProvider<GameCubit>(create: (context) => GameCubit()),
BlocProvider<GlobalSettingsCubit>(create: (context) => GlobalSettingsCubit()),
BlocProvider<GameSettingsCubit>(create: (context) => GameSettingsCubit()),
create: (context) => ApplicationThemeModeCubit(),
),
BlocProvider<ActivityCubit>(
create: (context) => ActivityCubit(),
),
BlocProvider<GlobalSettingsCubit>(
create: (context) => GlobalSettingsCubit(),
),
BlocProvider<ActivitySettingsCubit>(
create: (context) => ActivitySettingsCubit(),
),
],
child: BlocBuilder<ApplicationThemeModeCubit, ApplicationThemeModeState>(
builder: (BuildContext context, ApplicationThemeModeState state) {
return MaterialApp(
title: 'Tetris',
title: ApplicationConfig.appTitle,
home: const SkeletonScreen(),
// Theme stuff
......
import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
import 'package:tetrisdual/models/game/player.dart';
import 'package:tetrisdual/models/settings/settings_game.dart';
import 'package:tetrisdual/models/activity/player.dart';
import 'package:tetrisdual/models/settings/settings_activity.dart';
import 'package:tetrisdual/models/settings/settings_global.dart';
class Game {
Game({
class Activity {
Activity({
// Settings
required this.gameSettings,
required this.activitySettings,
required this.globalSettings,
// State
......@@ -24,7 +24,7 @@ class Game {
});
// Settings
final GameSettings gameSettings;
final ActivitySettings activitySettings;
final GlobalSettings globalSettings;
// State
......@@ -39,24 +39,25 @@ class Game {
// Game data
int currentPlayer;
factory Game.createEmpty() {
return Game(
factory Activity.createEmpty() {
return Activity(
// Settings
gameSettings: GameSettings.createDefault(),
activitySettings: ActivitySettings.createDefault(),
globalSettings: GlobalSettings.createDefault(),
);
}
factory Game.createNew({
GameSettings? gameSettings,
factory Activity.createNew({
ActivitySettings? activitySettings,
GlobalSettings? globalSettings,
}) {
final GameSettings newGameSettings = gameSettings ?? GameSettings.createDefault();
final ActivitySettings newActivitySettings =
activitySettings ?? ActivitySettings.createDefault();
final GlobalSettings newGlobalSettings = globalSettings ?? GlobalSettings.createDefault();
return Game(
return Activity(
// Settings
gameSettings: newGameSettings,
activitySettings: newActivitySettings,
globalSettings: newGlobalSettings,
// State
isRunning: true,
......@@ -76,9 +77,9 @@ class Game {
printlog('');
printlog('## Current game dump:');
printlog('');
printlog('$Game:');
printlog('$Activity:');
printlog(' Settings');
gameSettings.dump();
activitySettings.dump();
globalSettings.dump();
printlog(' State');
printlog(' isRunning: $isRunning');
......@@ -94,13 +95,13 @@ class Game {
@override
String toString() {
return '$Game(${toJson()})';
return '$Activity(${toJson()})';
}
Map<String, dynamic>? toJson() {
return <String, dynamic>{
// Settings
'gameSettings': gameSettings.toJson(),
'activitySettings': activitySettings.toJson(),
'globalSettings': globalSettings.toJson(),
// State
'isRunning': isRunning,
......
File moved
import 'dart:math';
import 'package:tetrisdual/models/game/counter.dart';
import 'package:tetrisdual/models/activity/counter.dart';
class Player {
Player(this.playerId);
......
import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
import 'package:tetrisdual/config/default_game_settings.dart';
import 'package:tetrisdual/config/default_activity_settings.dart';
class GameSettings {
class ActivitySettings {
final String gameType;
GameSettings({
ActivitySettings({
required this.gameType,
});
static String getGameTypeValueFromUnsafe(String gameType) {
if (DefaultGameSettings.allowedGameTypeValues.contains(gameType)) {
if (DefaultActivitySettings.allowedGameTypeValues.contains(gameType)) {
return gameType;
}
return DefaultGameSettings.defaultGameTypeValue;
return DefaultActivitySettings.defaultGameTypeValue;
}
factory GameSettings.createDefault() {
return GameSettings(
gameType: DefaultGameSettings.defaultGameTypeValue,
factory ActivitySettings.createDefault() {
return ActivitySettings(
gameType: DefaultActivitySettings.defaultGameTypeValue,
);
}
void dump() {
printlog('$GameSettings:');
printlog(' ${DefaultGameSettings.parameterCodeGameType}: $gameType');
printlog('$ActivitySettings:');
printlog(' ${DefaultActivitySettings.parameterCodeGameType}: $gameType');
printlog('');
}
@override
String toString() {
return '$GameSettings(${toJson()})';
return '$ActivitySettings(${toJson()})';
}
Map<String, dynamic>? toJson() {
return <String, dynamic>{
DefaultGameSettings.parameterCodeGameType: gameType,
DefaultActivitySettings.parameterCodeGameType: gameType,
};
}
}
import 'package:flutter/material.dart';
import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
import 'package:tetrisdual/cubit/game_cubit.dart';
import 'package:tetrisdual/models/game/game.dart';
import 'package:tetrisdual/ui/layouts/game_layout.dart';
import 'package:tetrisdual/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:flutter_custom_toolbox/flutter_toolbox.dart';
import 'package:tetrisdual/config/menu.dart';
import 'package:tetrisdual/cubit/nav_cubit.dart';
import 'package:tetrisdual/ui/widgets/global_app_bar.dart';
import 'package:tetrisdual/common/config/activity_page.dart';
import 'package:tetrisdual/common/config/screen.dart';
import 'package:tetrisdual/common/cubit/nav/nav_cubit_screens.dart';
import 'package:tetrisdual/common/ui/nav/global_app_bar.dart';
import 'package:tetrisdual/common/ui/nav/bottom_nav_bar.dart';
class SkeletonScreen extends StatelessWidget {
const SkeletonScreen({super.key});
@override
Widget build(BuildContext context) {
return BlocBuilder<NavCubitScreen, int>(
builder: (BuildContext context, int screenIndex) {
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(
child: Padding(
padding: const EdgeInsets.only(
top: 8,
left: 2,
right: 2,
),
child: Menu.getPageWidget(pageIndex),
);
},
child: Screen.getWidget(screenIndex),
),
),
backgroundColor: Theme.of(context).colorScheme.surface,
bottomNavigationBar: ActivityPage.displayBottomNavBar ? const BottomNavBar() : null,
);
},
);
}
}
import 'package:flutter/material.dart';
import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
import 'package:tetrisdual/cubit/game_cubit.dart';
import 'package:tetrisdual/cubit/activity/activity_cubit.dart';
class DeleteSavedGameButton extends StatelessWidget {
const DeleteSavedGameButton({super.key});
......@@ -11,7 +11,7 @@ class DeleteSavedGameButton extends StatelessWidget {
return StyledButton(
color: Colors.grey,
onPressed: () {
BlocProvider.of<GameCubit>(context).deleteSavedGame();
BlocProvider.of<ActivityCubit>(context).deleteSavedActivity();
},
child: const Image(
image: AssetImage('assets/ui/button_delete_saved_game.png'),
......
import 'package:flutter/material.dart';
import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
import 'package:tetrisdual/cubit/game_cubit.dart';
import 'package:tetrisdual/common/cubit/nav/nav_cubit_pages.dart';
import 'package:tetrisdual/cubit/activity/activity_cubit.dart';
class QuitGameButton extends StatelessWidget {
const QuitGameButton({super.key});
......@@ -11,7 +13,8 @@ class QuitGameButton extends StatelessWidget {
return StyledButton(
color: Colors.red,
onPressed: () {
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'),
......
import 'package:flutter/material.dart';
import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
import 'package:tetrisdual/cubit/game_cubit.dart';
import 'package:tetrisdual/cubit/settings_game_cubit.dart';
import 'package:tetrisdual/cubit/settings_global_cubit.dart';
import 'package:tetrisdual/common/cubit/nav/nav_cubit_pages.dart';
import 'package:tetrisdual/cubit/activity/activity_cubit.dart';
import 'package:tetrisdual/cubit/settings/settings_activity_cubit.dart';
import 'package:tetrisdual/cubit/settings/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<ActivitySettingsCubit, ActivitySettingsState>(
builder: (BuildContext context, ActivitySettingsState activitySettingsState) {
return BlocBuilder<GlobalSettingsCubit, GlobalSettingsState>(
builder: (BuildContext context, GlobalSettingsState globalSettingsState) {
return StyledButton(
color: Colors.blue,
onPressed: () {
BlocProvider.of<GameCubit>(context).startNewGame(
gameSettings: gameSettingsState.settings,
BlocProvider.of<ActivityCubit>(context).startNewActivity(
activitySettings: activitySettingsState.settings,
globalSettings: globalSettingsState.settings,
);
BlocProvider.of<NavCubitPage>(context).goToPageGame();
},
child: const Image(
image: AssetImage('assets/ui/button_start.png'),
......
import 'package:flutter/material.dart';
import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
import 'package:tetrisdual/cubit/game_cubit.dart';
import 'package:tetrisdual/common/cubit/nav/nav_cubit_pages.dart';
import 'package:tetrisdual/cubit/activity/activity_cubit.dart';
class ResumeSavedGameButton extends StatelessWidget {
const ResumeSavedGameButton({super.key});
......@@ -11,7 +13,8 @@ class ResumeSavedGameButton extends StatelessWidget {
return StyledButton(
color: Colors.blue,
onPressed: () {
BlocProvider.of<GameCubit>(context).resumeSavedGame();
BlocProvider.of<ActivityCubit>(context).resumeSavedActivity();
BlocProvider.of<NavCubitPage>(context).goToPageGame();
},
child: const Image(
image: AssetImage('assets/ui/button_resume_game.png'),
......
......@@ -3,8 +3,8 @@ import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
import 'package:tetrisdual/cubit/game_cubit.dart';
import 'package:tetrisdual/models/game/counter.dart';
import 'package:tetrisdual/cubit/activity/activity_cubit.dart';
import 'package:tetrisdual/models/activity/counter.dart';
class CounterWidget extends StatelessWidget {
const CounterWidget({super.key, required this.counter});
......@@ -48,7 +48,7 @@ class CounterWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
final GameCubit gameCubit = BlocProvider.of<GameCubit>(context);
final ActivityCubit activityCubit = BlocProvider.of<ActivityCubit>(context);
const spacer = TableRow(children: [
SizedBox(height: spacerHeight),
......@@ -59,17 +59,17 @@ class CounterWidget extends StatelessWidget {
return Table(
children: [
buildTouchWidget(gameCubit),
buildTouchWidget(activityCubit),
spacer,
buildLinesWidget(gameCubit),
buildLinesWidget(activityCubit),
spacer,
buildHolesWidget(gameCubit),
buildHolesWidget(activityCubit),
spacer,
],
);
}
TableRow buildTouchWidget(GameCubit gameCubit) {
TableRow buildTouchWidget(ActivityCubit activityCubit) {
return TableRow(
children: [
iconTouchingColor,
......@@ -82,7 +82,7 @@ class CounterWidget extends StatelessWidget {
icon: iconRemove,
onPressed: () {
counter.touch = false;
gameCubit.refresh();
activityCubit.refresh();
},
),
Center(
......@@ -101,14 +101,14 @@ class CounterWidget extends StatelessWidget {
icon: iconAdd,
onPressed: () {
counter.touch = true;
gameCubit.refresh();
activityCubit.refresh();
},
),
],
);
}
TableRow buildLinesWidget(GameCubit gameCubit) {
TableRow buildLinesWidget(ActivityCubit activityCubit) {
return TableRow(
children: [
iconRowsCount,
......@@ -121,7 +121,7 @@ class CounterWidget extends StatelessWidget {
icon: iconRemove,
onPressed: () {
counter.lines = max(counter.lines - 1, 0);
gameCubit.refresh();
activityCubit.refresh();
},
),
Center(
......@@ -146,14 +146,14 @@ class CounterWidget extends StatelessWidget {
icon: iconAdd,
onPressed: () {
counter.lines = min(counter.lines + 1, 4);
gameCubit.refresh();
activityCubit.refresh();
},
),
],
);
}
TableRow buildHolesWidget(GameCubit gameCubit) {
TableRow buildHolesWidget(ActivityCubit activityCubit) {
return TableRow(
children: [
iconHolesCount,
......@@ -166,7 +166,7 @@ class CounterWidget extends StatelessWidget {
icon: iconRemove,
onPressed: () {
counter.holes = max(counter.holes - 1, 0);
gameCubit.refresh();
activityCubit.refresh();
},
),
Center(
......@@ -191,7 +191,7 @@ class CounterWidget extends StatelessWidget {
icon: iconAdd,
onPressed: () {
counter.holes = min(counter.holes + 1, 9);
gameCubit.refresh();
activityCubit.refresh();
},
),
],
......
import 'package:flutter/material.dart';
import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
import 'package:tetrisdual/cubit/game_cubit.dart';
import 'package:tetrisdual/cubit/activity/activity_cubit.dart';
import 'package:tetrisdual/ui/widgets/game/player.dart';
import 'package:tetrisdual/ui/widgets/game/toggle_player.dart';
......@@ -10,7 +10,7 @@ class GameBoardWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
final GameCubit gameCubit = BlocProvider.of<GameCubit>(context);
final ActivityCubit activityCubit = BlocProvider.of<ActivityCubit>(context);
return Center(
child: Column(
......@@ -20,12 +20,12 @@ class GameBoardWidget extends StatelessWidget {
RotatedBox(
quarterTurns: 2,
child: PlayerWidget(
player: gameCubit.getPlayer(1),
player: activityCubit.getPlayer(1),
),
),
const TogglePlayerWidget(),
PlayerWidget(
player: gameCubit.getPlayer(2),
player: activityCubit.getPlayer(2),
),
],
),
......
import 'package:flutter/material.dart';
import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
import 'package:tetrisdual/cubit/game_cubit.dart';
import 'package:tetrisdual/models/game/player.dart';
import 'package:tetrisdual/cubit/activity/activity_cubit.dart';
import 'package:tetrisdual/models/activity/player.dart';
import 'package:tetrisdual/ui/widgets/game/counter.dart';
import 'package:tetrisdual/ui/widgets/game/submit.dart';
......@@ -13,15 +13,15 @@ class ManagerWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BlocBuilder<GameCubit, GameState>(
builder: (BuildContext context, GameState gameState) {
return BlocBuilder<ActivityCubit, ActivityState>(
builder: (BuildContext context, ActivityState activityState) {
return Expanded(
child: Container(
margin: const EdgeInsets.all(5),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: gameState.currentGame.currentPlayer == player.playerId
children: activityState.currentActivity.currentPlayer == player.playerId
? [
CounterWidget(counter: player.counter),
SubmitWidget(player: player),
......
import 'package:flutter/material.dart';
import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
import 'package:tetrisdual/cubit/game_cubit.dart';
import 'package:tetrisdual/models/game/player.dart';
import 'package:tetrisdual/cubit/activity/activity_cubit.dart';
import 'package:tetrisdual/models/activity/player.dart';
import 'package:tetrisdual/ui/widgets/game/manager.dart';
import 'package:tetrisdual/ui/widgets/game/tetrimino.dart';
......@@ -13,9 +13,9 @@ class PlayerWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BlocBuilder<GameCubit, GameState>(
builder: (BuildContext context, GameState gameState) {
final bool isActive = (gameState.currentGame.currentPlayer == player.playerId);
return BlocBuilder<ActivityCubit, ActivityState>(
builder: (BuildContext context, ActivityState activityState) {
final bool isActive = (activityState.currentActivity.currentPlayer == player.playerId);
final double screenWidth = MediaQuery.of(context).size.width;
final double tetriminoBlockWidth = screenWidth / 2.3;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment