diff --git a/android/gradle.properties b/android/gradle.properties
index dcf12984c36f3453d790ee3d76b4953ce8cb7158..33c43775a7db70e59256cad64931ad4fc01c2c7c 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=1.0.22
-app.versionCode=23
+app.versionName=1.0.23
+app.versionCode=24
diff --git a/assets/translations/en.json b/assets/translations/en.json
index f5e702ddc07406ea3f4ac0f7713b58bcf238b344..ca94af1202f50913ca29861c168ca3a6813f3578 100644
--- a/assets/translations/en.json
+++ b/assets/translations/en.json
@@ -1,5 +1,7 @@
 {
   "app_name": "Random application",
+  "bottom_nav_sample": "Sample",
+  "bottom_nav_chart": "Graph",
 
   "TOP": "TOP",
   "BOTTOM": "BOTTOM"
diff --git a/assets/translations/fr.json b/assets/translations/fr.json
index 1b75c0926fdd377711092fdc992a54b143e2af2b..6016e93819e90cfbf849b98f265175c97ba97433 100644
--- a/assets/translations/fr.json
+++ b/assets/translations/fr.json
@@ -1,5 +1,7 @@
 {
   "app_name": "Random application",
+  "bottom_nav_sample": "Démo",
+  "bottom_nav_chart": "Graph",
 
   "TOP": "HAUT",
   "BOTTOM": "BAS"
diff --git a/lib/activities/ActivityDemoPage.dart b/lib/activities/ActivityDemoPage.dart
index b8cceb192700ed2174a1da9b0900e50f99340f2b..d6c1dba48e3c98c612b14195dda0f4dfc02fb970 100644
--- a/lib/activities/ActivityDemoPage.dart
+++ b/lib/activities/ActivityDemoPage.dart
@@ -2,39 +2,10 @@ import 'package:easy_localization/easy_localization.dart';
 import 'package:flutter/material.dart';
 
 class ActivityDemoPage extends StatelessWidget {
-  static const String code = 'demo';
-  static const String route = '/' + code;
+  const ActivityDemoPage({super.key});
 
   @override
   Widget build(BuildContext context) {
-    Scaffold pageContent = Scaffold(
-      appBar: AppBar(
-        elevation: 0,
-        actions: <Widget>[
-          IconButton(
-            icon: const Icon(Icons.arrow_back),
-            onPressed: () {
-              print('reset activity');
-              Navigator.pop(context);
-            },
-          ),
-        ],
-      ),
-      backgroundColor: Theme.of(context).colorScheme.background,
-      body: Center(
-        child: Column(
-          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
-          crossAxisAlignment: CrossAxisAlignment.center,
-          mainAxisSize: MainAxisSize.max,
-          children: <Widget>[
-            Text('TOP').tr(),
-            SizedBox(height: 2),
-            Text('BOTTOM').tr(),
-          ],
-        ),
-      ),
-    );
-
     return SizedBox.expand(
       child: Container(
         child: FittedBox(
@@ -43,7 +14,18 @@ class ActivityDemoPage 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: <Widget>[
+                  Text('TOP').tr(),
+                  SizedBox(height: 2),
+                  Text('BOTTOM').tr(),
+                ],
+              ),
+            ),
           ),
         ),
       ),
diff --git a/lib/activities/ActivityGraphPage.dart b/lib/activities/ActivityGraphPage.dart
index da60d7ba89f4c69d0589f3efe0a42de5ef14fa1f..33fb267fcc2121e9e81f2df2477f74821669f3e6 100644
--- a/lib/activities/ActivityGraphPage.dart
+++ b/lib/activities/ActivityGraphPage.dart
@@ -2,56 +2,12 @@ import 'package:flutter/material.dart';
 import 'package:random/painters/GraphPainter.dart';
 
 class ActivityGraphPage extends StatelessWidget {
-  static const String code = 'graph';
-  static const String route = '/' + code;
+  const ActivityGraphPage({super.key});
 
   @override
   Widget build(BuildContext context) {
     double boardWidth = MediaQuery.of(context).size.width;
 
-    Scaffold pageContent = Scaffold(
-      appBar: AppBar(
-        elevation: 0,
-        actions: <Widget>[
-          IconButton(
-            icon: const Icon(Icons.arrow_back),
-            onPressed: () {
-              print('reset activity');
-              Navigator.pop(context);
-            },
-          ),
-        ],
-      ),
-      backgroundColor: Theme.of(context).colorScheme.background,
-      body: SafeArea(
-        child: Column(
-          mainAxisAlignment: MainAxisAlignment.start,
-          crossAxisAlignment: CrossAxisAlignment.center,
-          children: [
-            Center(
-              child: GestureDetector(
-                onTapUp: (details) {
-                  double xTap = details.localPosition.dx;
-                  double yTap = details.localPosition.dy;
-                  print('[' + xTap.toString() + ',' + yTap.toString() + ']');
-                },
-                child: Container(
-                  margin: EdgeInsets.all(4),
-                  padding: EdgeInsets.all(4),
-                  child: CustomPaint(
-                    size: Size(boardWidth, boardWidth),
-                    willChange: false,
-                    painter: GraphPainter(),
-                    isComplex: true,
-                  ),
-                ),
-              ),
-            ),
-          ],
-        ),
-      ),
-    );
-
     return SizedBox.expand(
       child: Container(
         child: FittedBox(
@@ -60,7 +16,33 @@ class ActivityGraphPage extends StatelessWidget {
           child: SizedBox(
             height: (MediaQuery.of(context).size.height),
             width: (MediaQuery.of(context).size.width),
-            child: pageContent,
+            child: SafeArea(
+              child: Column(
+                mainAxisAlignment: MainAxisAlignment.start,
+                crossAxisAlignment: CrossAxisAlignment.center,
+                children: [
+                  Center(
+                    child: GestureDetector(
+                      onTapUp: (details) {
+                        double xTap = details.localPosition.dx;
+                        double yTap = details.localPosition.dy;
+                        print('[' + xTap.toString() + ',' + yTap.toString() + ']');
+                      },
+                      child: Container(
+                        margin: EdgeInsets.all(4),
+                        padding: EdgeInsets.all(4),
+                        child: CustomPaint(
+                          size: Size(boardWidth, boardWidth),
+                          willChange: false,
+                          painter: GraphPainter(),
+                          isComplex: true,
+                        ),
+                      ),
+                    ),
+                  ),
+                ],
+              ),
+            ),
           ),
         ),
       ),
diff --git a/lib/cubit/bottom_nav_cubit.dart b/lib/cubit/bottom_nav_cubit.dart
new file mode 100644
index 0000000000000000000000000000000000000000..7a39813bfd5dd444a4b0ff8f4763acd0f1a5a47a
--- /dev/null
+++ b/lib/cubit/bottom_nav_cubit.dart
@@ -0,0 +1,21 @@
+import 'package:hydrated_bloc/hydrated_bloc.dart';
+
+class BottomNavCubit extends HydratedCubit<int> {
+  BottomNavCubit() : super(0);
+
+  void updateIndex(int index) => emit(index);
+
+  void getFirstScreen() => emit(0);
+
+  void getSecondScreen() => emit(1);
+
+  @override
+  int? fromJson(Map<String, dynamic> json) {
+    return json['pageIndex'] as int?;
+  }
+
+  @override
+  Map<String, dynamic>? toJson(int state) {
+    return <String, int>{'pageIndex': state};
+  }
+}
diff --git a/lib/main.dart b/lib/main.dart
index 82c70b7bb1ce8367ffa13601eb0b132d0f5acfe9..e7d191c3c40a776bda596b322c26c69ca4a44509 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -1,14 +1,23 @@
+import 'dart:io';
+
 import 'package:easy_localization/easy_localization.dart';
 import 'package:flutter/material.dart';
+import 'package:hive/hive.dart';
+import 'package:hydrated_bloc/hydrated_bloc.dart';
+import 'package:path_provider/path_provider.dart';
 
 import 'package:random/ui/screens/skeleton_screen.dart';
 import 'package:random/config/theme.dart';
-import 'package:random/activities/ActivityDemoPage.dart';
-import 'package:random/activities/ActivityGraphPage.dart';
 
 void main() async {
+  /// Initialize packages
   WidgetsFlutterBinding.ensureInitialized();
   await EasyLocalization.ensureInitialized();
+  final Directory tmpDir = await getTemporaryDirectory();
+  Hive.init(tmpDir.toString());
+  HydratedBloc.storage = await HydratedStorage.build(
+    storageDirectory: tmpDir,
+  );
 
   runApp(
     EasyLocalization(
@@ -33,32 +42,6 @@ class MyApp extends StatelessWidget {
       title: 'Random application',
       theme: appTheme,
       home: SkeletonScreen(),
-      onGenerateRoute: (settings) {
-        switch (settings.name) {
-          case ActivityDemoPage.route:
-            {
-              return MaterialPageRoute(
-                builder: (context) => ActivityDemoPage(),
-              );
-            }
-          case ActivityGraphPage.route:
-            {
-              return MaterialPageRoute(
-                builder: (context) => ActivityGraphPage(),
-              );
-            }
-
-          default:
-            {
-              print("Unknown menu entry: " + settings.name.toString());
-            }
-            break;
-        }
-
-        return null;
-      },
-
-      // Localization stuff
       localizationsDelegates: context.localizationDelegates,
       supportedLocales: context.supportedLocales,
       locale: context.locale,
diff --git a/lib/ui/screens/skeleton_screen.dart b/lib/ui/screens/skeleton_screen.dart
index cd13b088efda89f5714ca58c0fe3c7296fb5b1af..6d6e9faac7f6a8b3f50c41ff596fbc461560f559 100644
--- a/lib/ui/screens/skeleton_screen.dart
+++ b/lib/ui/screens/skeleton_screen.dart
@@ -1,55 +1,36 @@
 import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
 
 import 'package:random/activities/ActivityDemoPage.dart';
 import 'package:random/activities/ActivityGraphPage.dart';
+import 'package:random/cubit/bottom_nav_cubit.dart';
+import 'package:random/ui/widgets/custom_app_bar.dart';
+import 'package:random/ui/widgets/bottom_nav_bar.dart';
 
 class SkeletonScreen extends StatelessWidget {
-  static const String id = 'home';
+  const SkeletonScreen({super.key});
 
+  @override
   Widget build(BuildContext context) {
-    double screenWidth = MediaQuery.of(context).size.width;
+    const List<Widget> pageNavigation = <Widget>[
+      ActivityDemoPage(),
+      ActivityGraphPage(),
+    ];
 
-    Container _menuItem(String activityCode) {
-      double imageSize = screenWidth / 4;
-
-      String imageAsset = 'assets/menu/' + activityCode + '.png';
-
-      return Container(
-        margin: EdgeInsets.all(2),
-        child: TextButton(
-          style: TextButton.styleFrom(
-            padding: EdgeInsets.all(4),
-            backgroundColor: Theme.of(context).colorScheme.background,
-          ),
-          child: Image(
-            image: AssetImage(imageAsset),
-            width: imageSize,
-            height: imageSize,
-            fit: BoxFit.fill,
-          ),
-          onPressed: () {
-            Navigator.pushNamed(
-              context,
-              '/' + activityCode,
-            );
+    return BlocProvider<BottomNavCubit>(
+      create: (BuildContext context) => BottomNavCubit(),
+      child: Scaffold(
+        extendBodyBehindAppBar: true,
+        appBar: const CustomAppBarGone(),
+        body: BlocBuilder<BottomNavCubit, int>(
+          builder: (BuildContext context, int state) {
+            return AnimatedSwitcher(
+                duration: const Duration(milliseconds: 300),
+                child: pageNavigation.elementAt(state));
           },
         ),
-      );
-    }
-
-    return Scaffold(
-      extendBodyBehindAppBar: true,
-      backgroundColor: Theme.of(context).colorScheme.background,
-      body: Center(
-        child: Column(
-          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
-          crossAxisAlignment: CrossAxisAlignment.center,
-          mainAxisSize: MainAxisSize.max,
-          children: <Widget>[
-            _menuItem(ActivityDemoPage.code),
-            _menuItem(ActivityGraphPage.code),
-          ],
-        ),
+        bottomNavigationBar: const BottomNavBar(),
+        backgroundColor: Theme.of(context).colorScheme.background,
       ),
     );
   }
diff --git a/lib/ui/widgets/bottom_nav_bar.dart b/lib/ui/widgets/bottom_nav_bar.dart
new file mode 100644
index 0000000000000000000000000000000000000000..d656854e1934bd014c1a053286b45bbf0a4ec723
--- /dev/null
+++ b/lib/ui/widgets/bottom_nav_bar.dart
@@ -0,0 +1,47 @@
+import 'package:easy_localization/easy_localization.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+import 'package:ionicons/ionicons.dart';
+
+import 'package:random/cubit/bottom_nav_cubit.dart';
+
+class BottomNavBar extends StatelessWidget {
+  const BottomNavBar({super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    return Card(
+      margin: const EdgeInsets.only(top: 1, right: 4, left: 4),
+      elevation: 4,
+      shadowColor: Theme.of(context).colorScheme.shadow,
+      color: Theme.of(context).colorScheme.surfaceVariant,
+      shape: const RoundedRectangleBorder(
+        borderRadius: BorderRadius.only(
+          topLeft: Radius.circular(16),
+          topRight: Radius.circular(16),
+        ),
+      ),
+      child: BlocBuilder<BottomNavCubit, int>(builder: (BuildContext context, int state) {
+        return BottomNavigationBar(
+          currentIndex: state,
+          onTap: (int index) => context.read<BottomNavCubit>().updateIndex(index),
+          type: BottomNavigationBarType.fixed,
+          elevation: 0,
+          backgroundColor: Colors.transparent,
+          selectedItemColor: Theme.of(context).colorScheme.primary,
+          unselectedItemColor: Theme.of(context).textTheme.bodySmall!.color,
+          items: <BottomNavigationBarItem>[
+            BottomNavigationBarItem(
+              icon: const Icon(Ionicons.image_outline),
+              label: tr('bottom_nav_sample'),
+            ),
+            BottomNavigationBarItem(
+              icon: const Icon(Ionicons.pencil_outline),
+              label: tr('bottom_nav_chart'),
+            ),
+          ],
+        );
+      }),
+    );
+  }
+}
diff --git a/lib/ui/widgets/custom_app_bar.dart b/lib/ui/widgets/custom_app_bar.dart
new file mode 100644
index 0000000000000000000000000000000000000000..93c477e9160589a31be400f5542e7809727851bf
--- /dev/null
+++ b/lib/ui/widgets/custom_app_bar.dart
@@ -0,0 +1,33 @@
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+
+class CustomAppBarGone extends StatelessWidget implements PreferredSizeWidget {
+  const CustomAppBarGone({super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    final Brightness brightness = Theme.of(context).colorScheme.brightness;
+
+    return AppBar(
+      systemOverlayStyle: SystemUiOverlayStyle(
+        statusBarBrightness: brightness,
+        systemStatusBarContrastEnforced: false,
+        statusBarColor: Theme.of(context).colorScheme.background,
+        statusBarIconBrightness:
+            brightness == Brightness.dark ? Brightness.light : Brightness.dark,
+      ),
+      backgroundColor: Colors.transparent,
+      excludeHeaderSemantics: true,
+      shadowColor: Colors.transparent,
+      scrolledUnderElevation: 0,
+      surfaceTintColor: Colors.transparent,
+      foregroundColor: Colors.transparent,
+      elevation: 0,
+      bottomOpacity: 0,
+      toolbarOpacity: 0,
+    );
+  }
+
+  @override
+  Size get preferredSize => const Size.fromHeight(0);
+}
diff --git a/pubspec.lock b/pubspec.lock
index 307e7a3551b7bb03020b135cef2c6e8494646455..f0fbed261d7a349b9ff0b9b06f6d07d6b08137f8 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -9,6 +9,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "2.4.2"
+  bloc:
+    dependency: transitive
+    description:
+      name: bloc
+      sha256: "3820f15f502372d979121de1f6b97bfcf1630ebff8fe1d52fb2b0bfa49be5b49"
+      url: "https://pub.dev"
+    source: hosted
+    version: "8.1.2"
   characters:
     dependency: transitive
     description:
@@ -33,6 +41,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "1.17.2"
+  crypto:
+    dependency: transitive
+    description:
+      name: crypto
+      sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab
+      url: "https://pub.dev"
+    source: hosted
+    version: "3.0.3"
   easy_localization:
     dependency: "direct main"
     description:
@@ -70,6 +86,14 @@ packages:
     description: flutter
     source: sdk
     version: "0.0.0"
+  flutter_bloc:
+    dependency: "direct main"
+    description:
+      name: flutter_bloc
+      sha256: e74efb89ee6945bcbce74a5b3a5a3376b088e5f21f55c263fc38cbdc6237faae
+      url: "https://pub.dev"
+    source: hosted
+    version: "8.1.3"
   flutter_localizations:
     dependency: transitive
     description: flutter
@@ -80,6 +104,22 @@ packages:
     description: flutter
     source: sdk
     version: "0.0.0"
+  hive:
+    dependency: transitive
+    description:
+      name: hive
+      sha256: "8dcf6db979d7933da8217edcec84e9df1bdb4e4edc7fc77dbd5aa74356d6d941"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.2.3"
+  hydrated_bloc:
+    dependency: "direct main"
+    description:
+      name: hydrated_bloc
+      sha256: "24994e61f64904d911683cce1a31dc4ef611619da5253f1de2b7b8fc6f79a118"
+      url: "https://pub.dev"
+    source: hosted
+    version: "9.1.2"
   intl:
     dependency: transitive
     description:
@@ -88,6 +128,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "0.18.1"
+  ionicons:
+    dependency: "direct main"
+    description:
+      name: ionicons
+      sha256: "5496bc65a16115ecf05b15b78f494ee4a8869504357668f0a11d689e970523cf"
+      url: "https://pub.dev"
+    source: hosted
+    version: "0.2.2"
   material_color_utilities:
     dependency: transitive
     description:
@@ -104,6 +152,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "1.9.1"
+  nested:
+    dependency: transitive
+    description:
+      name: nested
+      sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20"
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.0.0"
   path:
     dependency: transitive
     description:
@@ -112,6 +168,30 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "1.8.3"
+  path_provider:
+    dependency: "direct main"
+    description:
+      name: path_provider
+      sha256: a1aa8aaa2542a6bc57e381f132af822420216c80d4781f7aa085ca3229208aaa
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.1.1"
+  path_provider_android:
+    dependency: transitive
+    description:
+      name: path_provider_android
+      sha256: e595b98692943b4881b219f0a9e3945118d3c16bd7e2813f98ec6e532d905f72
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.2.1"
+  path_provider_foundation:
+    dependency: transitive
+    description:
+      name: path_provider_foundation
+      sha256: "19314d595120f82aca0ba62787d58dde2cc6b5df7d2f0daf72489e38d1b57f2d"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.3.1"
   path_provider_linux:
     dependency: transitive
     description:
@@ -152,6 +232,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "2.1.6"
+  provider:
+    dependency: transitive
+    description:
+      name: provider
+      sha256: cdbe7530b12ecd9eb455bdaa2fcb8d4dad22e80b8afb4798b41479d5ce26847f
+      url: "https://pub.dev"
+    source: hosted
+    version: "6.0.5"
   shared_preferences:
     dependency: transitive
     description:
@@ -213,6 +301,22 @@ packages:
     description: flutter
     source: sdk
     version: "0.0.99"
+  synchronized:
+    dependency: transitive
+    description:
+      name: synchronized
+      sha256: "5fcbd27688af6082f5abd611af56ee575342c30e87541d0245f7ff99faa02c60"
+      url: "https://pub.dev"
+    source: hosted
+    version: "3.1.0"
+  typed_data:
+    dependency: transitive
+    description:
+      name: typed_data
+      sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.3.2"
   vector_math:
     dependency: transitive
     description:
diff --git a/pubspec.yaml b/pubspec.yaml
index ed763febaf57b50e3d0117444bb53b007e89ee8b..46f75c51a02b5b0f3bf67c68d9fe644eaca0ed5e 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -3,7 +3,7 @@ description: A random application, for testing purpose only.
 
 publish_to: 'none'
 
-version: 1.0.22+23
+version: 1.0.23+24
 
 environment:
   sdk: '^3.0.0'
@@ -13,9 +13,13 @@ dependencies:
     sdk: flutter
 
   easy_localization: ^3.0.1
+  flutter_bloc: ^8.1.1
+  path_provider: ^2.0.11
+  hydrated_bloc: ^9.0.0
+  ionicons: ^0.2.2
 
 flutter:
-  uses-material-design: true
+  uses-material-design: false
   assets:
     - assets/menu/
     - assets/translations/