From 06ec3495b1bfb3afc47803501bba91e2e0592718 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Harrault?= <benoit@harrault.fr> Date: Mon, 13 Nov 2023 02:04:00 +0100 Subject: [PATCH] Persist API data --- android/gradle.properties | 4 +- assets/translations/en.json | 1 + assets/translations/fr.json | 1 + .../metadata/android/en-US/changelogs/29.txt | 1 + .../metadata/android/fr-FR/changelogs/29.txt | 1 + lib/cubit/data_counts_by_day_cubit.dart | 39 ++++ lib/cubit/data_counts_by_day_state.dart | 15 ++ lib/cubit/data_counts_by_hour_cubit.dart | 39 ++++ lib/cubit/data_counts_by_hour_state.dart | 15 ++ lib/cubit/data_discoveries_cubit.dart | 39 ++++ lib/cubit/data_discoveries_state.dart | 15 ++ lib/cubit/data_statistics_global_cubit.dart | 39 ++++ lib/cubit/data_statistics_global_state.dart | 15 ++ lib/cubit/data_statistics_recent_cubit.dart | 39 ++++ lib/cubit/data_statistics_recent_state.dart | 15 ++ lib/cubit/data_timeline_cubit.dart | 39 ++++ lib/cubit/data_timeline_state.dart | 15 ++ lib/cubit/data_top_artists_cubit.dart | 39 ++++ lib/cubit/data_top_artists_state.dart | 15 ++ lib/models/counts_by_day.dart | 12 +- lib/models/counts_by_hour.dart | 12 +- lib/models/discoveries.dart | 12 +- lib/models/statistics_global.dart | 22 +- lib/models/statistics_recent.dart | 29 ++- lib/models/timeline.dart | 12 +- lib/models/topartists.dart | 16 +- lib/ui/widgets/app_bar.dart | 2 + lib/ui/widgets/cards/counts_by_day.dart | 45 ++-- lib/ui/widgets/cards/counts_by_hour.dart | 45 ++-- lib/ui/widgets/cards/discoveries.dart | 89 ++++---- lib/ui/widgets/cards/statistics_global.dart | 39 ++-- lib/ui/widgets/cards/statistics_recent.dart | 48 ++-- lib/ui/widgets/cards/timeline.dart | 59 +++-- lib/ui/widgets/cards/top_artists.dart | 45 ++-- lib/ui/widgets/content/statistics_global.dart | 10 +- lib/ui/widgets/content/statistics_recent.dart | 6 +- lib/ui/widgets/update_data.dart | 209 ++++++++++++++++++ pubspec.yaml | 2 +- 38 files changed, 835 insertions(+), 265 deletions(-) create mode 100644 fastlane/metadata/android/en-US/changelogs/29.txt create mode 100644 fastlane/metadata/android/fr-FR/changelogs/29.txt create mode 100644 lib/cubit/data_counts_by_day_cubit.dart create mode 100644 lib/cubit/data_counts_by_day_state.dart create mode 100644 lib/cubit/data_counts_by_hour_cubit.dart create mode 100644 lib/cubit/data_counts_by_hour_state.dart create mode 100644 lib/cubit/data_discoveries_cubit.dart create mode 100644 lib/cubit/data_discoveries_state.dart create mode 100644 lib/cubit/data_statistics_global_cubit.dart create mode 100644 lib/cubit/data_statistics_global_state.dart create mode 100644 lib/cubit/data_statistics_recent_cubit.dart create mode 100644 lib/cubit/data_statistics_recent_state.dart create mode 100644 lib/cubit/data_timeline_cubit.dart create mode 100644 lib/cubit/data_timeline_state.dart create mode 100644 lib/cubit/data_top_artists_cubit.dart create mode 100644 lib/cubit/data_top_artists_state.dart create mode 100644 lib/ui/widgets/update_data.dart diff --git a/android/gradle.properties b/android/gradle.properties index e644338..d965699 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.28 -app.versionCode=28 +app.versionName=0.0.29 +app.versionCode=29 diff --git a/assets/translations/en.json b/assets/translations/en.json index 3f4f688..6b82e28 100644 --- a/assets/translations/en.json +++ b/assets/translations/en.json @@ -1,5 +1,6 @@ { "app_name": "Scrobbles", + "": "", "bottom_nav_home": "Home", "bottom_nav_discoveries": "Discoveries", diff --git a/assets/translations/fr.json b/assets/translations/fr.json index 2f2fb63..84b4236 100644 --- a/assets/translations/fr.json +++ b/assets/translations/fr.json @@ -1,5 +1,6 @@ { "app_name": "Scrobbles", + "": "", "bottom_nav_home": "Accueil", "bottom_nav_discoveries": "Découvertes", diff --git a/fastlane/metadata/android/en-US/changelogs/29.txt b/fastlane/metadata/android/en-US/changelogs/29.txt new file mode 100644 index 0000000..78d9620 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/29.txt @@ -0,0 +1 @@ +Save scrobbles data from API. diff --git a/fastlane/metadata/android/fr-FR/changelogs/29.txt b/fastlane/metadata/android/fr-FR/changelogs/29.txt new file mode 100644 index 0000000..b251952 --- /dev/null +++ b/fastlane/metadata/android/fr-FR/changelogs/29.txt @@ -0,0 +1 @@ +Sauvegarde des données d'écoutes de l'API. diff --git a/lib/cubit/data_counts_by_day_cubit.dart b/lib/cubit/data_counts_by_day_cubit.dart new file mode 100644 index 0000000..032aec8 --- /dev/null +++ b/lib/cubit/data_counts_by_day_cubit.dart @@ -0,0 +1,39 @@ +import 'package:equatable/equatable.dart'; +import 'package:flutter/material.dart'; +import 'package:hydrated_bloc/hydrated_bloc.dart'; + +import 'package:scrobbles/models/counts_by_day.dart'; + +part 'data_counts_by_day_state.dart'; + +class DataCountsByDayCubit extends HydratedCubit<DataCountsByDayState> { + DataCountsByDayCubit() : super(const DataCountsByDayState()); + + void getData(DataCountsByDayState state) { + emit(state); + } + + CountsByDayData? getValue() { + return state.countsByDay; + } + + void setValue(CountsByDayData? countsByDay) { + emit(DataCountsByDayState( + countsByDay: countsByDay, + )); + } + + @override + DataCountsByDayState? fromJson(Map<String, dynamic> json) { + return DataCountsByDayState( + countsByDay: CountsByDayData.fromJson(json['countsByDay']), + ); + } + + @override + Map<String, Object?>? toJson(DataCountsByDayState state) { + return <String, Object?>{ + 'countsByDay': state.countsByDay?.toJson(), + }; + } +} diff --git a/lib/cubit/data_counts_by_day_state.dart b/lib/cubit/data_counts_by_day_state.dart new file mode 100644 index 0000000..724bd73 --- /dev/null +++ b/lib/cubit/data_counts_by_day_state.dart @@ -0,0 +1,15 @@ +part of 'data_counts_by_day_cubit.dart'; + +@immutable +class DataCountsByDayState extends Equatable { + const DataCountsByDayState({ + this.countsByDay, + }); + + final CountsByDayData? countsByDay; + + @override + List<Object?> get props => <Object?>[ + countsByDay, + ]; +} diff --git a/lib/cubit/data_counts_by_hour_cubit.dart b/lib/cubit/data_counts_by_hour_cubit.dart new file mode 100644 index 0000000..2184993 --- /dev/null +++ b/lib/cubit/data_counts_by_hour_cubit.dart @@ -0,0 +1,39 @@ +import 'package:equatable/equatable.dart'; +import 'package:flutter/material.dart'; +import 'package:hydrated_bloc/hydrated_bloc.dart'; + +import 'package:scrobbles/models/counts_by_hour.dart'; + +part 'data_counts_by_hour_state.dart'; + +class DataCountsByHourCubit extends HydratedCubit<DataCountsByHourState> { + DataCountsByHourCubit() : super(const DataCountsByHourState()); + + void getData(DataCountsByHourState state) { + emit(state); + } + + CountsByHourData? getValue() { + return state.countsByHour; + } + + void setValue(CountsByHourData? countsByHour) { + emit(DataCountsByHourState( + countsByHour: countsByHour, + )); + } + + @override + DataCountsByHourState? fromJson(Map<String, dynamic> json) { + return DataCountsByHourState( + countsByHour: CountsByHourData.fromJson(json['countsByHour']), + ); + } + + @override + Map<String, Object?>? toJson(DataCountsByHourState state) { + return <String, Object?>{ + 'countsByHour': state.countsByHour?.toJson(), + }; + } +} diff --git a/lib/cubit/data_counts_by_hour_state.dart b/lib/cubit/data_counts_by_hour_state.dart new file mode 100644 index 0000000..3fc9aef --- /dev/null +++ b/lib/cubit/data_counts_by_hour_state.dart @@ -0,0 +1,15 @@ +part of 'data_counts_by_hour_cubit.dart'; + +@immutable +class DataCountsByHourState extends Equatable { + const DataCountsByHourState({ + this.countsByHour, + }); + + final CountsByHourData? countsByHour; + + @override + List<Object?> get props => <Object?>[ + countsByHour, + ]; +} diff --git a/lib/cubit/data_discoveries_cubit.dart b/lib/cubit/data_discoveries_cubit.dart new file mode 100644 index 0000000..1b9ff97 --- /dev/null +++ b/lib/cubit/data_discoveries_cubit.dart @@ -0,0 +1,39 @@ +import 'package:equatable/equatable.dart'; +import 'package:flutter/material.dart'; +import 'package:hydrated_bloc/hydrated_bloc.dart'; + +import 'package:scrobbles/models/discoveries.dart'; + +part 'data_discoveries_state.dart'; + +class DataDiscoveriesCubit extends HydratedCubit<DataDiscoveriesState> { + DataDiscoveriesCubit() : super(const DataDiscoveriesState()); + + void getData(DataDiscoveriesState state) { + emit(state); + } + + DiscoveriesData? getValue() { + return state.discoveries; + } + + void setValue(DiscoveriesData? discoveries) { + emit(DataDiscoveriesState( + discoveries: discoveries, + )); + } + + @override + DataDiscoveriesState? fromJson(Map<String, dynamic> json) { + return DataDiscoveriesState( + discoveries: DiscoveriesData.fromJson(json['discoveries']), + ); + } + + @override + Map<String, Object?>? toJson(DataDiscoveriesState state) { + return <String, Object?>{ + 'discoveries': state.discoveries?.toJson(), + }; + } +} diff --git a/lib/cubit/data_discoveries_state.dart b/lib/cubit/data_discoveries_state.dart new file mode 100644 index 0000000..1d43883 --- /dev/null +++ b/lib/cubit/data_discoveries_state.dart @@ -0,0 +1,15 @@ +part of 'data_discoveries_cubit.dart'; + +@immutable +class DataDiscoveriesState extends Equatable { + const DataDiscoveriesState({ + this.discoveries, + }); + + final DiscoveriesData? discoveries; + + @override + List<Object?> get props => <Object?>[ + discoveries, + ]; +} diff --git a/lib/cubit/data_statistics_global_cubit.dart b/lib/cubit/data_statistics_global_cubit.dart new file mode 100644 index 0000000..28e7e6b --- /dev/null +++ b/lib/cubit/data_statistics_global_cubit.dart @@ -0,0 +1,39 @@ +import 'package:equatable/equatable.dart'; +import 'package:flutter/material.dart'; +import 'package:hydrated_bloc/hydrated_bloc.dart'; + +import 'package:scrobbles/models/statistics_global.dart'; + +part 'data_statistics_global_state.dart'; + +class DataStatisticsGlobalCubit extends HydratedCubit<DataStatisticsGlobalState> { + DataStatisticsGlobalCubit() : super(const DataStatisticsGlobalState()); + + void getData(DataStatisticsGlobalState state) { + emit(state); + } + + StatisticsGlobalData? getValue() { + return state.statisticsGlobal; + } + + void setValue(StatisticsGlobalData? statisticsGlobal) { + emit(DataStatisticsGlobalState( + statisticsGlobal: statisticsGlobal, + )); + } + + @override + DataStatisticsGlobalState? fromJson(Map<String, dynamic> json) { + return DataStatisticsGlobalState( + statisticsGlobal: StatisticsGlobalData.fromJson(json['statisticsGlobal']), + ); + } + + @override + Map<String, Object?>? toJson(DataStatisticsGlobalState state) { + return <String, Object?>{ + 'statisticsGlobal': state.statisticsGlobal?.toJson(), + }; + } +} diff --git a/lib/cubit/data_statistics_global_state.dart b/lib/cubit/data_statistics_global_state.dart new file mode 100644 index 0000000..89ef0fd --- /dev/null +++ b/lib/cubit/data_statistics_global_state.dart @@ -0,0 +1,15 @@ +part of 'data_statistics_global_cubit.dart'; + +@immutable +class DataStatisticsGlobalState extends Equatable { + const DataStatisticsGlobalState({ + this.statisticsGlobal, + }); + + final StatisticsGlobalData? statisticsGlobal; + + @override + List<Object?> get props => <Object?>[ + statisticsGlobal, + ]; +} diff --git a/lib/cubit/data_statistics_recent_cubit.dart b/lib/cubit/data_statistics_recent_cubit.dart new file mode 100644 index 0000000..d2bc445 --- /dev/null +++ b/lib/cubit/data_statistics_recent_cubit.dart @@ -0,0 +1,39 @@ +import 'package:equatable/equatable.dart'; +import 'package:flutter/material.dart'; +import 'package:hydrated_bloc/hydrated_bloc.dart'; + +import 'package:scrobbles/models/statistics_recent.dart'; + +part 'data_statistics_recent_state.dart'; + +class DataStatisticsRecentCubit extends HydratedCubit<DataStatisticsRecentState> { + DataStatisticsRecentCubit() : super(const DataStatisticsRecentState()); + + void getData(DataStatisticsRecentState state) { + emit(state); + } + + StatisticsRecentData? getValue() { + return state.statisticsRecent; + } + + void setValue(StatisticsRecentData? statisticsRecent) { + emit(DataStatisticsRecentState( + statisticsRecent: statisticsRecent, + )); + } + + @override + DataStatisticsRecentState? fromJson(Map<String, dynamic> json) { + return DataStatisticsRecentState( + statisticsRecent: StatisticsRecentData.fromJson(json['statisticsRecent']), + ); + } + + @override + Map<String, Object?>? toJson(DataStatisticsRecentState state) { + return <String, Object?>{ + 'statisticsRecent': state.statisticsRecent?.toJson(), + }; + } +} diff --git a/lib/cubit/data_statistics_recent_state.dart b/lib/cubit/data_statistics_recent_state.dart new file mode 100644 index 0000000..1bf9d2f --- /dev/null +++ b/lib/cubit/data_statistics_recent_state.dart @@ -0,0 +1,15 @@ +part of 'data_statistics_recent_cubit.dart'; + +@immutable +class DataStatisticsRecentState extends Equatable { + const DataStatisticsRecentState({ + this.statisticsRecent, + }); + + final StatisticsRecentData? statisticsRecent; + + @override + List<Object?> get props => <Object?>[ + statisticsRecent, + ]; +} diff --git a/lib/cubit/data_timeline_cubit.dart b/lib/cubit/data_timeline_cubit.dart new file mode 100644 index 0000000..597e594 --- /dev/null +++ b/lib/cubit/data_timeline_cubit.dart @@ -0,0 +1,39 @@ +import 'package:equatable/equatable.dart'; +import 'package:flutter/material.dart'; +import 'package:hydrated_bloc/hydrated_bloc.dart'; + +import 'package:scrobbles/models/timeline.dart'; + +part 'data_timeline_state.dart'; + +class DataTimelineCubit extends HydratedCubit<DataTimelineState> { + DataTimelineCubit() : super(const DataTimelineState()); + + void getData(DataTimelineState state) { + emit(state); + } + + TimelineData? getValue() { + return state.timeline; + } + + void setValue(TimelineData? timeline) { + emit(DataTimelineState( + timeline: timeline, + )); + } + + @override + DataTimelineState? fromJson(Map<String, dynamic> json) { + return DataTimelineState( + timeline: TimelineData.fromJson(json['timeline']), + ); + } + + @override + Map<String, Object?>? toJson(DataTimelineState state) { + return <String, Object?>{ + 'timeline': state.timeline?.toJson(), + }; + } +} diff --git a/lib/cubit/data_timeline_state.dart b/lib/cubit/data_timeline_state.dart new file mode 100644 index 0000000..b0531c7 --- /dev/null +++ b/lib/cubit/data_timeline_state.dart @@ -0,0 +1,15 @@ +part of 'data_timeline_cubit.dart'; + +@immutable +class DataTimelineState extends Equatable { + const DataTimelineState({ + this.timeline, + }); + + final TimelineData? timeline; + + @override + List<Object?> get props => <Object?>[ + timeline, + ]; +} diff --git a/lib/cubit/data_top_artists_cubit.dart b/lib/cubit/data_top_artists_cubit.dart new file mode 100644 index 0000000..0011c5e --- /dev/null +++ b/lib/cubit/data_top_artists_cubit.dart @@ -0,0 +1,39 @@ +import 'package:equatable/equatable.dart'; +import 'package:flutter/material.dart'; +import 'package:hydrated_bloc/hydrated_bloc.dart'; + +import 'package:scrobbles/models/topartists.dart'; + +part 'data_top_artists_state.dart'; + +class DataTopArtistsCubit extends HydratedCubit<DataTopArtistsState> { + DataTopArtistsCubit() : super(const DataTopArtistsState()); + + void getData(DataTopArtistsState state) { + emit(state); + } + + TopArtistsData? getValue(key) { + return state.topArtists; + } + + void setValue(TopArtistsData? topArtists) { + emit(DataTopArtistsState( + topArtists: topArtists, + )); + } + + @override + DataTopArtistsState? fromJson(Map<String, dynamic> json) { + return DataTopArtistsState( + topArtists: TopArtistsData.fromJson(json['topArtists']), + ); + } + + @override + Map<String, Object?>? toJson(DataTopArtistsState state) { + return <String, Object?>{ + 'topArtists': state.topArtists?.toJson(), + }; + } +} diff --git a/lib/cubit/data_top_artists_state.dart b/lib/cubit/data_top_artists_state.dart new file mode 100644 index 0000000..e6d14c0 --- /dev/null +++ b/lib/cubit/data_top_artists_state.dart @@ -0,0 +1,15 @@ +part of 'data_top_artists_cubit.dart'; + +@immutable +class DataTopArtistsState extends Equatable { + const DataTopArtistsState({ + this.topArtists, + }); + + final TopArtistsData? topArtists; + + @override + List<Object?> get props => <Object?>[ + topArtists, + ]; +} diff --git a/lib/models/counts_by_day.dart b/lib/models/counts_by_day.dart index fcb4551..27e41f6 100644 --- a/lib/models/counts_by_day.dart +++ b/lib/models/counts_by_day.dart @@ -19,11 +19,7 @@ class CountsByDayData { return CountsByDayData(data: data); } - factory CountsByDayData.createEmpty() { - return CountsByDayData.fromJson({'counts-by-day': {}}); - } - - String toString() { + Map<String, Object?>? toJson() { Map<String, double> map = {}; this.data.keys.forEach((day) { @@ -31,6 +27,10 @@ class CountsByDayData { map[day.toString()] = value != null ? value.toDouble() : 0.0; }); - return jsonEncode({'counts-by-day': map}); + return {'counts-by-day': map}; + } + + String toString() { + return jsonEncode(this.toJson()); } } diff --git a/lib/models/counts_by_hour.dart b/lib/models/counts_by_hour.dart index f0c6d50..7bf3802 100644 --- a/lib/models/counts_by_hour.dart +++ b/lib/models/counts_by_hour.dart @@ -21,11 +21,7 @@ class CountsByHourData { return CountsByHourData(data: data); } - factory CountsByHourData.createEmpty() { - return CountsByHourData.fromJson({}); - } - - String toString() { + Map<String, Object?>? toJson() { Map<String, double> map = {}; this.data.keys.forEach((day) { @@ -33,6 +29,10 @@ class CountsByHourData { map[day.toString()] = value != null ? value.toDouble() : 0.0; }); - return jsonEncode({'counts-by-hour': map}); + return {'counts-by-hour': map}; + } + + String toString() { + return jsonEncode(this.toJson()); } } diff --git a/lib/models/discoveries.dart b/lib/models/discoveries.dart index 14f5819..386098f 100644 --- a/lib/models/discoveries.dart +++ b/lib/models/discoveries.dart @@ -36,11 +36,7 @@ class DiscoveriesData { return DiscoveriesData(data: data); } - factory DiscoveriesData.createEmpty() { - return DiscoveriesData.fromJson({}); - } - - String toString() { + Map<String, Object?>? toJson() { Map<String, Map<String, int>> map = {}; this.data.keys.forEach((element) { @@ -51,6 +47,10 @@ class DiscoveriesData { }; }); - return jsonEncode(map); + return map; + } + + String toString() { + return jsonEncode(this.toJson()); } } diff --git a/lib/models/statistics_global.dart b/lib/models/statistics_global.dart index 4eb90fc..1f87265 100644 --- a/lib/models/statistics_global.dart +++ b/lib/models/statistics_global.dart @@ -1,8 +1,8 @@ import 'dart:convert'; class StatisticsGlobalData { - final int totalCount; - final DateTime lastScrobble; + final int? totalCount; + final DateTime? lastScrobble; const StatisticsGlobalData({ required this.totalCount, @@ -11,27 +11,25 @@ class StatisticsGlobalData { factory StatisticsGlobalData.fromJson(Map<String, dynamic>? json) { return StatisticsGlobalData( - totalCount: (json?['totalCount'] != null) ? (json?['totalCount'] as int) : 0, + totalCount: (json?['totalCount'] != null) ? (json?['totalCount'] as int) : null, lastScrobble: (json?['lastScrobble'] != null && json?['lastScrobble']['date'] != null) ? DateTime.parse( json?['lastScrobble']['date'], ) - : DateTime.now(), + : null, ); } - factory StatisticsGlobalData.createEmpty() { - return StatisticsGlobalData.fromJson({}); - } - - String toString() { - Map<String, dynamic> map = { + Map<String, Object?>? toJson() { + return <String, Object?>{ 'totalCount': this.totalCount, 'lastScrobble': { - 'date': this.lastScrobble.toString(), + 'date': this.lastScrobble != null ? this.lastScrobble.toString() : null, }, }; + } - return jsonEncode(map); + String toString() { + return jsonEncode(this.toJson()); } } diff --git a/lib/models/statistics_recent.dart b/lib/models/statistics_recent.dart index d72173f..1f342f9 100644 --- a/lib/models/statistics_recent.dart +++ b/lib/models/statistics_recent.dart @@ -1,10 +1,10 @@ import 'dart:convert'; class StatisticsRecentData { - final int recentCount; - final int firstPlayedArtistsCount; - final int firstPlayedTracksCount; - final int selectedPeriod; + final int? recentCount; + final int? firstPlayedArtistsCount; + final int? firstPlayedTracksCount; + final int? selectedPeriod; const StatisticsRecentData({ required this.recentCount, @@ -15,29 +15,28 @@ class StatisticsRecentData { factory StatisticsRecentData.fromJson(Map<String, dynamic>? json) { return StatisticsRecentData( - recentCount: (json?['recentCount'] != null) ? (json?['recentCount'] as int) : 0, + recentCount: (json?['recentCount'] != null) ? (json?['recentCount'] as int) : null, firstPlayedArtistsCount: (json?['firstPlayedArtistsCount'] != null) ? (json?['firstPlayedArtistsCount'] as int) - : 0, + : null, firstPlayedTracksCount: (json?['firstPlayedTracksCount'] != null) ? (json?['firstPlayedTracksCount'] as int) - : 0, - selectedPeriod: (json?['selectedPeriod'] != null) ? (json?['selectedPeriod'] as int) : 0, + : null, + selectedPeriod: + (json?['selectedPeriod'] != null) ? (json?['selectedPeriod'] as int) : null, ); } - factory StatisticsRecentData.createEmpty() { - return StatisticsRecentData.fromJson({}); - } - - String toString() { - Map<String, dynamic> map = { + Map<String, Object?>? toJson() { + return <String, Object?>{ 'recentCount': this.recentCount, 'firstPlayedArtistsCount': this.firstPlayedArtistsCount, 'firstPlayedTracksCount': this.firstPlayedTracksCount, 'selectedPeriod': this.selectedPeriod, }; + } - return jsonEncode(map); + String toString() { + return jsonEncode(this.toJson()); } } diff --git a/lib/models/timeline.dart b/lib/models/timeline.dart index b52a546..37f987b 100644 --- a/lib/models/timeline.dart +++ b/lib/models/timeline.dart @@ -36,11 +36,7 @@ class TimelineData { return TimelineData(data: data); } - factory TimelineData.createEmpty() { - return TimelineData.fromJson({}); - } - - String toString() { + Map<String, Object?>? toJson() { Map<String, Map<String, int>> map = {}; this.data.keys.forEach((element) { @@ -51,6 +47,10 @@ class TimelineData { }; }); - return jsonEncode(map); + return map; + } + + String toString() { + return jsonEncode(this.toJson()); } } diff --git a/lib/models/topartists.dart b/lib/models/topartists.dart index 9a7b418..6c27190 100644 --- a/lib/models/topartists.dart +++ b/lib/models/topartists.dart @@ -38,13 +38,7 @@ class TopArtistsData { ); } - factory TopArtistsData.createEmpty() { - return TopArtistsData.fromJson({ - 'top-artists': [], - }); - } - - String toString() { + Map<String, Object?>? toJson() { List<Map<String, Object>> listArtists = []; this.topArtists.forEach((TopArtistsDataValue? item) { @@ -54,8 +48,12 @@ class TopArtistsData { }); }); - return jsonEncode({ + return { 'top-artists': listArtists, - }); + }; + } + + String toString() { + return jsonEncode(this.toJson()); } } diff --git a/lib/ui/widgets/app_bar.dart b/lib/ui/widgets/app_bar.dart index 6db981e..63256fb 100644 --- a/lib/ui/widgets/app_bar.dart +++ b/lib/ui/widgets/app_bar.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:unicons/unicons.dart'; +import 'package:scrobbles/ui/widgets/update_data.dart'; import 'package:scrobbles/ui/widgets/header_app.dart'; class StandardAppBar extends StatelessWidget implements PreferredSizeWidget { @@ -13,6 +14,7 @@ class StandardAppBar extends StatelessWidget implements PreferredSizeWidget { return AppBar( title: const AppHeader(text: 'app_name'), actions: [ + UpdateData(), IconButton( onPressed: () { this.notifyParent(); diff --git a/lib/ui/widgets/cards/counts_by_day.dart b/lib/ui/widgets/cards/counts_by_day.dart index 59d80cb..98c6cfe 100644 --- a/lib/ui/widgets/cards/counts_by_day.dart +++ b/lib/ui/widgets/cards/counts_by_day.dart @@ -2,12 +2,12 @@ import 'dart:convert'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:scrobbles/cubit/data_counts_by_day_cubit.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}); @@ -15,30 +15,25 @@ class CardCountsByDay extends StatelessWidget { @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, - ), - ); - }, + return BlocProvider<DataCountsByDayCubit>( + create: (BuildContext context) => DataCountsByDayCubit(), + child: BlocBuilder<DataCountsByDayCubit, DataCountsByDayState>( + builder: (BuildContext context, DataCountsByDayState state) { + return CardContent( + color: Theme.of(context).colorScheme.surface, + title: 'counts_by_day'.tr( + namedArgs: { + 'daysCount': daysCount.toString(), + }, + ), + 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 6c0d91f..595818e 100644 --- a/lib/ui/widgets/cards/counts_by_hour.dart +++ b/lib/ui/widgets/cards/counts_by_hour.dart @@ -2,12 +2,12 @@ import 'dart:convert'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:scrobbles/cubit/data_counts_by_hour_cubit.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}); @@ -15,30 +15,25 @@ class CardCountsByHour extends StatelessWidget { @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, - ), - ); - }, + return BlocProvider<DataCountsByHourCubit>( + create: (BuildContext context) => DataCountsByHourCubit(), + child: BlocBuilder<DataCountsByHourCubit, DataCountsByHourState>( + builder: (BuildContext context, DataCountsByHourState state) { + return CardContent( + color: Theme.of(context).colorScheme.surface, + title: 'counts_by_hour'.tr( + namedArgs: { + 'daysCount': daysCount.toString(), + }, + ), + 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 f0cd96d..fb3baf5 100644 --- a/lib/ui/widgets/cards/discoveries.dart +++ b/lib/ui/widgets/cards/discoveries.dart @@ -2,13 +2,13 @@ import 'dart:convert'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:scrobbles/cubit/data_discoveries_cubit.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}); @@ -16,51 +16,50 @@ class CardDiscoveries extends StatelessWidget { @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}'); - } + return BlocProvider<DataDiscoveriesCubit>( + create: (BuildContext context) => DataDiscoveriesCubit(), + child: BlocBuilder<DataDiscoveriesCubit, DataDiscoveriesState>( + builder: (BuildContext context, DataDiscoveriesState state) { + final TextTheme textTheme = Theme.of(context).primaryTextTheme; - 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, - ), - ], - ), - ); - }, + 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(state.discoveries.toString())), + isLoading: false, + ), + const SizedBox(height: 8), + Text( + 'discoveries_tracks_title', + style: textTheme.titleMedium!.apply(fontWeightDelta: 2), + ).tr(), + const SizedBox(height: 8), + ChartDiscoveriesTracks( + chartData: + DiscoveriesData.fromJson(jsonDecode(state.discoveries.toString())), + isLoading: false, + ), + ], + ), + ); + }, + ), ); } } diff --git a/lib/ui/widgets/cards/statistics_global.dart b/lib/ui/widgets/cards/statistics_global.dart index 0d8feb8..4980d5c 100644 --- a/lib/ui/widgets/cards/statistics_global.dart +++ b/lib/ui/widgets/cards/statistics_global.dart @@ -2,38 +2,33 @@ import 'dart:convert'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:scrobbles/cubit/data_statistics_global_cubit.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, - ), - ); - }, + return BlocProvider<DataStatisticsGlobalCubit>( + create: (BuildContext context) => DataStatisticsGlobalCubit(), + child: BlocBuilder<DataStatisticsGlobalCubit, DataStatisticsGlobalState>( + builder: (BuildContext context, DataStatisticsGlobalState state) { + return CardContent( + color: Theme.of(context).colorScheme.primary, + title: 'global_statistics'.tr(), + content: ContentStatisticsGlobal( + statistics: + StatisticsGlobalData.fromJson(jsonDecode(state.statisticsGlobal.toString())), + isLoading: false, + ), + ); + }, + ), ); } } diff --git a/lib/ui/widgets/cards/statistics_recent.dart b/lib/ui/widgets/cards/statistics_recent.dart index 0925c42..9a14c8a 100644 --- a/lib/ui/widgets/cards/statistics_recent.dart +++ b/lib/ui/widgets/cards/statistics_recent.dart @@ -2,12 +2,12 @@ import 'dart:convert'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:scrobbles/cubit/data_statistics_recent_cubit.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}); @@ -16,30 +16,26 @@ class CardStatisticsRecent extends StatelessWidget { 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, - ), - ); - }, + // data context + return BlocProvider<DataStatisticsRecentCubit>( + create: (BuildContext context) => DataStatisticsRecentCubit(), + child: BlocBuilder<DataStatisticsRecentCubit, DataStatisticsRecentState>( + builder: (BuildContext context, DataStatisticsRecentState dataState) { + return CardContent( + color: Theme.of(context).colorScheme.primary, + title: 'recent_statistics'.tr( + namedArgs: { + 'daysCount': daysCount.toString(), + }, + ), + content: ContentStatisticsRecent( + statistics: StatisticsRecentData.fromJson( + jsonDecode(dataState.statisticsRecent.toString())), + isLoading: false, + ), + ); + }, + ), ); } } diff --git a/lib/ui/widgets/cards/timeline.dart b/lib/ui/widgets/cards/timeline.dart index a7ea95d..a7b20d4 100644 --- a/lib/ui/widgets/cards/timeline.dart +++ b/lib/ui/widgets/cards/timeline.dart @@ -2,13 +2,13 @@ import 'dart:convert'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:scrobbles/cubit/data_timeline_cubit.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}); @@ -16,36 +16,33 @@ class CardTimeline extends StatelessWidget { @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, - ), - ], - ), - ); - }, + return BlocProvider<DataTimelineCubit>( + create: (BuildContext context) => DataTimelineCubit(), + child: BlocBuilder<DataTimelineCubit, DataTimelineState>( + builder: (BuildContext context, DataTimelineState state) { + return CardContent( + color: Theme.of(context).colorScheme.surface, + title: 'timeline_title'.tr( + namedArgs: { + 'daysCount': daysCount.toString(), + }, + ), + content: Stack( + children: [ + ChartTimelineCounts( + chartData: TimelineData.fromJson(jsonDecode(state.timeline.toString())), + isLoading: false, + ), + ChartTimelineEclecticism( + chartData: TimelineData.fromJson(jsonDecode(state.timeline.toString())), + isLoading: false, + ), + ], + ), + ); + }, + ), ); } } diff --git a/lib/ui/widgets/cards/top_artists.dart b/lib/ui/widgets/cards/top_artists.dart index d589518..7e05208 100644 --- a/lib/ui/widgets/cards/top_artists.dart +++ b/lib/ui/widgets/cards/top_artists.dart @@ -2,12 +2,12 @@ import 'dart:convert'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:scrobbles/cubit/data_top_artists_cubit.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}); @@ -15,30 +15,25 @@ class CardTopArtists extends StatelessWidget { @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, - ), - ); - }, + return BlocProvider<DataTopArtistsCubit>( + create: (BuildContext context) => DataTopArtistsCubit(), + child: BlocBuilder<DataTopArtistsCubit, DataTopArtistsState>( + builder: (BuildContext context, DataTopArtistsState state) { + return CardContent( + color: Theme.of(context).colorScheme.surface, + title: 'top_artists_title'.tr( + namedArgs: { + 'daysCount': daysCount.toString(), + }, + ), + content: ChartTopArtists( + chartData: TopArtistsData.fromJson(jsonDecode(state.topArtists.toString())), + isLoading: false, + ), + ); + }, + ), ); } } diff --git a/lib/ui/widgets/content/statistics_global.dart b/lib/ui/widgets/content/statistics_global.dart index d171441..c68d249 100644 --- a/lib/ui/widgets/content/statistics_global.dart +++ b/lib/ui/widgets/content/statistics_global.dart @@ -24,7 +24,11 @@ class ContentStatisticsGlobal extends StatelessWidget { style: textTheme.bodyMedium, ).tr( namedArgs: { - 'count': this.isLoading ? placeholder : this.statistics.totalCount.toString(), + 'count': this.isLoading + ? placeholder + : (this.statistics.totalCount != null + ? this.statistics.totalCount.toString() + : ''), }, ), Text( @@ -34,7 +38,9 @@ class ContentStatisticsGlobal extends StatelessWidget { namedArgs: { 'datetime': this.isLoading ? placeholder - : DateFormat().format(this.statistics.lastScrobble), + : (this.statistics.lastScrobble != null + ? DateFormat().format(this.statistics.lastScrobble ?? DateTime.now()) + : ''), }, ), ], diff --git a/lib/ui/widgets/content/statistics_recent.dart b/lib/ui/widgets/content/statistics_recent.dart index 01f04ac..cecbff9 100644 --- a/lib/ui/widgets/content/statistics_recent.dart +++ b/lib/ui/widgets/content/statistics_recent.dart @@ -20,7 +20,11 @@ class ContentStatisticsRecent extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: <Widget>[ Text( - 'statistics_recent_scrobbles_count_and_discoveries', + (this.statistics.recentCount != null && + this.statistics.firstPlayedArtistsCount != null && + this.statistics.firstPlayedTracksCount != null) + ? 'statistics_recent_scrobbles_count_and_discoveries' + : '', style: textTheme.bodyMedium, ).tr( namedArgs: { diff --git a/lib/ui/widgets/update_data.dart b/lib/ui/widgets/update_data.dart new file mode 100644 index 0000000..7bc4101 --- /dev/null +++ b/lib/ui/widgets/update_data.dart @@ -0,0 +1,209 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +import 'package:scrobbles/cubit/data_counts_by_day_cubit.dart'; +import 'package:scrobbles/cubit/data_counts_by_hour_cubit.dart'; +import 'package:scrobbles/cubit/data_discoveries_cubit.dart'; +import 'package:scrobbles/cubit/data_statistics_global_cubit.dart'; +import 'package:scrobbles/cubit/data_statistics_recent_cubit.dart'; +import 'package:scrobbles/cubit/data_timeline_cubit.dart'; +import 'package:scrobbles/cubit/data_top_artists_cubit.dart'; +import 'package:scrobbles/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'; +import 'package:scrobbles/network/scrobbles.dart'; +import 'package:scrobbles/ui/widgets/error.dart'; + +class UpdateData extends StatelessWidget { + const UpdateData({super.key}); + + final int daysCount = 21; + final Widget loading = const Text('â³'); + final Widget done = const Text(''); + + @override + Widget build(BuildContext context) { + return Padding( + padding: EdgeInsets.all(4), + child: Stack( + children: [ + updateCountsByDay(daysCount), + updateCountsByHour(daysCount), + updateDiscoveries(daysCount), + updateStatisticsGlobal(), + updateStatisticsRecent(daysCount), + updateTimeline(daysCount), + updateTopArtists(daysCount), + ], + ), + ); + } + + Widget updateCountsByDay(int daysCount) { + late Future<CountsByDayData> futureCountsByDay = ScrobblesApi.fetchCountsByDay(daysCount); + + return BlocProvider<DataCountsByDayCubit>( + create: (BuildContext context) => DataCountsByDayCubit(), + child: BlocBuilder<DataCountsByDayCubit, DataCountsByDayState>( + builder: (BuildContext context, DataCountsByDayState state) { + return FutureBuilder<CountsByDayData>( + future: futureCountsByDay, + builder: (context, snapshot) { + if (snapshot.hasError) { + return ShowErrorWidget(message: '${snapshot.error}'); + } + + BlocProvider.of<DataCountsByDayCubit>(context).setValue(snapshot.data); + return !snapshot.hasData ? loading : done; + }, + ); + }, + ), + ); + } + + Widget updateCountsByHour(int daysCount) { + late Future<CountsByHourData> futureCountsByHour = + ScrobblesApi.fetchCountsByHour(daysCount); + + return BlocProvider<DataCountsByHourCubit>( + create: (BuildContext context) => DataCountsByHourCubit(), + child: BlocBuilder<DataCountsByHourCubit, DataCountsByHourState>( + builder: (BuildContext context, DataCountsByHourState state) { + return FutureBuilder<CountsByHourData>( + future: futureCountsByHour, + builder: (context, snapshot) { + if (snapshot.hasError) { + return ShowErrorWidget(message: '${snapshot.error}'); + } + + BlocProvider.of<DataCountsByHourCubit>(context).setValue(snapshot.data); + return !snapshot.hasData ? loading : done; + }, + ); + }, + ), + ); + } + + Widget updateDiscoveries(int daysCount) { + late Future<DiscoveriesData> futureDiscoveries = ScrobblesApi.fetchDiscoveries(daysCount); + + return BlocProvider<DataDiscoveriesCubit>( + create: (BuildContext context) => DataDiscoveriesCubit(), + child: BlocBuilder<DataDiscoveriesCubit, DataDiscoveriesState>( + builder: (BuildContext context, DataDiscoveriesState state) { + return FutureBuilder<DiscoveriesData>( + future: futureDiscoveries, + builder: (context, snapshot) { + if (snapshot.hasError) { + return ShowErrorWidget(message: '${snapshot.error}'); + } + + BlocProvider.of<DataDiscoveriesCubit>(context).setValue(snapshot.data); + return !snapshot.hasData ? loading : done; + }, + ); + }, + ), + ); + } + + Widget updateStatisticsGlobal() { + late Future<StatisticsGlobalData> futureStatisticsGlobal = + ScrobblesApi.fetchGlobalStatistics(); + + return BlocProvider<DataStatisticsGlobalCubit>( + create: (BuildContext context) => DataStatisticsGlobalCubit(), + child: BlocBuilder<DataStatisticsGlobalCubit, DataStatisticsGlobalState>( + builder: (BuildContext context, DataStatisticsGlobalState dataState) { + return FutureBuilder<StatisticsGlobalData>( + future: futureStatisticsGlobal, + builder: (context, snapshot) { + if (snapshot.hasError) { + return ShowErrorWidget(message: '${snapshot.error}'); + } + + BlocProvider.of<DataStatisticsGlobalCubit>(context).setValue(snapshot.data); + return !snapshot.hasData ? loading : done; + }, + ); + }, + ), + ); + } + + Widget updateStatisticsRecent(int daysCount) { + late Future<StatisticsRecentData> futureStatisticsRecent = + ScrobblesApi.fetchRecentStatistics(daysCount); + + return BlocProvider<DataStatisticsRecentCubit>( + create: (BuildContext context) => DataStatisticsRecentCubit(), + child: BlocBuilder<DataStatisticsRecentCubit, DataStatisticsRecentState>( + builder: (BuildContext context, DataStatisticsRecentState state) { + return FutureBuilder<StatisticsRecentData>( + future: futureStatisticsRecent, + builder: (context, snapshot) { + if (snapshot.hasError) { + return ShowErrorWidget(message: '${snapshot.error}'); + } + + BlocProvider.of<DataStatisticsRecentCubit>(context).setValue(snapshot.data); + return !snapshot.hasData ? loading : done; + }, + ); + }, + ), + ); + } + + Widget updateTimeline(int daysCount) { + late Future<TimelineData> futureTimeline = ScrobblesApi.fetchTimeline(daysCount); + + return BlocProvider<DataTimelineCubit>( + create: (BuildContext context) => DataTimelineCubit(), + child: BlocBuilder<DataTimelineCubit, DataTimelineState>( + builder: (BuildContext context, DataTimelineState state) { + return FutureBuilder<TimelineData>( + future: futureTimeline, + builder: (context, snapshot) { + if (snapshot.hasError) { + return ShowErrorWidget(message: '${snapshot.error}'); + } + + BlocProvider.of<DataTimelineCubit>(context).setValue(snapshot.data); + return !snapshot.hasData ? loading : done; + }, + ); + }, + ), + ); + } + + Widget updateTopArtists(int daysCount) { + late Future<TopArtistsData> futureTopArtists = ScrobblesApi.fetchTopArtists(daysCount); + + return BlocProvider<DataTopArtistsCubit>( + create: (BuildContext context) => DataTopArtistsCubit(), + child: BlocBuilder<DataTopArtistsCubit, DataTopArtistsState>( + builder: (BuildContext context, DataTopArtistsState state) { + return FutureBuilder<TopArtistsData>( + future: futureTopArtists, + builder: (context, snapshot) { + if (snapshot.hasError) { + return ShowErrorWidget(message: '${snapshot.error}'); + } + + BlocProvider.of<DataTopArtistsCubit>(context).setValue(snapshot.data); + return !snapshot.hasData ? loading : done; + }, + ); + }, + ), + ); + } +} diff --git a/pubspec.yaml b/pubspec.yaml index 33d49a5..0a0ceb2 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -3,7 +3,7 @@ description: Display scrobbles data and charts publish_to: 'none' -version: 0.0.28+28 +version: 0.0.29+29 environment: sdk: '^3.0.0' -- GitLab