diff --git a/android/gradle.properties b/android/gradle.properties
index 1f1e18fde2fb2162defa4f04b777246542b50926..9b5bace2138ec06078e8d1ada235d80aff083846 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.0.36
-app.versionCode=36
+app.versionName=0.0.37
+app.versionCode=37
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..c40bf79ffe85272000814513df69af38c0612b16
--- /dev/null
+++ b/assets/translations/en.json
@@ -0,0 +1,16 @@
+{
+  "app_name": "Colors",
+
+  "long_press_to_quit": "Long press to quit game...",
+
+  "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": "Colors, a colorful flood game.",
+  "about_version": "Version: {version}"
+}
diff --git a/assets/translations/fr.json b/assets/translations/fr.json
new file mode 100644
index 0000000000000000000000000000000000000000..895e185dafe2587e69063bc03ed5fcd1f8dcc27d
--- /dev/null
+++ b/assets/translations/fr.json
@@ -0,0 +1,16 @@
+{
+  "app_name": "Colors",
+
+  "long_press_to_quit": "Appuyer longtemps pour quitter le jeu...",
+
+  "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": "Colors, un jeu de remplissage haut en couleurs.",
+  "about_version": "Version : {version}"
+}
diff --git a/fastlane/metadata/android/en-US/changelogs/37.txt b/fastlane/metadata/android/en-US/changelogs/37.txt
new file mode 100644
index 0000000000000000000000000000000000000000..6b884ec4ea3e942b988f5815114a1c3ab59810b8
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/37.txt
@@ -0,0 +1 @@
+Improve game conception/architecture.
diff --git a/fastlane/metadata/android/fr-FR/changelogs/37.txt b/fastlane/metadata/android/fr-FR/changelogs/37.txt
new file mode 100644
index 0000000000000000000000000000000000000000..386b2cdcc090f19264599ba6dc6b215246489bce
--- /dev/null
+++ b/fastlane/metadata/android/fr-FR/changelogs/37.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..b969ec5c5b74440763eee143c4674cf0a46adffa
--- /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:colors/ui/screens/about_page.dart';
+import 'package:colors/ui/screens/game_page.dart';
+import 'package:colors/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..f33dca378aa5fabad4b97268304f15ebdc39b26d
--- /dev/null
+++ b/lib/cubit/bottom_nav_cubit.dart
@@ -0,0 +1,31 @@
+import 'package:hydrated_bloc/hydrated_bloc.dart';
+
+import 'package:colors/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/entities/cell.dart b/lib/entities/cell.dart
index 115dd0186c8010f29d42b486d9044a3cae91c595..9617e4c86349bda6532141e47c96f79297866184 100644
--- a/lib/entities/cell.dart
+++ b/lib/entities/cell.dart
@@ -1,6 +1,7 @@
+import 'package:flutter/material.dart';
+
 import 'package:colors/provider/data.dart';
 import 'package:colors/utils/board_utils.dart';
-import 'package:flutter/material.dart';
 
 class Cell {
   int value;
@@ -9,14 +10,14 @@ class Cell {
     this.value,
   );
 
-  Container widgetFillBoardWithColor(Data myProvider) {
-    String imageAsset = getImageAssetName(myProvider);
+  Container interactiveWidget(Data myProvider, ColorScheme colorScheme) {
+    final String imageAsset = 'assets/skins/${myProvider.parameterSkin}_$value.png';
 
     return Container(
       margin: const EdgeInsets.all(2),
       decoration: BoxDecoration(
         border: Border.all(
-          color: Colors.black,
+          color: colorScheme.onSurface,
           width: 4,
         ),
       ),
@@ -26,17 +27,11 @@ class Cell {
           fit: BoxFit.fill,
         ),
         onTap: () {
-          if (!myProvider.animationInProgress &&
-              myProvider.getFirstCellValue() != value) {
+          if (!myProvider.animationInProgress && myProvider.getFirstCellValue() != value) {
             BoardUtils.fillBoardFromFirstCell(myProvider, value);
           }
         },
       ),
     );
   }
-
-  String getImageAssetName(Data myProvider) {
-    int cellValue = value;
-    return 'assets/skins/${myProvider.parameterSkin}_$cellValue.png';
-  }
 }
diff --git a/lib/layout/board.dart b/lib/layout/board.dart
deleted file mode 100644
index 7991c5ec19a6d34be2f427f999b2a69d30a4e684..0000000000000000000000000000000000000000
--- a/lib/layout/board.dart
+++ /dev/null
@@ -1,36 +0,0 @@
-import 'package:colors/layout/board_painter.dart';
-import 'package:colors/provider/data.dart';
-import 'package:colors/utils/board_utils.dart';
-import 'package:flutter/material.dart';
-
-class Board {
-  static Container buildGameBoard(Data myProvider, double boardWidth) {
-    return Container(
-      margin: const EdgeInsets.all(4),
-      padding: const EdgeInsets.all(4),
-      child: Column(
-        children: [
-          Center(
-            child: GestureDetector(
-              onTapUp: (details) {
-                double xTap = details.localPosition.dx;
-                double yTap = details.localPosition.dy;
-                int boardSize = myProvider.boardSize;
-                int col = xTap ~/ (boardWidth / boardSize);
-                int row = yTap ~/ (boardWidth / boardSize);
-                int cellValue = myProvider.getCellValue(col, row);
-                BoardUtils.fillBoardFromFirstCell(myProvider, cellValue);
-              },
-              child: CustomPaint(
-                size: Size(boardWidth, boardWidth),
-                willChange: false,
-                painter: BoardPainter(myProvider),
-                isComplex: true,
-              ),
-            ),
-          ),
-        ],
-      ),
-    );
-  }
-}
diff --git a/lib/layout/game.dart b/lib/layout/game.dart
deleted file mode 100644
index d953163a3b10f71e6e266acb316ed248c2241144..0000000000000000000000000000000000000000
--- a/lib/layout/game.dart
+++ /dev/null
@@ -1,154 +0,0 @@
-import 'package:colors/entities/cell.dart';
-import 'package:colors/layout/board.dart';
-import 'package:colors/provider/data.dart';
-import 'package:colors/utils/game_utils.dart';
-import 'package:flutter/material.dart';
-
-class Game {
-  static Widget buildGameWidget(Data myProvider, double boardWidth) {
-    final bool gameIsFinished = myProvider.isGameFinished();
-
-    return Column(
-      mainAxisAlignment: MainAxisAlignment.start,
-      crossAxisAlignment: CrossAxisAlignment.center,
-      children: [
-        const SizedBox(height: 8),
-        Game.buildTopIndicatorWidget(myProvider),
-        const SizedBox(height: 2),
-        Expanded(
-          child: Board.buildGameBoard(myProvider, boardWidth),
-        ),
-        const SizedBox(height: 2),
-        Container(
-          child: gameIsFinished
-              ? Game.buildEndGameMessage(myProvider)
-              : Game.buildSelectColorBar(myProvider),
-        ),
-      ],
-    );
-  }
-
-  static Widget buildTopIndicatorWidget(Data myProvider) {
-    String progressIndicator = '${myProvider.progress}/${myProvider.progressTotal}';
-
-    if (myProvider.movesCount > 0) {
-      progressIndicator += ' (+${myProvider.progressDelta})';
-    }
-
-    Color maxMovesCountColor = Colors.grey;
-    if (myProvider.movesCount > myProvider.maxMovesCount) {
-      maxMovesCountColor = Colors.red;
-    }
-
-    return Table(
-      children: [
-        TableRow(
-          children: [
-            Column(
-              children: [
-                Text(
-                  myProvider.movesCount.toString(),
-                  style: const TextStyle(
-                    fontSize: 35,
-                    fontWeight: FontWeight.w600,
-                    color: Colors.black,
-                  ),
-                ),
-              ],
-            ),
-            Column(
-              children: [
-                Text(
-                  '(max: ${myProvider.maxMovesCount})',
-                  style: TextStyle(
-                    fontSize: 15,
-                    fontWeight: FontWeight.w600,
-                    color: maxMovesCountColor,
-                  ),
-                ),
-                Text(
-                  progressIndicator,
-                  style: const TextStyle(
-                    fontSize: 15,
-                    fontWeight: FontWeight.w600,
-                    color: Colors.green,
-                  ),
-                ),
-              ],
-            ),
-          ],
-        ),
-      ],
-    );
-  }
-
-  static Widget buildSelectColorBar(Data myProvider) {
-    int maxValue = myProvider.colorsCount;
-
-    return Container(
-      margin: const EdgeInsets.all(2),
-      padding: const EdgeInsets.all(2),
-      child: Table(
-        defaultColumnWidth: const IntrinsicColumnWidth(),
-        children: [
-          TableRow(
-            children: [
-              for (int value = 1; value <= maxValue; value++)
-                Column(
-                  children: [
-                    Cell(value).widgetFillBoardWithColor(myProvider),
-                  ],
-                ),
-            ],
-          ),
-        ],
-      ),
-    );
-  }
-
-  static TextButton buildRestartGameButton(Data myProvider) {
-    return TextButton(
-      style: ButtonStyle(
-        padding: MaterialStateProperty.all<EdgeInsets>(const EdgeInsets.all(0)),
-      ),
-      child: const Image(
-        image: AssetImage('assets/icons/button_back.png'),
-        fit: BoxFit.fill,
-      ),
-      onPressed: () => GameUtils.resetGame(myProvider),
-    );
-  }
-
-  static Widget buildEndGameMessage(Data myProvider) {
-    String decorationImageAssetName = '';
-    if (myProvider.gameWon) {
-      decorationImageAssetName = 'assets/icons/game_win.png';
-    } else {
-      decorationImageAssetName = 'assets/icons/game_fail.png';
-    }
-
-    Image decorationImage = Image(
-      image: AssetImage(decorationImageAssetName),
-      fit: BoxFit.fill,
-    );
-
-    return Container(
-      margin: const EdgeInsets.all(2),
-      padding: const EdgeInsets.all(2),
-      child: Table(
-        defaultColumnWidth: const IntrinsicColumnWidth(),
-        children: [
-          TableRow(
-            children: [
-              Column(children: [decorationImage]),
-              Column(children: [decorationImage]),
-              Column(children: [buildRestartGameButton(myProvider)]),
-              Column(children: [decorationImage]),
-              Column(children: [decorationImage]),
-            ],
-          ),
-        ],
-      ),
-    );
-  }
-}
diff --git a/lib/layout/parameters.dart b/lib/layout/parameters.dart
deleted file mode 100644
index c14295f101019d2e2bc3dd1d45bf92d03a018e66..0000000000000000000000000000000000000000
--- a/lib/layout/parameters.dart
+++ /dev/null
@@ -1,140 +0,0 @@
-import 'package:colors/provider/data.dart';
-import 'package:colors/utils/game_utils.dart';
-import 'package:flutter/material.dart';
-
-class Parameters {
-  static double separatorHeight = 2.0;
-  static double blockMargin = 8.0;
-  static double blockPadding = 3.0;
-  static Color buttonBackgroundColor = Colors.white;
-  static Color buttonBorderColorActive = Colors.blue;
-  static Color buttonBorderColorInactive = Colors.white;
-  static double buttonBorderWidth = 8.0;
-  static double buttonBorderRadius = 6.0;
-  static double buttonPadding = 0.0;
-  static double buttonMargin = 0.0;
-
-  static Widget buildParametersSelector(Data myProvider) {
-    List<Widget> lines = [];
-
-    List<String> parameters = myProvider.availableParameters;
-    for (var index = 0; index < parameters.length; index++) {
-      lines.add(Parameters.buildParameterSelector(myProvider, parameters[index]));
-      lines.add(SizedBox(height: Parameters.separatorHeight));
-    }
-
-    return Column(
-      mainAxisAlignment: MainAxisAlignment.start,
-      crossAxisAlignment: CrossAxisAlignment.center,
-      children: [
-        SizedBox(height: Parameters.separatorHeight),
-        Expanded(
-          child: Column(
-            mainAxisSize: MainAxisSize.min,
-            mainAxisAlignment: MainAxisAlignment.center,
-            children: lines,
-          ),
-        ),
-        SizedBox(height: Parameters.separatorHeight),
-        Container(
-          child: Parameters.buildStartGameButton(myProvider),
-        ),
-      ],
-    );
-  }
-
-  static Widget buildStartGameButton(Data myProvider) {
-    Column decorationImage = const Column(
-      children: [
-        Image(
-          image: AssetImage('assets/icons/game_win.png'),
-          fit: BoxFit.fill,
-        ),
-      ],
-    );
-
-    return Container(
-      margin: EdgeInsets.all(Parameters.blockMargin),
-      padding: EdgeInsets.all(Parameters.blockPadding),
-      child: Table(
-        defaultColumnWidth: const IntrinsicColumnWidth(),
-        children: [
-          TableRow(
-            children: [
-              decorationImage,
-              Column(
-                children: [
-                  TextButton(
-                    style: ButtonStyle(
-                      padding: MaterialStateProperty.all<EdgeInsets>(const EdgeInsets.all(0)),
-                    ),
-                    child: const Image(
-                      image: AssetImage('assets/icons/button_start.png'),
-                      fit: BoxFit.fill,
-                    ),
-                    onPressed: () => GameUtils.startGame(myProvider),
-                  ),
-                ],
-              ),
-              decorationImage,
-            ],
-          ),
-        ],
-      ),
-    );
-  }
-
-  static Widget buildParameterSelector(Data myProvider, String parameterCode) {
-    List<String> availableValues = myProvider.getParameterAvailableValues(parameterCode);
-
-    if (availableValues.length == 1) {
-      return const SizedBox(height: 0.0);
-    }
-
-    return Table(
-      defaultColumnWidth: const IntrinsicColumnWidth(),
-      children: [
-        TableRow(
-          children: [
-            for (var index = 0; index < availableValues.length; index++)
-              Column(
-                children: [
-                  _buildParameterButton(myProvider, parameterCode, availableValues[index])
-                ],
-              ),
-          ],
-        ),
-      ],
-    );
-  }
-
-  static Widget _buildParameterButton(
-      Data myProvider, String parameterCode, String parameterValue) {
-    String currentValue = myProvider.getParameterValue(parameterCode).toString();
-
-    bool isActive = (parameterValue == currentValue);
-    String imageAsset = 'assets/icons/${parameterCode}_$parameterValue.png';
-
-    return TextButton(
-      child: Container(
-        margin: EdgeInsets.all(Parameters.buttonMargin),
-        padding: EdgeInsets.all(Parameters.buttonPadding),
-        decoration: BoxDecoration(
-          color: Parameters.buttonBackgroundColor,
-          borderRadius: BorderRadius.circular(Parameters.buttonBorderRadius),
-          border: Border.all(
-            color: isActive
-                ? Parameters.buttonBorderColorActive
-                : Parameters.buttonBorderColorInactive,
-            width: Parameters.buttonBorderWidth,
-          ),
-        ),
-        child: Image(
-          image: AssetImage(imageAsset),
-          fit: BoxFit.fill,
-        ),
-      ),
-      onPressed: () => myProvider.setParameterValue(parameterCode, parameterValue),
-    );
-  }
-}
diff --git a/lib/main.dart b/lib/main.dart
index 07f193de2d50a7b851c7a7571992fba621a8245b..a74262fbb5d6b33e3e73d627917c9e3de41d675d 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -1,14 +1,42 @@
-import 'package:colors/provider/data.dart';
-import 'package:colors/screens/home.dart';
+import 'dart:io';
+
+import 'package:easy_localization/easy_localization.dart';
 import 'package:flutter/material.dart';
-import 'package:flutter/services.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:overlay_support/overlay_support.dart';
+import 'package:path_provider/path_provider.dart';
+import 'package:provider/provider.dart';
 
-void main() {
+import 'package:colors/config/theme.dart';
+import 'package:colors/cubit/bottom_nav_cubit.dart';
+import 'package:colors/cubit/theme_cubit.dart';
+import 'package:colors/provider/data.dart';
+import 'package:colors/ui/skeleton.dart';
+
+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 {
@@ -16,20 +44,34 @@ class MyApp extends StatelessWidget {
 
   @override
   Widget build(BuildContext context) {
-    return ChangeNotifierProvider(
-      create: (BuildContext context) => Data(),
-      child: Consumer<Data>(
-        builder: (context, data, child) {
-          return OverlaySupport(
-            child: MaterialApp(
-              debugShowCheckedModeBanner: false,
-              theme: ThemeData(
-                primaryColor: Colors.blue,
-                visualDensity: VisualDensity.adaptivePlatformDensity,
-              ),
-              home: const Home(),
-              routes: {
-                Home.id: (context) => const Home(),
+    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 OverlaySupport(
+                  child: MaterialApp(
+                    title: 'Minehunter',
+                    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,
+                  ),
+                );
               },
             ),
           );
diff --git a/lib/provider/data.dart b/lib/provider/data.dart
index bb84b587a7dd46ea8c354c73727d59b2fd8ea0c3..dfe31360d790bb8775fd4c78343024c10a400ed4 100644
--- a/lib/provider/data.dart
+++ b/lib/provider/data.dart
@@ -1,7 +1,10 @@
-import 'package:colors/entities/cell.dart';
 import 'package:flutter/foundation.dart';
 import 'package:shared_preferences/shared_preferences.dart';
 
+import 'package:colors/entities/cell.dart';
+
+typedef Board = List<List<Cell>>;
+
 class Data extends ChangeNotifier {
   // Configuration available parameters
   final List<String> _availableParameters = ['level', 'size', 'colors', 'skin'];
@@ -42,7 +45,7 @@ class Data extends ChangeNotifier {
   int _colorsCount = 0;
   int _movesCount = 0;
   int _maxMovesCount = 0;
-  List<List<Cell>> _cells = [];
+  Board _board = [];
 
   int _progress = 0;
   int _progressTotal = 0;
@@ -252,23 +255,23 @@ class Data extends ChangeNotifier {
     _colorsCount = colorsCount;
   }
 
-  List<List<Cell>> get cells => _cells;
-  void updateCells(List<List<Cell>> cells) {
-    _cells = cells;
+  Board get board => _board;
+  void updateBoard(Board board) {
+    _board = board;
     notifyListeners();
   }
 
   updateCellValue(int col, int row, int value) {
-    _cells[row][col].value = value;
+    _board[row][col].value = value;
     notifyListeners();
   }
 
   int getFirstCellValue() {
-    return _cells[0][0].value;
+    return _board[0][0].value;
   }
 
   int getCellValue(int col, int row) {
-    return _cells[row][col].value;
+    return _board[row][col].value;
   }
 
   int get movesCount => _movesCount;
diff --git a/lib/screens/home.dart b/lib/screens/home.dart
deleted file mode 100644
index ff66a143f410a8d903d50f59c4eb39450a5994fc..0000000000000000000000000000000000000000
--- a/lib/screens/home.dart
+++ /dev/null
@@ -1,60 +0,0 @@
-import 'package:colors/layout/game.dart';
-import 'package:colors/layout/parameters.dart';
-import 'package:colors/provider/data.dart';
-import 'package:colors/utils/game_utils.dart';
-import 'package:flutter/material.dart';
-import 'package:overlay_support/overlay_support.dart';
-import 'package:provider/provider.dart';
-
-class Home extends StatefulWidget {
-  const Home({super.key});
-
-  static const String id = 'home';
-
-  @override
-  HomeState createState() => HomeState();
-}
-
-class HomeState extends State<Home> {
-  @override
-  void initState() {
-    super.initState();
-
-    Data myProvider = Provider.of<Data>(context, listen: false);
-    myProvider.initParametersValues();
-  }
-
-  @override
-  Widget build(BuildContext context) {
-    Data myProvider = Provider.of<Data>(context);
-    double boardWidth = MediaQuery.of(context).size.width;
-
-    List<Widget> menuActions = [];
-
-    if (myProvider.gameIsRunning) {
-      menuActions = [
-        TextButton(
-          child: const Image(
-            image: AssetImage('assets/icons/button_back.png'),
-            fit: BoxFit.fill,
-          ),
-          onPressed: () => toast('Long press to quit game...'),
-          onLongPress: () => GameUtils.resetGame(myProvider),
-        ),
-      ];
-    }
-
-    return Scaffold(
-      appBar: AppBar(
-        actions: menuActions,
-      ),
-      body: SafeArea(
-        child: Center(
-          child: myProvider.gameIsRunning
-              ? Game.buildGameWidget(myProvider, boardWidth)
-              : Parameters.buildParametersSelector(myProvider),
-        ),
-      ),
-    );
-  }
-}
diff --git a/lib/ui/layout/game.dart b/lib/ui/layout/game.dart
new file mode 100644
index 0000000000000000000000000000000000000000..a91ceafa7578a1b92617b1406348a4d1c2ae4237
--- /dev/null
+++ b/lib/ui/layout/game.dart
@@ -0,0 +1,42 @@
+import 'package:flutter/material.dart';
+
+import 'package:colors/ui/layout/tileset.dart';
+import 'package:colors/provider/data.dart';
+import 'package:colors/ui/widgets/game/indicator_top.dart';
+import 'package:colors/ui/widgets/game/message_game_end.dart';
+import 'package:colors/ui/widgets/game/select_color_bar.dart';
+
+class Game extends StatelessWidget {
+  const Game({
+    super.key,
+    required this.myProvider,
+    required this.boardWidth,
+  });
+
+  final Data myProvider;
+  final double boardWidth;
+
+  @override
+  Widget build(BuildContext context) {
+    final bool gameIsFinished = myProvider.isGameFinished();
+
+    return Column(
+      mainAxisAlignment: MainAxisAlignment.start,
+      crossAxisAlignment: CrossAxisAlignment.center,
+      children: [
+        const SizedBox(height: 8),
+        TopIndicator(myProvider: myProvider),
+        const SizedBox(height: 2),
+        Expanded(
+          child: Tileset(myProvider: myProvider, boardWidth: boardWidth),
+        ),
+        const SizedBox(height: 2),
+        Container(
+          child: gameIsFinished
+              ? EndGameMessage(myProvider: myProvider)
+              : SelectColorBar(myProvider: myProvider),
+        ),
+      ],
+    );
+  }
+}
diff --git a/lib/ui/layout/parameters.dart b/lib/ui/layout/parameters.dart
new file mode 100644
index 0000000000000000000000000000000000000000..34a9a42e93adfc43b9757bc739f0b21d08a01191
--- /dev/null
+++ b/lib/ui/layout/parameters.dart
@@ -0,0 +1,119 @@
+import 'package:flutter/material.dart';
+
+import 'package:colors/ui/widgets/home/button_game_start_new.dart';
+import 'package:colors/provider/data.dart';
+
+class Parameters extends StatelessWidget {
+  const Parameters({super.key, required this.myProvider});
+
+  final Data myProvider;
+
+  static const double separatorHeight = 2.0;
+  static const double blockMargin = 3.0;
+  static const double blockPadding = 2.0;
+  static const Color buttonBackgroundColor = Colors.white;
+  static const Color buttonBorderColorActive = Colors.blue;
+  static const Color buttonBorderColorInactive = Colors.white;
+  static const double buttonBorderWidth = 10.0;
+  static const double buttonBorderRadius = 8.0;
+  static const double buttonPadding = 0.0;
+  static const double buttonMargin = 0.0;
+
+  @override
+  Widget build(BuildContext context) {
+    List<Widget> lines = [];
+
+    final List<String> parameters = myProvider.availableParameters;
+    for (int index = 0; index < parameters.length; index++) {
+      lines.add(buildParameterSelector(parameters[index]));
+      lines.add(const SizedBox(height: separatorHeight));
+    }
+
+    return Column(
+      mainAxisAlignment: MainAxisAlignment.start,
+      crossAxisAlignment: CrossAxisAlignment.center,
+      children: [
+        const SizedBox(height: separatorHeight),
+        Expanded(
+          child: Column(
+            mainAxisSize: MainAxisSize.min,
+            mainAxisAlignment: MainAxisAlignment.center,
+            children: lines,
+          ),
+        ),
+        const SizedBox(height: separatorHeight),
+        StartNewGameButton(myProvider: myProvider),
+      ],
+    );
+  }
+
+  static Image buildImageWidget(String imageAssetCode) {
+    return Image(
+      image: AssetImage('assets/icons/$imageAssetCode.png'),
+      fit: BoxFit.fill,
+    );
+  }
+
+  static Container buildImageContainerWidget(String imageAssetCode) {
+    return Container(
+      child: buildImageWidget(imageAssetCode),
+    );
+  }
+
+  static Column buildDecorationImageWidget() {
+    return Column(
+      children: [
+        TextButton(
+          child: buildImageContainerWidget('game_win'),
+          onPressed: () {},
+        ),
+      ],
+    );
+  }
+
+  Widget buildParameterSelector(String parameterCode) {
+    final List<String> availableValues = myProvider.getParameterAvailableValues(parameterCode);
+
+    if (availableValues.length == 1) {
+      return const SizedBox(height: 0.0);
+    }
+
+    return Table(
+      defaultColumnWidth: const IntrinsicColumnWidth(),
+      children: [
+        TableRow(
+          children: [
+            for (int index = 0; index < availableValues.length; index++)
+              Column(
+                children: [buildParameterButton(parameterCode, availableValues[index])],
+              ),
+          ],
+        ),
+      ],
+    );
+  }
+
+  Widget buildParameterButton(String parameterCode, String parameterValue) {
+    final String currentValue = myProvider.getParameterValue(parameterCode).toString();
+
+    final bool isActive = (parameterValue == currentValue);
+    final String imageAsset = '${parameterCode}_$parameterValue';
+
+    return TextButton(
+      child: Container(
+        margin: const EdgeInsets.all(buttonMargin),
+        padding: const EdgeInsets.all(buttonPadding),
+        decoration: BoxDecoration(
+          color: buttonBackgroundColor,
+          borderRadius: BorderRadius.circular(buttonBorderRadius),
+          border: Border.all(
+            color: isActive ? buttonBorderColorActive : buttonBorderColorInactive,
+            width: buttonBorderWidth,
+          ),
+        ),
+        child: buildImageWidget(imageAsset),
+      ),
+      onPressed: () => myProvider.setParameterValue(parameterCode, parameterValue),
+    );
+  }
+}
diff --git a/lib/ui/layout/tileset.dart b/lib/ui/layout/tileset.dart
new file mode 100644
index 0000000000000000000000000000000000000000..f18470dfd99d48971a2d63aa2dc4fd38c5672a11
--- /dev/null
+++ b/lib/ui/layout/tileset.dart
@@ -0,0 +1,50 @@
+import 'package:flutter/material.dart';
+
+import 'package:colors/ui/painters/board_painter.dart';
+import 'package:colors/provider/data.dart';
+import 'package:colors/utils/board_utils.dart';
+
+class Tileset extends StatelessWidget {
+  const Tileset({
+    super.key,
+    required this.myProvider,
+    required this.boardWidth,
+  });
+
+  final Data myProvider;
+  final double boardWidth;
+
+  @override
+  Widget build(BuildContext context) {
+    return Container(
+      margin: const EdgeInsets.all(4),
+      padding: const EdgeInsets.all(4),
+      child: Column(
+        children: [
+          Center(
+            child: GestureDetector(
+              onTapUp: (details) {
+                final double xTap = details.localPosition.dx;
+                final double yTap = details.localPosition.dy;
+                final int boardSize = myProvider.boardSize;
+                final int col = xTap ~/ (boardWidth / boardSize);
+                final int row = yTap ~/ (boardWidth / boardSize);
+                final int cellValue = myProvider.getCellValue(col, row);
+                BoardUtils.fillBoardFromFirstCell(myProvider, cellValue);
+              },
+              child: CustomPaint(
+                size: Size(boardWidth, boardWidth),
+                willChange: false,
+                painter: BoardPainter(
+                  myProvider: myProvider,
+                  colorScheme: Theme.of(context).colorScheme,
+                ),
+                isComplex: true,
+              ),
+            ),
+          ),
+        ],
+      ),
+    );
+  }
+}
diff --git a/lib/layout/board_painter.dart b/lib/ui/painters/board_painter.dart
similarity index 64%
rename from lib/layout/board_painter.dart
rename to lib/ui/painters/board_painter.dart
index c955c700e5878d37111908e0a57ad4b73c2ec231..2c017978b841a218d92c54aeefefaf4ddac1ff7c 100644
--- a/lib/layout/board_painter.dart
+++ b/lib/ui/painters/board_painter.dart
@@ -1,26 +1,28 @@
+import 'package:flutter/material.dart';
+
 import 'package:colors/entities/cell.dart';
-import 'package:colors/layout/color_theme.dart';
+import 'package:colors/utils/color_theme.dart';
 import 'package:colors/provider/data.dart';
-import 'package:flutter/material.dart';
 
 class BoardPainter extends CustomPainter {
-  const BoardPainter(this.myProvider);
+  const BoardPainter({required this.myProvider, required this.colorScheme});
 
   final Data myProvider;
+  final ColorScheme colorScheme;
 
   @override
   void paint(Canvas canvas, Size size) {
-    int boardSize = myProvider.boardSize;
-    List<List<Cell>> cells = myProvider.cells;
-    double cellSize = size.width / boardSize;
+    final int boardSize = myProvider.boardSize;
+    final Board board = myProvider.board;
+    final double cellSize = size.width / boardSize;
 
     // background
     for (var row = 0; row < boardSize; row++) {
-      double y = cellSize * row;
+      final double y = cellSize * row;
       for (var col = 0; col < boardSize; col++) {
-        double x = cellSize * col;
+        final double x = cellSize * col;
 
-        final Cell cell = cells[row][col];
+        final Cell cell = board[row][col];
         final int cellValue = cell.value;
         final int colorCode = ColorTheme.getColorCode(myProvider.parameterSkin, cellValue);
 
@@ -36,40 +38,40 @@ class BoardPainter extends CustomPainter {
     }
 
     // borders
-    double borderSize = 4;
+    const double borderSize = 4;
     final cellPaintBorder = Paint();
-    cellPaintBorder.color = Colors.black;
+    cellPaintBorder.color = colorScheme.onSurface;
     cellPaintBorder.strokeWidth = borderSize;
     cellPaintBorder.strokeCap = StrokeCap.round;
 
     for (var row = 0; row < boardSize; row++) {
-      double y = cellSize * row;
+      final double y = cellSize * row;
       for (var col = 0; col < boardSize; col++) {
-        double x = cellSize * col;
+        final double x = cellSize * col;
 
-        final Cell cell = cells[row][col];
+        final Cell cell = board[row][col];
         final int cellValue = cell.value;
 
         if ((row == 0) || (row > 1 && cellValue != myProvider.getCellValue(col, row - 1))) {
-          Offset borderStart = Offset(x, y);
-          Offset borderStop = Offset(x + cellSize, y);
+          final Offset borderStart = Offset(x, y);
+          final Offset borderStop = Offset(x + cellSize, y);
           canvas.drawLine(borderStart, borderStop, cellPaintBorder);
         }
         if ((row == boardSize - 1) ||
             ((row + 1) < boardSize && cellValue != myProvider.getCellValue(col, row + 1))) {
-          Offset borderStart = Offset(x, y + cellSize);
-          Offset borderStop = Offset(x + cellSize, y + cellSize);
+          final Offset borderStart = Offset(x, y + cellSize);
+          final Offset borderStop = Offset(x + cellSize, y + cellSize);
           canvas.drawLine(borderStart, borderStop, cellPaintBorder);
         }
         if ((col == 0) || (col > 1 && cellValue != myProvider.getCellValue(col - 1, row))) {
-          Offset borderStart = Offset(x, y);
-          Offset borderStop = Offset(x, y + cellSize);
+          final Offset borderStart = Offset(x, y);
+          final Offset borderStop = Offset(x, y + cellSize);
           canvas.drawLine(borderStart, borderStop, cellPaintBorder);
         }
         if ((col == boardSize - 1) ||
             ((col + 1) < boardSize && cellValue != myProvider.getCellValue(col + 1, row))) {
-          Offset borderStart = Offset(x + cellSize, y);
-          Offset borderStop = Offset(x + cellSize, y + cellSize);
+          final Offset borderStart = Offset(x + cellSize, y);
+          final Offset borderStop = Offset(x + cellSize, y + cellSize);
           canvas.drawLine(borderStart, borderStop, cellPaintBorder);
         }
       }
diff --git a/lib/ui/screens/about_page.dart b/lib/ui/screens/about_page.dart
new file mode 100644
index 0000000000000000000000000000000000000000..459d008ee58602b8b4fd0a391c7cb491d17f87b4
--- /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:colors/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..d974148b5edbb75ca28499adb6c2d9075c50ac8a
--- /dev/null
+++ b/lib/ui/screens/game_page.dart
@@ -0,0 +1,37 @@
+import 'package:flutter/material.dart';
+import 'package:provider/provider.dart';
+
+import 'package:colors/ui/layout/game.dart';
+import 'package:colors/ui/layout/parameters.dart';
+import 'package:colors/provider/data.dart';
+
+class GamePage extends StatefulWidget {
+  const GamePage({super.key});
+
+  @override
+  GamePageState createState() => GamePageState();
+}
+
+class GamePageState extends State<GamePage> {
+  @override
+  void initState() {
+    super.initState();
+
+    final Data myProvider = Provider.of<Data>(context, listen: false);
+    myProvider.initParametersValues();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    final Data myProvider = Provider.of<Data>(context);
+    final double boardWidth = MediaQuery.of(context).size.width;
+
+    return SafeArea(
+      child: Center(
+        child: myProvider.gameIsRunning
+            ? Game(myProvider: myProvider, boardWidth: boardWidth)
+            : Parameters(myProvider: myProvider),
+      ),
+    );
+  }
+}
diff --git a/lib/ui/screens/settings_page.dart b/lib/ui/screens/settings_page.dart
new file mode 100644
index 0000000000000000000000000000000000000000..dc59bbe6eaddffbfb957beef56e24ca3971ff485
--- /dev/null
+++ b/lib/ui/screens/settings_page.dart
@@ -0,0 +1,26 @@
+import 'package:flutter/material.dart';
+
+import 'package:colors/ui/widgets/header_app.dart';
+import 'package:colors/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..a428bc5bc1686928fb37c90d4f449185c666d792
--- /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:colors/config/menu.dart';
+import 'package:colors/cubit/bottom_nav_cubit.dart';
+import 'package:colors/provider/data.dart';
+import 'package:colors/ui/widgets/app_bar.dart';
+import 'package:colors/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..c998df686de1518562c0be63d4563946595d6b3e
--- /dev/null
+++ b/lib/ui/widgets/app_bar.dart
@@ -0,0 +1,37 @@
+import 'package:easy_localization/easy_localization.dart';
+import 'package:flutter/material.dart';
+import 'package:overlay_support/overlay_support.dart';
+
+import 'package:colors/provider/data.dart';
+import 'package:colors/ui/widgets/header_app.dart';
+import 'package:colors/utils/game_utils.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.gameIsRunning) {
+      menuActions.add(TextButton(
+        child: const Image(
+          image: AssetImage('assets/icons/button_back.png'),
+          fit: BoxFit.fill,
+        ),
+        onPressed: () => toast(tr('long_press_to_quit')),
+        onLongPress: () => GameUtils.quitGame(myProvider),
+      ));
+    }
+
+    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..87e30d5a4fe026469ba6feffa70e84dc67f9a4f8
--- /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:colors/config/menu.dart';
+import 'package:colors/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/game/indicator_top.dart b/lib/ui/widgets/game/indicator_top.dart
new file mode 100644
index 0000000000000000000000000000000000000000..85f0c11810ddb86d0ca651af238ff1b136c15d74
--- /dev/null
+++ b/lib/ui/widgets/game/indicator_top.dart
@@ -0,0 +1,64 @@
+import 'package:flutter/material.dart';
+
+import 'package:colors/provider/data.dart';
+
+class TopIndicator extends StatelessWidget {
+  const TopIndicator({super.key, required this.myProvider});
+
+  final Data myProvider;
+
+  @override
+  Widget build(BuildContext context) {
+    String progressIndicator = '${myProvider.progress}/${myProvider.progressTotal}';
+
+    if (myProvider.movesCount > 0) {
+      progressIndicator += ' (+${myProvider.progressDelta})';
+    }
+
+    Color maxMovesCountColor = Colors.grey;
+    if (myProvider.movesCount > myProvider.maxMovesCount) {
+      maxMovesCountColor = Colors.red;
+    }
+
+    return Table(
+      children: [
+        TableRow(
+          children: [
+            Column(
+              children: [
+                Text(
+                  myProvider.movesCount.toString(),
+                  style: const TextStyle(
+                    fontSize: 35,
+                    fontWeight: FontWeight.w600,
+                    color: Colors.black,
+                  ),
+                ),
+              ],
+            ),
+            Column(
+              children: [
+                Text(
+                  '(max: ${myProvider.maxMovesCount})',
+                  style: TextStyle(
+                    fontSize: 15,
+                    fontWeight: FontWeight.w600,
+                    color: maxMovesCountColor,
+                  ),
+                ),
+                Text(
+                  progressIndicator,
+                  style: const TextStyle(
+                    fontSize: 15,
+                    fontWeight: FontWeight.w600,
+                    color: Colors.green,
+                  ),
+                ),
+              ],
+            ),
+          ],
+        ),
+      ],
+    );
+  }
+}
diff --git a/lib/ui/widgets/game/message_game_end.dart b/lib/ui/widgets/game/message_game_end.dart
new file mode 100644
index 0000000000000000000000000000000000000000..4a9cd90d8a48818ea1f44541a02c9cfe406e3d8f
--- /dev/null
+++ b/lib/ui/widgets/game/message_game_end.dart
@@ -0,0 +1,44 @@
+import 'package:flutter/material.dart';
+
+import 'package:colors/ui/widgets/home/button_game_restart.dart';
+import 'package:colors/provider/data.dart';
+
+class EndGameMessage extends StatelessWidget {
+  const EndGameMessage({super.key, required this.myProvider});
+
+  final Data myProvider;
+
+  @override
+  Widget build(BuildContext context) {
+    String decorationImageAssetName = '';
+    if (myProvider.gameWon) {
+      decorationImageAssetName = 'assets/icons/game_win.png';
+    } else {
+      decorationImageAssetName = 'assets/icons/game_fail.png';
+    }
+
+    final Image decorationImage = Image(
+      image: AssetImage(decorationImageAssetName),
+      fit: BoxFit.fill,
+    );
+
+    return Container(
+      margin: const EdgeInsets.all(2),
+      padding: const EdgeInsets.all(2),
+      child: Table(
+        defaultColumnWidth: const IntrinsicColumnWidth(),
+        children: [
+          TableRow(
+            children: [
+              Column(children: [decorationImage]),
+              Column(children: [decorationImage]),
+              Column(children: [RestartGameButton(myProvider: myProvider)]),
+              Column(children: [decorationImage]),
+              Column(children: [decorationImage]),
+            ],
+          ),
+        ],
+      ),
+    );
+  }
+}
diff --git a/lib/ui/widgets/game/select_color_bar.dart b/lib/ui/widgets/game/select_color_bar.dart
new file mode 100644
index 0000000000000000000000000000000000000000..8211b46a9d9d47ab429c4996735c285c26f4aa30
--- /dev/null
+++ b/lib/ui/widgets/game/select_color_bar.dart
@@ -0,0 +1,36 @@
+import 'package:flutter/material.dart';
+
+import 'package:colors/entities/cell.dart';
+import 'package:colors/provider/data.dart';
+
+class SelectColorBar extends StatelessWidget {
+  const SelectColorBar({super.key, required this.myProvider});
+
+  final Data myProvider;
+
+  @override
+  Widget build(BuildContext context) {
+    final int maxValue = myProvider.colorsCount;
+    final ColorScheme colorScheme = Theme.of(context).colorScheme;
+
+    return Container(
+      margin: const EdgeInsets.all(2),
+      padding: const EdgeInsets.all(2),
+      child: Table(
+        defaultColumnWidth: const IntrinsicColumnWidth(),
+        children: [
+          TableRow(
+            children: [
+              for (int value = 1; value <= maxValue; value++)
+                Column(
+                  children: [
+                    Cell(value).interactiveWidget(myProvider, colorScheme),
+                  ],
+                ),
+            ],
+          ),
+        ],
+      ),
+    );
+  }
+}
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/home/button_game_restart.dart b/lib/ui/widgets/home/button_game_restart.dart
new file mode 100644
index 0000000000000000000000000000000000000000..364ca072c680b8b3a7afac129dc85d08750f7c5c
--- /dev/null
+++ b/lib/ui/widgets/home/button_game_restart.dart
@@ -0,0 +1,24 @@
+import 'package:flutter/material.dart';
+
+import 'package:colors/provider/data.dart';
+import 'package:colors/utils/game_utils.dart';
+
+class RestartGameButton extends StatelessWidget {
+  const RestartGameButton({super.key, required this.myProvider});
+
+  final Data myProvider;
+
+  @override
+  Widget build(BuildContext context) {
+    return TextButton(
+      style: ButtonStyle(
+        padding: MaterialStateProperty.all<EdgeInsets>(const EdgeInsets.all(0)),
+      ),
+      child: const Image(
+        image: AssetImage('assets/icons/button_back.png'),
+        fit: BoxFit.fill,
+      ),
+      onPressed: () => GameUtils.quitGame(myProvider),
+    );
+  }
+}
diff --git a/lib/ui/widgets/home/button_game_start_new.dart b/lib/ui/widgets/home/button_game_start_new.dart
new file mode 100644
index 0000000000000000000000000000000000000000..80466e2cee86a677b4a3b6754cb2426daa06bddd
--- /dev/null
+++ b/lib/ui/widgets/home/button_game_start_new.dart
@@ -0,0 +1,38 @@
+import 'package:flutter/material.dart';
+
+import 'package:colors/provider/data.dart';
+import 'package:colors/ui/layout/parameters.dart';
+import 'package:colors/utils/game_utils.dart';
+
+class StartNewGameButton extends StatelessWidget {
+  const StartNewGameButton({super.key, required this.myProvider});
+
+  final Data myProvider;
+
+  @override
+  Widget build(BuildContext context) {
+    return Container(
+      margin: const EdgeInsets.all(Parameters.blockMargin),
+      padding: const EdgeInsets.all(Parameters.blockPadding),
+      child: Table(
+        defaultColumnWidth: const IntrinsicColumnWidth(),
+        children: [
+          TableRow(
+            children: [
+              Parameters.buildDecorationImageWidget(),
+              Column(
+                children: [
+                  TextButton(
+                    child: Parameters.buildImageContainerWidget('button_start'),
+                    onPressed: () => GameUtils.startNewGame(myProvider),
+                  ),
+                ],
+              ),
+              Parameters.buildDecorationImageWidget(),
+            ],
+          ),
+        ],
+      ),
+    );
+  }
+}
diff --git a/lib/ui/widgets/settings/settings_form.dart b/lib/ui/widgets/settings/settings_form.dart
new file mode 100644
index 0000000000000000000000000000000000000000..69d9cebaa83e6ac8d4a222ff5bdaa08a900c3fa7
--- /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:colors/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..5fd7bd79e680c32a419bc9bea0c80e1fdec49348
--- /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:colors/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/lib/utils/board_utils.dart b/lib/utils/board_utils.dart
index 86b5dbcde4758a675916fd3c29504b61583dda3e..7a63ce83b58e8024c8b31bd36d37276c606c27f4 100644
--- a/lib/utils/board_utils.dart
+++ b/lib/utils/board_utils.dart
@@ -6,14 +6,14 @@ import 'package:colors/provider/data.dart';
 import 'package:colors/utils/tools.dart';
 
 class BoardUtils {
-  static printGrid(List cells) {
-    String stringValues = '012345678';
+  static printGrid(List board) {
+    const String stringValues = '012345678';
     printlog('');
     printlog('-------');
-    for (var rowIndex = 0; rowIndex < cells.length; rowIndex++) {
+    for (int rowIndex = 0; rowIndex < board.length; rowIndex++) {
       String row = '';
-      for (var colIndex = 0; colIndex < cells[rowIndex].length; colIndex++) {
-        row += stringValues[cells[rowIndex][colIndex].value];
+      for (int colIndex = 0; colIndex < board[rowIndex].length; colIndex++) {
+        row += stringValues[board[rowIndex][colIndex].value];
       }
       printlog(row);
     }
@@ -22,38 +22,38 @@ class BoardUtils {
   }
 
   static createNewBoard(Data myProvider) {
-    int boardSize = myProvider.boardSize;
-    int maxValue = myProvider.colorsCount;
+    final int boardSize = myProvider.boardSize;
+    final int maxValue = myProvider.colorsCount;
 
-    var rand = Random();
+    Random rand = Random();
 
-    List<List<Cell>> grid = [];
-    for (var rowIndex = 0; rowIndex < boardSize; rowIndex++) {
+    Board board = [];
+    for (int rowIndex = 0; rowIndex < boardSize; rowIndex++) {
       List<Cell> row = [];
-      for (var colIndex = 0; colIndex < boardSize; colIndex++) {
-        int value = 1 + rand.nextInt(maxValue);
+      for (int colIndex = 0; colIndex < boardSize; colIndex++) {
+        final int value = 1 + rand.nextInt(maxValue);
         row.add(Cell(value));
       }
-      grid.add(row);
+      board.add(row);
     }
-    printGrid(grid);
+    printGrid(board);
 
     myProvider.resetGame();
-    myProvider.updateCells(grid);
+    myProvider.updateBoard(board);
     myProvider.updateMaxMovesCount(computeMaxMovesCountLimit(myProvider));
 
-    int initProgress = BoardUtils.getSiblingFillableCells(myProvider, 0, 0, [
+    final int initProgress = BoardUtils.getSiblingFillableCells(myProvider, 0, 0, [
       [0, 0]
     ]).length;
     myProvider.updateProgress(initProgress);
   }
 
   static int computeMaxMovesCountLimit(myProvider) {
-    int boardSize = myProvider.boardSize;
-    int colorsCount = myProvider.colorsCount;
+    final int boardSize = myProvider.boardSize;
+    final int colorsCount = myProvider.colorsCount;
 
-    int baseMaxMovesCount = (30 * (boardSize * colorsCount) / (17 * 6)).round();
-    int deltaFromLevel =
+    final int baseMaxMovesCount = (30 * (boardSize * colorsCount) / (17 * 6)).round();
+    final int deltaFromLevel =
         myProvider.getMovesCountLimitDeltaFromLevelParameter(myProvider.parameterLevel);
 
     return baseMaxMovesCount + deltaFromLevel;
@@ -107,22 +107,22 @@ class BoardUtils {
     int col,
     List<List<int>> siblingCells,
   ) {
-    final List<List<Cell>> cells = myProvider.cells;
+    final Board board = myProvider.board;
     final int boardSize = myProvider.boardSize;
 
-    final int referenceValue = cells[row][col].value;
+    final int referenceValue = board[row][col].value;
 
-    for (var deltaRow = -1; deltaRow <= 1; deltaRow++) {
-      for (var deltaCol = -1; deltaCol <= 1; deltaCol++) {
+    for (int deltaRow = -1; deltaRow <= 1; deltaRow++) {
+      for (int deltaCol = -1; deltaCol <= 1; deltaCol++) {
         if (deltaCol == 0 || deltaRow == 0) {
           final int candidateRow = row + deltaRow;
           final int candidateCol = col + deltaCol;
 
           if ((candidateRow >= 0 && candidateRow < boardSize) &&
               (candidateCol >= 0 && candidateCol < boardSize)) {
-            if (cells[candidateRow][candidateCol].value == referenceValue) {
+            if (board[candidateRow][candidateCol].value == referenceValue) {
               bool alreadyFound = false;
-              for (var index = 0; index < siblingCells.length; index++) {
+              for (int index = 0; index < siblingCells.length; index++) {
                 if ((siblingCells[index][0] == candidateRow) &&
                     (siblingCells[index][1] == candidateCol)) {
                   alreadyFound = true;
@@ -147,17 +147,17 @@ class BoardUtils {
   }
 
   static bool checkBoardIsSolved(Data myProvider) {
-    final List<List<Cell>> cells = myProvider.cells;
+    final Board board = myProvider.board;
     final int boardSize = myProvider.boardSize;
 
     // check grid is fully completed and does not contain conflict
-    int previousValue = cells[0][0].value;
-    for (var row = 0; row < boardSize; row++) {
-      for (var col = 0; col < boardSize; col++) {
-        if (cells[row][col].value == 0 || cells[row][col].value != previousValue) {
+    int previousValue = board[0][0].value;
+    for (int row = 0; row < boardSize; row++) {
+      for (int col = 0; col < boardSize; col++) {
+        if (board[row][col].value == 0 || board[row][col].value != previousValue) {
           return false;
         }
-        previousValue = cells[row][col].value;
+        previousValue = board[row][col].value;
       }
     }
 
diff --git a/lib/layout/color_theme.dart b/lib/utils/color_theme.dart
similarity index 74%
rename from lib/layout/color_theme.dart
rename to lib/utils/color_theme.dart
index 86eb72b9c9a974109f0294abfd9c1d4a6007a403..476f82bd0fc18b97835e2dcfc101eff1365b53cb 100644
--- a/lib/layout/color_theme.dart
+++ b/lib/utils/color_theme.dart
@@ -1,5 +1,5 @@
 class ColorTheme {
-  static Map<String, List<int>> borderColors = {
+  static const Map<String, List<int>> borderColors = {
     'default': [
       0xffffff,
       0xe63a3f,
@@ -12,11 +12,11 @@ class ColorTheme {
       0xf2739d,
     ],
   };
-  static int defaultBorderColor = 0x808080;
+  static const int defaultBorderColor = 0x808080;
 
   static int getColorCode(String skin, int value) {
     if (borderColors.containsKey(skin) && null != borderColors[skin]) {
-      List<int>? skinColors = borderColors[skin];
+      final List<int>? skinColors = borderColors[skin];
       if (null != skinColors) {
         return skinColors.elementAt(value) | 0xFF000000;
       }
diff --git a/lib/utils/game_utils.dart b/lib/utils/game_utils.dart
index 699b19914dfb95bab35eea0e7a7d3a24c3c51c48..6b7e2cf53e809c641481d45bf950fa8d0d682d6f 100644
--- a/lib/utils/game_utils.dart
+++ b/lib/utils/game_utils.dart
@@ -3,11 +3,11 @@ import 'package:colors/utils/board_utils.dart';
 import 'package:colors/utils/tools.dart';
 
 class GameUtils {
-  static Future<void> resetGame(Data myProvider) async {
+  static void quitGame(Data myProvider) {
     myProvider.updateGameIsRunning(false);
   }
 
-  static Future<void> startGame(Data myProvider) async {
+  static void startNewGame(Data myProvider) {
     printlog('Starting game');
     printlog('- level: ${myProvider.parameterLevel}');
     printlog('- size: ${myProvider.boardSize}');
diff --git a/pubspec.lock b/pubspec.lock
index 6b1fdfef808496ebd4ff8ce5bb9e51bfbc6469e8..2885f1ae8482614c38711b57e048f2bd0e10e178 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -1,6 +1,14 @@
 # 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:
@@ -9,6 +17,14 @@ packages:
       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:
@@ -17,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:
@@ -25,6 +49,38 @@ 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:
@@ -46,6 +102,14 @@ packages:
     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:
@@ -54,11 +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:
@@ -99,14 +216,54 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "2.1.0"
-  path:
+  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:
@@ -199,10 +356,10 @@ packages:
     dependency: transitive
     description:
       name: shared_preferences_web
-      sha256: "9aee1089b36bd2aafe06582b7d7817fd317ef05fc30e6ba14bff247d0933042a"
+      sha256: "7b15ffb9387ea3e237bb7a66b8a23d2147663d391cafc5c8f37b2e7b4bde5d21"
       url: "https://pub.dev"
     source: hosted
-    version: "2.3.0"
+    version: "2.2.2"
   shared_preferences_windows:
     dependency: transitive
     description:
@@ -216,6 +373,54 @@ packages:
     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:
@@ -228,10 +433,10 @@ packages:
     dependency: transitive
     description:
       name: web
-      sha256: "1d9158c616048c38f712a6646e317a3426da10e884447626167240d45209cbad"
+      sha256: "4188706108906f002b3a293509234588823c8c979dc83304e229ff400c996b05"
       url: "https://pub.dev"
     source: hosted
-    version: "0.5.0"
+    version: "0.4.2"
   win32:
     dependency: transitive
     description:
@@ -249,5 +454,5 @@ packages:
     source: hosted
     version: "1.0.4"
 sdks:
-  dart: ">=3.3.0 <4.0.0"
-  flutter: ">=3.19.0"
+  dart: ">=3.3.0-279.1.beta <4.0.0"
+  flutter: ">=3.16.0"
diff --git a/pubspec.yaml b/pubspec.yaml
index aebf757fb95b27bf11e992979f3f51675a022a2a..2127446ea37e47c8a4e2d9af0cef7cf8ab79ed59 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,7 +1,8 @@
 name: colors
-description: colors application
+description: Fill the board, a colorfull game!
+
 publish_to: 'none'
-version: 0.0.36+36
+version: 0.0.37+37
 
 environment:
   sdk: '^3.0.0'
@@ -9,9 +10,20 @@ environment:
 dependencies:
   flutter:
     sdk: flutter
-  provider: ^6.0.5
-  shared_preferences: ^2.2.1
+
+  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
   overlay_support: ^2.1.0
+  shared_preferences: ^2.2.1
+  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:
     - assets/icons/
     - assets/skins/
+    - 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
+