diff --git a/android/gradle.properties b/android/gradle.properties
index 408253ceb04c0c7c49b3b9daf597f35b66ce16c1..e6443382b31fab5fc027b99dc079154f78f27d0b 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.27
-app.versionCode=27
+app.versionName=0.0.28
+app.versionCode=28
diff --git a/assets/translations/en.json b/assets/translations/en.json
index a2823ebf4473cf48e61d66216dc8b759dee922ed..3f4f688426c83324af070f6d7dba37ed2c91edc8 100644
--- a/assets/translations/en.json
+++ b/assets/translations/en.json
@@ -9,16 +9,16 @@
   "statistics_total_scrobbles_count": "Total scrobbles count: {count}",
   "statistics_last_scrobble": "Last scrobble: {datetime}",
 
-  "recent_statistics": "Recent statistics",
-  "statistics_selected_period": "On last {daysCount} days:",
+  "recent_statistics": "Recent statistics ({daysCount} days)",
   "statistics_recent_scrobbles_count_and_discoveries": "{count} scrobbles and {artistsCount} artists / {tracksCount} tracks discovered.",
 
   "timeline_title": "Recent scrobbles ({daysCount} days)",
   "counts_by_day": "Counts by day ({daysCount} days)",
   "counts_by_hour": "Counts by hour ({daysCount} days)",
 
-  "discoveries_artists_title": "Artists discoveries ({daysCount} days)",
-  "discoveries_tracks_title": "Tracks discoveries ({daysCount} days)",
+  "discoveries_title": "Discoveries ({daysCount} days)",
+  "discoveries_artists_title": "Artists",
+  "discoveries_tracks_title": "Tracks",
 
   "top_artists_title": "Top artists ({daysCount} days)",
 
diff --git a/assets/translations/fr.json b/assets/translations/fr.json
index 67d019d1490f2a0f5793ee643a021a717b6a1a08..2f2fb63737d1b841a51acf6acdfef26d9d77639f 100644
--- a/assets/translations/fr.json
+++ b/assets/translations/fr.json
@@ -9,16 +9,16 @@
   "statistics_total_scrobbles_count": "Nombre total d'écoutes : {count}",
   "statistics_last_scrobble": "Dernière écoute : {datetime}",
 
-  "recent_statistics": "Statistiques récentes",
-  "statistics_selected_period": "Sur les {daysCount} derniers jours :",
+  "recent_statistics": "Statistiques récentes ({daysCount} jours)",
   "statistics_recent_scrobbles_count_and_discoveries": "{count} écoutes et {artistsCount} artistes / {tracksCount} morceaux découverts.",
 
   "timeline_title": "Écoutes récentes ({daysCount} jours)",
   "counts_by_day": "Écoutes par jour ({daysCount} jours)",
   "counts_by_hour": "Écoutes par heure ({daysCount} jours)",
 
-  "discoveries_artists_title": "Artistes découverts ({daysCount} jours)",
-  "discoveries_tracks_title": "Morceaux découverts ({daysCount} jours)",
+  "discoveries_title": "Découvertes ({daysCount} jours)",
+  "discoveries_artists_title": "Artistes",
+  "discoveries_tracks_title": "Morceaux",
 
   "top_artists_title": "Top artistes ({daysCount} jours)",
 
diff --git a/fastlane/metadata/android/en-US/changelogs/28.txt b/fastlane/metadata/android/en-US/changelogs/28.txt
new file mode 100644
index 0000000000000000000000000000000000000000..b2da89ffc123cff8c927d474778de6ab41d91e33
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/28.txt
@@ -0,0 +1 @@
+Clean/improve/refactor code.
diff --git a/fastlane/metadata/android/fr-FR/changelogs/28.txt b/fastlane/metadata/android/fr-FR/changelogs/28.txt
new file mode 100644
index 0000000000000000000000000000000000000000..92d90dd777f068ad336c365bacc5a1bd4da13e42
--- /dev/null
+++ b/fastlane/metadata/android/fr-FR/changelogs/28.txt
@@ -0,0 +1 @@
+Nettoyage/améliorations/refactorisations de code.
diff --git a/lib/main.dart b/lib/main.dart
index c6ec2e707dc448f423707a8dcd1d8127de97db4b..da465fa5d11fcbbec47fef771ca38e6d50b72ff6 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -6,9 +6,8 @@ import 'package:hive/hive.dart';
 import 'package:hydrated_bloc/hydrated_bloc.dart';
 import 'package:path_provider/path_provider.dart';
 
-import 'config/theme.dart';
-
-import 'ui/screens/skeleton_screen.dart';
+import 'package:scrobbles/config/theme.dart';
+import 'package:scrobbles/ui/skeleton.dart';
 
 void main() async {
   /// Initialize packages
diff --git a/lib/models/counts_by_day.dart b/lib/models/counts_by_day.dart
index cff1d538da42f276efbc49788e68ae4f6090380a..fcb455165b86a7274fc7d83302e8223dc7101a2b 100644
--- a/lib/models/counts_by_day.dart
+++ b/lib/models/counts_by_day.dart
@@ -7,11 +7,11 @@ class CountsByDayData {
     required this.data,
   });
 
-  factory CountsByDayData.fromJson(Map<String, dynamic> json) {
+  factory CountsByDayData.fromJson(Map<String, dynamic>? json) {
     Map<int, double> data = {};
 
-    if (json['counts-by-day'] != null) {
-      json['counts-by-day'].keys.forEach((day) {
+    if (json?['counts-by-day'] != null) {
+      json?['counts-by-day'].keys.forEach((day) {
         data[int.parse(day)] = double.parse(json['counts-by-day'][day].toString());
       });
     }
@@ -20,7 +20,7 @@ class CountsByDayData {
   }
 
   factory CountsByDayData.createEmpty() {
-    return CountsByDayData.fromJson({});
+    return CountsByDayData.fromJson({'counts-by-day': {}});
   }
 
   String toString() {
diff --git a/lib/models/counts_by_hour.dart b/lib/models/counts_by_hour.dart
index 12857528cec1ac7a6dc8af6141a349b9cba11db8..f0c6d50f782af10472ae25db85bf8275e8762c40 100644
--- a/lib/models/counts_by_hour.dart
+++ b/lib/models/counts_by_hour.dart
@@ -7,11 +7,11 @@ class CountsByHourData {
     required this.data,
   });
 
-  factory CountsByHourData.fromJson(Map<String, dynamic> json) {
+  factory CountsByHourData.fromJson(Map<String, dynamic>? json) {
     Map<int, double> data = {};
 
-    if (json['counts-by-hour'] != null) {
-      json['counts-by-hour'].keys.forEach((day) {
+    if (json?['counts-by-hour'] != null) {
+      json?['counts-by-hour'].keys.forEach((day) {
         if (int.parse(day) != 24) {
           data[int.parse(day)] = double.parse(json['counts-by-hour'][day].toString());
         }
diff --git a/lib/models/discoveries.dart b/lib/models/discoveries.dart
index 3e67649b1eab4e2acb7133fab1e243052afcaefb..14f5819e5b095d4c493c9cc5d6b5c29eb66c5617 100644
--- a/lib/models/discoveries.dart
+++ b/lib/models/discoveries.dart
@@ -6,10 +6,10 @@ class DiscoveriesDataValue {
 
   const DiscoveriesDataValue({required this.newArtistsCount, required this.newTracksCount});
 
-  factory DiscoveriesDataValue.fromJson(Map<String, dynamic> json) {
+  factory DiscoveriesDataValue.fromJson(Map<String, dynamic>? json) {
     return DiscoveriesDataValue(
-      newArtistsCount: json['new-artists'] as int,
-      newTracksCount: json['new-tracks'] as int,
+      newArtistsCount: json?['new-artists'] as int,
+      newTracksCount: json?['new-tracks'] as int,
     );
   }
 }
@@ -21,10 +21,10 @@ class DiscoveriesData {
     required this.data,
   });
 
-  factory DiscoveriesData.fromJson(Map<String, dynamic> json) {
+  factory DiscoveriesData.fromJson(Map<String, dynamic>? json) {
     Map<String, DiscoveriesDataValue> data = {};
 
-    json.keys.forEach((date) {
+    json?.keys.forEach((date) {
       DiscoveriesDataValue value = DiscoveriesDataValue(
         newArtistsCount: json[date]['new-artists'] as int,
         newTracksCount: json[date]['new-tracks'] as int,
diff --git a/lib/models/statistics_global.dart b/lib/models/statistics_global.dart
index 0610e274f22ada6b9981745d18c656d5f28c96a1..4eb90fcfaa7d5a5b03aac17c610f3619f215a028 100644
--- a/lib/models/statistics_global.dart
+++ b/lib/models/statistics_global.dart
@@ -9,12 +9,12 @@ class StatisticsGlobalData {
     required this.lastScrobble,
   });
 
-  factory StatisticsGlobalData.fromJson(Map<String, dynamic> json) {
+  factory StatisticsGlobalData.fromJson(Map<String, dynamic>? json) {
     return StatisticsGlobalData(
-      totalCount: json['totalCount'] != null ? json['totalCount'] as int : 0,
-      lastScrobble: (json['lastScrobble'] != null && json['lastScrobble']['date'] != null)
+      totalCount: (json?['totalCount'] != null) ? (json?['totalCount'] as int) : 0,
+      lastScrobble: (json?['lastScrobble'] != null && json?['lastScrobble']['date'] != null)
           ? DateTime.parse(
-              json['lastScrobble']['date'],
+              json?['lastScrobble']['date'],
             )
           : DateTime.now(),
     );
diff --git a/lib/models/statistics_recent.dart b/lib/models/statistics_recent.dart
index 218dd1ff5c4d2eda5d545bf045d554aa0070e837..d72173fd0464c428ef27769e11f2c2eba8fa410d 100644
--- a/lib/models/statistics_recent.dart
+++ b/lib/models/statistics_recent.dart
@@ -13,14 +13,16 @@ class StatisticsRecentData {
     required this.selectedPeriod,
   });
 
-  factory StatisticsRecentData.fromJson(Map<String, dynamic> json) {
+  factory StatisticsRecentData.fromJson(Map<String, dynamic>? json) {
     return StatisticsRecentData(
-      recentCount: json['recentCount'] != null ? json['recentCount'] as int : 0,
-      firstPlayedArtistsCount:
-          json['firstPlayedArtistsCount'] != null ? json['firstPlayedArtistsCount'] as int : 0,
-      firstPlayedTracksCount:
-          json['firstPlayedTracksCount'] != null ? json['firstPlayedTracksCount'] as int : 0,
-      selectedPeriod: json['selectedPeriod'] != null ? json['selectedPeriod'] as int : 0,
+      recentCount: (json?['recentCount'] != null) ? (json?['recentCount'] as int) : 0,
+      firstPlayedArtistsCount: (json?['firstPlayedArtistsCount'] != null)
+          ? (json?['firstPlayedArtistsCount'] as int)
+          : 0,
+      firstPlayedTracksCount: (json?['firstPlayedTracksCount'] != null)
+          ? (json?['firstPlayedTracksCount'] as int)
+          : 0,
+      selectedPeriod: (json?['selectedPeriod'] != null) ? (json?['selectedPeriod'] as int) : 0,
     );
   }
 
diff --git a/lib/models/timeline.dart b/lib/models/timeline.dart
index 15042338609249c93bf68f395d11f0bba4c68838..b52a546b5ac6834b5ab50a05d92db31ec1d92bb8 100644
--- a/lib/models/timeline.dart
+++ b/lib/models/timeline.dart
@@ -6,10 +6,10 @@ class TimelineDataValue {
 
   const TimelineDataValue({required this.counts, required this.eclecticism});
 
-  factory TimelineDataValue.fromJson(Map<String, dynamic> json) {
+  factory TimelineDataValue.fromJson(Map<String, dynamic>? json) {
     return TimelineDataValue(
-      counts: json['counts'] as int,
-      eclecticism: json['eclecticism'] as int,
+      counts: json?['counts'] as int,
+      eclecticism: json?['eclecticism'] as int,
     );
   }
 }
@@ -21,10 +21,10 @@ class TimelineData {
     required this.data,
   });
 
-  factory TimelineData.fromJson(Map<String, dynamic> json) {
+  factory TimelineData.fromJson(Map<String, dynamic>? json) {
     Map<String, TimelineDataValue> data = {};
 
-    json.keys.forEach((date) {
+    json?.keys.forEach((date) {
       TimelineDataValue value = TimelineDataValue(
         counts: json[date]['counts'] as int,
         eclecticism: json[date]['eclecticism'] as int,
diff --git a/lib/models/topartists.dart b/lib/models/topartists.dart
index 52c06f2373298b9a57a88f9d1e295f751db3ae0e..9a7b4188c7d654de2c9395abcd94810cc36cd87e 100644
--- a/lib/models/topartists.dart
+++ b/lib/models/topartists.dart
@@ -6,10 +6,10 @@ class TopArtistsDataValue {
 
   const TopArtistsDataValue({required this.artistName, required this.count});
 
-  factory TopArtistsDataValue.fromJson(Map<String, dynamic> json) {
+  factory TopArtistsDataValue.fromJson(Map<String, dynamic>? json) {
     return TopArtistsDataValue(
-      artistName: json['artistName'] as String,
-      count: json['count'] as int,
+      artistName: json?['artistName'] as String,
+      count: json?['count'] as int,
     );
   }
 }
@@ -21,10 +21,10 @@ class TopArtistsData {
     required this.topArtists,
   });
 
-  factory TopArtistsData.fromJson(Map<String, dynamic> json) {
+  factory TopArtistsData.fromJson(Map<String, dynamic>? json) {
     List<TopArtistsDataValue> topArtists = [];
 
-    json['top-artists'].forEach((element) {
+    json?['top-artists'].forEach((element) {
       TopArtistsDataValue value = TopArtistsDataValue(
         artistName: element['artistName'] as String,
         count: element['count'] as int,
diff --git a/lib/network/scrobbles_api.dart b/lib/network/scrobbles.dart
similarity index 89%
rename from lib/network/scrobbles_api.dart
rename to lib/network/scrobbles.dart
index 3efb3f6a8e22fa2b3f6570a6675016f2c61e495d..ebfca8a82d63272abfa6df82ae1a6f2c8771d840 100644
--- a/lib/network/scrobbles_api.dart
+++ b/lib/network/scrobbles.dart
@@ -1,13 +1,13 @@
 import 'dart:convert';
 import 'package:http/http.dart' as http;
 
-import '../models/counts_by_day.dart';
-import '../models/counts_by_hour.dart';
-import '../models/discoveries.dart';
-import '../models/statistics_global.dart';
-import '../models/statistics_recent.dart';
-import '../models/timeline.dart';
-import '../models/topartists.dart';
+import 'package:scrobbles/models/counts_by_day.dart';
+import 'package:scrobbles/models/counts_by_hour.dart';
+import 'package:scrobbles/models/discoveries.dart';
+import 'package:scrobbles/models/statistics_global.dart';
+import 'package:scrobbles/models/statistics_recent.dart';
+import 'package:scrobbles/models/timeline.dart';
+import 'package:scrobbles/models/topartists.dart';
 
 class ScrobblesApi {
   static String baseUrl = 'https://scrobble.harrault.fr';
diff --git a/lib/ui/screens/discoveries_screen.dart b/lib/ui/screens/discoveries.dart
similarity index 59%
rename from lib/ui/screens/discoveries_screen.dart
rename to lib/ui/screens/discoveries.dart
index ca590c79bcc0cc864a305b2f56b86a6ba367b10b..fd5f836b9b929f9867fc570ebf15228ca4eef630 100644
--- a/lib/ui/screens/discoveries_screen.dart
+++ b/lib/ui/screens/discoveries.dart
@@ -1,15 +1,15 @@
 import 'package:flutter/material.dart';
 
-import '../widgets/main_screen/discoveries_card.dart';
+import 'package:scrobbles/ui/widgets/cards/discoveries.dart';
 
-class DiscoveriesScreen extends StatefulWidget {
-  const DiscoveriesScreen({super.key});
+class ScreenDiscoveries extends StatefulWidget {
+  const ScreenDiscoveries({super.key});
 
   @override
-  State<DiscoveriesScreen> createState() => _DiscoveriesScreenState();
+  State<ScreenDiscoveries> createState() => _ScreenDiscoveriesState();
 }
 
-class _DiscoveriesScreenState extends State<DiscoveriesScreen> {
+class _ScreenDiscoveriesState extends State<ScreenDiscoveries> {
   @override
   Widget build(BuildContext context) {
     return Material(
@@ -19,7 +19,7 @@ class _DiscoveriesScreenState extends State<DiscoveriesScreen> {
         physics: const BouncingScrollPhysics(),
         children: <Widget>[
           const SizedBox(height: 8),
-          const ChartDiscoveriesCard(),
+          const CardDiscoveries(),
           const SizedBox(height: 36),
         ],
       ),
diff --git a/lib/ui/screens/home.dart b/lib/ui/screens/home.dart
new file mode 100644
index 0000000000000000000000000000000000000000..c2acc00607c83b8dec1f39f13ee7168557689c3e
--- /dev/null
+++ b/lib/ui/screens/home.dart
@@ -0,0 +1,37 @@
+import 'package:flutter/material.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';
+import 'package:scrobbles/ui/widgets/cards/top_artists.dart';
+
+class ScreenHome extends StatefulWidget {
+  const ScreenHome({super.key});
+
+  @override
+  State<ScreenHome> createState() => _ScreenHomeState();
+}
+
+class _ScreenHomeState extends State<ScreenHome> {
+  @override
+  Widget build(BuildContext context) {
+    return Material(
+      color: Theme.of(context).colorScheme.background,
+      child: ListView(
+        padding: const EdgeInsets.symmetric(horizontal: 4),
+        physics: const BouncingScrollPhysics(),
+        children: <Widget>[
+          const SizedBox(height: 8),
+          const CardStatisticsGlobal(),
+          const SizedBox(height: 6),
+          const CardStatisticsRecent(),
+          const SizedBox(height: 6),
+          const CardTimeline(),
+          const SizedBox(height: 6),
+          const CardTopArtists(),
+          const SizedBox(height: 36),
+        ],
+      ),
+    );
+  }
+}
diff --git a/lib/ui/screens/home_screen.dart b/lib/ui/screens/home_screen.dart
deleted file mode 100644
index 5af4a2d9022c41fbdcf7227dc376eae935bf7ffe..0000000000000000000000000000000000000000
--- a/lib/ui/screens/home_screen.dart
+++ /dev/null
@@ -1,37 +0,0 @@
-import 'package:flutter/material.dart';
-
-import '../widgets/main_screen/statistics_global_card.dart';
-import '../widgets/main_screen/statistics_recent_card.dart';
-import '../widgets/main_screen/timeline_card.dart';
-import '../widgets/main_screen/topartists_card.dart';
-
-class HomeScreen extends StatefulWidget {
-  const HomeScreen({super.key});
-
-  @override
-  State<HomeScreen> createState() => _HomeScreenState();
-}
-
-class _HomeScreenState extends State<HomeScreen> {
-  @override
-  Widget build(BuildContext context) {
-    return Material(
-      color: Theme.of(context).colorScheme.background,
-      child: ListView(
-        padding: const EdgeInsets.symmetric(horizontal: 4),
-        physics: const BouncingScrollPhysics(),
-        children: <Widget>[
-          const SizedBox(height: 8),
-          const StatisticsGlobalCard(),
-          const SizedBox(height: 6),
-          const StatisticsRecentCard(),
-          const SizedBox(height: 6),
-          const ChartTimelineCard(),
-          const SizedBox(height: 6),
-          const ChartTopArtistsCard(),
-          const SizedBox(height: 36),
-        ],
-      ),
-    );
-  }
-}
diff --git a/lib/ui/screens/statistics_screen.dart b/lib/ui/screens/statistics.dart
similarity index 54%
rename from lib/ui/screens/statistics_screen.dart
rename to lib/ui/screens/statistics.dart
index c3f9e460c514f460c36b112a067e728b196b69fc..b71936138f78c8d054d70ccb5f3754da48a9c90d 100644
--- a/lib/ui/screens/statistics_screen.dart
+++ b/lib/ui/screens/statistics.dart
@@ -1,16 +1,16 @@
 import 'package:flutter/material.dart';
 
-import '../widgets/main_screen/counts_by_day_card.dart';
-import '../widgets/main_screen/counts_by_hour_card.dart';
+import 'package:scrobbles/ui/widgets/cards/counts_by_day.dart';
+import 'package:scrobbles/ui/widgets/cards/counts_by_hour.dart';
 
-class StatisticsScreen extends StatefulWidget {
-  const StatisticsScreen({super.key});
+class ScreenStatistics extends StatefulWidget {
+  const ScreenStatistics({super.key});
 
   @override
-  State<StatisticsScreen> createState() => _StatisticsScreenState();
+  State<ScreenStatistics> createState() => _ScreenStatisticsState();
 }
 
-class _StatisticsScreenState extends State<StatisticsScreen> {
+class _ScreenStatisticsState extends State<ScreenStatistics> {
   @override
   Widget build(BuildContext context) {
     return Material(
@@ -20,9 +20,9 @@ class _StatisticsScreenState extends State<StatisticsScreen> {
         physics: const BouncingScrollPhysics(),
         children: <Widget>[
           const SizedBox(height: 8),
-          const ChartCountsByDayCard(),
+          const CardCountsByDay(),
           const SizedBox(height: 6),
-          const ChartCountsByHourCard(),
+          const CardCountsByHour(),
           const SizedBox(height: 36),
         ],
       ),
diff --git a/lib/ui/screens/skeleton_screen.dart b/lib/ui/skeleton.dart
similarity index 80%
rename from lib/ui/screens/skeleton_screen.dart
rename to lib/ui/skeleton.dart
index 9a10a7827f39bc45905c938200862c827bf707c2..ad00a7b0684aeebd6b7ee724f968f81de8211bec 100644
--- a/lib/ui/screens/skeleton_screen.dart
+++ b/lib/ui/skeleton.dart
@@ -1,13 +1,12 @@
 import 'package:flutter/material.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
 
-import '../../cubit/bottom_nav_cubit.dart';
-import '../widgets/app_bar.dart';
-import '../widgets/bottom_nav_bar.dart';
-
-import 'discoveries_screen.dart';
-import 'home_screen.dart';
-import 'statistics_screen.dart';
+import 'package:scrobbles/cubit/bottom_nav_cubit.dart';
+import 'package:scrobbles/ui/screens/discoveries.dart';
+import 'package:scrobbles/ui/screens/home.dart';
+import 'package:scrobbles/ui/screens/statistics.dart';
+import 'package:scrobbles/ui/widgets/app_bar.dart';
+import 'package:scrobbles/ui/widgets/bottom_nav_bar.dart';
 
 class SkeletonScreen extends StatefulWidget {
   const SkeletonScreen({super.key});
@@ -20,9 +19,9 @@ class _SkeletonScreenState extends State<SkeletonScreen> {
   @override
   Widget build(BuildContext context) {
     const List<Widget> pageNavigation = <Widget>[
-      const HomeScreen(),
-      const DiscoveriesScreen(),
-      const StatisticsScreen(),
+      const ScreenHome(),
+      const ScreenDiscoveries(),
+      const ScreenStatistics(),
     ];
 
     return BlocProvider<BottomNavCubit>(
diff --git a/lib/ui/widgets/charts/custom_bar_chart.dart b/lib/ui/widgets/abstracts/custom_bar_chart.dart
similarity index 97%
rename from lib/ui/widgets/charts/custom_bar_chart.dart
rename to lib/ui/widgets/abstracts/custom_bar_chart.dart
index 8cdd32dc37b03b528ee28f90868880fb98547666..1ccfafb6d54f624b69aea11c3c15339a4fbae8e9 100644
--- a/lib/ui/widgets/charts/custom_bar_chart.dart
+++ b/lib/ui/widgets/abstracts/custom_bar_chart.dart
@@ -2,12 +2,13 @@ import 'package:easy_localization/easy_localization.dart';
 import 'package:fl_chart/fl_chart.dart';
 import 'package:flutter/material.dart';
 
-import '../../../config/app_colors.dart';
-import '../../../utils/color_extensions.dart';
+import 'package:scrobbles/config/app_colors.dart';
+import 'package:scrobbles/utils/color_extensions.dart';
 
 class CustomBarChart extends StatelessWidget {
   CustomBarChart({super.key});
 
+  final Widget placeholder = Text('⏳');
   final double chartHeight = 150.0;
   final double verticalTicksInterval = 10;
   final String verticalAxisTitleSuffix = '';
diff --git a/lib/ui/widgets/charts/custom_line_chart.dart b/lib/ui/widgets/abstracts/custom_line_chart.dart
similarity index 95%
rename from lib/ui/widgets/charts/custom_line_chart.dart
rename to lib/ui/widgets/abstracts/custom_line_chart.dart
index fadf283d5001e3a1e03f79698871b3590022c387..5e1a90cdad353c448667b23ddaa5c86baf2a9813 100644
--- a/lib/ui/widgets/charts/custom_line_chart.dart
+++ b/lib/ui/widgets/abstracts/custom_line_chart.dart
@@ -1,11 +1,12 @@
 import 'package:fl_chart/fl_chart.dart';
 import 'package:flutter/material.dart';
 
-import '../../../config/app_colors.dart';
+import 'package:scrobbles/config/app_colors.dart';
 
 class CustomLineChart extends StatelessWidget {
   CustomLineChart({super.key});
 
+  final Widget placeholder = Text('⏳');
   final double chartHeight = 150.0;
   final double titleFontSize = 10;
 
diff --git a/lib/ui/widgets/app_bar.dart b/lib/ui/widgets/app_bar.dart
index 3313e5967d296917875d853516a3bfcaa749f711..6db981e1ee2ba1a0c98cb52e6f5605586a6ff371 100644
--- a/lib/ui/widgets/app_bar.dart
+++ b/lib/ui/widgets/app_bar.dart
@@ -1,7 +1,7 @@
 import 'package:flutter/material.dart';
 import 'package:unicons/unicons.dart';
 
-import '../widgets/header.dart';
+import 'package:scrobbles/ui/widgets/header_app.dart';
 
 class StandardAppBar extends StatelessWidget implements PreferredSizeWidget {
   final Function() notifyParent;
@@ -11,7 +11,7 @@ class StandardAppBar extends StatelessWidget implements PreferredSizeWidget {
   @override
   Widget build(BuildContext context) {
     return AppBar(
-      title: const Header(text: 'app_name'),
+      title: const AppHeader(text: 'app_name'),
       actions: [
         IconButton(
           onPressed: () {
diff --git a/lib/ui/widgets/bottom_nav_bar.dart b/lib/ui/widgets/bottom_nav_bar.dart
index 02aa39a6ee1af8d7891ff29850ff13866db409fa..3d2fb30aef2cad40d0b7170087e45749bbb45d09 100644
--- a/lib/ui/widgets/bottom_nav_bar.dart
+++ b/lib/ui/widgets/bottom_nav_bar.dart
@@ -3,7 +3,7 @@ import 'package:flutter/material.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
 import 'package:ionicons/ionicons.dart';
 
-import '../../cubit/bottom_nav_cubit.dart';
+import 'package:scrobbles/cubit/bottom_nav_cubit.dart';
 
 class BottomNavBar extends StatelessWidget {
   const BottomNavBar({super.key});
diff --git a/lib/ui/widgets/card_content.dart b/lib/ui/widgets/card_content.dart
new file mode 100644
index 0000000000000000000000000000000000000000..26944757b9a9508c72dd25632952485cda5be510
--- /dev/null
+++ b/lib/ui/widgets/card_content.dart
@@ -0,0 +1,43 @@
+import 'package:flutter/material.dart';
+
+class CardContent extends StatelessWidget {
+  const CardContent({
+    super.key,
+    required this.title,
+    required this.color,
+    required this.content,
+  });
+
+  final String title;
+  final Color color;
+  final Widget content;
+
+  @override
+  Widget build(BuildContext context) {
+    return Card(
+      elevation: 2,
+      shadowColor: Theme.of(context).colorScheme.shadow,
+      color: this.color,
+      shape: const RoundedRectangleBorder(
+        borderRadius: BorderRadius.all(
+          Radius.circular(8),
+        ),
+      ),
+      child: Padding(
+        padding: const EdgeInsets.all(8.0),
+        child: Column(
+          mainAxisSize: MainAxisSize.min,
+          crossAxisAlignment: CrossAxisAlignment.start,
+          children: <Widget>[
+            Text(
+              this.title,
+              style: Theme.of(context).primaryTextTheme.titleLarge!.apply(fontWeightDelta: 2),
+            ),
+            const SizedBox(height: 8),
+            this.content,
+          ],
+        ),
+      ),
+    );
+  }
+}
diff --git a/lib/ui/widgets/cards/counts_by_day.dart b/lib/ui/widgets/cards/counts_by_day.dart
new file mode 100644
index 0000000000000000000000000000000000000000..59d80cbad962cb17e27ddef50dbfd5fc44d5a718
--- /dev/null
+++ b/lib/ui/widgets/cards/counts_by_day.dart
@@ -0,0 +1,44 @@
+import 'dart:convert';
+
+import 'package:easy_localization/easy_localization.dart';
+import 'package:flutter/material.dart';
+
+import 'package:scrobbles/models/counts_by_day.dart';
+import 'package:scrobbles/network/scrobbles.dart';
+import 'package:scrobbles/ui/widgets/card_content.dart';
+import 'package:scrobbles/ui/widgets/charts/counts_by_day.dart';
+import 'package:scrobbles/ui/widgets/error.dart';
+
+class CardCountsByDay extends StatelessWidget {
+  const CardCountsByDay({super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    final int daysCount = 21;
+    late Future<CountsByDayData> future = ScrobblesApi.fetchCountsByDay(daysCount);
+
+    return FutureBuilder<CountsByDayData>(
+      future: future,
+      builder: (context, snapshot) {
+        if (snapshot.hasError) {
+          return ShowErrorWidget(message: '${snapshot.error}');
+        }
+
+        return CardContent(
+          color: Theme.of(context).colorScheme.surface,
+          title: 'counts_by_day'.tr(
+            namedArgs: {
+              'daysCount': daysCount.toString(),
+            },
+          ),
+          content: ChartCountsByDay(
+            chartData: snapshot.hasData
+                ? CountsByDayData.fromJson(jsonDecode(snapshot.data.toString()))
+                : CountsByDayData.createEmpty(),
+            isLoading: !snapshot.hasData,
+          ),
+        );
+      },
+    );
+  }
+}
diff --git a/lib/ui/widgets/cards/counts_by_hour.dart b/lib/ui/widgets/cards/counts_by_hour.dart
new file mode 100644
index 0000000000000000000000000000000000000000..6c0d91f615dea75d57ecedd23ef85feaad4e6ee2
--- /dev/null
+++ b/lib/ui/widgets/cards/counts_by_hour.dart
@@ -0,0 +1,44 @@
+import 'dart:convert';
+
+import 'package:easy_localization/easy_localization.dart';
+import 'package:flutter/material.dart';
+
+import 'package:scrobbles/models/counts_by_hour.dart';
+import 'package:scrobbles/network/scrobbles.dart';
+import 'package:scrobbles/ui/widgets/card_content.dart';
+import 'package:scrobbles/ui/widgets/charts/counts_by_hour.dart';
+import 'package:scrobbles/ui/widgets/error.dart';
+
+class CardCountsByHour extends StatelessWidget {
+  const CardCountsByHour({super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    final int daysCount = 21;
+    late Future<CountsByHourData> future = ScrobblesApi.fetchCountsByHour(daysCount);
+
+    return FutureBuilder<CountsByHourData>(
+      future: future,
+      builder: (context, snapshot) {
+        if (snapshot.hasError) {
+          return ShowErrorWidget(message: '${snapshot.error}');
+        }
+
+        return CardContent(
+          color: Theme.of(context).colorScheme.surface,
+          title: 'counts_by_hour'.tr(
+            namedArgs: {
+              'daysCount': daysCount.toString(),
+            },
+          ),
+          content: ChartCountsByHour(
+            chartData: snapshot.hasData
+                ? CountsByHourData.fromJson(jsonDecode(snapshot.data.toString()))
+                : CountsByHourData.createEmpty(),
+            isLoading: !snapshot.hasData,
+          ),
+        );
+      },
+    );
+  }
+}
diff --git a/lib/ui/widgets/cards/discoveries.dart b/lib/ui/widgets/cards/discoveries.dart
new file mode 100644
index 0000000000000000000000000000000000000000..f0cd96d77d3486b895001617f8c02052b81a7d9f
--- /dev/null
+++ b/lib/ui/widgets/cards/discoveries.dart
@@ -0,0 +1,66 @@
+import 'dart:convert';
+
+import 'package:easy_localization/easy_localization.dart';
+import 'package:flutter/material.dart';
+
+import 'package:scrobbles/models/discoveries.dart';
+import 'package:scrobbles/network/scrobbles.dart';
+import 'package:scrobbles/ui/widgets/card_content.dart';
+import 'package:scrobbles/ui/widgets/charts/discoveries_artists.dart';
+import 'package:scrobbles/ui/widgets/charts/discoveries_tracks.dart';
+import 'package:scrobbles/ui/widgets/error.dart';
+
+class CardDiscoveries extends StatelessWidget {
+  const CardDiscoveries({super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    final int daysCount = 14;
+    late Future<DiscoveriesData> future = ScrobblesApi.fetchDiscoveries(daysCount);
+
+    return FutureBuilder<DiscoveriesData>(
+      future: future,
+      builder: (context, snapshot) {
+        if (snapshot.hasError) {
+          return ShowErrorWidget(message: '${snapshot.error}');
+        }
+
+        final TextTheme textTheme = Theme.of(context).primaryTextTheme;
+
+        return CardContent(
+          color: Theme.of(context).colorScheme.surface,
+          title: 'discoveries_title'.tr(
+            namedArgs: {
+              'daysCount': daysCount.toString(),
+            },
+          ),
+          content: Column(
+            mainAxisSize: MainAxisSize.min,
+            crossAxisAlignment: CrossAxisAlignment.start,
+            children: [
+              Text(
+                'discoveries_artists_title',
+                style: textTheme.titleMedium!.apply(fontWeightDelta: 2),
+              ).tr(),
+              const SizedBox(height: 8),
+              ChartDiscoveriesArtists(
+                chartData: DiscoveriesData.fromJson(jsonDecode(snapshot.data.toString())),
+                isLoading: !snapshot.hasData,
+              ),
+              const SizedBox(height: 8),
+              Text(
+                'discoveries_tracks_title',
+                style: textTheme.titleMedium!.apply(fontWeightDelta: 2),
+              ).tr(),
+              const SizedBox(height: 8),
+              ChartDiscoveriesTracks(
+                chartData: DiscoveriesData.fromJson(jsonDecode(snapshot.data.toString())),
+                isLoading: !snapshot.hasData,
+              ),
+            ],
+          ),
+        );
+      },
+    );
+  }
+}
diff --git a/lib/ui/widgets/cards/statistics_global.dart b/lib/ui/widgets/cards/statistics_global.dart
new file mode 100644
index 0000000000000000000000000000000000000000..0d8feb802d1f440b600e925322d64c813c9233d7
--- /dev/null
+++ b/lib/ui/widgets/cards/statistics_global.dart
@@ -0,0 +1,39 @@
+import 'dart:convert';
+
+import 'package:easy_localization/easy_localization.dart';
+import 'package:flutter/material.dart';
+
+import 'package:scrobbles/models/statistics_global.dart';
+import 'package:scrobbles/network/scrobbles.dart';
+import 'package:scrobbles/ui/widgets/card_content.dart';
+import 'package:scrobbles/ui/widgets/content/statistics_global.dart';
+import 'package:scrobbles/ui/widgets/error.dart';
+
+class CardStatisticsGlobal extends StatelessWidget {
+  const CardStatisticsGlobal({super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    late Future<StatisticsGlobalData> future = ScrobblesApi.fetchGlobalStatistics();
+
+    return FutureBuilder<StatisticsGlobalData>(
+      future: future,
+      builder: (context, snapshot) {
+        if (snapshot.hasError) {
+          return ShowErrorWidget(message: '${snapshot.error}');
+        }
+
+        return CardContent(
+          color: Theme.of(context).colorScheme.primary,
+          title: 'global_statistics'.tr(),
+          content: ContentStatisticsGlobal(
+            statistics: snapshot.hasData
+                ? StatisticsGlobalData.fromJson(jsonDecode(snapshot.data.toString()))
+                : StatisticsGlobalData.createEmpty(),
+            isLoading: !snapshot.hasData,
+          ),
+        );
+      },
+    );
+  }
+}
diff --git a/lib/ui/widgets/cards/statistics_recent.dart b/lib/ui/widgets/cards/statistics_recent.dart
new file mode 100644
index 0000000000000000000000000000000000000000..0925c42fc4f50c4b1cc048681148749ba3d0dfee
--- /dev/null
+++ b/lib/ui/widgets/cards/statistics_recent.dart
@@ -0,0 +1,45 @@
+import 'dart:convert';
+
+import 'package:easy_localization/easy_localization.dart';
+import 'package:flutter/material.dart';
+
+import 'package:scrobbles/models/statistics_recent.dart';
+import 'package:scrobbles/network/scrobbles.dart';
+import 'package:scrobbles/ui/widgets/card_content.dart';
+import 'package:scrobbles/ui/widgets/content/statistics_recent.dart';
+import 'package:scrobbles/ui/widgets/error.dart';
+
+class CardStatisticsRecent extends StatelessWidget {
+  const CardStatisticsRecent({super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    final int daysCount = 21;
+
+    late Future<StatisticsRecentData> future = ScrobblesApi.fetchRecentStatistics(daysCount);
+
+    return FutureBuilder<StatisticsRecentData>(
+      future: future,
+      builder: (context, snapshot) {
+        if (snapshot.hasError) {
+          return ShowErrorWidget(message: '${snapshot.error}');
+        }
+
+        return CardContent(
+          color: Theme.of(context).colorScheme.primary,
+          title: 'recent_statistics'.tr(
+            namedArgs: {
+              'daysCount': daysCount.toString(),
+            },
+          ),
+          content: ContentStatisticsRecent(
+            statistics: snapshot.hasData
+                ? StatisticsRecentData.fromJson(jsonDecode(snapshot.data.toString()))
+                : StatisticsRecentData.createEmpty(),
+            isLoading: !snapshot.hasData,
+          ),
+        );
+      },
+    );
+  }
+}
diff --git a/lib/ui/widgets/cards/timeline.dart b/lib/ui/widgets/cards/timeline.dart
new file mode 100644
index 0000000000000000000000000000000000000000..a7ea95df17ed99169f442080cae763e0ecfbe68e
--- /dev/null
+++ b/lib/ui/widgets/cards/timeline.dart
@@ -0,0 +1,51 @@
+import 'dart:convert';
+
+import 'package:easy_localization/easy_localization.dart';
+import 'package:flutter/material.dart';
+
+import 'package:scrobbles/models/timeline.dart';
+import 'package:scrobbles/network/scrobbles.dart';
+import 'package:scrobbles/ui/widgets/card_content.dart';
+import 'package:scrobbles/ui/widgets/charts/timeline_counts.dart';
+import 'package:scrobbles/ui/widgets/charts/timeline_eclecticism.dart';
+import 'package:scrobbles/ui/widgets/error.dart';
+
+class CardTimeline extends StatelessWidget {
+  const CardTimeline({super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    final int daysCount = 14;
+    late Future<TimelineData> future = ScrobblesApi.fetchTimeline(daysCount);
+
+    return FutureBuilder<TimelineData>(
+      future: future,
+      builder: (context, snapshot) {
+        if (snapshot.hasError) {
+          return ShowErrorWidget(message: '${snapshot.error}');
+        }
+
+        return CardContent(
+          color: Theme.of(context).colorScheme.surface,
+          title: 'timeline_title'.tr(
+            namedArgs: {
+              'daysCount': daysCount.toString(),
+            },
+          ),
+          content: Stack(
+            children: [
+              ChartTimelineCounts(
+                chartData: TimelineData.fromJson(jsonDecode(snapshot.data.toString())),
+                isLoading: !snapshot.hasData,
+              ),
+              ChartTimelineEclecticism(
+                chartData: TimelineData.fromJson(jsonDecode(snapshot.data.toString())),
+                isLoading: !snapshot.hasData,
+              ),
+            ],
+          ),
+        );
+      },
+    );
+  }
+}
diff --git a/lib/ui/widgets/cards/top_artists.dart b/lib/ui/widgets/cards/top_artists.dart
new file mode 100644
index 0000000000000000000000000000000000000000..d5895181a75d9d6cc1a27ccb8b5b5f5be5e36a02
--- /dev/null
+++ b/lib/ui/widgets/cards/top_artists.dart
@@ -0,0 +1,44 @@
+import 'dart:convert';
+
+import 'package:easy_localization/easy_localization.dart';
+import 'package:flutter/material.dart';
+
+import 'package:scrobbles/models/topartists.dart';
+import 'package:scrobbles/network/scrobbles.dart';
+import 'package:scrobbles/ui/widgets/card_content.dart';
+import 'package:scrobbles/ui/widgets/charts/top_artists.dart';
+import 'package:scrobbles/ui/widgets/error.dart';
+
+class CardTopArtists extends StatelessWidget {
+  const CardTopArtists({super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    final int daysCount = 14;
+    late Future<TopArtistsData> future = ScrobblesApi.fetchTopArtists(daysCount);
+
+    return FutureBuilder<TopArtistsData>(
+      future: future,
+      builder: (context, snapshot) {
+        if (snapshot.hasError) {
+          return ShowErrorWidget(message: '${snapshot.error}');
+        }
+
+        return CardContent(
+          color: Theme.of(context).colorScheme.surface,
+          title: 'top_artists_title'.tr(
+            namedArgs: {
+              'daysCount': daysCount.toString(),
+            },
+          ),
+          content: ChartTopArtists(
+            chartData: snapshot.hasData
+                ? TopArtistsData.fromJson(jsonDecode(snapshot.data.toString()))
+                : TopArtistsData.createEmpty(),
+            isLoading: !snapshot.hasData,
+          ),
+        );
+      },
+    );
+  }
+}
diff --git a/lib/ui/widgets/main_screen/counts_by_day_chart.dart b/lib/ui/widgets/charts/counts_by_day.dart
similarity index 76%
rename from lib/ui/widgets/main_screen/counts_by_day_chart.dart
rename to lib/ui/widgets/charts/counts_by_day.dart
index 360dcc16406f687b4d4b179c34d6999a54189f78..19492b4a201c9d5b25aa90c6b89c3921c6fa2b28 100644
--- a/lib/ui/widgets/main_screen/counts_by_day_chart.dart
+++ b/lib/ui/widgets/charts/counts_by_day.dart
@@ -2,14 +2,15 @@ import 'package:easy_localization/easy_localization.dart';
 import 'package:flutter/material.dart';
 import 'package:fl_chart/fl_chart.dart';
 
-import '../../../config/app_colors.dart';
-import '../../../models/counts_by_day.dart';
-import '../../../ui/widgets/charts/custom_bar_chart.dart';
+import 'package:scrobbles/config/app_colors.dart';
+import 'package:scrobbles/models/counts_by_day.dart';
+import 'package:scrobbles/ui/widgets/abstracts/custom_bar_chart.dart';
 
-class CountsByDayCardContentChart extends CustomBarChart {
+class ChartCountsByDay extends CustomBarChart {
   final CountsByDayData chartData;
+  final bool isLoading;
 
-  CountsByDayCardContentChart({super.key, required this.chartData});
+  ChartCountsByDay({super.key, required this.chartData, required this.isLoading});
 
   final double verticalTicksInterval = 5;
   final String verticalAxisTitleSuffix = '%';
@@ -18,12 +19,19 @@ class CountsByDayCardContentChart extends CustomBarChart {
   Widget build(BuildContext context) {
     return Container(
       height: this.chartHeight,
-      child: LayoutBuilder(builder: (context, constraints) {
-        return getBarChart(
-          barWidth: this.getBarWidth(constraints.maxWidth, this.chartData.data.keys.length),
-          backgroundColor: Theme.of(context).colorScheme.onSurface,
-        );
-      }),
+      child: this.isLoading
+          ? this.placeholder
+          : LayoutBuilder(
+              builder: (context, constraints) {
+                final double maxWidth = constraints.maxWidth;
+                final int barsCount = this.chartData.data.keys.length;
+
+                return getBarChart(
+                  barWidth: this.getBarWidth(maxWidth, barsCount),
+                  backgroundColor: Theme.of(context).colorScheme.onSurface,
+                );
+              },
+            ),
     );
   }
 
diff --git a/lib/ui/widgets/main_screen/counts_by_hour_chart.dart b/lib/ui/widgets/charts/counts_by_hour.dart
similarity index 63%
rename from lib/ui/widgets/main_screen/counts_by_hour_chart.dart
rename to lib/ui/widgets/charts/counts_by_hour.dart
index ec5766a96a978a05b31baeafddde8527d5a456a5..79c8167f87e2ff45e96c14cfd10743a88e4d79ff 100644
--- a/lib/ui/widgets/main_screen/counts_by_hour_chart.dart
+++ b/lib/ui/widgets/charts/counts_by_hour.dart
@@ -1,15 +1,16 @@
 import 'package:flutter/material.dart';
 import 'package:fl_chart/fl_chart.dart';
 
-import '../../../config/app_colors.dart';
-import '../../../models/counts_by_hour.dart';
-import '../../../ui/widgets/charts/custom_bar_chart.dart';
-import '../../../utils/color_extensions.dart';
+import 'package:scrobbles/config/app_colors.dart';
+import 'package:scrobbles/models/counts_by_hour.dart';
+import 'package:scrobbles/ui/widgets/abstracts/custom_bar_chart.dart';
+import 'package:scrobbles/utils/color_extensions.dart';
 
-class CountsByHourCardContentChart extends CustomBarChart {
+class ChartCountsByHour extends CustomBarChart {
   final CountsByHourData chartData;
+  final bool isLoading;
 
-  CountsByHourCardContentChart({super.key, required this.chartData});
+  ChartCountsByHour({super.key, required this.chartData, required this.isLoading});
 
   final double verticalTicksInterval = 5;
   final String verticalAxisTitleSuffix = '%';
@@ -18,12 +19,19 @@ class CountsByHourCardContentChart extends CustomBarChart {
   Widget build(BuildContext context) {
     return Container(
       height: this.chartHeight,
-      child: LayoutBuilder(builder: (context, constraints) {
-        return getBarChart(
-          barWidth: this.getBarWidth(constraints.maxWidth, this.chartData.data.keys.length),
-          backgroundColor: Theme.of(context).colorScheme.onSurface,
-        );
-      }),
+      child: this.isLoading
+          ? this.placeholder
+          : LayoutBuilder(
+              builder: (context, constraints) {
+                final double maxWidth = constraints.maxWidth;
+                final int barsCount = this.chartData.data.keys.length;
+
+                return getBarChart(
+                  barWidth: this.getBarWidth(maxWidth, barsCount),
+                  backgroundColor: Theme.of(context).colorScheme.onSurface,
+                );
+              },
+            ),
     );
   }
 
diff --git a/lib/ui/widgets/main_screen/discoveries_chart_artists.dart b/lib/ui/widgets/charts/discoveries_artists.dart
similarity index 61%
rename from lib/ui/widgets/main_screen/discoveries_chart_artists.dart
rename to lib/ui/widgets/charts/discoveries_artists.dart
index eb76c31397de32750c029a150efef7cb24e36e30..d441c275cf80edbc67a28fd60eb95de7f525a044 100644
--- a/lib/ui/widgets/main_screen/discoveries_chart_artists.dart
+++ b/lib/ui/widgets/charts/discoveries_artists.dart
@@ -1,26 +1,34 @@
 import 'package:flutter/material.dart';
 import 'package:fl_chart/fl_chart.dart';
 
-import '../../../config/app_colors.dart';
-import '../../../models/discoveries.dart';
-import '../../../utils/color_extensions.dart';
-import '../../../ui/widgets/charts/custom_bar_chart.dart';
+import 'package:scrobbles/config/app_colors.dart';
+import 'package:scrobbles/models/discoveries.dart';
+import 'package:scrobbles/ui/widgets/abstracts/custom_bar_chart.dart';
+import 'package:scrobbles/utils/color_extensions.dart';
 
 class ChartDiscoveriesArtists extends CustomBarChart {
   final DiscoveriesData chartData;
+  final bool isLoading;
 
-  ChartDiscoveriesArtists({super.key, required this.chartData});
+  ChartDiscoveriesArtists({super.key, required this.chartData, required this.isLoading});
 
   @override
   Widget build(BuildContext context) {
     return Container(
       height: this.chartHeight,
-      child: LayoutBuilder(builder: (context, constraints) {
-        return getBarChart(
-          barWidth: this.getBarWidth(constraints.maxWidth, this.chartData.data.keys.length),
-          backgroundColor: Theme.of(context).colorScheme.onSurface,
-        );
-      }),
+      child: this.isLoading
+          ? this.placeholder
+          : LayoutBuilder(
+              builder: (context, constraints) {
+                final double maxWidth = constraints.maxWidth;
+                final int barsCount = this.chartData.data.keys.length;
+
+                return getBarChart(
+                  barWidth: this.getBarWidth(maxWidth, barsCount),
+                  backgroundColor: Theme.of(context).colorScheme.onSurface,
+                );
+              },
+            ),
     );
   }
 
diff --git a/lib/ui/widgets/main_screen/discoveries_chart_tracks.dart b/lib/ui/widgets/charts/discoveries_tracks.dart
similarity index 61%
rename from lib/ui/widgets/main_screen/discoveries_chart_tracks.dart
rename to lib/ui/widgets/charts/discoveries_tracks.dart
index 622911d660fb4632236f1e096bee45a111cdf898..343c02d29f62b7691d6167773f1465c8d2be27d7 100644
--- a/lib/ui/widgets/main_screen/discoveries_chart_tracks.dart
+++ b/lib/ui/widgets/charts/discoveries_tracks.dart
@@ -1,26 +1,34 @@
 import 'package:flutter/material.dart';
 import 'package:fl_chart/fl_chart.dart';
 
-import '../../../config/app_colors.dart';
-import '../../../models/discoveries.dart';
-import '../../../utils/color_extensions.dart';
-import '../../../ui/widgets/charts/custom_bar_chart.dart';
+import 'package:scrobbles/config/app_colors.dart';
+import 'package:scrobbles/models/discoveries.dart';
+import 'package:scrobbles/ui/widgets/abstracts/custom_bar_chart.dart';
+import 'package:scrobbles/utils/color_extensions.dart';
 
 class ChartDiscoveriesTracks extends CustomBarChart {
   final DiscoveriesData chartData;
+  final bool isLoading;
 
-  ChartDiscoveriesTracks({super.key, required this.chartData});
+  ChartDiscoveriesTracks({super.key, required this.chartData, required this.isLoading});
 
   @override
   Widget build(BuildContext context) {
     return Container(
       height: this.chartHeight,
-      child: LayoutBuilder(builder: (context, constraints) {
-        return getBarChart(
-          barWidth: this.getBarWidth(constraints.maxWidth, this.chartData.data.keys.length),
-          backgroundColor: Theme.of(context).colorScheme.onSurface,
-        );
-      }),
+      child: this.isLoading
+          ? this.placeholder
+          : LayoutBuilder(
+              builder: (context, constraints) {
+                final double maxWidth = constraints.maxWidth;
+                final int barsCount = this.chartData.data.keys.length;
+
+                return getBarChart(
+                  barWidth: this.getBarWidth(maxWidth, barsCount),
+                  backgroundColor: Theme.of(context).colorScheme.onSurface,
+                );
+              },
+            ),
     );
   }
 
diff --git a/lib/ui/widgets/main_screen/timeline_chart_counts.dart b/lib/ui/widgets/charts/timeline_counts.dart
similarity index 62%
rename from lib/ui/widgets/main_screen/timeline_chart_counts.dart
rename to lib/ui/widgets/charts/timeline_counts.dart
index bdfa0c575b3785bd8e2fe0930ebe927d45532f73..8e5fec0b82c53f51065acb6e55fe813fab104a3f 100644
--- a/lib/ui/widgets/main_screen/timeline_chart_counts.dart
+++ b/lib/ui/widgets/charts/timeline_counts.dart
@@ -1,14 +1,15 @@
 import 'package:flutter/material.dart';
 import 'package:fl_chart/fl_chart.dart';
 
-import '../../../config/app_colors.dart';
-import '../../../models/timeline.dart';
-import '../../../ui/widgets/charts/custom_bar_chart.dart';
+import 'package:scrobbles/config/app_colors.dart';
+import 'package:scrobbles/models/timeline.dart';
+import 'package:scrobbles/ui/widgets/abstracts/custom_bar_chart.dart';
 
 class ChartTimelineCounts extends CustomBarChart {
   final TimelineData chartData;
+  final bool isLoading;
 
-  ChartTimelineCounts({super.key, required this.chartData});
+  ChartTimelineCounts({super.key, required this.chartData, required this.isLoading});
 
   final double verticalTicksInterval = 50;
 
@@ -16,12 +17,19 @@ class ChartTimelineCounts extends CustomBarChart {
   Widget build(BuildContext context) {
     return Container(
       height: this.chartHeight,
-      child: LayoutBuilder(builder: (context, constraints) {
-        return getBarChart(
-          barWidth: this.getBarWidth(constraints.maxWidth, this.chartData.data.keys.length),
-          backgroundColor: Theme.of(context).colorScheme.onSurface,
-        );
-      }),
+      child: this.isLoading
+          ? this.placeholder
+          : LayoutBuilder(
+              builder: (context, constraints) {
+                final double maxWidth = constraints.maxWidth;
+                final int barsCount = this.chartData.data.keys.length;
+
+                return getBarChart(
+                  barWidth: this.getBarWidth(maxWidth, barsCount),
+                  backgroundColor: Theme.of(context).colorScheme.onSurface,
+                );
+              },
+            ),
     );
   }
 
diff --git a/lib/ui/widgets/main_screen/timeline_chart_eclecticism.dart b/lib/ui/widgets/charts/timeline_eclecticism.dart
similarity index 66%
rename from lib/ui/widgets/main_screen/timeline_chart_eclecticism.dart
rename to lib/ui/widgets/charts/timeline_eclecticism.dart
index 71e358e478067c805203df528b190593e12e67c0..f5ddd96261d04c600a75e6516991a6fa51f40a70 100644
--- a/lib/ui/widgets/main_screen/timeline_chart_eclecticism.dart
+++ b/lib/ui/widgets/charts/timeline_eclecticism.dart
@@ -1,15 +1,16 @@
 import 'package:flutter/material.dart';
 import 'package:fl_chart/fl_chart.dart';
 
-import '../../../config/app_colors.dart';
-import '../../../models/timeline.dart';
-import '../../../ui/widgets/charts/custom_line_chart.dart';
-import '../../../utils/color_extensions.dart';
+import 'package:scrobbles/config/app_colors.dart';
+import 'package:scrobbles/models/timeline.dart';
+import 'package:scrobbles/ui/widgets/abstracts/custom_line_chart.dart';
+import 'package:scrobbles/utils/color_extensions.dart';
 
 class ChartTimelineEclecticism extends CustomLineChart {
   final TimelineData chartData;
+  final bool isLoading;
 
-  ChartTimelineEclecticism({super.key, required this.chartData});
+  ChartTimelineEclecticism({super.key, required this.chartData, required this.isLoading});
 
   @override
   Widget build(BuildContext context) {
@@ -17,20 +18,22 @@ class ChartTimelineEclecticism extends CustomLineChart {
 
     return Container(
       height: this.chartHeight,
-      child: LineChart(
-        LineChartData(
-          lineBarsData: getDataEclecticism(),
-          borderData: getBorderData(),
-          gridData: getGridData(),
-          titlesData: getTitlesData(),
-          lineTouchData: const LineTouchData(enabled: false),
-          minX: horizontalScale['min'],
-          maxX: horizontalScale['max'],
-          maxY: 100,
-          minY: 0,
-        ),
-        duration: const Duration(milliseconds: 250),
-      ),
+      child: this.isLoading
+          ? this.placeholder
+          : LineChart(
+              LineChartData(
+                lineBarsData: getDataEclecticism(),
+                borderData: getBorderData(),
+                gridData: getGridData(),
+                titlesData: getTitlesData(),
+                lineTouchData: const LineTouchData(enabled: false),
+                minX: horizontalScale['min'],
+                maxX: horizontalScale['max'],
+                maxY: 100,
+                minY: 0,
+              ),
+              duration: const Duration(milliseconds: 250),
+            ),
     );
   }
 
diff --git a/lib/ui/widgets/main_screen/topartists_chart.dart b/lib/ui/widgets/charts/top_artists.dart
similarity index 71%
rename from lib/ui/widgets/main_screen/topartists_chart.dart
rename to lib/ui/widgets/charts/top_artists.dart
index 0a6bcd87d72b992e9e0341c8cc995eb96835f788..5b0de9c0b7508904d5684e96b3fe3b89269d0423 100644
--- a/lib/ui/widgets/main_screen/topartists_chart.dart
+++ b/lib/ui/widgets/charts/top_artists.dart
@@ -1,39 +1,44 @@
 import 'package:flutter/material.dart';
 import 'package:fl_chart/fl_chart.dart';
 
-import '../../../config/app_colors.dart';
-import '../../../models/topartists.dart';
-import '../../../utils/color_extensions.dart';
+import 'package:scrobbles/config/app_colors.dart';
+import 'package:scrobbles/models/topartists.dart';
+import 'package:scrobbles/utils/color_extensions.dart';
 
 class ChartTopArtists extends StatelessWidget {
   final TopArtistsData chartData;
+  final bool isLoading;
 
-  ChartTopArtists({super.key, required this.chartData});
+  ChartTopArtists({super.key, required this.chartData, required this.isLoading});
+
+  final Widget placeholder = Text('⏳');
 
   @override
   Widget build(BuildContext context) {
     return AspectRatio(
       aspectRatio: 2.1,
-      child: Row(
-        children: <Widget>[
-          Expanded(
-            child: AspectRatio(
-              aspectRatio: 1,
-              child: PieChart(
-                PieChartData(
-                  sections: getPieChartData(),
-                  sectionsSpace: 2,
-                  centerSpaceRadius: 40,
-                  startDegreeOffset: -45,
-                  pieTouchData: PieTouchData(enabled: false),
-                  borderData: FlBorderData(show: false),
+      child: this.isLoading
+          ? this.placeholder
+          : Row(
+              children: <Widget>[
+                Expanded(
+                  child: AspectRatio(
+                    aspectRatio: 1,
+                    child: PieChart(
+                      PieChartData(
+                        sections: getPieChartData(),
+                        sectionsSpace: 2,
+                        centerSpaceRadius: 40,
+                        startDegreeOffset: -45,
+                        pieTouchData: PieTouchData(enabled: false),
+                        borderData: FlBorderData(show: false),
+                      ),
+                    ),
+                  ),
                 ),
-              ),
+                buildLegendWidget(),
+              ],
             ),
-          ),
-          buildLegendWidget(),
-        ],
-      ),
     );
   }
 
diff --git a/lib/ui/widgets/main_screen/statistics_global_content.dart b/lib/ui/widgets/content/statistics_global.dart
similarity index 77%
rename from lib/ui/widgets/main_screen/statistics_global_content.dart
rename to lib/ui/widgets/content/statistics_global.dart
index 4459347a97511be5e656be7bc026d81dbfef2b93..d1714413244128c4c9882458fb08db6d4e57509b 100644
--- a/lib/ui/widgets/main_screen/statistics_global_content.dart
+++ b/lib/ui/widgets/content/statistics_global.dart
@@ -1,29 +1,24 @@
 import 'package:easy_localization/easy_localization.dart';
 import 'package:flutter/material.dart';
 
-import '../../../models/statistics_global.dart';
+import 'package:scrobbles/models/statistics_global.dart';
 
-class StatisticsGlobalContent extends StatelessWidget {
+class ContentStatisticsGlobal extends StatelessWidget {
   final StatisticsGlobalData statistics;
   final bool isLoading;
 
-  const StatisticsGlobalContent(
+  const ContentStatisticsGlobal(
       {super.key, required this.statistics, required this.isLoading});
 
   @override
   Widget build(BuildContext context) {
     final TextTheme textTheme = Theme.of(context).primaryTextTheme;
-
-    final String placeholder = '⏳';
+    const String placeholder = '⏳';
 
     return Column(
       mainAxisSize: MainAxisSize.min,
       crossAxisAlignment: CrossAxisAlignment.start,
       children: <Widget>[
-        Text(
-          'global_statistics',
-          style: textTheme.titleLarge!.apply(fontWeightDelta: 2),
-        ).tr(),
         Text(
           'statistics_total_scrobbles_count',
           style: textTheme.bodyMedium,
diff --git a/lib/ui/widgets/main_screen/statistics_recent_content.dart b/lib/ui/widgets/content/statistics_recent.dart
similarity index 64%
rename from lib/ui/widgets/main_screen/statistics_recent_content.dart
rename to lib/ui/widgets/content/statistics_recent.dart
index cd95b00e940d1d98ec8809e11b47003fccb02ff1..01f04aca04f52195a4c1b9b509210ac88d784a84 100644
--- a/lib/ui/widgets/main_screen/statistics_recent_content.dart
+++ b/lib/ui/widgets/content/statistics_recent.dart
@@ -1,38 +1,24 @@
 import 'package:easy_localization/easy_localization.dart';
 import 'package:flutter/material.dart';
 
-import '../../../models/statistics_recent.dart';
+import 'package:scrobbles/models/statistics_recent.dart';
 
-class StatisticsRecentContent extends StatelessWidget {
+class ContentStatisticsRecent extends StatelessWidget {
   final StatisticsRecentData statistics;
   final bool isLoading;
 
-  const StatisticsRecentContent(
+  const ContentStatisticsRecent(
       {super.key, required this.statistics, required this.isLoading});
 
   @override
   Widget build(BuildContext context) {
     final TextTheme textTheme = Theme.of(context).primaryTextTheme;
-
-    final String placeholder = '⏳';
+    const String placeholder = '⏳';
 
     return Column(
       mainAxisSize: MainAxisSize.min,
       crossAxisAlignment: CrossAxisAlignment.start,
       children: <Widget>[
-        Text(
-          'recent_statistics',
-          style: textTheme.titleLarge!.apply(fontWeightDelta: 2),
-        ).tr(),
-        Text(
-          'statistics_selected_period',
-          style: textTheme.bodyMedium!.apply(fontWeightDelta: 2),
-        ).tr(
-          namedArgs: {
-            'daysCount':
-                this.isLoading ? placeholder : this.statistics.selectedPeriod.toString(),
-          },
-        ),
         Text(
           'statistics_recent_scrobbles_count_and_discoveries',
           style: textTheme.bodyMedium,
diff --git a/lib/ui/widgets/header.dart b/lib/ui/widgets/header_app.dart
similarity index 78%
rename from lib/ui/widgets/header.dart
rename to lib/ui/widgets/header_app.dart
index 2187ef84a2dbad4dd0cfa7986bdb4473b0af0462..77b015bc6cb8712734f5383ca58cd818e0a51f0f 100644
--- a/lib/ui/widgets/header.dart
+++ b/lib/ui/widgets/header_app.dart
@@ -1,8 +1,8 @@
 import 'package:easy_localization/easy_localization.dart';
 import 'package:flutter/material.dart';
 
-class Header extends StatelessWidget {
-  const Header({super.key, required this.text});
+class AppHeader extends StatelessWidget {
+  const AppHeader({super.key, required this.text});
 
   final String text;
 
diff --git a/lib/ui/widgets/main_screen/counts_by_day_card.dart b/lib/ui/widgets/main_screen/counts_by_day_card.dart
deleted file mode 100644
index 7f46132a55df0a5de49633525d777d4dfa900ceb..0000000000000000000000000000000000000000
--- a/lib/ui/widgets/main_screen/counts_by_day_card.dart
+++ /dev/null
@@ -1,48 +0,0 @@
-import 'dart:convert';
-
-import 'package:flutter/material.dart';
-
-import '../../../models/counts_by_day.dart';
-import '../../../network/scrobbles_api.dart';
-import '../../../ui/widgets/error.dart';
-import '../../../ui/widgets/main_screen/counts_by_day_content.dart';
-
-class ChartCountsByDayCard extends StatelessWidget {
-  const ChartCountsByDayCard({super.key});
-
-  @override
-  Widget build(BuildContext context) {
-    final int daysCount = 21;
-    late Future<CountsByDayData> futureCountsByDay = ScrobblesApi.fetchCountsByDay(daysCount);
-
-    return FutureBuilder<CountsByDayData>(
-      future: futureCountsByDay,
-      builder: (context, snapshot) {
-        if (snapshot.hasError) {
-          return ShowErrorWidget(message: '${snapshot.error}');
-        }
-
-        return Card(
-          elevation: 2,
-          shadowColor: Theme.of(context).colorScheme.shadow,
-          color: Theme.of(context).colorScheme.surface,
-          shape: const RoundedRectangleBorder(
-            borderRadius: BorderRadius.all(
-              Radius.circular(8),
-            ),
-          ),
-          child: Padding(
-            padding: const EdgeInsets.all(8.0),
-            child: ChartCountsByDayCardContent(
-              daysCount: daysCount,
-              chartData: snapshot.hasData
-                  ? CountsByDayData.fromJson(jsonDecode(snapshot.data.toString()))
-                  : CountsByDayData.createEmpty(),
-              isLoading: !snapshot.hasData,
-            ),
-          ),
-        );
-      },
-    );
-  }
-}
diff --git a/lib/ui/widgets/main_screen/counts_by_day_content.dart b/lib/ui/widgets/main_screen/counts_by_day_content.dart
deleted file mode 100644
index 3e3196205964131e6f7d75fa73b74fcad3fb0b22..0000000000000000000000000000000000000000
--- a/lib/ui/widgets/main_screen/counts_by_day_content.dart
+++ /dev/null
@@ -1,43 +0,0 @@
-import 'dart:convert';
-
-import 'package:easy_localization/easy_localization.dart';
-import 'package:flutter/material.dart';
-
-import '../../../models/counts_by_day.dart';
-import '../../../ui/widgets/main_screen/counts_by_day_chart.dart';
-
-class ChartCountsByDayCardContent extends StatelessWidget {
-  final int daysCount;
-  final CountsByDayData chartData;
-  final bool isLoading;
-
-  const ChartCountsByDayCardContent(
-      {super.key, required this.daysCount, required this.chartData, required this.isLoading});
-
-  @override
-  Widget build(BuildContext context) {
-    final TextTheme textTheme = Theme.of(context).primaryTextTheme;
-    final String placeholder = '⏳';
-
-    return Column(
-      mainAxisSize: MainAxisSize.min,
-      crossAxisAlignment: CrossAxisAlignment.start,
-      children: <Widget>[
-        Text(
-          'counts_by_day',
-          style: textTheme.titleLarge!.apply(fontWeightDelta: 2),
-        ).tr(
-          namedArgs: {
-            'daysCount': this.daysCount.toString(),
-          },
-        ),
-        const SizedBox(height: 8),
-        this.isLoading
-            ? Text(placeholder)
-            : CountsByDayCardContentChart(
-                chartData: CountsByDayData.fromJson(jsonDecode(this.chartData.toString())),
-              ),
-      ],
-    );
-  }
-}
diff --git a/lib/ui/widgets/main_screen/counts_by_hour_card.dart b/lib/ui/widgets/main_screen/counts_by_hour_card.dart
deleted file mode 100644
index 8060aed27bcb37e41b52fa9261f3a535c5511957..0000000000000000000000000000000000000000
--- a/lib/ui/widgets/main_screen/counts_by_hour_card.dart
+++ /dev/null
@@ -1,49 +0,0 @@
-import 'dart:convert';
-
-import 'package:flutter/material.dart';
-
-import '../../../models/counts_by_hour.dart';
-import '../../../network/scrobbles_api.dart';
-import '../../../ui/widgets/error.dart';
-import '../../../ui/widgets/main_screen/counts_by_hour_content.dart';
-
-class ChartCountsByHourCard extends StatelessWidget {
-  const ChartCountsByHourCard({super.key});
-
-  @override
-  Widget build(BuildContext context) {
-    final int daysCount = 21;
-    late Future<CountsByHourData> futureCountsByHour =
-        ScrobblesApi.fetchCountsByHour(daysCount);
-
-    return FutureBuilder<CountsByHourData>(
-      future: futureCountsByHour,
-      builder: (context, snapshot) {
-        if (snapshot.hasError) {
-          return ShowErrorWidget(message: '${snapshot.error}');
-        }
-
-        return Card(
-          elevation: 2,
-          shadowColor: Theme.of(context).colorScheme.shadow,
-          color: Theme.of(context).colorScheme.surface,
-          shape: const RoundedRectangleBorder(
-            borderRadius: BorderRadius.all(
-              Radius.circular(8),
-            ),
-          ),
-          child: Padding(
-            padding: const EdgeInsets.all(8.0),
-            child: ChartCountsByHourCardContent(
-              daysCount: daysCount,
-              chartData: snapshot.hasData
-                  ? CountsByHourData.fromJson(jsonDecode(snapshot.data.toString()))
-                  : CountsByHourData.createEmpty(),
-              isLoading: !snapshot.hasData,
-            ),
-          ),
-        );
-      },
-    );
-  }
-}
diff --git a/lib/ui/widgets/main_screen/counts_by_hour_content.dart b/lib/ui/widgets/main_screen/counts_by_hour_content.dart
deleted file mode 100644
index d53c34fcd8a3f0ecd994296d559564bbb63df351..0000000000000000000000000000000000000000
--- a/lib/ui/widgets/main_screen/counts_by_hour_content.dart
+++ /dev/null
@@ -1,43 +0,0 @@
-import 'dart:convert';
-
-import 'package:easy_localization/easy_localization.dart';
-import 'package:flutter/material.dart';
-
-import '../../../models/counts_by_hour.dart';
-import '../../../ui/widgets/main_screen/counts_by_hour_chart.dart';
-
-class ChartCountsByHourCardContent extends StatelessWidget {
-  final int daysCount;
-  final CountsByHourData chartData;
-  final bool isLoading;
-
-  const ChartCountsByHourCardContent(
-      {super.key, required this.daysCount, required this.chartData, required this.isLoading});
-
-  @override
-  Widget build(BuildContext context) {
-    final TextTheme textTheme = Theme.of(context).primaryTextTheme;
-    final String placeholder = '⏳';
-
-    return Column(
-      mainAxisSize: MainAxisSize.min,
-      crossAxisAlignment: CrossAxisAlignment.start,
-      children: <Widget>[
-        Text(
-          'counts_by_hour',
-          style: textTheme.titleLarge!.apply(fontWeightDelta: 2),
-        ).tr(
-          namedArgs: {
-            'daysCount': this.daysCount.toString(),
-          },
-        ),
-        const SizedBox(height: 8),
-        this.isLoading
-            ? Text(placeholder)
-            : CountsByHourCardContentChart(
-                chartData: CountsByHourData.fromJson(jsonDecode(this.chartData.toString())),
-              ),
-      ],
-    );
-  }
-}
diff --git a/lib/ui/widgets/main_screen/discoveries_card.dart b/lib/ui/widgets/main_screen/discoveries_card.dart
deleted file mode 100644
index 57f0d046398e94079a882f691c8edc3c9b0a27c7..0000000000000000000000000000000000000000
--- a/lib/ui/widgets/main_screen/discoveries_card.dart
+++ /dev/null
@@ -1,61 +0,0 @@
-import 'dart:convert';
-
-import 'package:flutter/material.dart';
-
-import '../../../models/discoveries.dart';
-import '../../../network/scrobbles_api.dart';
-import '../../../ui/widgets/error.dart';
-import 'discoveries_content_artists.dart';
-import 'discoveries_content_tracks.dart';
-
-class ChartDiscoveriesCard extends StatelessWidget {
-  const ChartDiscoveriesCard({super.key});
-
-  @override
-  Widget build(BuildContext context) {
-    final int daysCount = 14;
-    late Future<DiscoveriesData> futureTimeline = ScrobblesApi.fetchDiscoveries(daysCount);
-
-    return FutureBuilder<DiscoveriesData>(
-      future: futureTimeline,
-      builder: (context, snapshot) {
-        if (snapshot.hasError) {
-          return ShowErrorWidget(message: '${snapshot.error}');
-        }
-
-        return Card(
-          elevation: 2,
-          shadowColor: Theme.of(context).colorScheme.shadow,
-          color: Theme.of(context).colorScheme.surface,
-          shape: const RoundedRectangleBorder(
-            borderRadius: BorderRadius.all(
-              Radius.circular(8),
-            ),
-          ),
-          child: Padding(
-            padding: const EdgeInsets.all(8.0),
-            child: Column(
-              children: [
-                ChartDiscoveriesArtistsCardContent(
-                  daysCount: daysCount,
-                  chartData: snapshot.hasData
-                      ? DiscoveriesData.fromJson(jsonDecode(snapshot.data.toString()))
-                      : DiscoveriesData.createEmpty(),
-                  isLoading: !snapshot.hasData,
-                ),
-                const SizedBox(height: 8),
-                ChartDiscoveriesTracksCardContent(
-                  daysCount: daysCount,
-                  chartData: snapshot.hasData
-                      ? DiscoveriesData.fromJson(jsonDecode(snapshot.data.toString()))
-                      : DiscoveriesData.createEmpty(),
-                  isLoading: !snapshot.hasData,
-                ),
-              ],
-            ),
-          ),
-        );
-      },
-    );
-  }
-}
diff --git a/lib/ui/widgets/main_screen/discoveries_content_artists.dart b/lib/ui/widgets/main_screen/discoveries_content_artists.dart
deleted file mode 100644
index b608e9dd2dffc1ecf6693f5803d164d40b20f2d9..0000000000000000000000000000000000000000
--- a/lib/ui/widgets/main_screen/discoveries_content_artists.dart
+++ /dev/null
@@ -1,43 +0,0 @@
-import 'dart:convert';
-
-import 'package:easy_localization/easy_localization.dart';
-import 'package:flutter/material.dart';
-
-import '../../../models/discoveries.dart';
-import 'discoveries_chart_artists.dart';
-
-class ChartDiscoveriesArtistsCardContent extends StatelessWidget {
-  final int daysCount;
-  final DiscoveriesData chartData;
-  final bool isLoading;
-
-  const ChartDiscoveriesArtistsCardContent(
-      {super.key, required this.daysCount, required this.chartData, required this.isLoading});
-
-  @override
-  Widget build(BuildContext context) {
-    final TextTheme textTheme = Theme.of(context).primaryTextTheme;
-    final String placeholder = '⏳';
-
-    return Column(
-      mainAxisSize: MainAxisSize.min,
-      crossAxisAlignment: CrossAxisAlignment.start,
-      children: <Widget>[
-        Text(
-          'discoveries_artists_title',
-          style: textTheme.titleLarge!.apply(fontWeightDelta: 2),
-        ).tr(
-          namedArgs: {
-            'daysCount': this.daysCount.toString(),
-          },
-        ),
-        const SizedBox(height: 8),
-        this.isLoading
-            ? Text(placeholder)
-            : ChartDiscoveriesArtists(
-                chartData: DiscoveriesData.fromJson(jsonDecode(this.chartData.toString())),
-              ),
-      ],
-    );
-  }
-}
diff --git a/lib/ui/widgets/main_screen/discoveries_content_tracks.dart b/lib/ui/widgets/main_screen/discoveries_content_tracks.dart
deleted file mode 100644
index 9ca8ff1f5137065662141cd8f479271eba929330..0000000000000000000000000000000000000000
--- a/lib/ui/widgets/main_screen/discoveries_content_tracks.dart
+++ /dev/null
@@ -1,43 +0,0 @@
-import 'dart:convert';
-
-import 'package:easy_localization/easy_localization.dart';
-import 'package:flutter/material.dart';
-
-import '../../../models/discoveries.dart';
-import 'discoveries_chart_tracks.dart';
-
-class ChartDiscoveriesTracksCardContent extends StatelessWidget {
-  final int daysCount;
-  final DiscoveriesData chartData;
-  final bool isLoading;
-
-  const ChartDiscoveriesTracksCardContent(
-      {super.key, required this.daysCount, required this.chartData, required this.isLoading});
-
-  @override
-  Widget build(BuildContext context) {
-    final TextTheme textTheme = Theme.of(context).primaryTextTheme;
-    final String placeholder = '⏳';
-
-    return Column(
-      mainAxisSize: MainAxisSize.min,
-      crossAxisAlignment: CrossAxisAlignment.start,
-      children: <Widget>[
-        Text(
-          'discoveries_tracks_title',
-          style: textTheme.titleLarge!.apply(fontWeightDelta: 2),
-        ).tr(
-          namedArgs: {
-            'daysCount': this.daysCount.toString(),
-          },
-        ),
-        const SizedBox(height: 8),
-        this.isLoading
-            ? Text(placeholder)
-            : ChartDiscoveriesTracks(
-                chartData: DiscoveriesData.fromJson(jsonDecode(this.chartData.toString())),
-              ),
-      ],
-    );
-  }
-}
diff --git a/lib/ui/widgets/main_screen/statistics_global_card.dart b/lib/ui/widgets/main_screen/statistics_global_card.dart
deleted file mode 100644
index 1a7474c5ebd78ee2c98eec9eb5c4855ca766bc55..0000000000000000000000000000000000000000
--- a/lib/ui/widgets/main_screen/statistics_global_card.dart
+++ /dev/null
@@ -1,46 +0,0 @@
-import 'dart:convert';
-
-import 'package:flutter/material.dart';
-
-import '../../../models/statistics_global.dart';
-import '../../../network/scrobbles_api.dart';
-import '../../../ui/widgets/error.dart';
-import 'statistics_global_content.dart';
-
-class StatisticsGlobalCard extends StatelessWidget {
-  const StatisticsGlobalCard({super.key});
-
-  @override
-  Widget build(BuildContext context) {
-    late Future<StatisticsGlobalData> future = ScrobblesApi.fetchGlobalStatistics();
-
-    return FutureBuilder<StatisticsGlobalData>(
-      future: future,
-      builder: (context, snapshot) {
-        if (snapshot.hasError) {
-          return ShowErrorWidget(message: '${snapshot.error}');
-        }
-
-        return Card(
-          elevation: 2,
-          shadowColor: Theme.of(context).colorScheme.shadow,
-          color: Theme.of(context).colorScheme.primary,
-          shape: const RoundedRectangleBorder(
-            borderRadius: BorderRadius.all(
-              Radius.circular(8),
-            ),
-          ),
-          child: Padding(
-            padding: const EdgeInsets.all(8.0),
-            child: StatisticsGlobalContent(
-              statistics: snapshot.hasData
-                  ? StatisticsGlobalData.fromJson(jsonDecode(snapshot.data.toString()))
-                  : StatisticsGlobalData.createEmpty(),
-              isLoading: !snapshot.hasData,
-            ),
-          ),
-        );
-      },
-    );
-  }
-}
diff --git a/lib/ui/widgets/main_screen/statistics_recent_card.dart b/lib/ui/widgets/main_screen/statistics_recent_card.dart
deleted file mode 100644
index 5f12d27b2145aa2d8265e6a62acea3aa25256538..0000000000000000000000000000000000000000
--- a/lib/ui/widgets/main_screen/statistics_recent_card.dart
+++ /dev/null
@@ -1,48 +0,0 @@
-import 'dart:convert';
-
-import 'package:flutter/material.dart';
-
-import '../../../models/statistics_recent.dart';
-import '../../../network/scrobbles_api.dart';
-import '../../../ui/widgets/error.dart';
-import 'statistics_recent_content.dart';
-
-class StatisticsRecentCard extends StatelessWidget {
-  const StatisticsRecentCard({super.key});
-
-  @override
-  Widget build(BuildContext context) {
-    final int daysCount = 21;
-
-    late Future<StatisticsRecentData> future = ScrobblesApi.fetchRecentStatistics(daysCount);
-
-    return FutureBuilder<StatisticsRecentData>(
-      future: future,
-      builder: (context, snapshot) {
-        if (snapshot.hasError) {
-          return ShowErrorWidget(message: '${snapshot.error}');
-        }
-
-        return Card(
-          elevation: 2,
-          shadowColor: Theme.of(context).colorScheme.shadow,
-          color: Theme.of(context).colorScheme.primary,
-          shape: const RoundedRectangleBorder(
-            borderRadius: BorderRadius.all(
-              Radius.circular(8),
-            ),
-          ),
-          child: Padding(
-            padding: const EdgeInsets.all(8.0),
-            child: StatisticsRecentContent(
-              statistics: snapshot.hasData
-                  ? StatisticsRecentData.fromJson(jsonDecode(snapshot.data.toString()))
-                  : StatisticsRecentData.createEmpty(),
-              isLoading: !snapshot.hasData,
-            ),
-          ),
-        );
-      },
-    );
-  }
-}
diff --git a/lib/ui/widgets/main_screen/timeline_card.dart b/lib/ui/widgets/main_screen/timeline_card.dart
deleted file mode 100644
index 931ea2292fe3cbbaed5f44c03f88771a4961eaa3..0000000000000000000000000000000000000000
--- a/lib/ui/widgets/main_screen/timeline_card.dart
+++ /dev/null
@@ -1,48 +0,0 @@
-import 'dart:convert';
-
-import 'package:flutter/material.dart';
-
-import '../../../models/timeline.dart';
-import '../../../network/scrobbles_api.dart';
-import '../../../ui/widgets/error.dart';
-import '../../../ui/widgets/main_screen/timeline_content.dart';
-
-class ChartTimelineCard extends StatelessWidget {
-  const ChartTimelineCard({super.key});
-
-  @override
-  Widget build(BuildContext context) {
-    final int daysCount = 14;
-    late Future<TimelineData> futureTimeline = ScrobblesApi.fetchTimeline(daysCount);
-
-    return FutureBuilder<TimelineData>(
-      future: futureTimeline,
-      builder: (context, snapshot) {
-        if (snapshot.hasError) {
-          return ShowErrorWidget(message: '${snapshot.error}');
-        }
-
-        return Card(
-          elevation: 2,
-          shadowColor: Theme.of(context).colorScheme.shadow,
-          color: Theme.of(context).colorScheme.surface,
-          shape: const RoundedRectangleBorder(
-            borderRadius: BorderRadius.all(
-              Radius.circular(8),
-            ),
-          ),
-          child: Padding(
-            padding: const EdgeInsets.all(8.0),
-            child: ChartTimelineCardContent(
-              daysCount: daysCount,
-              chartData: snapshot.hasData
-                  ? TimelineData.fromJson(jsonDecode(snapshot.data.toString()))
-                  : TimelineData.createEmpty(),
-              isLoading: !snapshot.hasData,
-            ),
-          ),
-        );
-      },
-    );
-  }
-}
diff --git a/lib/ui/widgets/main_screen/timeline_content.dart b/lib/ui/widgets/main_screen/timeline_content.dart
deleted file mode 100644
index 1533ee1740202592639c273ef2c6a667b2219091..0000000000000000000000000000000000000000
--- a/lib/ui/widgets/main_screen/timeline_content.dart
+++ /dev/null
@@ -1,51 +0,0 @@
-import 'dart:convert';
-
-import 'package:easy_localization/easy_localization.dart';
-import 'package:flutter/material.dart';
-
-import '../../../models/timeline.dart';
-import 'timeline_chart_counts.dart';
-import 'timeline_chart_eclecticism.dart';
-
-class ChartTimelineCardContent extends StatelessWidget {
-  final int daysCount;
-  final TimelineData chartData;
-  final bool isLoading;
-
-  const ChartTimelineCardContent(
-      {super.key, required this.daysCount, required this.chartData, required this.isLoading});
-
-  @override
-  Widget build(BuildContext context) {
-    final TextTheme textTheme = Theme.of(context).primaryTextTheme;
-    final String placeholder = '⏳';
-
-    return Column(
-      mainAxisSize: MainAxisSize.min,
-      crossAxisAlignment: CrossAxisAlignment.start,
-      children: <Widget>[
-        Text(
-          'timeline_title',
-          style: textTheme.titleLarge!.apply(fontWeightDelta: 2),
-        ).tr(
-          namedArgs: {
-            'daysCount': this.daysCount.toString(),
-          },
-        ),
-        const SizedBox(height: 8),
-        this.isLoading
-            ? Text(placeholder)
-            : Stack(
-                children: [
-                  ChartTimelineCounts(
-                    chartData: TimelineData.fromJson(jsonDecode(this.chartData.toString())),
-                  ),
-                  ChartTimelineEclecticism(
-                    chartData: TimelineData.fromJson(jsonDecode(this.chartData.toString())),
-                  ),
-                ],
-              ),
-      ],
-    );
-  }
-}
diff --git a/lib/ui/widgets/main_screen/topartists_card.dart b/lib/ui/widgets/main_screen/topartists_card.dart
deleted file mode 100644
index e26de073de48ec1862749d77da6d776bd8518506..0000000000000000000000000000000000000000
--- a/lib/ui/widgets/main_screen/topartists_card.dart
+++ /dev/null
@@ -1,48 +0,0 @@
-import 'dart:convert';
-
-import 'package:flutter/material.dart';
-
-import '../../../models/topartists.dart';
-import '../../../network/scrobbles_api.dart';
-import '../../../ui/widgets/error.dart';
-import '../../../ui/widgets/main_screen/topartists_content.dart';
-
-class ChartTopArtistsCard extends StatelessWidget {
-  const ChartTopArtistsCard({super.key});
-
-  @override
-  Widget build(BuildContext context) {
-    final int daysCount = 14;
-    late Future<TopArtistsData> futureTimeline = ScrobblesApi.fetchTopArtists(daysCount);
-
-    return FutureBuilder<TopArtistsData>(
-      future: futureTimeline,
-      builder: (context, snapshot) {
-        if (snapshot.hasError) {
-          return ShowErrorWidget(message: '${snapshot.error}');
-        }
-
-        return Card(
-          elevation: 2,
-          shadowColor: Theme.of(context).colorScheme.shadow,
-          color: Theme.of(context).colorScheme.surface,
-          shape: const RoundedRectangleBorder(
-            borderRadius: BorderRadius.all(
-              Radius.circular(8),
-            ),
-          ),
-          child: Padding(
-            padding: const EdgeInsets.all(8.0),
-            child: ChartTopArtistsCardContent(
-              daysCount: daysCount,
-              chartData: snapshot.hasData
-                  ? TopArtistsData.fromJson(jsonDecode(snapshot.data.toString()))
-                  : TopArtistsData.createEmpty(),
-              isLoading: !snapshot.hasData,
-            ),
-          ),
-        );
-      },
-    );
-  }
-}
diff --git a/lib/ui/widgets/main_screen/topartists_content.dart b/lib/ui/widgets/main_screen/topartists_content.dart
deleted file mode 100644
index 00d41e804a75c0410a43cc18e739a55fed707b38..0000000000000000000000000000000000000000
--- a/lib/ui/widgets/main_screen/topartists_content.dart
+++ /dev/null
@@ -1,43 +0,0 @@
-import 'dart:convert';
-
-import 'package:easy_localization/easy_localization.dart';
-import 'package:flutter/material.dart';
-
-import '../../../models/topartists.dart';
-import '../../../ui/widgets/main_screen/topartists_chart.dart';
-
-class ChartTopArtistsCardContent extends StatelessWidget {
-  final int daysCount;
-  final TopArtistsData chartData;
-  final bool isLoading;
-
-  const ChartTopArtistsCardContent(
-      {super.key, required this.daysCount, required this.chartData, required this.isLoading});
-
-  @override
-  Widget build(BuildContext context) {
-    final TextTheme textTheme = Theme.of(context).primaryTextTheme;
-    final String placeholder = '⏳';
-
-    return Column(
-      mainAxisSize: MainAxisSize.min,
-      crossAxisAlignment: CrossAxisAlignment.start,
-      children: <Widget>[
-        Text(
-          'top_artists_title',
-          style: textTheme.titleLarge!.apply(fontWeightDelta: 2),
-        ).tr(
-          namedArgs: {
-            'daysCount': this.daysCount.toString(),
-          },
-        ),
-        const SizedBox(height: 8),
-        this.isLoading
-            ? Text(placeholder)
-            : ChartTopArtists(
-                chartData: TopArtistsData.fromJson(jsonDecode(this.chartData.toString())),
-              ),
-      ],
-    );
-  }
-}
diff --git a/pubspec.yaml b/pubspec.yaml
index ad3eda281acecdf67b7bb555ab1604836e9c0f78..33d49a5ca6245f447ac76bf60cc8d7e6dd46e73d 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -3,7 +3,7 @@ description: Display scrobbles data and charts
 
 publish_to: 'none'
 
-version: 0.0.27+27
+version: 0.0.28+28
 
 environment:
   sdk: '^3.0.0'