diff --git a/android/gradle.properties b/android/gradle.properties index 7ecc3f8ab655a592b129b0bcb8aaa8507c2a5be6..289e6accac51eee8a9ed1a90ef9a955c1958f120 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -1,5 +1,5 @@ org.gradle.jvmargs=-Xmx1536M android.useAndroidX=true android.enableJetifier=true -app.versionName=0.1.38 -app.versionCode=62 +app.versionName=0.1.39 +app.versionCode=63 diff --git a/assets/fonts/Nunito-Bold.ttf b/assets/fonts/Nunito-Bold.ttf new file mode 100644 index 0000000000000000000000000000000000000000..6519feb781449ebe0015cbc74dfd9e13110fbba9 Binary files /dev/null and b/assets/fonts/Nunito-Bold.ttf differ diff --git a/assets/fonts/Nunito-Light.ttf b/assets/fonts/Nunito-Light.ttf new file mode 100644 index 0000000000000000000000000000000000000000..8a0736c41cd6c2a1225d356bf274de1d0afc3497 Binary files /dev/null and b/assets/fonts/Nunito-Light.ttf differ diff --git a/assets/fonts/Nunito-Medium.ttf b/assets/fonts/Nunito-Medium.ttf new file mode 100644 index 0000000000000000000000000000000000000000..88fccdc0638b6f5d6ac49d9d269dc3d518618ad1 Binary files /dev/null and b/assets/fonts/Nunito-Medium.ttf differ diff --git a/assets/fonts/Nunito-Regular.ttf b/assets/fonts/Nunito-Regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..e7b8375a896ef0cd8e06730a78c84532b377e784 Binary files /dev/null and b/assets/fonts/Nunito-Regular.ttf differ diff --git a/assets/translations/en.json b/assets/translations/en.json new file mode 100644 index 0000000000000000000000000000000000000000..7a959c85f39256092adb9e8b230109e61283fb63 --- /dev/null +++ b/assets/translations/en.json @@ -0,0 +1,14 @@ +{ + "app_name": "Word guess", + + "bottom_nav_home": "Game", + "bottom_nav_settings": "Settings", + "bottom_nav_about": "About", + + "settings_title": "Settings", + "settings_label_theme": "Theme mode", + + "about_title": "About", + "about_content": "Word guess game.", + "about_version": "Version: {version}" +} diff --git a/assets/translations/fr.json b/assets/translations/fr.json new file mode 100644 index 0000000000000000000000000000000000000000..de1e73a173d57d55b362a6a9c92c6d5c88e4cd77 --- /dev/null +++ b/assets/translations/fr.json @@ -0,0 +1,14 @@ +{ + "app_name": "Trouve le mot", + + "bottom_nav_home": "Jeu", + "bottom_nav_settings": "Réglages", + "bottom_nav_about": "Infos", + + "settings_title": "Réglages", + "settings_label_theme": "Thème de couleurs", + + "about_title": "Informations", + "about_content": "Trouve le mot.", + "about_version": "Version : {version}" +} diff --git a/fastlane/metadata/android/en-US/changelogs/63.txt b/fastlane/metadata/android/en-US/changelogs/63.txt new file mode 100644 index 0000000000000000000000000000000000000000..6b884ec4ea3e942b988f5815114a1c3ab59810b8 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/63.txt @@ -0,0 +1 @@ +Improve game conception/architecture. diff --git a/fastlane/metadata/android/fr-FR/changelogs/63.txt b/fastlane/metadata/android/fr-FR/changelogs/63.txt new file mode 100644 index 0000000000000000000000000000000000000000..386b2cdcc090f19264599ba6dc6b215246489bce --- /dev/null +++ b/fastlane/metadata/android/fr-FR/changelogs/63.txt @@ -0,0 +1 @@ +Amélioration de la conception/architecture du jeu. diff --git a/lib/config/menu.dart b/lib/config/menu.dart new file mode 100644 index 0000000000000000000000000000000000000000..13081ea3b21b0c581d8dec4088186de0a98e3683 --- /dev/null +++ b/lib/config/menu.dart @@ -0,0 +1,54 @@ +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:unicons/unicons.dart'; + +import 'package:wordguessing/ui/screens/about_page.dart'; +import 'package:wordguessing/ui/screens/game_page.dart'; +import 'package:wordguessing/ui/screens/settings_page.dart'; + +class MenuItem { + final String code; + final Icon icon; + final Widget page; + + const MenuItem({ + required this.code, + required this.icon, + required this.page, + }); +} + +class Menu { + static List<MenuItem> items = [ + const MenuItem( + code: 'bottom_nav_home', + icon: Icon(UniconsLine.home), + page: GamePage(), + ), + const MenuItem( + code: 'bottom_nav_settings', + icon: Icon(UniconsLine.setting), + page: SettingsPage(), + ), + const MenuItem( + code: 'bottom_nav_about', + icon: Icon(UniconsLine.info_circle), + page: AboutPage(), + ), + ]; + + static Widget getPageWidget(int pageIndex) { + return Menu.items.elementAt(pageIndex).page; + } + + static List<BottomNavigationBarItem> getMenuItems() { + return Menu.items + .map((MenuItem item) => BottomNavigationBarItem( + icon: item.icon, + label: tr(item.code), + )) + .toList(); + } + + static int itemsCount = Menu.items.length; +} diff --git a/lib/config/theme.dart b/lib/config/theme.dart new file mode 100644 index 0000000000000000000000000000000000000000..be390348c7868e7c63387df13e13c46de43f8a23 --- /dev/null +++ b/lib/config/theme.dart @@ -0,0 +1,196 @@ +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; diff --git a/lib/cubit/bottom_nav_cubit.dart b/lib/cubit/bottom_nav_cubit.dart new file mode 100644 index 0000000000000000000000000000000000000000..96d5a6948ba1212c462227ef08403039b55e266d --- /dev/null +++ b/lib/cubit/bottom_nav_cubit.dart @@ -0,0 +1,31 @@ +import 'package:hydrated_bloc/hydrated_bloc.dart'; + +import 'package:wordguessing/config/menu.dart'; + +class BottomNavCubit extends HydratedCubit<int> { + BottomNavCubit() : super(0); + + void updateIndex(int index) { + if (isIndexAllowed(index)) { + emit(index); + } else { + goToHomePage(); + } + } + + bool isIndexAllowed(int index) { + return (index >= 0) && (index < Menu.itemsCount); + } + + void goToHomePage() => emit(0); + + @override + int fromJson(Map<String, dynamic> json) { + return 0; + } + + @override + Map<String, dynamic>? toJson(int state) { + return <String, int>{'pageIndex': state}; + } +} diff --git a/lib/cubit/theme_cubit.dart b/lib/cubit/theme_cubit.dart new file mode 100644 index 0000000000000000000000000000000000000000..b793e895dbb0c672d451cd403e0036c3d9ac9b42 --- /dev/null +++ b/lib/cubit/theme_cubit.dart @@ -0,0 +1,31 @@ +import 'package:equatable/equatable.dart'; +import 'package:flutter/material.dart'; +import 'package:hydrated_bloc/hydrated_bloc.dart'; + +part 'theme_state.dart'; + +class ThemeCubit extends HydratedCubit<ThemeModeState> { + ThemeCubit() : super(const ThemeModeState()); + + void getTheme(ThemeModeState state) { + emit(state); + } + + @override + ThemeModeState? fromJson(Map<String, dynamic> json) { + switch (json['themeMode']) { + case 'ThemeMode.dark': + return const ThemeModeState(themeMode: ThemeMode.dark); + case 'ThemeMode.light': + return const ThemeModeState(themeMode: ThemeMode.light); + case 'ThemeMode.system': + default: + return const ThemeModeState(themeMode: ThemeMode.system); + } + } + + @override + Map<String, String>? toJson(ThemeModeState state) { + return <String, String>{'themeMode': state.themeMode.toString()}; + } +} diff --git a/lib/cubit/theme_state.dart b/lib/cubit/theme_state.dart new file mode 100644 index 0000000000000000000000000000000000000000..e479a50f12fe72a35a1fd1722ff72afbb692a136 --- /dev/null +++ b/lib/cubit/theme_state.dart @@ -0,0 +1,15 @@ +part of 'theme_cubit.dart'; + +@immutable +class ThemeModeState extends Equatable { + const ThemeModeState({ + this.themeMode, + }); + + final ThemeMode? themeMode; + + @override + List<Object?> get props => <Object?>[ + themeMode, + ]; +} diff --git a/lib/main.dart b/lib/main.dart index 714a9fa8c3be7466ccdbc8941b1dfeb8878f250f..5dac5d3c52ce806d2155eae497dcae8f22810553 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,17 +1,41 @@ +import 'dart:io'; + +import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/services.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:provider/provider.dart'; +import 'package:wordguessing/config/theme.dart'; +import 'package:wordguessing/cubit/bottom_nav_cubit.dart'; +import 'package:wordguessing/cubit/theme_cubit.dart'; import 'package:wordguessing/provider/data.dart'; -import 'package:wordguessing/screens/game_pick_image.dart'; -import 'package:wordguessing/screens/game_pick_word.dart'; -import 'package:wordguessing/screens/home.dart'; -import 'package:wordguessing/utils/tools.dart'; +import 'package:wordguessing/ui/skeleton.dart'; -void main() { +void main() async { + /// Initialize packages WidgetsFlutterBinding.ensureInitialized(); - SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]) - .then((value) => runApp(const MyApp())); + await EasyLocalization.ensureInitialized(); + final Directory tmpDir = await getTemporaryDirectory(); + Hive.init(tmpDir.toString()); + HydratedBloc.storage = await HydratedStorage.build( + storageDirectory: tmpDir, + ); + + 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 { @@ -19,31 +43,34 @@ class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { - return ChangeNotifierProvider( - create: (BuildContext context) => Data(), - child: Consumer<Data>(builder: (context, data, child) { - return MaterialApp( - title: 'Jeux de mots et lettres', - theme: ThemeData( - primarySwatch: Colors.blue, + return MultiBlocProvider( + providers: [ + BlocProvider<BottomNavCubit>(create: (context) => BottomNavCubit()), + BlocProvider<ThemeCubit>(create: (context) => ThemeCubit()), + ], + child: BlocBuilder<ThemeCubit, ThemeModeState>( + builder: (BuildContext context, ThemeModeState state) { + return ChangeNotifierProvider( + create: (BuildContext context) => Data(), + child: Consumer<Data>( + builder: (context, data, child) { + return MaterialApp( + title: 'Jeux de mots et lettres', + home: const SkeletonScreen(), + + // Theme stuff + theme: lightTheme, + darkTheme: darkTheme, + themeMode: state.themeMode, + + // Localization stuff + localizationsDelegates: context.localizationDelegates, + supportedLocales: context.supportedLocales, + locale: context.locale, + debugShowCheckedModeBanner: false, + ); + }, ), - home: const Home(), - onGenerateRoute: (settings) { - switch (settings.name) { - case '/game-pick-word': - return MaterialPageRoute(builder: (context) => const GamePickWordPage()); - - case '/game-pick-image': - return MaterialPageRoute( - builder: (context) => const GamePickImagePage(), - ); - - default: - printlog("Unknown menu entry"); - } - - return null; - }, ); }), ); diff --git a/lib/provider/data.dart b/lib/provider/data.dart index c5559fd078007da84de91fcaab179530a81cc370..476ed718cdc77abe927802975ba9890cc9ff62a7 100644 --- a/lib/provider/data.dart +++ b/lib/provider/data.dart @@ -2,7 +2,11 @@ import 'package:flutter/foundation.dart'; import 'package:wordguessing/models/word.dart'; +enum GameType { pickWord, pickImage } + class Data extends ChangeNotifier { + GameType? _gameType; + // Language String _lang = ''; @@ -18,6 +22,18 @@ class Data extends ChangeNotifier { int _goodAnswers = 0; int _wrongAnswers = 0; + GameType? get gameType => _gameType; + + void updateGameType(GameType gameType) { + _gameType = gameType; + notifyListeners(); + } + + void resetGameType() { + _gameType = null; + notifyListeners(); + } + String get lang => _lang; void updateLang(String value) { @@ -55,6 +71,7 @@ class Data extends ChangeNotifier { } void resetGame() { + resetGameType(); updateLang(''); updateQuestionsCount(0); updateGoodAnswers(0); diff --git a/lib/screens/game.dart b/lib/ui/games/abstract_game.dart similarity index 85% rename from lib/screens/game.dart rename to lib/ui/games/abstract_game.dart index 00ede253129c7f06cc7a81bc1f796c9f24536b9f..6e25e32d90e0f2340aa2daaf187011a43aecb71d 100644 --- a/lib/screens/game.dart +++ b/lib/ui/games/abstract_game.dart @@ -3,13 +3,12 @@ import 'package:provider/provider.dart'; import 'package:wordguessing/provider/data.dart'; -class Game extends StatelessWidget { - const Game({super.key}); +class GameAbstract extends StatelessWidget { + const GameAbstract({super.key}); final int countWords = 4; Future<void> startGame(Data myProvider, String lang) async { - myProvider.resetGame(); myProvider.updateLang(lang); await nextWord(myProvider); } @@ -137,27 +136,6 @@ class Game extends StatelessWidget { Widget buildPage(BuildContext context) { final Data myProvider = Provider.of<Data>(context); - final Scaffold pageContent = Scaffold( - appBar: AppBar( - elevation: 0, - actions: <Widget>[ - IconButton( - icon: const Icon(Icons.loop), - onPressed: () => myProvider.resetGame(), - ), - ], - ), - backgroundColor: Colors.blue, - body: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisSize: MainAxisSize.max, - children: buildPageContent(myProvider), - ), - ), - ); - return SizedBox.expand( child: FittedBox( fit: BoxFit.contain, @@ -165,7 +143,14 @@ class Game extends StatelessWidget { child: SizedBox( height: (MediaQuery.of(context).size.height), width: (MediaQuery.of(context).size.width), - child: pageContent, + child: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisSize: MainAxisSize.max, + children: buildPageContent(myProvider), + ), + ), ), ), ); diff --git a/lib/screens/game_pick_image.dart b/lib/ui/games/game_pick_image.dart similarity index 97% rename from lib/screens/game_pick_image.dart rename to lib/ui/games/game_pick_image.dart index e0facc8cc34f1456f30de8656ad0ff37efbdd2dd..7f771c49dbca2b49fe295b292244a82156135955 100644 --- a/lib/screens/game_pick_image.dart +++ b/lib/ui/games/game_pick_image.dart @@ -2,10 +2,10 @@ import 'package:flutter/material.dart'; import 'package:wordguessing/models/word.dart'; import 'package:wordguessing/provider/data.dart'; -import 'package:wordguessing/screens/game.dart'; +import 'package:wordguessing/ui/games/abstract_game.dart'; import 'package:wordguessing/utils/random_pick_words.dart'; -class GamePickImagePage extends Game { +class GamePickImagePage extends GameAbstract { const GamePickImagePage({super.key}); @override diff --git a/lib/screens/game_pick_word.dart b/lib/ui/games/game_pick_word.dart similarity index 97% rename from lib/screens/game_pick_word.dart rename to lib/ui/games/game_pick_word.dart index 86b842d69c214d7dcdbdcb8588f50f2f7b5d0fd1..d1b8b97bb330f41fceae6df9ee6e22b659e9f676 100644 --- a/lib/screens/game_pick_word.dart +++ b/lib/ui/games/game_pick_word.dart @@ -2,10 +2,10 @@ import 'package:flutter/material.dart'; import 'package:wordguessing/models/word.dart'; import 'package:wordguessing/provider/data.dart'; -import 'package:wordguessing/screens/game.dart'; +import 'package:wordguessing/ui/games/abstract_game.dart'; import 'package:wordguessing/utils/random_pick_words.dart'; -class GamePickWordPage extends Game { +class GamePickWordPage extends GameAbstract { const GamePickWordPage({super.key}); @override diff --git a/lib/screens/home.dart b/lib/ui/games/game_selector.dart similarity index 51% rename from lib/screens/home.dart rename to lib/ui/games/game_selector.dart index e83989992c5d71837bebd95d617b4052e1a3558a..882d9521f02c8d42368f1b51d34456b50465ff6a 100644 --- a/lib/screens/home.dart +++ b/lib/ui/games/game_selector.dart @@ -3,16 +3,14 @@ import 'package:provider/provider.dart'; import 'package:wordguessing/provider/data.dart'; -class Home extends StatelessWidget { - const Home({super.key}); - - static const String id = 'home'; +class GameSelector extends StatelessWidget { + const GameSelector({super.key}); @override Widget build(BuildContext context) { final Data myProvider = Provider.of<Data>(context); - Container buildMenuItemContainer(String code, Color color) { + Widget buildMenuItemContainer(String code, Color color) { const double imageSize = 150; final String imageAsset = 'assets/menu/$code.png'; @@ -35,28 +33,32 @@ class Home extends StatelessWidget { ), onTap: () { myProvider.resetGame(); - Navigator.pushNamed( - context, - '/$code', - ); + switch (code) { + case 'game-pick-word': + myProvider.updateGameType(GameType.pickWord); + break; + case 'game-pick-image': + myProvider.updateGameType(GameType.pickImage); + break; + default: + } }, ), ); } - return Scaffold( - backgroundColor: Colors.blue, - body: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisSize: MainAxisSize.max, - children: <Widget>[ - buildMenuItemContainer('game-pick-word', Colors.pink), - buildMenuItemContainer('game-pick-image', Colors.yellow), - ], - ), + Widget content = Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisSize: MainAxisSize.max, + children: <Widget>[ + buildMenuItemContainer('game-pick-word', Colors.pink), + buildMenuItemContainer('game-pick-image', Colors.yellow), + ], ), ); + + return content; } } diff --git a/lib/ui/screens/about_page.dart b/lib/ui/screens/about_page.dart new file mode 100644 index 0000000000000000000000000000000000000000..05d19322774be26931233ecd40beb1adffe27b55 --- /dev/null +++ b/lib/ui/screens/about_page.dart @@ -0,0 +1,41 @@ +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:package_info_plus/package_info_plus.dart'; + +import 'package:wordguessing/ui/widgets/header_app.dart'; + +class AboutPage extends StatelessWidget { + const AboutPage({super.key}); + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 8), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: <Widget>[ + const SizedBox(height: 8), + const AppHeader(text: 'about_title'), + const Text('about_content').tr(), + FutureBuilder<PackageInfo>( + future: PackageInfo.fromPlatform(), + builder: (context, snapshot) { + switch (snapshot.connectionState) { + case ConnectionState.done: + return const Text('about_version').tr( + namedArgs: { + 'version': snapshot.data!.version, + }, + ); + default: + return const SizedBox(); + } + }, + ), + ], + ), + ); + } +} diff --git a/lib/ui/screens/game_page.dart b/lib/ui/screens/game_page.dart new file mode 100644 index 0000000000000000000000000000000000000000..df3c84376e9d37a3040d09e0665f19d3abca2165 --- /dev/null +++ b/lib/ui/screens/game_page.dart @@ -0,0 +1,25 @@ +import 'package:flutter/material.dart'; +import 'package:provider/provider.dart'; + +import 'package:wordguessing/provider/data.dart'; +import 'package:wordguessing/ui/games/game_pick_image.dart'; +import 'package:wordguessing/ui/games/game_pick_word.dart'; +import 'package:wordguessing/ui/games/game_selector.dart'; + +class GamePage extends StatelessWidget { + const GamePage({super.key}); + + @override + Widget build(BuildContext context) { + final Data myProvider = Provider.of<Data>(context); + + switch (myProvider.gameType) { + case GameType.pickImage: + return const GamePickImagePage(); + case GameType.pickWord: + return const GamePickWordPage(); + default: + return const GameSelector(); + } + } +} diff --git a/lib/ui/screens/settings_page.dart b/lib/ui/screens/settings_page.dart new file mode 100644 index 0000000000000000000000000000000000000000..df50c147d84f6b0b8358bdc18fc6898cadefc1fb --- /dev/null +++ b/lib/ui/screens/settings_page.dart @@ -0,0 +1,26 @@ +import 'package:flutter/material.dart'; + +import 'package:wordguessing/ui/widgets/header_app.dart'; +import 'package:wordguessing/ui/widgets/settings/settings_form.dart'; + +class SettingsPage extends StatelessWidget { + const SettingsPage({super.key}); + + @override + Widget build(BuildContext context) { + return const Padding( + padding: EdgeInsets.symmetric(horizontal: 8), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: <Widget>[ + SizedBox(height: 8), + AppHeader(text: 'settings_title'), + SizedBox(height: 8), + SettingsForm(), + ], + ), + ); + } +} diff --git a/lib/ui/skeleton.dart b/lib/ui/skeleton.dart new file mode 100644 index 0000000000000000000000000000000000000000..bc0a8a0bffaf7382bcf8473fd6ecfd12aff9b37a --- /dev/null +++ b/lib/ui/skeleton.dart @@ -0,0 +1,49 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_swipe/flutter_swipe.dart'; +import 'package:provider/provider.dart'; + +import 'package:wordguessing/config/menu.dart'; +import 'package:wordguessing/cubit/bottom_nav_cubit.dart'; +import 'package:wordguessing/provider/data.dart'; +import 'package:wordguessing/ui/widgets/app_bar.dart'; +import 'package:wordguessing/ui/widgets/bottom_nav_bar.dart'; + +class SkeletonScreen extends StatefulWidget { + const SkeletonScreen({super.key}); + + @override + State<SkeletonScreen> createState() => _SkeletonScreenState(); +} + +class _SkeletonScreenState extends State<SkeletonScreen> { + @override + Widget build(BuildContext context) { + final Data myProvider = Provider.of<Data>(context); + + return Scaffold( + extendBodyBehindAppBar: false, + appBar: StandardAppBar(myProvider: myProvider), + body: Swiper( + itemCount: Menu.itemsCount, + itemBuilder: (BuildContext context, int index) { + return Menu.getPageWidget(index); + }, + pagination: SwiperPagination( + margin: const EdgeInsets.all(0), + builder: SwiperCustomPagination( + builder: (BuildContext context, SwiperPluginConfig config) { + return BottomNavBar(swipeController: config.controller); + }, + ), + ), + onIndexChanged: (newPageIndex) { + BlocProvider.of<BottomNavCubit>(context).updateIndex(newPageIndex); + }, + outer: true, + loop: false, + ), + backgroundColor: Theme.of(context).colorScheme.background, + ); + } +} diff --git a/lib/ui/widgets/app_bar.dart b/lib/ui/widgets/app_bar.dart new file mode 100644 index 0000000000000000000000000000000000000000..73038ecffd02c00b457707a647a0b9b57ebdaa3f --- /dev/null +++ b/lib/ui/widgets/app_bar.dart @@ -0,0 +1,32 @@ +import 'package:flutter/material.dart'; + +import 'package:wordguessing/provider/data.dart'; +import 'package:wordguessing/ui/widgets/header_app.dart'; + +class StandardAppBar extends StatelessWidget implements PreferredSizeWidget { + const StandardAppBar({super.key, required this.myProvider}); + + final Data myProvider; + + @override + Widget build(BuildContext context) { + final List<Widget> menuActions = []; + + if (myProvider.gameType != null) { + menuActions.add( + IconButton( + icon: const Icon(Icons.loop), + onPressed: () => myProvider.resetGame(), + ), + ); + } + + return AppBar( + title: const AppHeader(text: 'app_name'), + actions: menuActions, + ); + } + + @override + Size get preferredSize => const Size.fromHeight(50); +} diff --git a/lib/ui/widgets/bottom_nav_bar.dart b/lib/ui/widgets/bottom_nav_bar.dart new file mode 100644 index 0000000000000000000000000000000000000000..4e1d708cac14eb145f0934a92f552782d72ca978 --- /dev/null +++ b/lib/ui/widgets/bottom_nav_bar.dart @@ -0,0 +1,40 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_swipe/flutter_swipe.dart'; + +import 'package:wordguessing/config/menu.dart'; +import 'package:wordguessing/cubit/bottom_nav_cubit.dart'; + +class BottomNavBar extends StatelessWidget { + const BottomNavBar({super.key, required this.swipeController}); + + final SwiperController swipeController; + + @override + Widget build(BuildContext context) { + return Card( + margin: const EdgeInsets.all(0), + elevation: 4, + shadowColor: Theme.of(context).colorScheme.shadow, + color: Theme.of(context).colorScheme.surfaceVariant, + shape: const ContinuousRectangleBorder(), + child: BlocBuilder<BottomNavCubit, int>( + builder: (BuildContext context, int state) { + return BottomNavigationBar( + currentIndex: state, + onTap: (int index) { + context.read<BottomNavCubit>().updateIndex(index); + swipeController.move(index); + }, + type: BottomNavigationBarType.fixed, + elevation: 0, + backgroundColor: Colors.transparent, + selectedItemColor: Theme.of(context).colorScheme.primary, + unselectedItemColor: Theme.of(context).textTheme.bodySmall!.color, + items: Menu.getMenuItems(), + ); + }, + ), + ); + } +} diff --git a/lib/ui/widgets/header_app.dart b/lib/ui/widgets/header_app.dart new file mode 100644 index 0000000000000000000000000000000000000000..bf54b77375fbd0260f876f2885d0572b71715383 --- /dev/null +++ b/lib/ui/widgets/header_app.dart @@ -0,0 +1,23 @@ +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; + +class AppHeader extends StatelessWidget { + const AppHeader({super.key, required this.text}); + + final String text; + + @override + Widget build(BuildContext context) { + return Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + tr(text), + textAlign: TextAlign.start, + style: Theme.of(context).textTheme.headlineMedium!.apply(fontWeightDelta: 2), + ), + ], + ); + } +} diff --git a/lib/ui/widgets/settings/settings_form.dart b/lib/ui/widgets/settings/settings_form.dart new file mode 100644 index 0000000000000000000000000000000000000000..cb59277121264dace76f59d41290687c575f3a4f --- /dev/null +++ b/lib/ui/widgets/settings/settings_form.dart @@ -0,0 +1,63 @@ +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:unicons/unicons.dart'; + +import 'package:wordguessing/ui/widgets/settings/theme_card.dart'; + +class SettingsForm extends StatefulWidget { + const SettingsForm({super.key}); + + @override + State<SettingsForm> createState() => _SettingsFormState(); +} + +class _SettingsFormState extends State<SettingsForm> { + @override + void dispose() { + super.dispose(); + } + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + } + + @override + Widget build(BuildContext context) { + return Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: <Widget>[ + // Light/dark theme + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.center, + children: <Widget>[ + const Text('settings_label_theme').tr(), + const Row( + mainAxisAlignment: MainAxisAlignment.end, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + ThemeCard( + mode: ThemeMode.system, + icon: UniconsLine.cog, + ), + ThemeCard( + mode: ThemeMode.light, + icon: UniconsLine.sun, + ), + ThemeCard( + mode: ThemeMode.dark, + icon: UniconsLine.moon, + ) + ], + ), + ], + ), + + const SizedBox(height: 16), + ], + ); + } +} diff --git a/lib/ui/widgets/settings/theme_card.dart b/lib/ui/widgets/settings/theme_card.dart new file mode 100644 index 0000000000000000000000000000000000000000..bd1b3ab5b0ee216d3836ec8ba19a30181f65be23 --- /dev/null +++ b/lib/ui/widgets/settings/theme_card.dart @@ -0,0 +1,47 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +import 'package:wordguessing/cubit/theme_cubit.dart'; + +class ThemeCard extends StatelessWidget { + const ThemeCard({ + super.key, + required this.mode, + required this.icon, + }); + + final IconData icon; + final ThemeMode mode; + + @override + Widget build(BuildContext context) { + return BlocBuilder<ThemeCubit, ThemeModeState>( + builder: (BuildContext context, ThemeModeState state) { + return Card( + elevation: 2, + shadowColor: Theme.of(context).colorScheme.shadow, + color: state.themeMode == mode + ? Theme.of(context).colorScheme.primary + : Theme.of(context).colorScheme.surface, + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(12)), + ), + margin: const EdgeInsets.all(5), + child: InkWell( + onTap: () => BlocProvider.of<ThemeCubit>(context).getTheme( + ThemeModeState(themeMode: mode), + ), + borderRadius: const BorderRadius.all(Radius.circular(12)), + child: Icon( + icon, + size: 32, + color: state.themeMode != mode + ? Theme.of(context).colorScheme.primary + : Colors.white, + ), + ), + ); + }, + ); + } +} diff --git a/pubspec.lock b/pubspec.lock index b15ebfbb8fc4b11d61a5733db2b95e116d18c681..53bc85dec4bae56188e56f74edcd0c91e60c1f18 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1,6 +1,30 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: + args: + dependency: transitive + description: + name: args + sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596 + url: "https://pub.dev" + source: hosted + version: "2.4.2" + async: + dependency: transitive + description: + name: async + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + url: "https://pub.dev" + source: hosted + version: "2.11.0" + bloc: + dependency: transitive + description: + name: bloc + sha256: f53a110e3b48dcd78136c10daa5d51512443cea5e1348c9d80a320095fa2db9e + url: "https://pub.dev" + source: hosted + version: "8.1.3" characters: dependency: transitive description: @@ -9,6 +33,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.0" + clock: + dependency: transitive + description: + name: clock + sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf + url: "https://pub.dev" + source: hosted + version: "1.1.1" collection: dependency: transitive description: @@ -17,11 +49,67 @@ packages: url: "https://pub.dev" source: hosted version: "1.18.0" + crypto: + dependency: transitive + description: + name: crypto + sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab + url: "https://pub.dev" + source: hosted + version: "3.0.3" + easy_localization: + dependency: "direct main" + description: + name: easy_localization + sha256: c145aeb6584aedc7c862ab8c737c3277788f47488bfdf9bae0fe112bd0a4789c + url: "https://pub.dev" + source: hosted + version: "3.0.5" + easy_logger: + dependency: transitive + description: + name: easy_logger + sha256: c764a6e024846f33405a2342caf91c62e357c24b02c04dbc712ef232bf30ffb7 + url: "https://pub.dev" + source: hosted + version: "0.0.2" + equatable: + dependency: "direct main" + description: + name: equatable + sha256: c2b87cb7756efdf69892005af546c56c0b5037f54d2a88269b4f347a505e3ca2 + url: "https://pub.dev" + source: hosted + version: "2.0.5" + ffi: + dependency: transitive + description: + name: ffi + sha256: "493f37e7df1804778ff3a53bd691d8692ddf69702cf4c1c1096a2e41b4779e21" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + file: + dependency: transitive + description: + name: file + sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" + url: "https://pub.dev" + source: hosted + version: "7.0.0" flutter: dependency: "direct main" description: flutter source: sdk version: "0.0.0" + flutter_bloc: + dependency: "direct main" + description: + name: flutter_bloc + sha256: "87325da1ac757fcc4813e6b34ed5dd61169973871fdf181d6c2109dd6935ece1" + url: "https://pub.dev" + source: hosted + version: "8.1.4" flutter_lints: dependency: "direct dev" description: @@ -30,6 +118,64 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.1" + flutter_localizations: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + flutter_swipe: + dependency: "direct main" + description: + name: flutter_swipe + sha256: dc6541bac3a0545ce15a3fa15913f6250532062960bf6b0ad4562d02f14a8545 + url: "https://pub.dev" + source: hosted + version: "1.0.1" + flutter_web_plugins: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + hive: + dependency: "direct main" + description: + name: hive + sha256: "8dcf6db979d7933da8217edcec84e9df1bdb4e4edc7fc77dbd5aa74356d6d941" + url: "https://pub.dev" + source: hosted + version: "2.2.3" + http: + dependency: transitive + description: + name: http + sha256: a2bbf9d017fcced29139daa8ed2bba4ece450ab222871df93ca9eec6f80c34ba + url: "https://pub.dev" + source: hosted + version: "1.2.0" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + url: "https://pub.dev" + source: hosted + version: "4.0.2" + hydrated_bloc: + dependency: "direct main" + description: + name: hydrated_bloc + sha256: "00a2099680162e74b5a836b8a7f446e478520a9cae9f6032e028ad8129f4432d" + url: "https://pub.dev" + source: hosted + version: "9.1.4" + intl: + dependency: transitive + description: + name: intl + sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d" + url: "https://pub.dev" + source: hosted + version: "0.18.1" lints: dependency: transitive description: @@ -62,6 +208,94 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.0" + package_info_plus: + dependency: "direct main" + description: + name: package_info_plus + sha256: "88bc797f44a94814f2213db1c9bd5badebafdfb8290ca9f78d4b9ee2a3db4d79" + url: "https://pub.dev" + source: hosted + version: "5.0.1" + package_info_plus_platform_interface: + dependency: transitive + description: + name: package_info_plus_platform_interface + sha256: "9bc8ba46813a4cc42c66ab781470711781940780fd8beddd0c3da62506d3a6c6" + url: "https://pub.dev" + source: hosted + version: "2.0.1" + path: + dependency: "direct main" + description: + name: path + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" + url: "https://pub.dev" + source: hosted + version: "1.9.0" + path_provider: + dependency: "direct main" + description: + name: path_provider + sha256: b27217933eeeba8ff24845c34003b003b2b22151de3c908d0e679e8fe1aa078b + url: "https://pub.dev" + source: hosted + version: "2.1.2" + path_provider_android: + dependency: transitive + description: + name: path_provider_android + sha256: "477184d672607c0a3bf68fbbf601805f92ef79c82b64b4d6eb318cbca4c48668" + url: "https://pub.dev" + source: hosted + version: "2.2.2" + path_provider_foundation: + dependency: transitive + description: + name: path_provider_foundation + sha256: "5a7999be66e000916500be4f15a3633ebceb8302719b47b9cc49ce924125350f" + url: "https://pub.dev" + source: hosted + version: "2.3.2" + path_provider_linux: + dependency: transitive + description: + name: path_provider_linux + sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 + url: "https://pub.dev" + source: hosted + version: "2.2.1" + path_provider_platform_interface: + dependency: transitive + description: + name: path_provider_platform_interface + sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + path_provider_windows: + dependency: transitive + description: + name: path_provider_windows + sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170" + url: "https://pub.dev" + source: hosted + version: "2.2.1" + platform: + dependency: transitive + description: + name: platform + sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec" + url: "https://pub.dev" + source: hosted + version: "3.1.4" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" + url: "https://pub.dev" + source: hosted + version: "2.1.8" provider: dependency: "direct main" description: @@ -70,11 +304,115 @@ packages: url: "https://pub.dev" source: hosted version: "6.1.2" + shared_preferences: + dependency: transitive + description: + name: shared_preferences + sha256: "81429e4481e1ccfb51ede496e916348668fd0921627779233bd24cc3ff6abd02" + url: "https://pub.dev" + source: hosted + version: "2.2.2" + shared_preferences_android: + dependency: transitive + description: + name: shared_preferences_android + sha256: "8568a389334b6e83415b6aae55378e158fbc2314e074983362d20c562780fb06" + url: "https://pub.dev" + source: hosted + version: "2.2.1" + shared_preferences_foundation: + dependency: transitive + description: + name: shared_preferences_foundation + sha256: "7708d83064f38060c7b39db12aefe449cb8cdc031d6062280087bc4cdb988f5c" + url: "https://pub.dev" + source: hosted + version: "2.3.5" + shared_preferences_linux: + dependency: transitive + description: + name: shared_preferences_linux + sha256: "9f2cbcf46d4270ea8be39fa156d86379077c8a5228d9dfdb1164ae0bb93f1faa" + url: "https://pub.dev" + source: hosted + version: "2.3.2" + shared_preferences_platform_interface: + dependency: transitive + description: + name: shared_preferences_platform_interface + sha256: "22e2ecac9419b4246d7c22bfbbda589e3acf5c0351137d87dd2939d984d37c3b" + url: "https://pub.dev" + source: hosted + version: "2.3.2" + shared_preferences_web: + dependency: transitive + description: + name: shared_preferences_web + sha256: "7b15ffb9387ea3e237bb7a66b8a23d2147663d391cafc5c8f37b2e7b4bde5d21" + url: "https://pub.dev" + source: hosted + version: "2.2.2" + shared_preferences_windows: + dependency: transitive + description: + name: shared_preferences_windows + sha256: "841ad54f3c8381c480d0c9b508b89a34036f512482c407e6df7a9c4aa2ef8f59" + url: "https://pub.dev" + source: hosted + version: "2.3.2" sky_engine: dependency: transitive description: flutter source: sdk version: "0.0.99" + source_span: + dependency: transitive + description: + name: source_span + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" + url: "https://pub.dev" + source: hosted + version: "1.10.0" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + synchronized: + dependency: transitive + description: + name: synchronized + sha256: "539ef412b170d65ecdafd780f924e5be3f60032a1128df156adad6c5b373d558" + url: "https://pub.dev" + source: hosted + version: "3.1.0+1" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" + source: hosted + version: "1.2.1" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c + url: "https://pub.dev" + source: hosted + version: "1.3.2" + unicons: + dependency: "direct main" + description: + name: unicons + sha256: dbfcf93ff4d4ea19b324113857e358e4882115ab85db04417a4ba1c72b17a670 + url: "https://pub.dev" + source: hosted + version: "2.1.1" vector_math: dependency: transitive description: @@ -83,6 +421,30 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" + web: + dependency: transitive + description: + name: web + sha256: "4188706108906f002b3a293509234588823c8c979dc83304e229ff400c996b05" + url: "https://pub.dev" + source: hosted + version: "0.4.2" + win32: + dependency: transitive + description: + name: win32 + sha256: "8cb58b45c47dcb42ab3651533626161d6b67a2921917d8d429791f76972b3480" + url: "https://pub.dev" + source: hosted + version: "5.3.0" + xdg_directories: + dependency: transitive + description: + name: xdg_directories + sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d + url: "https://pub.dev" + source: hosted + version: "1.0.4" sdks: - dart: ">=3.2.0-0 <4.0.0" - flutter: ">=1.16.0" + dart: ">=3.3.0 <4.0.0" + flutter: ">=3.16.0" diff --git a/pubspec.yaml b/pubspec.yaml index d97773d8549a68b6695843437dfe67c271281f9e..1deb1bf984aa492cbcf2fca016208c6d39d134c8 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,8 @@ name: wordguessing description: A wordguessing game application. + publish_to: 'none' -version: 0.1.38+62 +version: 0.1.39+63 environment: sdk: '^3.0.0' @@ -9,7 +10,18 @@ environment: dependencies: flutter: sdk: flutter + + easy_localization: ^3.0.1 + equatable: ^2.0.5 + flutter_bloc: ^8.1.1 + flutter_swipe: ^1.0.1 + hive: ^2.2.3 + hydrated_bloc: ^9.0.0 + package_info_plus: ^5.0.1 + path: ^1.9.0 + path_provider: ^2.0.11 provider: ^6.0.5 + unicons: ^2.1.1 dev_dependencies: flutter_lints: ^3.0.1 @@ -21,3 +33,17 @@ flutter: - assets/images/ - assets/menu/ - assets/placeholder.png + - assets/translations/ + + fonts: + - family: Nunito + fonts: + - asset: assets/fonts/Nunito-Bold.ttf + weight: 700 + - asset: assets/fonts/Nunito-Medium.ttf + weight: 500 + - asset: assets/fonts/Nunito-Regular.ttf + weight: 400 + - asset: assets/fonts/Nunito-Light.ttf + weight: 300 +