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

Add basic game

parent 25784924
No related branches found
No related tags found
1 merge request!19Resolve "Add basic game"
Pipeline #5557 passed
Showing
with 1342 additions and 99 deletions
import 'package:sortgame/utils/tools.dart';
class DefaultGlobalSettings {
static const List<String> availableParameters = [];
static List<int> getAvailableValues(String parameterCode) {
printlog('Did not find any available value for global parameter "$parameterCode".');
return [];
}
}
import 'package:flutter/material.dart';
/// Colors from Tailwind CSS (v3.0) - June 2022
///
/// https://tailwindcss.com/docs/customizing-colors
const int _primaryColor = 0xFF6366F1;
const MaterialColor primarySwatch = MaterialColor(_primaryColor, <int, Color>{
50: Color(0xFFEEF2FF), // indigo-50
100: Color(0xFFE0E7FF), // indigo-100
200: Color(0xFFC7D2FE), // indigo-200
300: Color(0xFFA5B4FC), // indigo-300
400: Color(0xFF818CF8), // indigo-400
500: Color(_primaryColor), // indigo-500
600: Color(0xFF4F46E5), // indigo-600
700: Color(0xFF4338CA), // indigo-700
800: Color(0xFF3730A3), // indigo-800
900: Color(0xFF312E81), // indigo-900
});
const int _textColor = 0xFF64748B;
const MaterialColor textSwatch = MaterialColor(_textColor, <int, Color>{
50: Color(0xFFF8FAFC), // slate-50
100: Color(0xFFF1F5F9), // slate-100
200: Color(0xFFE2E8F0), // slate-200
300: Color(0xFFCBD5E1), // slate-300
400: Color(0xFF94A3B8), // slate-400
500: Color(_textColor), // slate-500
600: Color(0xFF475569), // slate-600
700: Color(0xFF334155), // slate-700
800: Color(0xFF1E293B), // slate-800
900: Color(0xFF0F172A), // slate-900
});
const Color errorColor = Color(0xFFDC2626); // red-600
final ColorScheme lightColorScheme = ColorScheme.light(
primary: primarySwatch.shade500,
secondary: primarySwatch.shade500,
onSecondary: Colors.white,
error: errorColor,
background: textSwatch.shade200,
onBackground: textSwatch.shade500,
onSurface: textSwatch.shade500,
surface: textSwatch.shade50,
surfaceVariant: Colors.white,
shadow: textSwatch.shade900.withOpacity(.1),
);
final ColorScheme darkColorScheme = ColorScheme.dark(
primary: primarySwatch.shade500,
secondary: primarySwatch.shade500,
onSecondary: Colors.white,
error: errorColor,
background: const Color(0xFF171724),
onBackground: textSwatch.shade400,
onSurface: textSwatch.shade300,
surface: const Color(0xFF262630),
surfaceVariant: const Color(0xFF282832),
shadow: textSwatch.shade900.withOpacity(.2),
);
final ThemeData lightTheme = ThemeData(
colorScheme: lightColorScheme,
fontFamily: 'Nunito',
textTheme: TextTheme(
displayLarge: TextStyle(
color: textSwatch.shade700,
fontFamily: 'Nunito',
),
displayMedium: TextStyle(
color: textSwatch.shade600,
fontFamily: 'Nunito',
),
displaySmall: TextStyle(
color: textSwatch.shade500,
fontFamily: 'Nunito',
),
headlineLarge: TextStyle(
color: textSwatch.shade700,
fontFamily: 'Nunito',
),
headlineMedium: TextStyle(
color: textSwatch.shade600,
fontFamily: 'Nunito',
),
headlineSmall: TextStyle(
color: textSwatch.shade500,
fontFamily: 'Nunito',
),
titleLarge: TextStyle(
color: textSwatch.shade700,
fontFamily: 'Nunito',
),
titleMedium: TextStyle(
color: textSwatch.shade600,
fontFamily: 'Nunito',
),
titleSmall: TextStyle(
color: textSwatch.shade500,
fontFamily: 'Nunito',
),
bodyLarge: TextStyle(
color: textSwatch.shade700,
fontFamily: 'Nunito',
),
bodyMedium: TextStyle(
color: textSwatch.shade600,
fontFamily: 'Nunito',
),
bodySmall: TextStyle(
color: textSwatch.shade500,
fontFamily: 'Nunito',
),
labelLarge: TextStyle(
color: textSwatch.shade700,
fontFamily: 'Nunito',
),
labelMedium: TextStyle(
color: textSwatch.shade600,
fontFamily: 'Nunito',
),
labelSmall: TextStyle(
color: textSwatch.shade500,
fontFamily: 'Nunito',
),
),
);
final ThemeData darkTheme = lightTheme.copyWith(
colorScheme: darkColorScheme,
textTheme: TextTheme(
displayLarge: TextStyle(
color: textSwatch.shade200,
fontFamily: 'Nunito',
),
displayMedium: TextStyle(
color: textSwatch.shade300,
fontFamily: 'Nunito',
),
displaySmall: TextStyle(
color: textSwatch.shade400,
fontFamily: 'Nunito',
),
headlineLarge: TextStyle(
color: textSwatch.shade200,
fontFamily: 'Nunito',
),
headlineMedium: TextStyle(
color: textSwatch.shade300,
fontFamily: 'Nunito',
),
headlineSmall: TextStyle(
color: textSwatch.shade400,
fontFamily: 'Nunito',
),
titleLarge: TextStyle(
color: textSwatch.shade200,
fontFamily: 'Nunito',
),
titleMedium: TextStyle(
color: textSwatch.shade300,
fontFamily: 'Nunito',
),
titleSmall: TextStyle(
color: textSwatch.shade400,
fontFamily: 'Nunito',
),
bodyLarge: TextStyle(
color: textSwatch.shade200,
fontFamily: 'Nunito',
),
bodyMedium: TextStyle(
color: textSwatch.shade300,
fontFamily: 'Nunito',
),
bodySmall: TextStyle(
color: textSwatch.shade400,
fontFamily: 'Nunito',
),
labelLarge: TextStyle(
color: textSwatch.shade200,
fontFamily: 'Nunito',
),
labelMedium: TextStyle(
color: textSwatch.shade300,
fontFamily: 'Nunito',
),
labelSmall: TextStyle(
color: textSwatch.shade400,
fontFamily: 'Nunito',
),
),
);
final ThemeData appTheme = darkTheme;
import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart';
import 'package:hydrated_bloc/hydrated_bloc.dart';
import 'package:sortgame/models/game.dart';
import 'package:sortgame/models/settings_game.dart';
import 'package:sortgame/models/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(
items: state.currentGame.items,
gameSettings: state.currentGame.gameSettings,
globalSettings: state.currentGame.globalSettings,
isRunning: state.currentGame.isRunning,
isFinished: state.currentGame.isFinished,
position: state.currentGame.position,
score: state.currentGame.score,
);
game.dump();
updateState(game);
}
void quitGame() {
state.currentGame.updateGameIsRunning(false);
refresh();
}
void increasePosition() {
if (state.currentGame.position < state.currentGame.items.length) {
state.currentGame.increasePosition();
} else {
state.currentGame.updateGameIsFinished(true);
}
refresh();
}
void increaseScore(int increment) {
state.currentGame.increaseScore(increment);
refresh();
}
void startNewGame({
required GameSettings gameSettings,
required GlobalSettings globalSettings,
}) {
Game newGame = Game.createNew(
gameSettings: gameSettings,
globalSettings: globalSettings,
);
newGame.dump();
updateState(newGame);
refresh();
}
@override
GameState? fromJson(Map<String, dynamic> json) {
Game currentGame = json['currentGame'] as Game;
return GameState(
currentGame: currentGame,
);
}
@override
Map<String, dynamic>? toJson(GameState state) {
return <String, dynamic>{
'currentGame': state.currentGame.toJson(),
};
}
}
part of 'game_cubit.dart';
@immutable
class GameState extends Equatable {
const GameState({
required this.currentGame,
});
final Game currentGame;
@override
List<dynamic> get props => <dynamic>[
currentGame,
];
Map<String, dynamic> get values => <String, dynamic>{
'currentGame': currentGame,
};
}
import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart';
import 'package:hydrated_bloc/hydrated_bloc.dart';
import 'package:sortgame/models/settings_game.dart';
import 'package:sortgame/utils/tools.dart';
part 'settings_game_state.dart';
class GameSettingsCubit extends HydratedCubit<GameSettingsState> {
GameSettingsCubit() : super(GameSettingsState(settings: GameSettings.createDefault()));
void setValues({
int? itemsCount,
}) {
emit(
GameSettingsState(
settings: GameSettings(
itemsCount: itemsCount ?? state.settings.itemsCount,
),
),
);
}
int getParameterValue(String code) {
switch (code) {
case 'itemsCount':
return GameSettings.getItemsCountValueFromUnsafe(state.settings.itemsCount);
}
return 0;
}
void setParameterValue(String code, int value) {
printlog('GameSettingsCubit.setParameterValue');
printlog('code: $code / value: $value');
int itemsCount = code == 'itemsCount' ? value : getParameterValue('itemsCount');
setValues(
itemsCount: itemsCount,
);
}
@override
GameSettingsState? fromJson(Map<String, dynamic> json) {
int itemsCount = json['itemsCount'] as int;
return GameSettingsState(
settings: GameSettings(
itemsCount: itemsCount,
),
);
}
@override
Map<String, dynamic>? toJson(GameSettingsState state) {
return <String, dynamic>{
'itemsCount': state.settings.itemsCount,
};
}
}
part of 'settings_game_cubit.dart';
@immutable
class GameSettingsState extends Equatable {
const GameSettingsState({
required this.settings,
});
final GameSettings settings;
@override
List<dynamic> get props => <dynamic>[
settings,
];
Map<String, dynamic> get values => <String, dynamic>{
'settings': settings,
};
}
import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart';
import 'package:hydrated_bloc/hydrated_bloc.dart';
import 'package:sortgame/models/settings_global.dart';
import 'package:sortgame/utils/tools.dart';
part 'settings_global_state.dart';
class GlobalSettingsCubit extends HydratedCubit<GlobalSettingsState> {
GlobalSettingsCubit() : super(GlobalSettingsState(settings: GlobalSettings.createDefault()));
void setValues() {
emit(
GlobalSettingsState(
settings: GlobalSettings(),
),
);
}
int getParameterValue(String code) {
switch (code) {}
return 0;
}
void setParameterValue(String code, int value) {
printlog('GlobalSettingsCubit.setParameterValue');
printlog('code: $code / value: $value');
setValues();
}
@override
GlobalSettingsState? fromJson(Map<String, dynamic> json) {
return GlobalSettingsState(
settings: GlobalSettings(),
);
}
@override
Map<String, dynamic>? toJson(GlobalSettingsState state) {
return <String, dynamic>{};
}
}
part of 'settings_global_cubit.dart';
@immutable
class GlobalSettingsState extends Equatable {
const GlobalSettingsState({
required this.settings,
});
final GlobalSettings settings;
@override
List<dynamic> get props => <dynamic>[
settings,
];
Map<String, dynamic> get values => <String, dynamic>{
'settings': settings,
};
}
import 'package:sortgame/data/game_data.dart';
import 'package:sortgame/models/data/category.dart';
import 'package:sortgame/models/data/game_item.dart';
import 'package:sortgame/models/data/item.dart';
import 'package:sortgame/utils/tools.dart';
class FetchDataHelper {
FetchDataHelper();
final List<Category> _categories = [];
List<Category> get categories => _categories;
final List<Item> _items = [];
List<Item> get items => _items;
final List<GameItem> _mapping = [];
void init() {
try {
const gameData = GameData.data;
final List<dynamic> rawCategories = gameData['categories'] as List<dynamic>;
for (var rawElement in rawCategories) {
final element = rawElement.toString();
_categories.add(Category(key: element, text: element));
}
final List<dynamic> rawItems = gameData['items'] as List<dynamic>;
for (var rawElement in rawItems) {
final element = rawElement.toString();
_items.add(Item(key: element, text: element));
}
final Map<String, dynamic> rawMapping = gameData['mapping'] as Map<String, dynamic>;
final Map<String, dynamic> rawMappingItems = rawMapping['items'] as Map<String, dynamic>;
rawMappingItems.forEach(
(String itemName, itemMappings) {
List<String> rawIsCategories = itemMappings['is'] as List<String>;
List<String> rawIsNotCategories = itemMappings['isnot'] as List<String>;
_mapping.add(GameItem(
item: Item(
key: itemName,
text: itemName,
),
isCategory: rawIsCategories
.map((String category) => Category(key: category, text: category))
.toList(),
isNotCategory: rawIsNotCategories
.map((String category) => Category(key: category, text: category))
.toList(),
));
},
);
} catch (e) {
printlog("$e");
}
}
List<GameItem> getItems(int count) {
if (_mapping.isEmpty) {
init();
}
List<GameItem> items = _mapping;
// Remove items without enough data
items.removeWhere((GameItem question) =>
(question.isCategory.isEmpty || question.isNotCategory.isEmpty));
items.shuffle();
return items.take(count).toList();
}
}
class GameData {
static const Map<String, dynamic> data = {
"categories": ["artificiel", "gazeux", "inerte", "liquide", "naturel", "solide", "vivant"],
"exclusions": [
["liquide", "solide", "gazeux"],
["inerte", "vivant"],
["naturel", "artificiel"]
],
"items": [
"ABEILLE",
"AMPOULE",
"ARBRE",
"ASPIRATEUR",
"BALAI",
"BANANE",
"BERCEAU",
"BONBON",
"BOUGIE",
"BROUETTE",
"CAFETIÈRE",
"CANARD",
"CASQUETTE",
"CHAISE",
"CHAUSSURE",
"CINTRE",
"COCCINELLE",
"CONFITURE",
"CORDE",
"CROCODILE",
"DROMADAIRE",
"FENÊTRE",
"FOURMI",
"FUSÉE",
"GOURDE",
"GUÊPE",
"HÉLICOPTÈRE",
"KANGOUROU",
"LAMPE",
"LICORNE",
"LIVRE",
"MAISON",
"MOUCHE",
"NOEUD",
"ORAGE",
"OURS",
"PAPILLON",
"PEIGNE",
"PENDULE",
"PIANO",
"PIZZA",
"POMME",
"POULET",
"PUZZLE",
"PÊCHE",
"REQUIN",
"ROSE",
"SAC À DOS",
"SANGLIER",
"SAVON",
"SINGE",
"STADE",
"TABOURET",
"TARTINE",
"TIROIR",
"TORTUE",
"TROMPETTE",
"VACHE",
"VOILIER",
"ZÈBRE"
],
"mapping": {
"items": {
"ABEILLE": {
"is": ["naturel", "vivant"],
"isnot": ["artificiel", "gazeux", "inerte"],
"na": ["liquide"]
},
"AMPOULE": {
"is": ["artificiel", "inerte", "solide"],
"isnot": ["gazeux", "liquide", "naturel", "vivant"],
"na": []
},
"ARBRE": {
"is": ["naturel", "vivant"],
"isnot": ["artificiel", "inerte", "liquide"],
"na": []
},
"ASPIRATEUR": {
"is": ["artificiel", "inerte", "solide"],
"isnot": ["gazeux", "liquide", "naturel", "vivant"],
"na": []
},
"BALAI": {
"is": ["artificiel", "inerte", "solide"],
"isnot": ["gazeux", "liquide", "naturel", "vivant"],
"na": []
},
"BANANE": {
"is": ["solide", "vivant"],
"isnot": ["gazeux", "inerte", "liquide"],
"na": []
},
"BERCEAU": {
"is": ["artificiel", "inerte"],
"isnot": ["liquide", "naturel", "vivant"],
"na": []
},
"BONBON": {
"is": ["artificiel", "inerte", "solide"],
"isnot": ["gazeux", "liquide", "naturel", "vivant"],
"na": []
},
"BOUGIE": {
"is": ["artificiel", "inerte", "solide"],
"isnot": ["gazeux", "liquide", "naturel", "vivant"],
"na": []
},
"BROUETTE": {
"is": ["artificiel", "inerte"],
"isnot": ["liquide", "naturel", "vivant"],
"na": []
},
"CAFETIÈRE": {
"is": ["inerte"],
"isnot": ["liquide", "vivant"],
"na": []
},
"CANARD": {
"is": ["naturel", "solide", "vivant"],
"isnot": ["artificiel", "gazeux", "inerte", "liquide"],
"na": ["liquide"]
},
"CASQUETTE": {
"is": ["artificiel", "inerte"],
"isnot": ["liquide", "naturel", "vivant"],
"na": []
},
"CHAISE": {
"is": ["artificiel", "inerte", "solide"],
"isnot": ["gazeux", "liquide", "naturel", "vivant"],
"na": []
},
"CHAUSSURE": {
"is": ["artificiel", "inerte", "solide"],
"isnot": ["gazeux", "liquide", "naturel", "vivant"],
"na": []
},
"CINTRE": {
"is": ["artificiel", "inerte", "solide"],
"isnot": ["gazeux", "liquide", "naturel", "vivant"],
"na": []
},
"COCCINELLE": {
"is": ["naturel", "vivant"],
"isnot": ["artificiel", "gazeux", "inerte"],
"na": ["liquide", "solide"]
},
"CONFITURE": {
"is": ["inerte", "solide"],
"isnot": ["gazeux", "liquide", "vivant"],
"na": ["liquide"]
},
"CORDE": {
"is": ["artificiel", "inerte", "solide"],
"isnot": ["gazeux", "liquide", "naturel", "vivant"],
"na": []
},
"CROCODILE": {
"is": ["naturel", "vivant"],
"isnot": ["artificiel", "gazeux", "inerte"],
"na": ["liquide", "solide"]
},
"DROMADAIRE": {
"is": ["naturel", "solide", "vivant"],
"isnot": ["artificiel", "gazeux", "inerte", "liquide"],
"na": []
},
"FENÊTRE": {
"is": ["artificiel", "inerte"],
"isnot": ["naturel", "vivant"],
"na": ["liquide"]
},
"FOURMI": {
"is": ["naturel", "solide", "vivant"],
"isnot": ["artificiel", "gazeux", "inerte", "liquide"],
"na": ["liquide"]
},
"FUSÉE": {
"is": ["artificiel", "inerte", "solide"],
"isnot": ["gazeux", "liquide", "naturel", "vivant"],
"na": []
},
"GOURDE": {
"is": ["artificiel", "solide"],
"isnot": ["gazeux", "liquide", "naturel"],
"na": []
},
"GUÊPE": {
"is": ["naturel", "vivant"],
"isnot": ["artificiel", "inerte"],
"na": ["liquide"]
},
"HÉLICOPTÈRE": {
"is": ["artificiel", "inerte"],
"isnot": ["gazeux", "naturel", "vivant"],
"na": []
},
"KANGOUROU": {
"is": ["naturel", "solide", "vivant"],
"isnot": ["artificiel", "gazeux", "inerte", "liquide"],
"na": []
},
"LAMPE": {
"is": ["artificiel", "inerte", "solide"],
"isnot": ["gazeux", "liquide", "naturel", "vivant"],
"na": []
},
"LICORNE": {
"is": ["naturel", "solide", "vivant"],
"isnot": ["artificiel", "gazeux", "inerte", "liquide"],
"na": ["naturel"]
},
"LIVRE": {
"is": ["artificiel"],
"isnot": ["liquide", "naturel"],
"na": []
},
"MAISON": {
"is": ["artificiel", "inerte", "solide"],
"isnot": ["gazeux", "liquide", "naturel", "vivant"],
"na": []
},
"MOUCHE": {
"is": ["naturel"],
"isnot": ["artificiel"],
"na": ["liquide"]
},
"NOEUD": {
"is": ["inerte"],
"isnot": ["liquide", "vivant"],
"na": ["artificiel", "solide"]
},
"ORAGE": {
"is": ["inerte", "naturel"],
"isnot": ["artificiel", "vivant"],
"na": ["solide"]
},
"OURS": {
"is": ["naturel", "vivant"],
"isnot": ["artificiel", "gazeux", "inerte"],
"na": ["liquide"]
},
"PAPILLON": {
"is": ["naturel", "vivant"],
"isnot": ["artificiel", "gazeux", "inerte"],
"na": ["solide"]
},
"PEIGNE": {
"is": ["artificiel", "inerte", "solide"],
"isnot": ["gazeux", "liquide", "naturel", "vivant"],
"na": []
},
"PENDULE": {
"is": ["artificiel", "inerte", "solide"],
"isnot": ["gazeux", "liquide", "naturel", "vivant"],
"na": []
},
"PIANO": {
"is": ["artificiel", "inerte", "solide"],
"isnot": ["gazeux", "liquide", "naturel", "vivant"],
"na": []
},
"PIZZA": {
"is": ["artificiel", "inerte"],
"isnot": ["gazeux", "liquide", "naturel", "vivant"],
"na": []
},
"POMME": {
"is": ["naturel", "solide", "vivant"],
"isnot": ["artificiel", "gazeux", "inerte", "liquide"],
"na": []
},
"POULET": {
"is": ["naturel", "vivant"],
"isnot": ["artificiel", "gazeux", "inerte"],
"na": ["liquide", "solide"]
},
"PUZZLE": {
"is": ["artificiel", "inerte"],
"isnot": ["gazeux", "liquide", "naturel", "vivant"],
"na": []
},
"PÊCHE": {
"is": ["naturel", "vivant"],
"isnot": ["artificiel", "gazeux", "inerte", "liquide"],
"na": []
},
"REQUIN": {
"is": ["naturel", "vivant"],
"isnot": ["artificiel", "inerte"],
"na": []
},
"ROSE": {
"is": ["naturel", "solide", "vivant"],
"isnot": ["artificiel", "gazeux", "inerte", "liquide"],
"na": []
},
"SAC À DOS": {
"is": ["artificiel", "inerte", "solide"],
"isnot": ["gazeux", "liquide", "naturel", "vivant"],
"na": []
},
"SANGLIER": {
"is": ["naturel"],
"isnot": ["artificiel", "gazeux"],
"na": ["solide"]
},
"SAVON": {
"is": ["artificiel", "inerte"],
"isnot": ["naturel", "vivant"],
"na": ["liquide", "solide"]
},
"SINGE": {
"is": ["naturel", "vivant"],
"isnot": ["artificiel", "inerte"],
"na": []
},
"STADE": {
"is": ["artificiel", "inerte", "solide"],
"isnot": ["gazeux", "liquide", "naturel", "vivant"],
"na": []
},
"TABOURET": {
"is": ["artificiel", "inerte", "solide"],
"isnot": ["gazeux", "liquide", "naturel", "vivant"],
"na": []
},
"TARTINE": {
"is": ["artificiel", "inerte", "solide"],
"isnot": ["gazeux", "liquide", "naturel", "vivant"],
"na": []
},
"TIROIR": {
"is": ["artificiel", "inerte", "solide"],
"isnot": ["gazeux", "liquide", "naturel", "vivant"],
"na": []
},
"TORTUE": {
"is": ["naturel", "solide", "vivant"],
"isnot": ["artificiel", "gazeux", "inerte", "liquide"],
"na": ["liquide"]
},
"TROMPETTE": {
"is": ["inerte", "solide"],
"isnot": ["gazeux", "liquide", "vivant"],
"na": []
},
"VACHE": {
"is": ["naturel", "solide", "vivant"],
"isnot": ["artificiel", "gazeux", "inerte", "liquide"],
"na": ["liquide"]
},
"VOILIER": {
"is": ["artificiel", "inerte", "solide"],
"isnot": ["gazeux", "liquide", "naturel", "vivant"],
"na": []
},
"ZÈBRE": {
"is": ["naturel", "vivant"],
"isnot": ["artificiel", "gazeux", "inerte"],
"na": ["solide"]
}
}
}
};
}
import 'dart:io';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:hive/hive.dart';
import 'package:hydrated_bloc/hydrated_bloc.dart';
import 'package:path_provider/path_provider.dart';
import 'package:sortgame/config/theme.dart';
import 'package:sortgame/cubit/game_cubit.dart';
import 'package:sortgame/cubit/settings_game_cubit.dart';
import 'package:sortgame/cubit/settings_global_cubit.dart';
import 'package:sortgame/ui/skeleton.dart';
import 'provider/data.dart';
import 'screens/home.dart';
void main() async {
// Initialize packages
WidgetsFlutterBinding.ensureInitialized();
await EasyLocalization.ensureInitialized();
final Directory tmpDir = await getTemporaryDirectory();
Hive.init(tmpDir.toString());
HydratedBloc.storage = await HydratedStorage.build(
storageDirectory: tmpDir,
);
void main() => runApp(const MyApp());
runApp(
EasyLocalization(
path: 'assets/translations',
supportedLocales: const <Locale>[
Locale('en'),
Locale('fr'),
],
fallbackLocale: const Locale('en'),
useFallbackTranslations: true,
child: const MyApp(),
),
);
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (BuildContext context) => Data(),
child: Consumer<Data>(builder: (context, data, child) {
return MaterialApp(
return MultiBlocProvider(
providers: [
BlocProvider<GameCubit>(create: (context) => GameCubit()),
BlocProvider<GlobalSettingsCubit>(create: (context) => GlobalSettingsCubit()),
BlocProvider<GameSettingsCubit>(create: (context) => GameSettingsCubit()),
],
child: MaterialApp(
title: 'SortGame',
theme: appTheme,
home: const SkeletonScreen(),
// Localization stuff
localizationsDelegates: context.localizationDelegates,
supportedLocales: context.supportedLocales,
locale: context.locale,
debugShowCheckedModeBanner: false,
theme: ThemeData(
primaryColor: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: const Home(),
routes: {
Home.id: (context) => const Home(),
},
);
}),
);
}
}
class Category {
final String key;
final String text;
const Category({
required this.key,
required this.text,
});
Map<String, dynamic> toJson() {
return {
'key': key,
'text': text,
};
}
@override
String toString() {
return toJson().toString();
}
}
import 'package:sortgame/models/data/category.dart';
import 'package:sortgame/models/data/item.dart';
class GameItem {
final Item item;
final List<Category> isCategory;
final List<Category> isNotCategory;
GameItem({
required this.item,
required this.isCategory,
required this.isNotCategory,
});
@override
String toString() {
return '$GameItem(${toJson()})';
}
Map<String, dynamic>? toJson() {
return <String, dynamic>{
'item': item.toJson(),
'isCategory': isCategory.toString(),
'isNotCategory': isNotCategory.toString(),
};
}
}
class Item {
final String key;
final String text;
const Item({
required this.key,
required this.text,
});
Map<String, dynamic> toJson() {
return {
'key': key,
'text': text,
};
}
@override
String toString() {
return toJson().toString();
}
}
import 'package:sortgame/data/fetch_data_helper.dart';
import 'package:sortgame/models/data/game_item.dart';
import 'package:sortgame/models/settings_game.dart';
import 'package:sortgame/models/settings_global.dart';
import 'package:sortgame/utils/tools.dart';
class Game {
final List<GameItem> items;
final GameSettings gameSettings;
final GlobalSettings globalSettings;
bool isRunning = false;
bool isFinished = false;
int position = 1;
int score = 0;
Game({
required this.items,
required this.gameSettings,
required this.globalSettings,
this.isRunning = false,
this.isFinished = false,
this.position = 1,
this.score = 0,
});
factory Game.createNull() {
return Game(
items: [],
gameSettings: GameSettings.createDefault(),
globalSettings: GlobalSettings.createDefault(),
);
}
factory Game.createNew({
GameSettings? gameSettings,
GlobalSettings? globalSettings,
}) {
GameSettings newGameSettings = gameSettings ?? GameSettings.createDefault();
GlobalSettings newGlobalSettings = globalSettings ?? GlobalSettings.createDefault();
List<GameItem> items = FetchDataHelper().getItems(newGameSettings.itemsCount);
return Game(
items: items,
gameSettings: newGameSettings,
globalSettings: newGlobalSettings,
isRunning: true,
);
}
void increaseScore(int? count) {
score += (count ?? 0);
}
void increasePosition() {
position += 1;
}
void updateGameIsRunning(bool gameIsRunning) {
isRunning = gameIsRunning;
}
void updateGameIsFinished(bool gameIsFinished) {
isFinished = gameIsFinished;
}
GameItem getCurrentQuestion() {
return items[position - 1];
}
void dump() {
printlog('');
printlog('## Current game dump:');
printlog('');
gameSettings.dump();
globalSettings.dump();
printlog('');
items.toString();
printlog('');
printlog('Game: ');
printlog(' isRunning: $isRunning');
printlog(' isFinished: $isFinished');
printlog(' position: $position');
printlog(' score: $score');
printlog('');
}
@override
String toString() {
return '$Game(${toJson()})';
}
Map<String, dynamic>? toJson() {
return <String, dynamic>{
'items': items.toString(),
'gameSettings': gameSettings.toJson(),
'globalSettings': globalSettings.toJson(),
'isRunning': isRunning,
'isFinished': isFinished,
'position': position,
'score': score,
};
}
}
import 'package:sortgame/config/default_game_settings.dart';
import 'package:sortgame/utils/tools.dart';
class GameSettings {
final int itemsCount;
GameSettings({
required this.itemsCount,
});
static int getItemsCountValueFromUnsafe(int itemsCount) {
if (DefaultGameSettings.allowedItemsCountValues.contains(itemsCount)) {
return itemsCount;
}
return DefaultGameSettings.defaultItemsCountValue;
}
factory GameSettings.createDefault() {
return GameSettings(
itemsCount: DefaultGameSettings.defaultItemsCountValue,
);
}
void dump() {
printlog('Settings: ');
printlog(' itemsCount: $itemsCount');
}
@override
String toString() {
return '$GameSettings(${toJson()})';
}
Map<String, dynamic>? toJson() {
return <String, dynamic>{
'itemsCount': itemsCount,
};
}
}
import 'package:sortgame/utils/tools.dart';
class GlobalSettings {
GlobalSettings();
factory GlobalSettings.createDefault() {
return GlobalSettings();
}
void dump() {
printlog('Settings: ');
}
@override
String toString() {
return '$GlobalSettings(${toJson()})';
}
Map<String, dynamic>? toJson() {
return <String, dynamic>{};
}
}
import 'package:flutter/foundation.dart';
class Data extends ChangeNotifier {
bool _searchingImage = false;
String _image = '';
bool get searchingImage => _searchingImage;
set searchingImage(bool value) {
_searchingImage = value;
notifyListeners();
}
String get image => _image;
set updateImage(String value) {
_image = value;
notifyListeners();
}
void resetGame() {
_image = '';
notifyListeners();
}
}
import 'package:flutter/material.dart';
import 'package:sortgame/utils/tools.dart';
class Home extends StatelessWidget {
const Home({super.key});
static const String id = 'home';
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Sorting game'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
margin: const EdgeInsets.all(4),
padding: const EdgeInsets.all(4),
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(4),
border: Border.all(
color: Colors.green,
width: 4,
),
),
child: TextButton(
child: const Text(
'🎲',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 50,
fontWeight: FontWeight.w600,
color: Colors.black,
),
),
onPressed: () => printlog('X'),
),
),
],
),
],
),
),
);
}
}
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:sortgame/config/default_game_settings.dart';
import 'package:sortgame/models/settings_game.dart';
import 'package:sortgame/models/settings_global.dart';
import 'package:sortgame/utils/tools.dart';
class ParameterPainter extends CustomPainter {
const ParameterPainter({
required this.code,
required this.value,
required this.isSelected,
required this.gameSettings,
required this.globalSettings,
});
final String code;
final int value;
final bool isSelected;
final GameSettings gameSettings;
final GlobalSettings globalSettings;
@override
void paint(Canvas canvas, Size size) {
// force square
final double canvasSize = min(size.width, size.height);
const Color borderColorEnabled = Colors.blue;
const Color borderColorDisabled = Colors.white;
// "enabled/disabled" border
final paint = Paint();
paint.style = PaintingStyle.stroke;
paint.color = isSelected ? borderColorEnabled : borderColorDisabled;
paint.strokeJoin = StrokeJoin.round;
paint.strokeWidth = 20 / 100 * canvasSize;
canvas.drawRect(
Rect.fromPoints(const Offset(0, 0), Offset(canvasSize, canvasSize)), paint);
// content
switch (code) {
case 'itemsCount':
paintItemsCountParameterItem(value, canvas, canvasSize);
break;
default:
printlog('Unknown parameter: $code/$value');
paintUnknownParameterItem(value, canvas, canvasSize);
}
}
@override
bool shouldRepaint(CustomPainter oldDelegate) {
return false;
}
// "unknown" parameter -> simple bock with text
void paintUnknownParameterItem(
final int value,
final Canvas canvas,
final double size,
) {
final paint = Paint();
paint.strokeJoin = StrokeJoin.round;
paint.strokeWidth = 3 / 100 * size;
paint.color = Colors.grey;
paint.style = PaintingStyle.fill;
canvas.drawRect(Rect.fromPoints(const Offset(0, 0), Offset(size, size)), paint);
final textSpan = TextSpan(
text: '?\n$value',
style: const TextStyle(
color: Colors.black,
fontSize: 18,
fontWeight: FontWeight.bold,
),
);
final textPainter = TextPainter(
text: textSpan,
textDirection: TextDirection.ltr,
);
textPainter.layout();
textPainter.paint(
canvas,
Offset(
(size - textPainter.width) * 0.5,
(size - textPainter.height) * 0.5,
),
);
}
void paintItemsCountParameterItem(
final int value,
final Canvas canvas,
final double size,
) {
Color backgroundColor = Colors.grey;
switch (value) {
case DefaultGameSettings.itemsCountValueLow:
backgroundColor = Colors.green;
break;
case DefaultGameSettings.itemsCountValueMedium:
backgroundColor = Colors.orange;
break;
case DefaultGameSettings.itemsCountValueHigh:
backgroundColor = Colors.red;
break;
case DefaultGameSettings.itemsCountValueVeryHigh:
backgroundColor = Colors.purple;
break;
default:
printlog('Wrong value for itemsCount parameter value: $value');
}
final paint = Paint();
paint.strokeJoin = StrokeJoin.round;
paint.strokeWidth = 3 / 100 * size;
// Colored background
paint.color = backgroundColor;
paint.style = PaintingStyle.fill;
canvas.drawRect(Rect.fromPoints(const Offset(0, 0), Offset(size, size)), paint);
// centered text value
final textSpan = TextSpan(
text: value.toString(),
style: TextStyle(
color: Colors.black,
fontSize: size / 4,
fontWeight: FontWeight.bold,
),
);
final textPainter = TextPainter(
text: textSpan,
textDirection: TextDirection.ltr,
);
textPainter.layout();
textPainter.paint(
canvas,
Offset(
(size - textPainter.width) * 0.5,
(size - textPainter.height) * 0.5,
),
);
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment