From db07fd49955166249eef82c32f3383fd70664c64 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Beno=C3=AEt=20Harrault?= <benoit@harrault.fr>
Date: Thu, 24 Oct 2024 11:58:30 +0200
Subject: [PATCH] Normalize Activity application architecture

---
 .../metadata/android/en-US/changelogs/66.txt  |  1 +
 .../metadata/android/fr-FR/changelogs/66.txt  |  1 +
 lib/{ => common}/config/activity_page.dart    | 28 +++---
 lib/{ => common}/config/screen.dart           | 22 ++---
 .../cubit/nav}/nav_cubit_pages.dart           |  8 +-
 .../cubit/nav}/nav_cubit_screens.dart         | 12 +--
 lib/{ => common}/ui/nav/bottom_nav_bar.dart   | 28 +++---
 lib/{ => common}/ui/nav/global_app_bar.dart   | 35 +++----
 lib/{ => common}/ui/pages/discoveries.dart    |  6 +-
 lib/{ => common}/ui/pages/home.dart           |  8 +-
 lib/{ => common}/ui/pages/statistics.dart     |  6 +-
 lib/{ => common}/ui/screens/about.dart        |  2 +-
 lib/{ => common}/ui/screens/activity.dart     | 12 +--
 lib/{ => common}/ui/screens/settings.dart     |  2 +-
 .../ui/settings/settings_form.dart            |  2 +-
 lib/config/application_config.dart            |  3 +
 lib/config/default_activity_settings.dart     | 28 ++++++
 lib/config/default_global_settings.dart       | 37 ++++++++
 lib/cubit/activity/activity_cubit.dart        | 65 +++++++++++++
 lib/cubit/activity/activity_state.dart        | 15 +++
 .../data_counts_by_day_cubit.dart             |  2 +-
 .../data_counts_by_day_state.dart             |  0
 .../data_counts_by_hour_cubit.dart            |  2 +-
 .../data_counts_by_hour_state.dart            |  0
 .../data_discoveries_cubit.dart               |  2 +-
 .../data_discoveries_state.dart               |  0
 .../{ => activity}/data_heatmap_cubit.dart    |  2 +-
 .../{ => activity}/data_heatmap_state.dart    |  0
 .../data_new_artists_cubit.dart               |  2 +-
 .../data_new_artists_state.dart               |  0
 .../{ => activity}/data_new_tracks_cubit.dart |  2 +-
 .../{ => activity}/data_new_tracks_state.dart |  0
 .../data_statistics_global_cubit.dart         |  0
 .../data_statistics_global_state.dart         |  0
 .../data_statistics_recent_cubit.dart         |  2 +-
 .../data_statistics_recent_state.dart         |  0
 .../{ => activity}/data_timeline_cubit.dart   |  2 +-
 .../{ => activity}/data_timeline_state.dart   |  0
 .../data_top_artists_cubit.dart               |  2 +-
 .../data_top_artists_state.dart               |  0
 .../settings/settings_activity_cubit.dart     | 62 ++++++++++++
 .../settings/settings_activity_state.dart     | 15 +++
 .../{ => settings}/settings_global_cubit.dart |  0
 .../{ => settings}/settings_global_state.dart |  0
 lib/main.dart                                 | 94 +++++++++++++------
 lib/models/activity/activity.dart             | 77 +++++++++++++++
 lib/models/settings/settings_activity.dart    | 42 +++++++++
 lib/models/settings/settings_global.dart      | 42 +++++++++
 lib/ui/skeleton.dart                          |  9 +-
 lib/ui/widgets/cards/counts_by_day.dart       |  4 +-
 lib/ui/widgets/cards/counts_by_hour.dart      |  4 +-
 lib/ui/widgets/cards/discoveries.dart         |  4 +-
 lib/ui/widgets/cards/heatmap.dart             |  4 +-
 lib/ui/widgets/cards/new_artists.dart         |  2 +-
 lib/ui/widgets/cards/new_tracks.dart          |  2 +-
 lib/ui/widgets/cards/statistics_global.dart   |  2 +-
 lib/ui/widgets/cards/statistics_recent.dart   |  4 +-
 lib/ui/widgets/cards/timeline.dart            |  4 +-
 lib/ui/widgets/cards/top_artists.dart         |  4 +-
 pubspec.lock                                  |  8 +-
 pubspec.yaml                                  |  2 +-
 61 files changed, 573 insertions(+), 151 deletions(-)
 create mode 100644 fastlane/metadata/android/en-US/changelogs/66.txt
 create mode 100644 fastlane/metadata/android/fr-FR/changelogs/66.txt
 rename lib/{ => common}/config/activity_page.dart (76%)
 rename lib/{ => common}/config/screen.dart (67%)
 rename lib/{cubit => common/cubit/nav}/nav_cubit_pages.dart (73%)
 rename lib/{cubit => common/cubit/nav}/nav_cubit_screens.dart (71%)
 rename lib/{ => common}/ui/nav/bottom_nav_bar.dart (66%)
 rename lib/{ => common}/ui/nav/global_app_bar.dart (64%)
 rename lib/{ => common}/ui/pages/discoveries.dart (84%)
 rename lib/{ => common}/ui/pages/home.dart (82%)
 rename lib/{ => common}/ui/pages/statistics.dart (83%)
 rename lib/{ => common}/ui/screens/about.dart (96%)
 rename lib/{ => common}/ui/screens/activity.dart (75%)
 rename lib/{ => common}/ui/screens/settings.dart (88%)
 rename lib/{ => common}/ui/settings/settings_form.dart (99%)
 create mode 100644 lib/config/application_config.dart
 create mode 100644 lib/config/default_activity_settings.dart
 create mode 100644 lib/cubit/activity/activity_cubit.dart
 create mode 100644 lib/cubit/activity/activity_state.dart
 rename lib/cubit/{ => activity}/data_counts_by_day_cubit.dart (96%)
 rename lib/cubit/{ => activity}/data_counts_by_day_state.dart (100%)
 rename lib/cubit/{ => activity}/data_counts_by_hour_cubit.dart (96%)
 rename lib/cubit/{ => activity}/data_counts_by_hour_state.dart (100%)
 rename lib/cubit/{ => activity}/data_discoveries_cubit.dart (96%)
 rename lib/cubit/{ => activity}/data_discoveries_state.dart (100%)
 rename lib/cubit/{ => activity}/data_heatmap_cubit.dart (96%)
 rename lib/cubit/{ => activity}/data_heatmap_state.dart (100%)
 rename lib/cubit/{ => activity}/data_new_artists_cubit.dart (96%)
 rename lib/cubit/{ => activity}/data_new_artists_state.dart (100%)
 rename lib/cubit/{ => activity}/data_new_tracks_cubit.dart (96%)
 rename lib/cubit/{ => activity}/data_new_tracks_state.dart (100%)
 rename lib/cubit/{ => activity}/data_statistics_global_cubit.dart (100%)
 rename lib/cubit/{ => activity}/data_statistics_global_state.dart (100%)
 rename lib/cubit/{ => activity}/data_statistics_recent_cubit.dart (96%)
 rename lib/cubit/{ => activity}/data_statistics_recent_state.dart (100%)
 rename lib/cubit/{ => activity}/data_timeline_cubit.dart (96%)
 rename lib/cubit/{ => activity}/data_timeline_state.dart (100%)
 rename lib/cubit/{ => activity}/data_top_artists_cubit.dart (96%)
 rename lib/cubit/{ => activity}/data_top_artists_state.dart (100%)
 create mode 100644 lib/cubit/settings/settings_activity_cubit.dart
 create mode 100644 lib/cubit/settings/settings_activity_state.dart
 rename lib/cubit/{ => settings}/settings_global_cubit.dart (100%)
 rename lib/cubit/{ => settings}/settings_global_state.dart (100%)
 create mode 100644 lib/models/activity/activity.dart
 create mode 100644 lib/models/settings/settings_activity.dart
 create mode 100644 lib/models/settings/settings_global.dart

diff --git a/fastlane/metadata/android/en-US/changelogs/66.txt b/fastlane/metadata/android/en-US/changelogs/66.txt
new file mode 100644
index 0000000..ac2c90e
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/66.txt
@@ -0,0 +1 @@
+Normalize Activity application architecture.
diff --git a/fastlane/metadata/android/fr-FR/changelogs/66.txt b/fastlane/metadata/android/fr-FR/changelogs/66.txt
new file mode 100644
index 0000000..1d6843d
--- /dev/null
+++ b/fastlane/metadata/android/fr-FR/changelogs/66.txt
@@ -0,0 +1 @@
+Harmonisation des applications en Activity.
diff --git a/lib/config/activity_page.dart b/lib/common/config/activity_page.dart
similarity index 76%
rename from lib/config/activity_page.dart
rename to lib/common/config/activity_page.dart
index b58d295..79141eb 100644
--- a/lib/config/activity_page.dart
+++ b/lib/common/config/activity_page.dart
@@ -1,42 +1,44 @@
 import 'package:flutter/material.dart';
 import 'package:ionicons/ionicons.dart';
 
-import 'package:scrobbles/ui/pages/discoveries.dart';
-import 'package:scrobbles/ui/pages/home.dart';
-import 'package:scrobbles/ui/pages/statistics.dart';
+import 'package:scrobbles/common/ui/pages/discoveries.dart';
+import 'package:scrobbles/common/ui/pages/home.dart';
+import 'package:scrobbles/common/ui/pages/statistics.dart';
 
 class ActivityPageItem {
+  final String code;
   final Icon icon;
   final Widget page;
-  final String code;
 
   const ActivityPageItem({
+    required this.code,
     required this.icon,
     required this.page,
-    required this.code,
   });
 }
 
 class ActivityPage {
+  static const bool displayBottomNavBar = false;
+
   static const indexHome = 0;
   static const pageHome = ActivityPageItem(
+    code: 'page_home',
     icon: Icon(Ionicons.home_outline),
     page: PageHome(),
-    code: 'page_home',
   );
 
   static const indexDiscoveries = 1;
   static const pageDiscoveries = ActivityPageItem(
+    code: 'page_discoveries',
     icon: Icon(Ionicons.star_outline),
     page: PageDiscoveries(),
-    code: 'page_discoveries',
   );
 
   static const indexStatistics = 2;
   static const pageStatistics = ActivityPageItem(
+    code: 'page_statistics',
     icon: Icon(Ionicons.bar_chart_outline),
     page: PageStatistics(),
-    code: 'page_statistics',
   );
 
   static Map<int, ActivityPageItem> items = {
@@ -45,17 +47,13 @@ class ActivityPage {
     indexStatistics: pageStatistics,
   };
 
+  static int defaultPageIndex = indexHome;
+
   static bool isIndexAllowed(int pageIndex) {
     return items.keys.contains(pageIndex);
   }
 
-  static ActivityPageItem getPageItem(int pageIndex) {
-    return items[pageIndex] ?? pageHome;
-  }
-
-  static Widget getPageWidget(int pageIndex) {
+  static Widget getWidget(int pageIndex) {
     return items[pageIndex]?.page ?? pageHome.page;
   }
-
-  static int itemsCount = ActivityPage.items.length;
 }
diff --git a/lib/config/screen.dart b/lib/common/config/screen.dart
similarity index 67%
rename from lib/config/screen.dart
rename to lib/common/config/screen.dart
index da777c0..f73face 100644
--- a/lib/config/screen.dart
+++ b/lib/common/config/screen.dart
@@ -1,42 +1,42 @@
 import 'package:flutter/material.dart';
 import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
 
-import 'package:scrobbles/ui/screens/about.dart';
-import 'package:scrobbles/ui/screens/activity.dart';
-import 'package:scrobbles/ui/screens/settings.dart';
+import 'package:scrobbles/common/ui/screens/about.dart';
+import 'package:scrobbles/common/ui/screens/activity.dart';
+import 'package:scrobbles/common/ui/screens/settings.dart';
 
 class ScreenItem {
+  final String code;
   final Icon icon;
   final Widget screen;
-  final bool displayBottomNavBar;
 
   const ScreenItem({
+    required this.code,
     required this.icon,
     required this.screen,
-    required this.displayBottomNavBar,
   });
 }
 
 class Screen {
   static const indexActivity = 0;
   static const screenActivity = ScreenItem(
+    code: 'screen_activity',
     icon: Icon(UniconsLine.home),
     screen: ScreenActivity(),
-    displayBottomNavBar: true,
   );
 
   static const indexSettings = 1;
   static const screenSettings = ScreenItem(
+    code: 'screen_settings',
     icon: Icon(UniconsLine.setting),
     screen: ScreenSettings(),
-    displayBottomNavBar: false,
   );
 
   static const indexAbout = 2;
   static const screenAbout = ScreenItem(
+    code: 'screen_about',
     icon: Icon(UniconsLine.info_circle),
     screen: ScreenAbout(),
-    displayBottomNavBar: false,
   );
 
   static Map<int, ScreenItem> items = {
@@ -52,10 +52,4 @@ class Screen {
   static Widget getWidget(int screenIndex) {
     return items[screenIndex]?.screen ?? screenActivity.screen;
   }
-
-  static bool displayBottomNavBar(int screenIndex) {
-    return items[screenIndex]?.displayBottomNavBar ?? screenActivity.displayBottomNavBar;
-  }
-
-  static int itemsCount = Screen.items.length;
 }
diff --git a/lib/cubit/nav_cubit_pages.dart b/lib/common/cubit/nav/nav_cubit_pages.dart
similarity index 73%
rename from lib/cubit/nav_cubit_pages.dart
rename to lib/common/cubit/nav/nav_cubit_pages.dart
index 10d729d..9ad7c65 100644
--- a/lib/cubit/nav_cubit_pages.dart
+++ b/lib/common/cubit/nav/nav_cubit_pages.dart
@@ -1,6 +1,6 @@
 import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
 
-import 'package:scrobbles/config/activity_page.dart';
+import 'package:scrobbles/common/config/activity_page.dart';
 
 class NavCubitPage extends HydratedCubit<int> {
   NavCubitPage() : super(0);
@@ -13,8 +13,8 @@ class NavCubitPage extends HydratedCubit<int> {
     }
   }
 
-  void goToHomePage() {
-    emit(ActivityPage.indexHome);
+  void goToPageHome() {
+    updateIndex(ActivityPage.indexHome);
   }
 
   @override
@@ -24,6 +24,6 @@ class NavCubitPage extends HydratedCubit<int> {
 
   @override
   Map<String, dynamic>? toJson(int state) {
-    return <String, int>{'pageIndex': state};
+    return <String, int>{'index': state};
   }
 }
diff --git a/lib/cubit/nav_cubit_screens.dart b/lib/common/cubit/nav/nav_cubit_screens.dart
similarity index 71%
rename from lib/cubit/nav_cubit_screens.dart
rename to lib/common/cubit/nav/nav_cubit_screens.dart
index 4376701..77f3b61 100644
--- a/lib/cubit/nav_cubit_screens.dart
+++ b/lib/common/cubit/nav/nav_cubit_screens.dart
@@ -1,6 +1,6 @@
 import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
 
-import 'package:scrobbles/config/screen.dart';
+import 'package:scrobbles/common/config/screen.dart';
 
 class NavCubitScreen extends HydratedCubit<int> {
   NavCubitScreen() : super(0);
@@ -9,19 +9,19 @@ class NavCubitScreen extends HydratedCubit<int> {
     if (Screen.isIndexAllowed(index)) {
       emit(index);
     } else {
-      goToActivityPage();
+      goToScreenActivity();
     }
   }
 
-  void goToActivityPage() {
+  void goToScreenActivity() {
     emit(Screen.indexActivity);
   }
 
-  void goToSettingsPage() {
+  void goToScreenSettings() {
     emit(Screen.indexSettings);
   }
 
-  void goToAboutPage() {
+  void goToScreenAbout() {
     emit(Screen.indexAbout);
   }
 
@@ -32,6 +32,6 @@ class NavCubitScreen extends HydratedCubit<int> {
 
   @override
   Map<String, dynamic>? toJson(int state) {
-    return <String, int>{'screenIndex': state};
+    return <String, int>{'index': state};
   }
 }
diff --git a/lib/ui/nav/bottom_nav_bar.dart b/lib/common/ui/nav/bottom_nav_bar.dart
similarity index 66%
rename from lib/ui/nav/bottom_nav_bar.dart
rename to lib/common/ui/nav/bottom_nav_bar.dart
index f6d4739..9449caf 100644
--- a/lib/ui/nav/bottom_nav_bar.dart
+++ b/lib/common/ui/nav/bottom_nav_bar.dart
@@ -2,13 +2,16 @@ import 'package:flutter/material.dart';
 import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
 import 'package:flutter_swipe/flutter_swipe.dart';
 
-import 'package:scrobbles/config/activity_page.dart';
-import 'package:scrobbles/cubit/nav_cubit_pages.dart';
+import 'package:scrobbles/common/config/activity_page.dart';
+import 'package:scrobbles/common/cubit/nav/nav_cubit_pages.dart';
 
 class BottomNavBar extends StatelessWidget {
-  const BottomNavBar({super.key, required this.swipeController});
+  const BottomNavBar({
+    super.key,
+    this.swipeController,
+  });
 
-  final SwiperController swipeController;
+  final SwiperController? swipeController;
 
   @override
   Widget build(BuildContext context) {
@@ -20,23 +23,20 @@ class BottomNavBar extends StatelessWidget {
       shape: const ContinuousRectangleBorder(),
       child: BlocBuilder<NavCubitPage, int>(
         builder: (BuildContext context, int pageIndex) {
-          final List<ActivityPageItem> pageItems = [
-            ActivityPage.pageHome,
-            ActivityPage.pageDiscoveries,
-            ActivityPage.pageStatistics,
-          ];
-          final List<BottomNavigationBarItem> items = pageItems.map((ActivityPageItem item) {
-            return BottomNavigationBarItem(
+          final List<BottomNavigationBarItem> items = [];
+
+          ActivityPage.items.forEach((int pageIndex, ActivityPageItem item) {
+            items.add(BottomNavigationBarItem(
               icon: item.icon,
               label: tr(item.code),
-            );
-          }).toList();
+            ));
+          });
 
           return BottomNavigationBar(
             currentIndex: pageIndex,
             onTap: (int index) {
               BlocProvider.of<NavCubitPage>(context).updateIndex(index);
-              swipeController.move(index);
+              swipeController?.move(index);
             },
             type: BottomNavigationBarType.fixed,
             elevation: 0,
diff --git a/lib/ui/nav/global_app_bar.dart b/lib/common/ui/nav/global_app_bar.dart
similarity index 64%
rename from lib/ui/nav/global_app_bar.dart
rename to lib/common/ui/nav/global_app_bar.dart
index 542643f..9fc602b 100644
--- a/lib/ui/nav/global_app_bar.dart
+++ b/lib/common/ui/nav/global_app_bar.dart
@@ -1,19 +1,20 @@
 import 'package:flutter/material.dart';
 import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
 
-import 'package:scrobbles/cubit/data_counts_by_day_cubit.dart';
-import 'package:scrobbles/cubit/data_counts_by_hour_cubit.dart';
-import 'package:scrobbles/cubit/data_discoveries_cubit.dart';
-import 'package:scrobbles/cubit/data_heatmap_cubit.dart';
-import 'package:scrobbles/cubit/data_new_artists_cubit.dart';
-import 'package:scrobbles/cubit/data_new_tracks_cubit.dart';
-import 'package:scrobbles/cubit/data_statistics_global_cubit.dart';
-import 'package:scrobbles/cubit/data_statistics_recent_cubit.dart';
-import 'package:scrobbles/cubit/data_timeline_cubit.dart';
-import 'package:scrobbles/cubit/data_top_artists_cubit.dart';
-import 'package:scrobbles/cubit/nav_cubit_pages.dart';
-import 'package:scrobbles/config/screen.dart';
-import 'package:scrobbles/cubit/nav_cubit_screens.dart';
+import 'package:scrobbles/common/config/screen.dart';
+import 'package:scrobbles/common/cubit/nav/nav_cubit_pages.dart';
+import 'package:scrobbles/common/cubit/nav/nav_cubit_screens.dart';
+
+import 'package:scrobbles/cubit/activity/data_counts_by_day_cubit.dart';
+import 'package:scrobbles/cubit/activity/data_counts_by_hour_cubit.dart';
+import 'package:scrobbles/cubit/activity/data_discoveries_cubit.dart';
+import 'package:scrobbles/cubit/activity/data_heatmap_cubit.dart';
+import 'package:scrobbles/cubit/activity/data_new_artists_cubit.dart';
+import 'package:scrobbles/cubit/activity/data_new_tracks_cubit.dart';
+import 'package:scrobbles/cubit/activity/data_statistics_global_cubit.dart';
+import 'package:scrobbles/cubit/activity/data_statistics_recent_cubit.dart';
+import 'package:scrobbles/cubit/activity/data_timeline_cubit.dart';
+import 'package:scrobbles/cubit/activity/data_top_artists_cubit.dart';
 
 class GlobalAppBar extends StatelessWidget implements PreferredSizeWidget {
   const GlobalAppBar({super.key});
@@ -28,7 +29,7 @@ class GlobalAppBar extends StatelessWidget implements PreferredSizeWidget {
           // go to Settings page
           menuActions.add(IconButton(
             onPressed: () {
-              BlocProvider.of<NavCubitScreen>(context).goToSettingsPage();
+              BlocProvider.of<NavCubitScreen>(context).goToScreenSettings();
             },
             icon: Screen.screenSettings.icon,
           ));
@@ -36,7 +37,7 @@ class GlobalAppBar extends StatelessWidget implements PreferredSizeWidget {
           // go to About page
           menuActions.add(IconButton(
             onPressed: () {
-              BlocProvider.of<NavCubitScreen>(context).goToAboutPage();
+              BlocProvider.of<NavCubitScreen>(context).goToScreenAbout();
             },
             icon: Screen.screenAbout.icon,
           ));
@@ -61,8 +62,8 @@ class GlobalAppBar extends StatelessWidget implements PreferredSizeWidget {
           // back to Home page
           menuActions.add(IconButton(
             onPressed: () {
-              BlocProvider.of<NavCubitScreen>(context).goToActivityPage();
-              BlocProvider.of<NavCubitPage>(context).goToHomePage();
+              BlocProvider.of<NavCubitScreen>(context).goToScreenActivity();
+              BlocProvider.of<NavCubitPage>(context).goToPageHome();
             },
             icon: Screen.screenActivity.icon,
           ));
diff --git a/lib/ui/pages/discoveries.dart b/lib/common/ui/pages/discoveries.dart
similarity index 84%
rename from lib/ui/pages/discoveries.dart
rename to lib/common/ui/pages/discoveries.dart
index 1df3ff9..a4cc4c7 100644
--- a/lib/ui/pages/discoveries.dart
+++ b/lib/common/ui/pages/discoveries.dart
@@ -1,9 +1,9 @@
 import 'package:flutter/material.dart';
 import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
 
-import 'package:scrobbles/cubit/data_discoveries_cubit.dart';
-import 'package:scrobbles/cubit/data_new_artists_cubit.dart';
-import 'package:scrobbles/cubit/data_new_tracks_cubit.dart';
+import 'package:scrobbles/cubit/activity/data_discoveries_cubit.dart';
+import 'package:scrobbles/cubit/activity/data_new_artists_cubit.dart';
+import 'package:scrobbles/cubit/activity/data_new_tracks_cubit.dart';
 import 'package:scrobbles/ui/widgets/cards/discoveries.dart';
 import 'package:scrobbles/ui/widgets/cards/new_artists.dart';
 import 'package:scrobbles/ui/widgets/cards/new_tracks.dart';
diff --git a/lib/ui/pages/home.dart b/lib/common/ui/pages/home.dart
similarity index 82%
rename from lib/ui/pages/home.dart
rename to lib/common/ui/pages/home.dart
index c28f4a0..dce7eeb 100644
--- a/lib/ui/pages/home.dart
+++ b/lib/common/ui/pages/home.dart
@@ -1,10 +1,10 @@
 import 'package:flutter/material.dart';
 import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
 
-import 'package:scrobbles/cubit/data_statistics_global_cubit.dart';
-import 'package:scrobbles/cubit/data_statistics_recent_cubit.dart';
-import 'package:scrobbles/cubit/data_timeline_cubit.dart';
-import 'package:scrobbles/cubit/data_top_artists_cubit.dart';
+import 'package:scrobbles/cubit/activity/data_statistics_global_cubit.dart';
+import 'package:scrobbles/cubit/activity/data_statistics_recent_cubit.dart';
+import 'package:scrobbles/cubit/activity/data_timeline_cubit.dart';
+import 'package:scrobbles/cubit/activity/data_top_artists_cubit.dart';
 import 'package:scrobbles/ui/widgets/cards/statistics_global.dart';
 import 'package:scrobbles/ui/widgets/cards/statistics_recent.dart';
 import 'package:scrobbles/ui/widgets/cards/timeline.dart';
diff --git a/lib/ui/pages/statistics.dart b/lib/common/ui/pages/statistics.dart
similarity index 83%
rename from lib/ui/pages/statistics.dart
rename to lib/common/ui/pages/statistics.dart
index f96aba4..9c07d8f 100644
--- a/lib/ui/pages/statistics.dart
+++ b/lib/common/ui/pages/statistics.dart
@@ -1,9 +1,9 @@
 import 'package:flutter/material.dart';
 import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
 
-import 'package:scrobbles/cubit/data_counts_by_day_cubit.dart';
-import 'package:scrobbles/cubit/data_counts_by_hour_cubit.dart';
-import 'package:scrobbles/cubit/data_heatmap_cubit.dart';
+import 'package:scrobbles/cubit/activity/data_counts_by_day_cubit.dart';
+import 'package:scrobbles/cubit/activity/data_counts_by_hour_cubit.dart';
+import 'package:scrobbles/cubit/activity/data_heatmap_cubit.dart';
 import 'package:scrobbles/ui/widgets/cards/counts_by_day.dart';
 import 'package:scrobbles/ui/widgets/cards/counts_by_hour.dart';
 import 'package:scrobbles/ui/widgets/cards/heatmap.dart';
diff --git a/lib/ui/screens/about.dart b/lib/common/ui/screens/about.dart
similarity index 96%
rename from lib/ui/screens/about.dart
rename to lib/common/ui/screens/about.dart
index 85c38c3..f7a14a9 100644
--- a/lib/ui/screens/about.dart
+++ b/lib/common/ui/screens/about.dart
@@ -14,7 +14,7 @@ class ScreenAbout extends StatelessWidget {
         mainAxisSize: MainAxisSize.max,
         children: <Widget>[
           const SizedBox(height: 8),
-          AppTitle(text: tr('about_title')),
+          const AppTitle(text: 'about_title'),
           const Text('about_content').tr(),
           FutureBuilder<PackageInfo>(
             future: PackageInfo.fromPlatform(),
diff --git a/lib/ui/screens/activity.dart b/lib/common/ui/screens/activity.dart
similarity index 75%
rename from lib/ui/screens/activity.dart
rename to lib/common/ui/screens/activity.dart
index c8db336..7eeb5fa 100644
--- a/lib/ui/screens/activity.dart
+++ b/lib/common/ui/screens/activity.dart
@@ -2,10 +2,10 @@ import 'package:flutter/material.dart';
 import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
 import 'package:flutter_swipe/flutter_swipe.dart';
 
-import 'package:scrobbles/config/activity_page.dart';
-import 'package:scrobbles/config/screen.dart';
-import 'package:scrobbles/cubit/nav_cubit_pages.dart';
-import 'package:scrobbles/ui/nav/bottom_nav_bar.dart';
+import 'package:scrobbles/common/config/activity_page.dart';
+import 'package:scrobbles/common/config/screen.dart';
+import 'package:scrobbles/common/cubit/nav/nav_cubit_pages.dart';
+import 'package:scrobbles/common/ui/nav/bottom_nav_bar.dart';
 
 class ScreenActivity extends StatelessWidget {
   const ScreenActivity({super.key});
@@ -15,9 +15,9 @@ class ScreenActivity extends StatelessWidget {
     return BlocBuilder<NavCubitPage, int>(
       builder: (BuildContext context, int pageIndex) {
         return Swiper(
-          itemCount: Screen.itemsCount,
+          itemCount: Screen.items.length,
           itemBuilder: (BuildContext context, int pageIndex) {
-            return ActivityPage.getPageWidget(pageIndex);
+            return ActivityPage.getWidget(pageIndex);
           },
           pagination: SwiperPagination(
             margin: const EdgeInsets.all(0),
diff --git a/lib/ui/screens/settings.dart b/lib/common/ui/screens/settings.dart
similarity index 88%
rename from lib/ui/screens/settings.dart
rename to lib/common/ui/screens/settings.dart
index 678e290..bd02cde 100644
--- a/lib/ui/screens/settings.dart
+++ b/lib/common/ui/screens/settings.dart
@@ -1,7 +1,7 @@
 import 'package:flutter/material.dart';
 import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
 
-import 'package:scrobbles/ui/settings/settings_form.dart';
+import 'package:scrobbles/common/ui/settings/settings_form.dart';
 
 class ScreenSettings extends StatelessWidget {
   const ScreenSettings({super.key});
diff --git a/lib/ui/settings/settings_form.dart b/lib/common/ui/settings/settings_form.dart
similarity index 99%
rename from lib/ui/settings/settings_form.dart
rename to lib/common/ui/settings/settings_form.dart
index 97372a0..40dca8d 100644
--- a/lib/ui/settings/settings_form.dart
+++ b/lib/common/ui/settings/settings_form.dart
@@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
 import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
 
 import 'package:scrobbles/config/default_global_settings.dart';
-import 'package:scrobbles/cubit/settings_global_cubit.dart';
+import 'package:scrobbles/cubit/settings/settings_global_cubit.dart';
 
 class SettingsForm extends StatefulWidget {
   const SettingsForm({super.key});
diff --git a/lib/config/application_config.dart b/lib/config/application_config.dart
new file mode 100644
index 0000000..68335d6
--- /dev/null
+++ b/lib/config/application_config.dart
@@ -0,0 +1,3 @@
+class ApplicationConfig {
+  static const String appTitle = 'Scrobbles';
+}
diff --git a/lib/config/default_activity_settings.dart b/lib/config/default_activity_settings.dart
new file mode 100644
index 0000000..1f33c90
--- /dev/null
+++ b/lib/config/default_activity_settings.dart
@@ -0,0 +1,28 @@
+import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
+
+class DefaultActivitySettings {
+  // available game parameters codes
+  static const String parameterCodeDashboardType = 'dashboardType';
+  static const List<String> availableParameters = [
+    parameterCodeDashboardType,
+  ];
+
+  // dashboard type: available values
+  static const String dashboardTypeDefault = 'default';
+  static const List<String> allowedDashboardTypeValues = [
+    dashboardTypeDefault,
+  ];
+  // dashboard type: default value
+  static const String defaultDashboardTypeValue = dashboardTypeDefault;
+
+  // available values from parameter code
+  static List<String> getAvailableValues(String parameterCode) {
+    switch (parameterCode) {
+      case parameterCodeDashboardType:
+        return DefaultActivitySettings.allowedDashboardTypeValues;
+    }
+
+    printlog('Did not find any available value for game parameter "$parameterCode".');
+    return [];
+  }
+}
diff --git a/lib/config/default_global_settings.dart b/lib/config/default_global_settings.dart
index 0565d15..f64cb1f 100644
--- a/lib/config/default_global_settings.dart
+++ b/lib/config/default_global_settings.dart
@@ -1,4 +1,32 @@
+import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
+
 class DefaultGlobalSettings {
+  // available global parameters codes
+  static const String parameterCodeSkin = 'skin';
+  static const List<String> availableParameters = [
+    parameterCodeSkin,
+  ];
+
+  // skin: available values
+  static const String skinValueDefault = 'default';
+  static const List<String> allowedSkinValues = [
+    skinValueDefault,
+  ];
+  // skin: default value
+  static const String defaultSkinValue = skinValueDefault;
+
+  // available values from parameter code
+  static List<String> getAvailableValues(String parameterCode) {
+    switch (parameterCode) {
+      case parameterCodeSkin:
+        return DefaultGlobalSettings.allowedSkinValues;
+    }
+
+    printlog('Did not find any available value for global parameter "$parameterCode".');
+    return [];
+  }
+
+  @Deprecated("Should be removed / normalized")
   static const List<int> allowedDaysCountValues = [
     7,
     14,
@@ -7,17 +35,26 @@ class DefaultGlobalSettings {
     60,
     90,
   ];
+
+  @Deprecated("Should be removed / normalized")
   static const List<int> allowedCountValues = [
     5,
     10,
     20,
   ];
 
+  @Deprecated("Should be removed / normalized")
   static const int defaultDiscoveriesDaysCount = 14;
+  @Deprecated("Should be removed / normalized")
   static const int defaultDistributionDaysCount = 21;
+  @Deprecated("Should be removed / normalized")
   static const int defaultStatisticsRecentDaysCount = 21;
+  @Deprecated("Should be removed / normalized")
   static const int defaultTimelineDaysCount = 14;
+  @Deprecated("Should be removed / normalized")
   static const int defaultTopArtistsDaysCount = 14;
+  @Deprecated("Should be removed / normalized")
   static const int defaultNewArtistsCount = 5;
+  @Deprecated("Should be removed / normalized")
   static const int defaultNewTracksCount = 5;
 }
diff --git a/lib/cubit/activity/activity_cubit.dart b/lib/cubit/activity/activity_cubit.dart
new file mode 100644
index 0000000..7a0b36c
--- /dev/null
+++ b/lib/cubit/activity/activity_cubit.dart
@@ -0,0 +1,65 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
+
+import 'package:scrobbles/models/activity/activity.dart';
+import 'package:scrobbles/models/settings/settings_activity.dart';
+import 'package:scrobbles/models/settings/settings_global.dart';
+
+part 'activity_state.dart';
+
+class ActivityCubit extends HydratedCubit<ActivityState> {
+  ActivityCubit()
+      : super(ActivityState(
+          currentActivity: Activity.createNull(),
+        ));
+
+  void updateState(Activity activity) {
+    emit(ActivityState(
+      currentActivity: activity,
+    ));
+  }
+
+  void refresh() {
+    final Activity activity = Activity(
+      // Settings
+      activitySettings: state.currentActivity.activitySettings,
+      globalSettings: state.currentActivity.globalSettings,
+      // State
+      isRunning: state.currentActivity.isRunning,
+    );
+
+    updateState(activity);
+  }
+
+  void startNewActivity({
+    required ActivitySettings activitySettings,
+    required GlobalSettings globalSettings,
+  }) {
+    final Activity newActivity = Activity.createNew(
+      // Settings
+      activitySettings: activitySettings,
+      globalSettings: globalSettings,
+    );
+
+    newActivity.dump();
+
+    updateState(newActivity);
+    refresh();
+  }
+
+  @override
+  ActivityState? fromJson(Map<String, dynamic> json) {
+    final Activity currentActivity = json['currentActivity'] as Activity;
+
+    return ActivityState(
+      currentActivity: currentActivity,
+    );
+  }
+
+  @override
+  Map<String, dynamic>? toJson(ActivityState state) {
+    return <String, dynamic>{
+      'currentActivity': state.currentActivity.toJson(),
+    };
+  }
+}
diff --git a/lib/cubit/activity/activity_state.dart b/lib/cubit/activity/activity_state.dart
new file mode 100644
index 0000000..887b45e
--- /dev/null
+++ b/lib/cubit/activity/activity_state.dart
@@ -0,0 +1,15 @@
+part of 'activity_cubit.dart';
+
+@immutable
+class ActivityState extends Equatable {
+  const ActivityState({
+    required this.currentActivity,
+  });
+
+  final Activity currentActivity;
+
+  @override
+  List<dynamic> get props => <dynamic>[
+        currentActivity,
+      ];
+}
diff --git a/lib/cubit/data_counts_by_day_cubit.dart b/lib/cubit/activity/data_counts_by_day_cubit.dart
similarity index 96%
rename from lib/cubit/data_counts_by_day_cubit.dart
rename to lib/cubit/activity/data_counts_by_day_cubit.dart
index a676e4b..59c7482 100644
--- a/lib/cubit/data_counts_by_day_cubit.dart
+++ b/lib/cubit/activity/data_counts_by_day_cubit.dart
@@ -1,7 +1,7 @@
 import 'package:flutter/material.dart';
 import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
 
-import 'package:scrobbles/cubit/settings_global_cubit.dart';
+import 'package:scrobbles/cubit/settings/settings_global_cubit.dart';
 import 'package:scrobbles/models/data/counts_by_day.dart';
 import 'package:scrobbles/network/scrobbles.dart';
 
diff --git a/lib/cubit/data_counts_by_day_state.dart b/lib/cubit/activity/data_counts_by_day_state.dart
similarity index 100%
rename from lib/cubit/data_counts_by_day_state.dart
rename to lib/cubit/activity/data_counts_by_day_state.dart
diff --git a/lib/cubit/data_counts_by_hour_cubit.dart b/lib/cubit/activity/data_counts_by_hour_cubit.dart
similarity index 96%
rename from lib/cubit/data_counts_by_hour_cubit.dart
rename to lib/cubit/activity/data_counts_by_hour_cubit.dart
index 7d81782..6d07f45 100644
--- a/lib/cubit/data_counts_by_hour_cubit.dart
+++ b/lib/cubit/activity/data_counts_by_hour_cubit.dart
@@ -1,7 +1,7 @@
 import 'package:flutter/material.dart';
 import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
 
-import 'package:scrobbles/cubit/settings_global_cubit.dart';
+import 'package:scrobbles/cubit/settings/settings_global_cubit.dart';
 import 'package:scrobbles/models/data/counts_by_hour.dart';
 import 'package:scrobbles/network/scrobbles.dart';
 
diff --git a/lib/cubit/data_counts_by_hour_state.dart b/lib/cubit/activity/data_counts_by_hour_state.dart
similarity index 100%
rename from lib/cubit/data_counts_by_hour_state.dart
rename to lib/cubit/activity/data_counts_by_hour_state.dart
diff --git a/lib/cubit/data_discoveries_cubit.dart b/lib/cubit/activity/data_discoveries_cubit.dart
similarity index 96%
rename from lib/cubit/data_discoveries_cubit.dart
rename to lib/cubit/activity/data_discoveries_cubit.dart
index 561f32d..4ea5c57 100644
--- a/lib/cubit/data_discoveries_cubit.dart
+++ b/lib/cubit/activity/data_discoveries_cubit.dart
@@ -1,7 +1,7 @@
 import 'package:flutter/material.dart';
 import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
 
-import 'package:scrobbles/cubit/settings_global_cubit.dart';
+import 'package:scrobbles/cubit/settings/settings_global_cubit.dart';
 import 'package:scrobbles/models/data/discoveries.dart';
 import 'package:scrobbles/network/scrobbles.dart';
 
diff --git a/lib/cubit/data_discoveries_state.dart b/lib/cubit/activity/data_discoveries_state.dart
similarity index 100%
rename from lib/cubit/data_discoveries_state.dart
rename to lib/cubit/activity/data_discoveries_state.dart
diff --git a/lib/cubit/data_heatmap_cubit.dart b/lib/cubit/activity/data_heatmap_cubit.dart
similarity index 96%
rename from lib/cubit/data_heatmap_cubit.dart
rename to lib/cubit/activity/data_heatmap_cubit.dart
index 3fe1d99..3d386c3 100644
--- a/lib/cubit/data_heatmap_cubit.dart
+++ b/lib/cubit/activity/data_heatmap_cubit.dart
@@ -1,7 +1,7 @@
 import 'package:flutter/material.dart';
 import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
 
-import 'package:scrobbles/cubit/settings_global_cubit.dart';
+import 'package:scrobbles/cubit/settings/settings_global_cubit.dart';
 import 'package:scrobbles/models/data/heatmap.dart';
 import 'package:scrobbles/network/scrobbles.dart';
 
diff --git a/lib/cubit/data_heatmap_state.dart b/lib/cubit/activity/data_heatmap_state.dart
similarity index 100%
rename from lib/cubit/data_heatmap_state.dart
rename to lib/cubit/activity/data_heatmap_state.dart
diff --git a/lib/cubit/data_new_artists_cubit.dart b/lib/cubit/activity/data_new_artists_cubit.dart
similarity index 96%
rename from lib/cubit/data_new_artists_cubit.dart
rename to lib/cubit/activity/data_new_artists_cubit.dart
index c01f2f7..c5ae1c9 100644
--- a/lib/cubit/data_new_artists_cubit.dart
+++ b/lib/cubit/activity/data_new_artists_cubit.dart
@@ -1,7 +1,7 @@
 import 'package:flutter/material.dart';
 import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
 
-import 'package:scrobbles/cubit/settings_global_cubit.dart';
+import 'package:scrobbles/cubit/settings/settings_global_cubit.dart';
 import 'package:scrobbles/models/data/new_artists.dart';
 import 'package:scrobbles/network/scrobbles.dart';
 
diff --git a/lib/cubit/data_new_artists_state.dart b/lib/cubit/activity/data_new_artists_state.dart
similarity index 100%
rename from lib/cubit/data_new_artists_state.dart
rename to lib/cubit/activity/data_new_artists_state.dart
diff --git a/lib/cubit/data_new_tracks_cubit.dart b/lib/cubit/activity/data_new_tracks_cubit.dart
similarity index 96%
rename from lib/cubit/data_new_tracks_cubit.dart
rename to lib/cubit/activity/data_new_tracks_cubit.dart
index f786af4..849ae75 100644
--- a/lib/cubit/data_new_tracks_cubit.dart
+++ b/lib/cubit/activity/data_new_tracks_cubit.dart
@@ -1,7 +1,7 @@
 import 'package:flutter/material.dart';
 import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
 
-import 'package:scrobbles/cubit/settings_global_cubit.dart';
+import 'package:scrobbles/cubit/settings/settings_global_cubit.dart';
 import 'package:scrobbles/models/data/new_tracks.dart';
 import 'package:scrobbles/network/scrobbles.dart';
 
diff --git a/lib/cubit/data_new_tracks_state.dart b/lib/cubit/activity/data_new_tracks_state.dart
similarity index 100%
rename from lib/cubit/data_new_tracks_state.dart
rename to lib/cubit/activity/data_new_tracks_state.dart
diff --git a/lib/cubit/data_statistics_global_cubit.dart b/lib/cubit/activity/data_statistics_global_cubit.dart
similarity index 100%
rename from lib/cubit/data_statistics_global_cubit.dart
rename to lib/cubit/activity/data_statistics_global_cubit.dart
diff --git a/lib/cubit/data_statistics_global_state.dart b/lib/cubit/activity/data_statistics_global_state.dart
similarity index 100%
rename from lib/cubit/data_statistics_global_state.dart
rename to lib/cubit/activity/data_statistics_global_state.dart
diff --git a/lib/cubit/data_statistics_recent_cubit.dart b/lib/cubit/activity/data_statistics_recent_cubit.dart
similarity index 96%
rename from lib/cubit/data_statistics_recent_cubit.dart
rename to lib/cubit/activity/data_statistics_recent_cubit.dart
index 86a5def..0b19c0a 100644
--- a/lib/cubit/data_statistics_recent_cubit.dart
+++ b/lib/cubit/activity/data_statistics_recent_cubit.dart
@@ -1,7 +1,7 @@
 import 'package:flutter/material.dart';
 import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
 
-import 'package:scrobbles/cubit/settings_global_cubit.dart';
+import 'package:scrobbles/cubit/settings/settings_global_cubit.dart';
 import 'package:scrobbles/models/data/statistics_recent.dart';
 import 'package:scrobbles/network/scrobbles.dart';
 
diff --git a/lib/cubit/data_statistics_recent_state.dart b/lib/cubit/activity/data_statistics_recent_state.dart
similarity index 100%
rename from lib/cubit/data_statistics_recent_state.dart
rename to lib/cubit/activity/data_statistics_recent_state.dart
diff --git a/lib/cubit/data_timeline_cubit.dart b/lib/cubit/activity/data_timeline_cubit.dart
similarity index 96%
rename from lib/cubit/data_timeline_cubit.dart
rename to lib/cubit/activity/data_timeline_cubit.dart
index 45a1bbb..7242401 100644
--- a/lib/cubit/data_timeline_cubit.dart
+++ b/lib/cubit/activity/data_timeline_cubit.dart
@@ -1,7 +1,7 @@
 import 'package:flutter/material.dart';
 import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
 
-import 'package:scrobbles/cubit/settings_global_cubit.dart';
+import 'package:scrobbles/cubit/settings/settings_global_cubit.dart';
 import 'package:scrobbles/models/data/timeline.dart';
 import 'package:scrobbles/network/scrobbles.dart';
 
diff --git a/lib/cubit/data_timeline_state.dart b/lib/cubit/activity/data_timeline_state.dart
similarity index 100%
rename from lib/cubit/data_timeline_state.dart
rename to lib/cubit/activity/data_timeline_state.dart
diff --git a/lib/cubit/data_top_artists_cubit.dart b/lib/cubit/activity/data_top_artists_cubit.dart
similarity index 96%
rename from lib/cubit/data_top_artists_cubit.dart
rename to lib/cubit/activity/data_top_artists_cubit.dart
index b67fade..4692b8c 100644
--- a/lib/cubit/data_top_artists_cubit.dart
+++ b/lib/cubit/activity/data_top_artists_cubit.dart
@@ -1,7 +1,7 @@
 import 'package:flutter/material.dart';
 import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
 
-import 'package:scrobbles/cubit/settings_global_cubit.dart';
+import 'package:scrobbles/cubit/settings/settings_global_cubit.dart';
 import 'package:scrobbles/models/data/topartists.dart';
 import 'package:scrobbles/network/scrobbles.dart';
 
diff --git a/lib/cubit/data_top_artists_state.dart b/lib/cubit/activity/data_top_artists_state.dart
similarity index 100%
rename from lib/cubit/data_top_artists_state.dart
rename to lib/cubit/activity/data_top_artists_state.dart
diff --git a/lib/cubit/settings/settings_activity_cubit.dart b/lib/cubit/settings/settings_activity_cubit.dart
new file mode 100644
index 0000000..e536492
--- /dev/null
+++ b/lib/cubit/settings/settings_activity_cubit.dart
@@ -0,0 +1,62 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
+
+import 'package:scrobbles/config/default_activity_settings.dart';
+import 'package:scrobbles/models/settings/settings_activity.dart';
+
+part 'settings_activity_state.dart';
+
+class ActivitySettingsCubit extends HydratedCubit<ActivitySettingsState> {
+  ActivitySettingsCubit()
+      : super(ActivitySettingsState(settings: ActivitySettings.createDefault()));
+
+  void setValues({
+    String? dashboardType,
+  }) {
+    emit(
+      ActivitySettingsState(
+        settings: ActivitySettings(
+          dashboardType: dashboardType ?? state.settings.dashboardType,
+        ),
+      ),
+    );
+  }
+
+  String getParameterValue(String code) {
+    switch (code) {
+      case DefaultActivitySettings.parameterCodeDashboardType:
+        return ActivitySettings.getDashboardTypeValueFromUnsafe(state.settings.dashboardType);
+    }
+
+    return '';
+  }
+
+  void setParameterValue(String code, String value) {
+    final String dashboardType = code == DefaultActivitySettings.parameterCodeDashboardType
+        ? value
+        : getParameterValue(DefaultActivitySettings.parameterCodeDashboardType);
+
+    setValues(
+      dashboardType: dashboardType,
+    );
+  }
+
+  @override
+  ActivitySettingsState? fromJson(Map<String, dynamic> json) {
+    final String dashboardType =
+        json[DefaultActivitySettings.parameterCodeDashboardType] as String;
+
+    return ActivitySettingsState(
+      settings: ActivitySettings(
+        dashboardType: dashboardType,
+      ),
+    );
+  }
+
+  @override
+  Map<String, dynamic>? toJson(ActivitySettingsState state) {
+    return <String, dynamic>{
+      DefaultActivitySettings.parameterCodeDashboardType: state.settings.dashboardType,
+    };
+  }
+}
diff --git a/lib/cubit/settings/settings_activity_state.dart b/lib/cubit/settings/settings_activity_state.dart
new file mode 100644
index 0000000..2b2de42
--- /dev/null
+++ b/lib/cubit/settings/settings_activity_state.dart
@@ -0,0 +1,15 @@
+part of 'settings_activity_cubit.dart';
+
+@immutable
+class ActivitySettingsState extends Equatable {
+  const ActivitySettingsState({
+    required this.settings,
+  });
+
+  final ActivitySettings settings;
+
+  @override
+  List<dynamic> get props => <dynamic>[
+        settings,
+      ];
+}
diff --git a/lib/cubit/settings_global_cubit.dart b/lib/cubit/settings/settings_global_cubit.dart
similarity index 100%
rename from lib/cubit/settings_global_cubit.dart
rename to lib/cubit/settings/settings_global_cubit.dart
diff --git a/lib/cubit/settings_global_state.dart b/lib/cubit/settings/settings_global_state.dart
similarity index 100%
rename from lib/cubit/settings_global_state.dart
rename to lib/cubit/settings/settings_global_state.dart
diff --git a/lib/main.dart b/lib/main.dart
index 3dbb8d6..02ce7f1 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -4,19 +4,23 @@ import 'package:flutter/material.dart';
 import 'package:flutter/services.dart';
 import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
 
-import 'package:scrobbles/cubit/nav_cubit_pages.dart';
-import 'package:scrobbles/cubit/nav_cubit_screens.dart';
-import 'package:scrobbles/cubit/data_counts_by_day_cubit.dart';
-import 'package:scrobbles/cubit/data_counts_by_hour_cubit.dart';
-import 'package:scrobbles/cubit/data_discoveries_cubit.dart';
-import 'package:scrobbles/cubit/data_heatmap_cubit.dart';
-import 'package:scrobbles/cubit/data_new_artists_cubit.dart';
-import 'package:scrobbles/cubit/data_new_tracks_cubit.dart';
-import 'package:scrobbles/cubit/data_statistics_global_cubit.dart';
-import 'package:scrobbles/cubit/data_statistics_recent_cubit.dart';
-import 'package:scrobbles/cubit/data_timeline_cubit.dart';
-import 'package:scrobbles/cubit/data_top_artists_cubit.dart';
-import 'package:scrobbles/cubit/settings_global_cubit.dart';
+import 'package:scrobbles/common/cubit/nav/nav_cubit_pages.dart';
+import 'package:scrobbles/common/cubit/nav/nav_cubit_screens.dart';
+
+import 'package:scrobbles/config/application_config.dart';
+import 'package:scrobbles/cubit/activity/activity_cubit.dart';
+import 'package:scrobbles/cubit/activity/data_counts_by_day_cubit.dart';
+import 'package:scrobbles/cubit/activity/data_counts_by_hour_cubit.dart';
+import 'package:scrobbles/cubit/activity/data_discoveries_cubit.dart';
+import 'package:scrobbles/cubit/activity/data_heatmap_cubit.dart';
+import 'package:scrobbles/cubit/activity/data_new_artists_cubit.dart';
+import 'package:scrobbles/cubit/activity/data_new_tracks_cubit.dart';
+import 'package:scrobbles/cubit/activity/data_statistics_global_cubit.dart';
+import 'package:scrobbles/cubit/activity/data_statistics_recent_cubit.dart';
+import 'package:scrobbles/cubit/activity/data_timeline_cubit.dart';
+import 'package:scrobbles/cubit/activity/data_top_artists_cubit.dart';
+import 'package:scrobbles/cubit/settings/settings_activity_cubit.dart';
+import 'package:scrobbles/cubit/settings/settings_global_cubit.dart';
 import 'package:scrobbles/ui/skeleton.dart';
 
 void main() async {
@@ -49,28 +53,62 @@ class MyApp extends StatelessWidget {
   Widget build(BuildContext context) {
     return MultiBlocProvider(
       providers: [
-        BlocProvider<NavCubitPage>(create: (context) => NavCubitPage()),
-        BlocProvider<NavCubitScreen>(create: (context) => NavCubitScreen()),
+        // default providers
+        BlocProvider<NavCubitPage>(
+          create: (context) => NavCubitPage(),
+        ),
+        BlocProvider<NavCubitScreen>(
+          create: (context) => NavCubitScreen(),
+        ),
         BlocProvider<ApplicationThemeModeCubit>(
-            create: (context) => ApplicationThemeModeCubit()),
-        BlocProvider<GlobalSettingsCubit>(create: (context) => GlobalSettingsCubit()),
-        BlocProvider<DataCountsByDayCubit>(create: (context) => DataCountsByDayCubit()),
-        BlocProvider<DataCountsByHourCubit>(create: (context) => DataCountsByHourCubit()),
-        BlocProvider<DataDiscoveriesCubit>(create: (context) => DataDiscoveriesCubit()),
-        BlocProvider<DataHeatmapCubit>(create: (context) => DataHeatmapCubit()),
-        BlocProvider<DataNewArtistsCubit>(create: (context) => DataNewArtistsCubit()),
-        BlocProvider<DataNewTracksCubit>(create: (context) => DataNewTracksCubit()),
+          create: (context) => ApplicationThemeModeCubit(),
+        ),
+        BlocProvider<ActivityCubit>(
+          create: (context) => ActivityCubit(),
+        ),
+        BlocProvider<GlobalSettingsCubit>(
+          create: (context) => GlobalSettingsCubit(),
+        ),
+        BlocProvider<ActivitySettingsCubit>(
+          create: (context) => ActivitySettingsCubit(),
+        ),
+
+        // custom providers
+        BlocProvider<DataCountsByDayCubit>(
+          create: (context) => DataCountsByDayCubit(),
+        ),
+        BlocProvider<DataCountsByHourCubit>(
+          create: (context) => DataCountsByHourCubit(),
+        ),
+        BlocProvider<DataDiscoveriesCubit>(
+          create: (context) => DataDiscoveriesCubit(),
+        ),
+        BlocProvider<DataHeatmapCubit>(
+          create: (context) => DataHeatmapCubit(),
+        ),
+        BlocProvider<DataNewArtistsCubit>(
+          create: (context) => DataNewArtistsCubit(),
+        ),
+        BlocProvider<DataNewTracksCubit>(
+          create: (context) => DataNewTracksCubit(),
+        ),
         BlocProvider<DataStatisticsGlobalCubit>(
-            create: (context) => DataStatisticsGlobalCubit()),
+          create: (context) => DataStatisticsGlobalCubit(),
+        ),
         BlocProvider<DataStatisticsRecentCubit>(
-            create: (context) => DataStatisticsRecentCubit()),
-        BlocProvider<DataTimelineCubit>(create: (context) => DataTimelineCubit()),
-        BlocProvider<DataTopArtistsCubit>(create: (context) => DataTopArtistsCubit()),
+          create: (context) => DataStatisticsRecentCubit(),
+        ),
+        BlocProvider<DataTimelineCubit>(
+          create: (context) => DataTimelineCubit(),
+        ),
+        BlocProvider<DataTopArtistsCubit>(
+          create: (context) => DataTopArtistsCubit(),
+        ),
       ],
       child: BlocBuilder<ApplicationThemeModeCubit, ApplicationThemeModeState>(
         builder: (BuildContext context, ApplicationThemeModeState state) {
           return MaterialApp(
-            title: 'Scrobbles',
+            title: ApplicationConfig.appTitle,
             home: const SkeletonScreen(),
 
             // Theme stuff
diff --git a/lib/models/activity/activity.dart b/lib/models/activity/activity.dart
new file mode 100644
index 0000000..973cd03
--- /dev/null
+++ b/lib/models/activity/activity.dart
@@ -0,0 +1,77 @@
+import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
+
+import 'package:scrobbles/models/settings/settings_activity.dart';
+import 'package:scrobbles/models/settings/settings_global.dart';
+
+class Activity {
+  Activity({
+    // Settings
+    required this.activitySettings,
+    required this.globalSettings,
+
+    // State
+    this.isRunning = false,
+  });
+
+  // Settings
+  final ActivitySettings activitySettings;
+  final GlobalSettings globalSettings;
+
+  // State
+  bool isRunning;
+
+  factory Activity.createNull() {
+    return Activity(
+      // Settings
+      activitySettings: ActivitySettings.createDefault(),
+      globalSettings: GlobalSettings.createDefault(),
+    );
+  }
+
+  factory Activity.createNew({
+    ActivitySettings? activitySettings,
+    GlobalSettings? globalSettings,
+  }) {
+    final ActivitySettings newActivitySettings =
+        activitySettings ?? ActivitySettings.createDefault();
+    final GlobalSettings newGlobalSettings = globalSettings ?? GlobalSettings.createDefault();
+
+    return Activity(
+      // Settings
+      activitySettings: newActivitySettings,
+      globalSettings: newGlobalSettings,
+      // State
+      isRunning: true,
+    );
+  }
+
+  bool get canBeResumed => true;
+
+  void dump() {
+    printlog('');
+    printlog('## Current game dump:');
+    printlog('');
+    printlog('$Activity:');
+    printlog('  Settings');
+    activitySettings.dump();
+    globalSettings.dump();
+    printlog('  State');
+    printlog('    isRunning: $isRunning');
+    printlog('');
+  }
+
+  @override
+  String toString() {
+    return '$Activity(${toJson()})';
+  }
+
+  Map<String, dynamic>? toJson() {
+    return <String, dynamic>{
+      // Settings
+      'activitySettings': activitySettings.toJson(),
+      'globalSettings': globalSettings.toJson(),
+      // State
+      'isRunning': isRunning,
+    };
+  }
+}
diff --git a/lib/models/settings/settings_activity.dart b/lib/models/settings/settings_activity.dart
new file mode 100644
index 0000000..c270607
--- /dev/null
+++ b/lib/models/settings/settings_activity.dart
@@ -0,0 +1,42 @@
+import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
+
+import 'package:scrobbles/config/default_activity_settings.dart';
+
+class ActivitySettings {
+  final String dashboardType;
+
+  ActivitySettings({
+    required this.dashboardType,
+  });
+
+  factory ActivitySettings.createDefault() {
+    return ActivitySettings(
+      dashboardType: DefaultActivitySettings.defaultDashboardTypeValue,
+    );
+  }
+
+  static String getDashboardTypeValueFromUnsafe(String dashboardType) {
+    if (DefaultActivitySettings.allowedDashboardTypeValues.contains(dashboardType)) {
+      return dashboardType;
+    }
+
+    return DefaultActivitySettings.defaultDashboardTypeValue;
+  }
+
+  void dump() {
+    printlog('$ActivitySettings:');
+    printlog('  ${DefaultActivitySettings.parameterCodeDashboardType}: $dashboardType');
+    printlog('');
+  }
+
+  @override
+  String toString() {
+    return '$ActivitySettings(${toJson()})';
+  }
+
+  Map<String, dynamic>? toJson() {
+    return <String, dynamic>{
+      DefaultActivitySettings.parameterCodeDashboardType: dashboardType,
+    };
+  }
+}
diff --git a/lib/models/settings/settings_global.dart b/lib/models/settings/settings_global.dart
new file mode 100644
index 0000000..666f87e
--- /dev/null
+++ b/lib/models/settings/settings_global.dart
@@ -0,0 +1,42 @@
+import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
+
+import 'package:scrobbles/config/default_global_settings.dart';
+
+class GlobalSettings {
+  String skin;
+
+  GlobalSettings({
+    required this.skin,
+  });
+
+  static String getSkinValueFromUnsafe(String skin) {
+    if (DefaultGlobalSettings.allowedSkinValues.contains(skin)) {
+      return skin;
+    }
+
+    return DefaultGlobalSettings.defaultSkinValue;
+  }
+
+  factory GlobalSettings.createDefault() {
+    return GlobalSettings(
+      skin: DefaultGlobalSettings.defaultSkinValue,
+    );
+  }
+
+  void dump() {
+    printlog('$GlobalSettings:');
+    printlog('  ${DefaultGlobalSettings.parameterCodeSkin}: $skin');
+    printlog('');
+  }
+
+  @override
+  String toString() {
+    return '$GlobalSettings(${toJson()})';
+  }
+
+  Map<String, dynamic>? toJson() {
+    return <String, dynamic>{
+      DefaultGlobalSettings.parameterCodeSkin: skin,
+    };
+  }
+}
diff --git a/lib/ui/skeleton.dart b/lib/ui/skeleton.dart
index 3bb0c80..74f4965 100644
--- a/lib/ui/skeleton.dart
+++ b/lib/ui/skeleton.dart
@@ -1,9 +1,11 @@
 import 'package:flutter/material.dart';
 import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
 
-import 'package:scrobbles/config/screen.dart';
-import 'package:scrobbles/cubit/nav_cubit_screens.dart';
-import 'package:scrobbles/ui/nav/global_app_bar.dart';
+import 'package:scrobbles/common/config/activity_page.dart';
+import 'package:scrobbles/common/config/screen.dart';
+import 'package:scrobbles/common/cubit/nav/nav_cubit_screens.dart';
+import 'package:scrobbles/common/ui/nav/global_app_bar.dart';
+import 'package:scrobbles/common/ui/nav/bottom_nav_bar.dart';
 
 class SkeletonScreen extends StatelessWidget {
   const SkeletonScreen({super.key});
@@ -27,6 +29,7 @@ class SkeletonScreen extends StatelessWidget {
             ),
           ),
           backgroundColor: Theme.of(context).colorScheme.surface,
+          bottomNavigationBar: ActivityPage.displayBottomNavBar ? const BottomNavBar() : null,
         );
       },
     );
diff --git a/lib/ui/widgets/cards/counts_by_day.dart b/lib/ui/widgets/cards/counts_by_day.dart
index 259fd29..672a873 100644
--- a/lib/ui/widgets/cards/counts_by_day.dart
+++ b/lib/ui/widgets/cards/counts_by_day.dart
@@ -1,8 +1,8 @@
 import 'package:flutter/material.dart';
 import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
 
-import 'package:scrobbles/cubit/data_counts_by_day_cubit.dart';
-import 'package:scrobbles/cubit/settings_global_cubit.dart';
+import 'package:scrobbles/cubit/activity/data_counts_by_day_cubit.dart';
+import 'package:scrobbles/cubit/settings/settings_global_cubit.dart';
 import 'package:scrobbles/models/data/counts_by_day.dart';
 import 'package:scrobbles/ui/widgets/card_content.dart';
 import 'package:scrobbles/ui/widgets/charts/counts_by_day.dart';
diff --git a/lib/ui/widgets/cards/counts_by_hour.dart b/lib/ui/widgets/cards/counts_by_hour.dart
index dee7584..d7d296a 100644
--- a/lib/ui/widgets/cards/counts_by_hour.dart
+++ b/lib/ui/widgets/cards/counts_by_hour.dart
@@ -1,8 +1,8 @@
 import 'package:flutter/material.dart';
 import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
 
-import 'package:scrobbles/cubit/data_counts_by_hour_cubit.dart';
-import 'package:scrobbles/cubit/settings_global_cubit.dart';
+import 'package:scrobbles/cubit/activity/data_counts_by_hour_cubit.dart';
+import 'package:scrobbles/cubit/settings/settings_global_cubit.dart';
 import 'package:scrobbles/models/data/counts_by_hour.dart';
 import 'package:scrobbles/ui/widgets/card_content.dart';
 import 'package:scrobbles/ui/widgets/charts/counts_by_hour.dart';
diff --git a/lib/ui/widgets/cards/discoveries.dart b/lib/ui/widgets/cards/discoveries.dart
index d1e4baf..3937a50 100644
--- a/lib/ui/widgets/cards/discoveries.dart
+++ b/lib/ui/widgets/cards/discoveries.dart
@@ -1,8 +1,8 @@
 import 'package:flutter/material.dart';
 import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
 
-import 'package:scrobbles/cubit/data_discoveries_cubit.dart';
-import 'package:scrobbles/cubit/settings_global_cubit.dart';
+import 'package:scrobbles/cubit/activity/data_discoveries_cubit.dart';
+import 'package:scrobbles/cubit/settings/settings_global_cubit.dart';
 import 'package:scrobbles/models/data/discoveries.dart';
 import 'package:scrobbles/ui/widgets/card_content.dart';
 import 'package:scrobbles/ui/widgets/charts/discoveries_artists.dart';
diff --git a/lib/ui/widgets/cards/heatmap.dart b/lib/ui/widgets/cards/heatmap.dart
index e51a667..ffc40ff 100644
--- a/lib/ui/widgets/cards/heatmap.dart
+++ b/lib/ui/widgets/cards/heatmap.dart
@@ -1,8 +1,8 @@
 import 'package:flutter/material.dart';
 import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
 
-import 'package:scrobbles/cubit/data_heatmap_cubit.dart';
-import 'package:scrobbles/cubit/settings_global_cubit.dart';
+import 'package:scrobbles/cubit/activity/data_heatmap_cubit.dart';
+import 'package:scrobbles/cubit/settings/settings_global_cubit.dart';
 import 'package:scrobbles/models/data/heatmap.dart';
 import 'package:scrobbles/ui/widgets/card_content.dart';
 import 'package:scrobbles/ui/widgets/charts/heatmap.dart';
diff --git a/lib/ui/widgets/cards/new_artists.dart b/lib/ui/widgets/cards/new_artists.dart
index 365d5d6..0ca1c69 100644
--- a/lib/ui/widgets/cards/new_artists.dart
+++ b/lib/ui/widgets/cards/new_artists.dart
@@ -1,7 +1,7 @@
 import 'package:flutter/material.dart';
 import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
 
-import 'package:scrobbles/cubit/data_new_artists_cubit.dart';
+import 'package:scrobbles/cubit/activity/data_new_artists_cubit.dart';
 import 'package:scrobbles/ui/widgets/card_content.dart';
 
 class CardNewArtists extends StatelessWidget {
diff --git a/lib/ui/widgets/cards/new_tracks.dart b/lib/ui/widgets/cards/new_tracks.dart
index 0a73fd3..cbcd99f 100644
--- a/lib/ui/widgets/cards/new_tracks.dart
+++ b/lib/ui/widgets/cards/new_tracks.dart
@@ -1,7 +1,7 @@
 import 'package:flutter/material.dart';
 import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
 
-import 'package:scrobbles/cubit/data_new_tracks_cubit.dart';
+import 'package:scrobbles/cubit/activity/data_new_tracks_cubit.dart';
 import 'package:scrobbles/ui/widgets/card_content.dart';
 
 class CardNewTracks extends StatelessWidget {
diff --git a/lib/ui/widgets/cards/statistics_global.dart b/lib/ui/widgets/cards/statistics_global.dart
index a1480cd..2eeadf8 100644
--- a/lib/ui/widgets/cards/statistics_global.dart
+++ b/lib/ui/widgets/cards/statistics_global.dart
@@ -1,7 +1,7 @@
 import 'package:flutter/material.dart';
 import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
 
-import 'package:scrobbles/cubit/data_statistics_global_cubit.dart';
+import 'package:scrobbles/cubit/activity/data_statistics_global_cubit.dart';
 import 'package:scrobbles/models/data/statistics_global.dart';
 import 'package:scrobbles/ui/widgets/card_content.dart';
 import 'package:scrobbles/ui/widgets/content/statistics_global.dart';
diff --git a/lib/ui/widgets/cards/statistics_recent.dart b/lib/ui/widgets/cards/statistics_recent.dart
index e3312da..219063c 100644
--- a/lib/ui/widgets/cards/statistics_recent.dart
+++ b/lib/ui/widgets/cards/statistics_recent.dart
@@ -1,8 +1,8 @@
 import 'package:flutter/material.dart';
 import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
 
-import 'package:scrobbles/cubit/data_statistics_recent_cubit.dart';
-import 'package:scrobbles/cubit/settings_global_cubit.dart';
+import 'package:scrobbles/cubit/activity/data_statistics_recent_cubit.dart';
+import 'package:scrobbles/cubit/settings/settings_global_cubit.dart';
 import 'package:scrobbles/models/data/statistics_recent.dart';
 import 'package:scrobbles/ui/widgets/card_content.dart';
 import 'package:scrobbles/ui/widgets/content/statistics_recent.dart';
diff --git a/lib/ui/widgets/cards/timeline.dart b/lib/ui/widgets/cards/timeline.dart
index cf9d688..9412817 100644
--- a/lib/ui/widgets/cards/timeline.dart
+++ b/lib/ui/widgets/cards/timeline.dart
@@ -1,8 +1,8 @@
 import 'package:flutter/material.dart';
 import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
 
-import 'package:scrobbles/cubit/data_timeline_cubit.dart';
-import 'package:scrobbles/cubit/settings_global_cubit.dart';
+import 'package:scrobbles/cubit/activity/data_timeline_cubit.dart';
+import 'package:scrobbles/cubit/settings/settings_global_cubit.dart';
 import 'package:scrobbles/models/data/timeline.dart';
 import 'package:scrobbles/ui/widgets/card_content.dart';
 import 'package:scrobbles/ui/widgets/charts/timeline_counts.dart';
diff --git a/lib/ui/widgets/cards/top_artists.dart b/lib/ui/widgets/cards/top_artists.dart
index a58127c..87f7a49 100644
--- a/lib/ui/widgets/cards/top_artists.dart
+++ b/lib/ui/widgets/cards/top_artists.dart
@@ -1,8 +1,8 @@
 import 'package:flutter/material.dart';
 import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
 
-import 'package:scrobbles/cubit/data_top_artists_cubit.dart';
-import 'package:scrobbles/cubit/settings_global_cubit.dart';
+import 'package:scrobbles/cubit/activity/data_top_artists_cubit.dart';
+import 'package:scrobbles/cubit/settings/settings_global_cubit.dart';
 import 'package:scrobbles/models/data/topartists.dart';
 import 'package:scrobbles/ui/widgets/card_content.dart';
 import 'package:scrobbles/ui/widgets/charts/top_artists.dart';
diff --git a/pubspec.lock b/pubspec.lock
index abad950..03f2aab 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -269,10 +269,10 @@ packages:
     dependency: transitive
     description:
       name: path_provider
-      sha256: fec0d61223fba3154d87759e3cc27fe2c8dc498f6386c6d6fc80d1afdd1bf378
+      sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd"
       url: "https://pub.dev"
     source: hosted
-    version: "2.1.4"
+    version: "2.1.5"
   path_provider_android:
     dependency: transitive
     description:
@@ -466,10 +466,10 @@ packages:
     dependency: transitive
     description:
       name: win32
-      sha256: "2735daae5150e8b1dfeb3eb0544b4d3af0061e9e82cef063adcd583bdae4306a"
+      sha256: "10169d3934549017f0ae278ccb07f828f9d6ea21573bab0fb77b0e1ef0fce454"
       url: "https://pub.dev"
     source: hosted
-    version: "5.7.0"
+    version: "5.7.2"
   xdg_directories:
     dependency: transitive
     description:
diff --git a/pubspec.yaml b/pubspec.yaml
index 715fc23..5939c74 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -3,7 +3,7 @@ description: Display scrobbles data and charts
 
 publish_to: "none"
 
-version: 0.3.1+65
+version: 0.4.0+66
 
 environment:
   sdk: "^3.0.0"
-- 
GitLab