From e96de07f4ea6eb96ab70887d0a7e102a0e2a433d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Beno=C3=AEt=20Harrault?= <benoit@harrault.fr>
Date: Thu, 30 Nov 2023 15:19:56 +0100
Subject: [PATCH] Add days count selectors in settings page

---
 android/gradle.properties                     |   4 +-
 assets/translations/en.json                   |   7 +
 assets/translations/fr.json                   |   6 +
 .../metadata/android/en-US/changelogs/36.txt  |   1 +
 .../metadata/android/fr-FR/changelogs/36.txt  |   1 +
 lib/config/default_settings.dart              |  16 ++
 lib/config/settings.dart                      |   8 -
 lib/cubit/settings_cubit.dart                 |  69 +++++-
 lib/cubit/settings_state.dart                 |  28 ++-
 lib/ui/widgets/cards/counts_by_day.dart       |   8 +-
 lib/ui/widgets/cards/counts_by_hour.dart      |   8 +-
 lib/ui/widgets/cards/discoveries.dart         |   8 +-
 lib/ui/widgets/cards/statistics_recent.dart   |   8 +-
 lib/ui/widgets/cards/timeline.dart            |  10 +-
 lib/ui/widgets/cards/top_artists.dart         |   8 +-
 lib/ui/widgets/settings_form.dart             | 227 ++++++++++++++++--
 pubspec.yaml                                  |   2 +-
 17 files changed, 364 insertions(+), 55 deletions(-)
 create mode 100644 fastlane/metadata/android/en-US/changelogs/36.txt
 create mode 100644 fastlane/metadata/android/fr-FR/changelogs/36.txt
 create mode 100644 lib/config/default_settings.dart
 delete mode 100644 lib/config/settings.dart

diff --git a/android/gradle.properties b/android/gradle.properties
index 32638a3..1f1e18f 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.35
-app.versionCode=35
+app.versionName=0.0.36
+app.versionCode=36
diff --git a/assets/translations/en.json b/assets/translations/en.json
index 6b7214c..d9a54c4 100644
--- a/assets/translations/en.json
+++ b/assets/translations/en.json
@@ -27,6 +27,13 @@
   "settings_title": "Settings",
   "settings_label_username": "Username: ",
   "settings_label_security_token": "Security token: ",
+  "settings_label_counts_by_day_days_count": "Counts by day: ",
+  "settings_label_counts_by_hour_days_count": "Counts by hour: ",
+  "settings_label_discoveries_days_count": "Discoveries: ",
+  "settings_label_statistics_recent_days_count": "Recent statistics: ",
+  "settings_label_timeline_days_count": "Timeline: ",
+  "settings_label_top_artists_days_count": "Top Artists: ",
+
   "settings_button_save": "Save",
 
   "MON": "MON",
diff --git a/assets/translations/fr.json b/assets/translations/fr.json
index b495f44..c2c257d 100644
--- a/assets/translations/fr.json
+++ b/assets/translations/fr.json
@@ -27,6 +27,12 @@
   "settings_title": "Paramètres",
   "settings_label_username": "Utilisateur : ",
   "settings_label_security_token": "Jeton de sécurité : ",
+  "settings_label_counts_by_day_days_count": "Répartition par heure : ",
+  "settings_label_counts_by_hour_days_count": "Répartition par jour : ",
+  "settings_label_discoveries_days_count": "Découvertes : ",
+  "settings_label_statistics_recent_days_count": "Statistiques récentes : ",
+  "settings_label_timeline_days_count": "Timeline : ",
+  "settings_label_top_artists_days_count": "Top Artistes : ",
   "settings_button_save": "Enregistrer",
 
   "MON": "LUN",
diff --git a/fastlane/metadata/android/en-US/changelogs/36.txt b/fastlane/metadata/android/en-US/changelogs/36.txt
new file mode 100644
index 0000000..a653225
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/36.txt
@@ -0,0 +1 @@
+Add days count selectors in settings page.
diff --git a/fastlane/metadata/android/fr-FR/changelogs/36.txt b/fastlane/metadata/android/fr-FR/changelogs/36.txt
new file mode 100644
index 0000000..9c22553
--- /dev/null
+++ b/fastlane/metadata/android/fr-FR/changelogs/36.txt
@@ -0,0 +1 @@
+Ajout de sélecteurs de nombre de jours dans le paramétrage.
diff --git a/lib/config/default_settings.dart b/lib/config/default_settings.dart
new file mode 100644
index 0000000..c90ec49
--- /dev/null
+++ b/lib/config/default_settings.dart
@@ -0,0 +1,16 @@
+class DefaultSettings {
+  static const List<int> allowedValues = [
+    7,
+    14,
+    21,
+    30,
+    60,
+    90,
+  ];
+  static const int defaultCountsByDayDaysCount = 21;
+  static const int defaultCountsByHourDaysCount = 21;
+  static const int defaultDiscoveriesDaysCount = 14;
+  static const int defaultStatisticsRecentDaysCount = 21;
+  static const int defaultTimelineDaysCount = 14;
+  static const int defaultTopArtistsDaysCount = 14;
+}
diff --git a/lib/config/settings.dart b/lib/config/settings.dart
deleted file mode 100644
index 2c62c87..0000000
--- a/lib/config/settings.dart
+++ /dev/null
@@ -1,8 +0,0 @@
-class Settings {
-  static const int countsByDayDaysCount = 21;
-  static const int countsByHourDaysCount = 21;
-  static const int discoveriesDaysCount = 14;
-  static const int statisticsRecentDaysCount = 21;
-  static const int timelineDaysCount = 14;
-  static const int topArtistsDaysCount = 14;
-}
diff --git a/lib/cubit/settings_cubit.dart b/lib/cubit/settings_cubit.dart
index 45df233..e471dd2 100644
--- a/lib/cubit/settings_cubit.dart
+++ b/lib/cubit/settings_cubit.dart
@@ -2,6 +2,8 @@ import 'package:equatable/equatable.dart';
 import 'package:flutter/material.dart';
 import 'package:hydrated_bloc/hydrated_bloc.dart';
 
+import 'package:scrobbles/config/default_settings.dart';
+
 part 'settings_state.dart';
 
 class SettingsCubit extends HydratedCubit<SettingsState> {
@@ -15,13 +17,49 @@ class SettingsCubit extends HydratedCubit<SettingsState> {
     return state.securityToken ?? '';
   }
 
+  int getCountsByDayDaysCount() {
+    return state.countsByDayDaysCount ?? DefaultSettings.defaultCountsByDayDaysCount;
+  }
+
+  int getCountsByHourDaysCount() {
+    return state.countsByHourDaysCount ?? DefaultSettings.defaultCountsByHourDaysCount;
+  }
+
+  int getDiscoveriesDaysCount() {
+    return state.discoveriesDaysCount ?? DefaultSettings.defaultDiscoveriesDaysCount;
+  }
+
+  int getStatisticsRecentDaysCount() {
+    return state.statisticsRecentDaysCount ?? DefaultSettings.defaultStatisticsRecentDaysCount;
+  }
+
+  int getTimelineDaysCount() {
+    return state.timelineDaysCount ?? DefaultSettings.defaultTimelineDaysCount;
+  }
+
+  int getTopArtistsDaysCount() {
+    return state.topArtistsDaysCount ?? DefaultSettings.defaultTopArtistsDaysCount;
+  }
+
   void setValues({
     String? username,
     String? securityToken,
+    int? countsByDayDaysCount,
+    int? countsByHourDaysCount,
+    int? discoveriesDaysCount,
+    int? statisticsRecentDaysCount,
+    int? timelineDaysCount,
+    int? topArtistsDaysCount,
   }) {
     emit(SettingsState(
-      username: username != null ? username : state.username,
-      securityToken: securityToken != null ? securityToken : state.securityToken,
+      username: username ?? state.username,
+      securityToken: securityToken ?? state.securityToken,
+      countsByDayDaysCount: countsByDayDaysCount ?? state.countsByDayDaysCount,
+      countsByHourDaysCount: countsByHourDaysCount ?? state.countsByHourDaysCount,
+      discoveriesDaysCount: discoveriesDaysCount ?? state.discoveriesDaysCount,
+      statisticsRecentDaysCount: statisticsRecentDaysCount ?? state.statisticsRecentDaysCount,
+      timelineDaysCount: timelineDaysCount ?? state.timelineDaysCount,
+      topArtistsDaysCount: topArtistsDaysCount ?? state.topArtistsDaysCount,
     ));
   }
 
@@ -29,18 +67,41 @@ class SettingsCubit extends HydratedCubit<SettingsState> {
   SettingsState? fromJson(Map<String, dynamic> json) {
     String username = json['username'] as String;
     String securityToken = json['securityToken'] as String;
+    int countsByDayDaysCount = json['countsByDayDaysCount'] as int;
+    int countsByHourDaysCount = json['countsByHourDaysCount'] as int;
+    int discoveriesDaysCount = json['discoveriesDaysCount'] as int;
+    int statisticsRecentDaysCount = json['statisticsRecentDaysCount'] as int;
+    int timelineDaysCount = json['timelineDaysCount'] as int;
+    int topArtistsDaysCount = json['topArtistsDaysCount'] as int;
 
     return SettingsState(
       username: username,
       securityToken: securityToken,
+      countsByDayDaysCount: countsByDayDaysCount,
+      countsByHourDaysCount: countsByHourDaysCount,
+      discoveriesDaysCount: discoveriesDaysCount,
+      statisticsRecentDaysCount: statisticsRecentDaysCount,
+      timelineDaysCount: timelineDaysCount,
+      topArtistsDaysCount: topArtistsDaysCount,
     );
   }
 
   @override
-  Map<String, String>? toJson(SettingsState state) {
-    return <String, String>{
+  Map<String, dynamic>? toJson(SettingsState state) {
+    return <String, dynamic>{
       'username': state.username ?? '',
       'securityToken': state.securityToken ?? '',
+      'countsByDayDaysCount':
+          state.countsByDayDaysCount ?? DefaultSettings.defaultCountsByDayDaysCount,
+      'countsByHourDaysCount':
+          state.countsByHourDaysCount ?? DefaultSettings.defaultCountsByHourDaysCount,
+      'discoveriesDaysCount':
+          state.discoveriesDaysCount ?? DefaultSettings.defaultDiscoveriesDaysCount,
+      'statisticsRecentDaysCount':
+          state.statisticsRecentDaysCount ?? DefaultSettings.defaultStatisticsRecentDaysCount,
+      'timelineDaysCount': state.timelineDaysCount ?? DefaultSettings.defaultTimelineDaysCount,
+      'topArtistsDaysCount':
+          state.topArtistsDaysCount ?? DefaultSettings.defaultTopArtistsDaysCount,
     };
   }
 }
diff --git a/lib/cubit/settings_state.dart b/lib/cubit/settings_state.dart
index c32e6bb..848b348 100644
--- a/lib/cubit/settings_state.dart
+++ b/lib/cubit/settings_state.dart
@@ -5,19 +5,43 @@ class SettingsState extends Equatable {
   const SettingsState({
     this.username,
     this.securityToken,
+    this.countsByDayDaysCount,
+    this.countsByHourDaysCount,
+    this.discoveriesDaysCount,
+    this.statisticsRecentDaysCount,
+    this.timelineDaysCount,
+    this.topArtistsDaysCount,
   });
 
   final String? username;
   final String? securityToken;
+  final int? countsByDayDaysCount;
+  final int? countsByHourDaysCount;
+  final int? discoveriesDaysCount;
+  final int? statisticsRecentDaysCount;
+  final int? timelineDaysCount;
+  final int? topArtistsDaysCount;
 
   @override
-  List<String?> get props => <String?>[
+  List<dynamic> get props => <dynamic>[
         username,
         securityToken,
+        countsByDayDaysCount,
+        countsByHourDaysCount,
+        discoveriesDaysCount,
+        statisticsRecentDaysCount,
+        timelineDaysCount,
+        topArtistsDaysCount,
       ];
 
-  Map<String, String?> get values => <String, String?>{
+  Map<String, dynamic> get values => <String, dynamic>{
         'username': username,
         'securityToken': securityToken,
+        'countsByDayDaysCount': countsByDayDaysCount,
+        'countsByHourDaysCount': countsByHourDaysCount,
+        'discoveriesDaysCount': discoveriesDaysCount,
+        'statisticsRecentDaysCount': statisticsRecentDaysCount,
+        'timelineDaysCount': timelineDaysCount,
+        'topArtistsDaysCount': topArtistsDaysCount,
       };
 }
diff --git a/lib/ui/widgets/cards/counts_by_day.dart b/lib/ui/widgets/cards/counts_by_day.dart
index 43c7249..f92a433 100644
--- a/lib/ui/widgets/cards/counts_by_day.dart
+++ b/lib/ui/widgets/cards/counts_by_day.dart
@@ -4,8 +4,8 @@ import 'package:easy_localization/easy_localization.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
 
-import 'package:scrobbles/config/settings.dart';
 import 'package:scrobbles/cubit/data_counts_by_day_cubit.dart';
+import 'package:scrobbles/cubit/settings_cubit.dart';
 import 'package:scrobbles/models/counts_by_day.dart';
 import 'package:scrobbles/network/scrobbles.dart';
 import 'package:scrobbles/ui/widgets/card_content.dart';
@@ -17,7 +17,9 @@ class CardCountsByDay extends StatelessWidget {
 
   @override
   Widget build(BuildContext context) {
-    final int daysCount = Settings.countsByDayDaysCount;
+    SettingsCubit settings = BlocProvider.of<SettingsCubit>(context);
+
+    final int daysCount = settings.getCountsByDayDaysCount();
 
     return BlocBuilder<DataCountsByDayCubit, DataCountsByDayState>(
       builder: (BuildContext context, DataCountsByDayState state) {
@@ -28,7 +30,7 @@ class CardCountsByDay extends StatelessWidget {
               'daysCount': daysCount.toString(),
             },
           ),
-          loader: updateCountsByDay(Settings.countsByDayDaysCount),
+          loader: updateCountsByDay(daysCount),
           content: ChartCountsByDay(
             chartData: CountsByDayData.fromJson(jsonDecode(state.countsByDay.toString())),
             isLoading: false,
diff --git a/lib/ui/widgets/cards/counts_by_hour.dart b/lib/ui/widgets/cards/counts_by_hour.dart
index 319748b..f24d837 100644
--- a/lib/ui/widgets/cards/counts_by_hour.dart
+++ b/lib/ui/widgets/cards/counts_by_hour.dart
@@ -4,8 +4,8 @@ import 'package:easy_localization/easy_localization.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
 
-import 'package:scrobbles/config/settings.dart';
 import 'package:scrobbles/cubit/data_counts_by_hour_cubit.dart';
+import 'package:scrobbles/cubit/settings_cubit.dart';
 import 'package:scrobbles/models/counts_by_hour.dart';
 import 'package:scrobbles/network/scrobbles.dart';
 import 'package:scrobbles/ui/widgets/card_content.dart';
@@ -17,7 +17,9 @@ class CardCountsByHour extends StatelessWidget {
 
   @override
   Widget build(BuildContext context) {
-    final int daysCount = Settings.countsByHourDaysCount;
+    SettingsCubit settings = BlocProvider.of<SettingsCubit>(context);
+
+    final int daysCount = settings.getCountsByHourDaysCount();
 
     return BlocBuilder<DataCountsByHourCubit, DataCountsByHourState>(
       builder: (BuildContext context, DataCountsByHourState state) {
@@ -28,7 +30,7 @@ class CardCountsByHour extends StatelessWidget {
               'daysCount': daysCount.toString(),
             },
           ),
-          loader: updateCountsByHour(Settings.countsByHourDaysCount),
+          loader: updateCountsByHour(daysCount),
           content: ChartCountsByHour(
             chartData: CountsByHourData.fromJson(jsonDecode(state.countsByHour.toString())),
             isLoading: false,
diff --git a/lib/ui/widgets/cards/discoveries.dart b/lib/ui/widgets/cards/discoveries.dart
index c285627..1177798 100644
--- a/lib/ui/widgets/cards/discoveries.dart
+++ b/lib/ui/widgets/cards/discoveries.dart
@@ -4,8 +4,8 @@ import 'package:easy_localization/easy_localization.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
 
-import 'package:scrobbles/config/settings.dart';
 import 'package:scrobbles/cubit/data_discoveries_cubit.dart';
+import 'package:scrobbles/cubit/settings_cubit.dart';
 import 'package:scrobbles/models/discoveries.dart';
 import 'package:scrobbles/network/scrobbles.dart';
 import 'package:scrobbles/ui/widgets/card_content.dart';
@@ -18,7 +18,9 @@ class CardDiscoveries extends StatelessWidget {
 
   @override
   Widget build(BuildContext context) {
-    final int daysCount = Settings.discoveriesDaysCount;
+    SettingsCubit settings = BlocProvider.of<SettingsCubit>(context);
+
+    final int daysCount = settings.getDiscoveriesDaysCount();
 
     return BlocBuilder<DataDiscoveriesCubit, DataDiscoveriesState>(
       builder: (BuildContext context, DataDiscoveriesState state) {
@@ -31,7 +33,7 @@ class CardDiscoveries extends StatelessWidget {
               'daysCount': daysCount.toString(),
             },
           ),
-          loader: updateDiscoveries(Settings.discoveriesDaysCount),
+          loader: updateDiscoveries(daysCount),
           content: Column(
             mainAxisSize: MainAxisSize.min,
             crossAxisAlignment: CrossAxisAlignment.start,
diff --git a/lib/ui/widgets/cards/statistics_recent.dart b/lib/ui/widgets/cards/statistics_recent.dart
index 2c227fc..0d9dc26 100644
--- a/lib/ui/widgets/cards/statistics_recent.dart
+++ b/lib/ui/widgets/cards/statistics_recent.dart
@@ -4,8 +4,8 @@ import 'package:easy_localization/easy_localization.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
 
-import 'package:scrobbles/config/settings.dart';
 import 'package:scrobbles/cubit/data_statistics_recent_cubit.dart';
+import 'package:scrobbles/cubit/settings_cubit.dart';
 import 'package:scrobbles/models/statistics_recent.dart';
 import 'package:scrobbles/network/scrobbles.dart';
 import 'package:scrobbles/ui/widgets/card_content.dart';
@@ -17,7 +17,9 @@ class CardStatisticsRecent extends StatelessWidget {
 
   @override
   Widget build(BuildContext context) {
-    final int daysCount = Settings.statisticsRecentDaysCount;
+    SettingsCubit settings = BlocProvider.of<SettingsCubit>(context);
+
+    final int daysCount = settings.getStatisticsRecentDaysCount();
 
     return BlocBuilder<DataStatisticsRecentCubit, DataStatisticsRecentState>(
       builder: (BuildContext context, DataStatisticsRecentState dataState) {
@@ -28,7 +30,7 @@ class CardStatisticsRecent extends StatelessWidget {
               'daysCount': daysCount.toString(),
             },
           ),
-          loader: updateStatisticsRecent(Settings.statisticsRecentDaysCount),
+          loader: updateStatisticsRecent(daysCount),
           content: ContentStatisticsRecent(
             statistics: StatisticsRecentData.fromJson(
                 jsonDecode(dataState.statisticsRecent.toString())),
diff --git a/lib/ui/widgets/cards/timeline.dart b/lib/ui/widgets/cards/timeline.dart
index 1ac2cf4..50540ac 100644
--- a/lib/ui/widgets/cards/timeline.dart
+++ b/lib/ui/widgets/cards/timeline.dart
@@ -4,8 +4,8 @@ import 'package:easy_localization/easy_localization.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
 
-import 'package:scrobbles/config/settings.dart';
 import 'package:scrobbles/cubit/data_timeline_cubit.dart';
+import 'package:scrobbles/cubit/settings_cubit.dart';
 import 'package:scrobbles/models/timeline.dart';
 import 'package:scrobbles/network/scrobbles.dart';
 import 'package:scrobbles/ui/widgets/card_content.dart';
@@ -18,7 +18,9 @@ class CardTimeline extends StatelessWidget {
 
   @override
   Widget build(BuildContext context) {
-    final int daysCount = Settings.timelineDaysCount;
+    SettingsCubit settings = BlocProvider.of<SettingsCubit>(context);
+
+    final int daysCount = settings.getTimelineDaysCount();
 
     return BlocBuilder<DataTimelineCubit, DataTimelineState>(
       builder: (BuildContext context, DataTimelineState state) {
@@ -29,7 +31,7 @@ class CardTimeline extends StatelessWidget {
               'daysCount': daysCount.toString(),
             },
           ),
-          loader: updateTimeline(Settings.timelineDaysCount),
+          loader: updateTimeline(daysCount),
           content: Stack(
             children: [
               ChartTimelineCounts(
@@ -62,7 +64,7 @@ class CardTimeline extends StatelessWidget {
               return ShowErrorWidget(message: '${snapshot.error}');
             }
 
-              BlocProvider.of<DataTimelineCubit>(context).update(snapshot.data);
+            BlocProvider.of<DataTimelineCubit>(context).update(snapshot.data);
 
             return !snapshot.hasData ? loading : done;
           },
diff --git a/lib/ui/widgets/cards/top_artists.dart b/lib/ui/widgets/cards/top_artists.dart
index 176c673..1e352cf 100644
--- a/lib/ui/widgets/cards/top_artists.dart
+++ b/lib/ui/widgets/cards/top_artists.dart
@@ -4,8 +4,8 @@ import 'package:easy_localization/easy_localization.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
 
-import 'package:scrobbles/config/settings.dart';
 import 'package:scrobbles/cubit/data_top_artists_cubit.dart';
+import 'package:scrobbles/cubit/settings_cubit.dart';
 import 'package:scrobbles/models/topartists.dart';
 import 'package:scrobbles/network/scrobbles.dart';
 import 'package:scrobbles/ui/widgets/card_content.dart';
@@ -17,7 +17,9 @@ class CardTopArtists extends StatelessWidget {
 
   @override
   Widget build(BuildContext context) {
-    final int daysCount = Settings.topArtistsDaysCount;
+    SettingsCubit settings = BlocProvider.of<SettingsCubit>(context);
+
+    final int daysCount = settings.getTopArtistsDaysCount();
 
     return BlocBuilder<DataTopArtistsCubit, DataTopArtistsState>(
       builder: (BuildContext context, DataTopArtistsState state) {
@@ -28,7 +30,7 @@ class CardTopArtists extends StatelessWidget {
               'daysCount': daysCount.toString(),
             },
           ),
-          loader: updateTopArtists(Settings.topArtistsDaysCount),
+          loader: updateTopArtists(daysCount),
           content: ChartTopArtists(
             chartData: TopArtistsData.fromJson(jsonDecode(state.topArtists.toString())),
             isLoading: false,
diff --git a/lib/ui/widgets/settings_form.dart b/lib/ui/widgets/settings_form.dart
index 5af5f14..3ea6266 100644
--- a/lib/ui/widgets/settings_form.dart
+++ b/lib/ui/widgets/settings_form.dart
@@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
 import 'package:unicons/unicons.dart';
 
+import 'package:scrobbles/config/default_settings.dart';
 import 'package:scrobbles/cubit/settings_cubit.dart';
 
 class SettingsForm extends StatefulWidget {
@@ -16,6 +17,50 @@ class _SettingsFormState extends State<SettingsForm> {
   final usernameController = TextEditingController();
   final securityTokenController = TextEditingController();
 
+  int countsByDayDaysCount = DefaultSettings.defaultCountsByDayDaysCount;
+  int countsByHourDaysCount = DefaultSettings.defaultCountsByHourDaysCount;
+  int discoveriesDaysCount = DefaultSettings.defaultDiscoveriesDaysCount;
+  int statisticsRecentDaysCount = DefaultSettings.defaultStatisticsRecentDaysCount;
+  int timelineDaysCount = DefaultSettings.defaultTimelineDaysCount;
+  int topArtistsDaysCount = DefaultSettings.defaultTopArtistsDaysCount;
+
+  List<bool> _selectedCountsByDayDaysCount = [];
+  List<bool> _selectedCountsByHourDaysCount = [];
+  List<bool> _selectedDiscoveriesDaysCount = [];
+  List<bool> _selectedStatisticsRecentDaysCount = [];
+  List<bool> _selectedTimelineDaysCount = [];
+  List<bool> _selectedTopArtistsDaysCount = [];
+
+  @override
+  void didChangeDependencies() {
+    SettingsCubit settings = BlocProvider.of<SettingsCubit>(context);
+
+    usernameController.text = settings.getUsername();
+    securityTokenController.text = settings.getSecurityToken();
+
+    countsByDayDaysCount = settings.getCountsByDayDaysCount();
+    countsByHourDaysCount = settings.getCountsByHourDaysCount();
+    discoveriesDaysCount = settings.getDiscoveriesDaysCount();
+    statisticsRecentDaysCount = settings.getStatisticsRecentDaysCount();
+    timelineDaysCount = settings.getTimelineDaysCount();
+    topArtistsDaysCount = settings.getTopArtistsDaysCount();
+
+    _selectedCountsByDayDaysCount =
+        DefaultSettings.allowedValues.map((e) => (e == countsByDayDaysCount)).toList();
+    _selectedCountsByHourDaysCount =
+        DefaultSettings.allowedValues.map((e) => (e == countsByHourDaysCount)).toList();
+    _selectedDiscoveriesDaysCount =
+        DefaultSettings.allowedValues.map((e) => (e == discoveriesDaysCount)).toList();
+    _selectedStatisticsRecentDaysCount =
+        DefaultSettings.allowedValues.map((e) => (e == statisticsRecentDaysCount)).toList();
+    _selectedTimelineDaysCount =
+        DefaultSettings.allowedValues.map((e) => (e == timelineDaysCount)).toList();
+    _selectedTopArtistsDaysCount =
+        DefaultSettings.allowedValues.map((e) => (e == topArtistsDaysCount)).toList();
+
+    super.didChangeDependencies();
+  }
+
   @override
   void dispose() {
     usernameController.dispose();
@@ -25,15 +70,16 @@ class _SettingsFormState extends State<SettingsForm> {
 
   @override
   Widget build(BuildContext context) {
-    SettingsCubit settings = BlocProvider.of<SettingsCubit>(context);
-
-    usernameController.text = settings.getUsername();
-    securityTokenController.text = settings.getSecurityToken();
-
     void saveSettings() {
       BlocProvider.of<SettingsCubit>(context).setValues(
         username: usernameController.text,
         securityToken: securityTokenController.text,
+        countsByDayDaysCount: countsByDayDaysCount,
+        countsByHourDaysCount: countsByHourDaysCount,
+        discoveriesDaysCount: discoveriesDaysCount,
+        statisticsRecentDaysCount: statisticsRecentDaysCount,
+        timelineDaysCount: timelineDaysCount,
+        topArtistsDaysCount: topArtistsDaysCount,
       );
     }
 
@@ -42,22 +88,165 @@ class _SettingsFormState extends State<SettingsForm> {
       crossAxisAlignment: CrossAxisAlignment.start,
       mainAxisSize: MainAxisSize.max,
       children: <Widget>[
-        Text('settings_label_username').tr(),
-        TextFormField(
-          controller: usernameController,
-          decoration: InputDecoration(
-            border: UnderlineInputBorder(),
-          ),
+        // Username
+        // Text('settings_label_username').tr(),
+        // TextFormField(
+        //   controller: usernameController,
+        //   decoration: InputDecoration(
+        //     border: UnderlineInputBorder(),
+        //   ),
+        // ),
+        // SizedBox(height: 16),
+
+        // Security token
+        // Text('settings_label_security_token').tr(),
+        // TextFormField(
+        //   controller: securityTokenController,
+        //   decoration: InputDecoration(
+        //     border: UnderlineInputBorder(),
+        //   ),
+        // ),
+        // SizedBox(height: 20),
+
+        // Counts by day
+        Row(
+          mainAxisAlignment: MainAxisAlignment.spaceBetween,
+          crossAxisAlignment: CrossAxisAlignment.center,
+          children: [
+            Text('settings_label_counts_by_day_days_count').tr(),
+            ToggleButtons(
+              onPressed: (int index) {
+                setState(() {
+                  countsByDayDaysCount = DefaultSettings.allowedValues[index];
+                  for (int i = 0; i < _selectedCountsByDayDaysCount.length; i++) {
+                    _selectedCountsByDayDaysCount[i] = i == index;
+                  }
+                });
+              },
+              borderRadius: const BorderRadius.all(Radius.circular(8)),
+              constraints: const BoxConstraints(minHeight: 30.0, minWidth: 30.0),
+              isSelected: _selectedCountsByDayDaysCount,
+              children: DefaultSettings.allowedValues.map((e) => Text(e.toString())).toList(),
+            ),
+          ],
         ),
-        SizedBox(height: 16),
-        Text('settings_label_security_token').tr(),
-        TextFormField(
-          controller: securityTokenController,
-          decoration: InputDecoration(
-            border: UnderlineInputBorder(),
-          ),
+
+        // Counts by hour
+        Row(
+          mainAxisAlignment: MainAxisAlignment.spaceBetween,
+          crossAxisAlignment: CrossAxisAlignment.center,
+          children: [
+            Text('settings_label_counts_by_hour_days_count').tr(),
+            ToggleButtons(
+              onPressed: (int index) {
+                setState(() {
+                  countsByHourDaysCount = DefaultSettings.allowedValues[index];
+                  for (int i = 0; i < _selectedCountsByHourDaysCount.length; i++) {
+                    _selectedCountsByHourDaysCount[i] = i == index;
+                  }
+                });
+              },
+              borderRadius: const BorderRadius.all(Radius.circular(8)),
+              constraints: const BoxConstraints(minHeight: 30.0, minWidth: 30.0),
+              isSelected: _selectedCountsByHourDaysCount,
+              children: DefaultSettings.allowedValues.map((e) => Text(e.toString())).toList(),
+            ),
+          ],
+        ),
+
+        // Discoveries
+        Row(
+          mainAxisAlignment: MainAxisAlignment.spaceBetween,
+          crossAxisAlignment: CrossAxisAlignment.center,
+          children: [
+            Text('settings_label_discoveries_days_count').tr(),
+            ToggleButtons(
+              onPressed: (int index) {
+                setState(() {
+                  discoveriesDaysCount = DefaultSettings.allowedValues[index];
+                  for (int i = 0; i < _selectedDiscoveriesDaysCount.length; i++) {
+                    _selectedDiscoveriesDaysCount[i] = i == index;
+                  }
+                });
+              },
+              borderRadius: const BorderRadius.all(Radius.circular(8)),
+              constraints: const BoxConstraints(minHeight: 30.0, minWidth: 30.0),
+              isSelected: _selectedDiscoveriesDaysCount,
+              children: DefaultSettings.allowedValues.map((e) => Text(e.toString())).toList(),
+            ),
+          ],
         ),
-        SizedBox(height: 20),
+
+        // Statistics (recent)
+        Row(
+          mainAxisAlignment: MainAxisAlignment.spaceBetween,
+          crossAxisAlignment: CrossAxisAlignment.center,
+          children: [
+            Text('settings_label_statistics_recent_days_count').tr(),
+            ToggleButtons(
+              onPressed: (int index) {
+                setState(() {
+                  statisticsRecentDaysCount = DefaultSettings.allowedValues[index];
+                  for (int i = 0; i < _selectedStatisticsRecentDaysCount.length; i++) {
+                    _selectedStatisticsRecentDaysCount[i] = i == index;
+                  }
+                });
+              },
+              borderRadius: const BorderRadius.all(Radius.circular(8)),
+              constraints: const BoxConstraints(minHeight: 30.0, minWidth: 30.0),
+              isSelected: _selectedStatisticsRecentDaysCount,
+              children: DefaultSettings.allowedValues.map((e) => Text(e.toString())).toList(),
+            ),
+          ],
+        ),
+
+        // Timeline
+        Row(
+          mainAxisAlignment: MainAxisAlignment.spaceBetween,
+          crossAxisAlignment: CrossAxisAlignment.center,
+          children: [
+            Text('settings_label_timeline_days_count').tr(),
+            ToggleButtons(
+              onPressed: (int index) {
+                setState(() {
+                  timelineDaysCount = DefaultSettings.allowedValues[index];
+                  for (int i = 0; i < _selectedTimelineDaysCount.length; i++) {
+                    _selectedTimelineDaysCount[i] = i == index;
+                  }
+                });
+              },
+              borderRadius: const BorderRadius.all(Radius.circular(8)),
+              constraints: const BoxConstraints(minHeight: 30.0, minWidth: 30.0),
+              isSelected: _selectedTimelineDaysCount,
+              children: DefaultSettings.allowedValues.map((e) => Text(e.toString())).toList(),
+            ),
+          ],
+        ),
+
+        // Top Artists
+        Row(
+          mainAxisAlignment: MainAxisAlignment.spaceBetween,
+          crossAxisAlignment: CrossAxisAlignment.center,
+          children: [
+            Text('settings_label_top_artists_days_count').tr(),
+            ToggleButtons(
+              onPressed: (int index) {
+                setState(() {
+                  topArtistsDaysCount = DefaultSettings.allowedValues[index];
+                  for (int i = 0; i < _selectedTopArtistsDaysCount.length; i++) {
+                    _selectedTopArtistsDaysCount[i] = i == index;
+                  }
+                });
+              },
+              borderRadius: const BorderRadius.all(Radius.circular(8)),
+              constraints: const BoxConstraints(minHeight: 30.0, minWidth: 30.0),
+              isSelected: _selectedTopArtistsDaysCount,
+              children: DefaultSettings.allowedValues.map((e) => Text(e.toString())).toList(),
+            ),
+          ],
+        ),
+
+        // Save
         ElevatedButton(
           child: Row(
             mainAxisAlignment: MainAxisAlignment.center,
diff --git a/pubspec.yaml b/pubspec.yaml
index 8a873de..39544e3 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -3,7 +3,7 @@ description: Display scrobbles data and charts
 
 publish_to: 'none'
 
-version: 0.0.35+35
+version: 0.0.36+36
 
 environment:
   sdk: '^3.0.0'
-- 
GitLab