Skip to content
Snippets Groups Projects
Commit 66edad8f authored by Benoît Harrault's avatar Benoît Harrault
Browse files

Improve global statistics widget

parent 6f50801a
No related branches found
No related tags found
1 merge request!7Resolve "Improve global statistics widget"
Pipeline #4435 passed
This commit is part of merge request !7. Comments created here will be created in the context of that merge request.
org.gradle.jvmargs=-Xmx1536M org.gradle.jvmargs=-Xmx1536M
android.useAndroidX=true android.useAndroidX=true
android.enableJetifier=true android.enableJetifier=true
app.versionName=0.0.5 app.versionName=0.0.6
app.versionCode=5 app.versionCode=6
...@@ -2,11 +2,9 @@ ...@@ -2,11 +2,9 @@
"app_name": "Scrobbles", "app_name": "Scrobbles",
"global_statistics": "Global statistics", "global_statistics": "Global statistics",
"statistics_total_scrobbles_count": "Total scrobbles count:", "statistics_total_scrobbles_count": "Total scrobbles count: {count}",
"statistics_last_scrobble": "Last scrobble: ", "statistics_last_scrobble": "Last scrobble: {datetime}",
"statistics_selected_period": "On last {daysCount} days:", "statistics_selected_period": "On last {daysCount} days:",
"statistics_recent_scrobbles_count": "Scrobbles:", "statistics_recent_scrobbles_count": "Scrobbles: {count}",
"statistics_discoveries": "Discoveries:", "statistics_discoveries": "Discoveries: {artistsCount} artists / {tracksCount} tracks"
"statistics_discoveries_artists": "artists",
"statistics_discoveries_tracks": "tracks"
} }
...@@ -2,11 +2,9 @@ ...@@ -2,11 +2,9 @@
"app_name": "Scrobbles", "app_name": "Scrobbles",
"global_statistics": "Statistiques globales d'écoutes", "global_statistics": "Statistiques globales d'écoutes",
"statistics_total_scrobbles_count": "Nombre total d'écoutes :", "statistics_total_scrobbles_count": "Nombre total d'écoutes : {count}",
"statistics_last_scrobble": "Dernière écoute :", "statistics_last_scrobble": "Dernière écoute : {datetime}",
"statistics_selected_period": "Sur les {daysCount} derniers jours:", "statistics_selected_period": "Sur les {daysCount} derniers jours:",
"statistics_recent_scrobbles_count": "Écoutes :", "statistics_recent_scrobbles_count": "Écoutes : {count}",
"statistics_discoveries": "Découvertes :", "statistics_discoveries": "Découvertes : {artistsCount} artistes / {tracksCount} morceaux"
"statistics_discoveries_artists": "artistes",
"statistics_discoveries_tracks": "morceaux"
} }
Improve global statistic bloc
Amélioration du bloc de statistiques globales
import 'dart:convert';
class StatisticsData { class StatisticsData {
final int totalCount; final int totalCount;
final int recentCount; final int recentCount;
...@@ -17,14 +19,37 @@ class StatisticsData { ...@@ -17,14 +19,37 @@ class StatisticsData {
factory StatisticsData.fromJson(Map<String, dynamic> json) { factory StatisticsData.fromJson(Map<String, dynamic> json) {
return StatisticsData( return StatisticsData(
totalCount: json['totalCount'] as int, totalCount: json['totalCount'] != null ? json['totalCount'] as int : 0,
recentCount: json['recentCount'] as int, recentCount: json['recentCount'] != null ? json['recentCount'] as int : 0,
firstPlayedArtistsCount: json['firstPlayedArtistsCount'] as int, firstPlayedArtistsCount:
firstPlayedTracksCount: json['firstPlayedTracksCount'] as int, json['firstPlayedArtistsCount'] != null ? json['firstPlayedArtistsCount'] as int : 0,
selectedPeriod: json['selectedPeriod'] as int, firstPlayedTracksCount:
lastScrobble: DateTime.parse( json['firstPlayedTracksCount'] != null ? json['firstPlayedTracksCount'] as int : 0,
selectedPeriod: json['selectedPeriod'] != null ? json['selectedPeriod'] as int : 0,
lastScrobble: (json['lastScrobble'] != null && json['lastScrobble']['date'] != null)
? DateTime.parse(
json['lastScrobble']['date'], json['lastScrobble']['date'],
), )
: DateTime.now(),
); );
} }
factory StatisticsData.createEmpty() {
return StatisticsData.fromJson({});
}
String toString() {
Map<String, dynamic> map = {
'totalCount': this.totalCount,
'recentCount': this.recentCount,
'firstPlayedArtistsCount': this.firstPlayedArtistsCount,
'firstPlayedTracksCount': this.firstPlayedTracksCount,
'selectedPeriod': this.selectedPeriod,
'lastScrobble': {
'date': this.lastScrobble.toString(),
},
};
return jsonEncode(map);
}
} }
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../widgets/header.dart'; import '../widgets/header.dart';
import '../widgets/main_screen/statistics.dart'; import '../widgets/main_screen/statistics_card.dart';
class MainScreen extends StatelessWidget { class MainScreen extends StatelessWidget {
const MainScreen({super.key}); const MainScreen({super.key});
...@@ -15,7 +15,7 @@ class MainScreen extends StatelessWidget { ...@@ -15,7 +15,7 @@ class MainScreen extends StatelessWidget {
physics: const BouncingScrollPhysics(), physics: const BouncingScrollPhysics(),
children: <Widget>[ children: <Widget>[
const Header(text: 'app_name'), const Header(text: 'app_name'),
const Statistics(), const StatisticsCard(),
const SizedBox(height: 36), const SizedBox(height: 36),
], ],
), ),
......
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import '../../../models/statistics.dart';
import '../../../network/scrobbles_api.dart';
import '../../../ui/widgets/error.dart';
class Statistics extends StatelessWidget {
const Statistics({super.key});
@override
Widget build(BuildContext context) {
late Future<StatisticsData> futureAlbum = ScrobblesApi.fetchStatistics();
return FutureBuilder<StatisticsData>(
future: futureAlbum,
builder: (context, snapshot) {
if (snapshot.hasData) {
final TextTheme textTheme = Theme.of(context).primaryTextTheme;
return Card(
elevation: 2,
shadowColor: Theme.of(context).colorScheme.shadow,
color: Theme.of(context).colorScheme.primary,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(12))),
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
tr('global_statistics'),
style: textTheme.titleLarge!.apply(fontWeightDelta: 2),
),
Text(
tr('statistics_total_scrobbles_count') +
' ' +
snapshot.data!.totalCount.toString(),
style: textTheme.bodyMedium,
),
Text(
tr('statistics_last_scrobble') +
' ' +
DateFormat().format(snapshot.data!.lastScrobble),
style: textTheme.bodyMedium,
),
Text(
'statistics_selected_period',
style: textTheme.bodyMedium,
).tr(namedArgs: {'daysCount': snapshot.data!.selectedPeriod.toString()}),
Text(
tr('statistics_recent_scrobbles_count') +
' ' +
snapshot.data!.recentCount.toString(),
style: textTheme.bodyMedium,
),
Text(
tr('statistics_discoveries') +
' ' +
snapshot.data!.firstPlayedArtistsCount.toString() +
' ' +
tr('statistics_discoveries_artists') +
' / ' +
snapshot.data!.firstPlayedTracksCount.toString() +
' ' +
tr('statistics_discoveries_tracks'),
style: textTheme.bodyMedium,
),
],
),
),
);
} else if (snapshot.hasError) {
return ShowErrorWidget(message: '${snapshot.error}');
}
return const CircularProgressIndicator();
},
);
}
}
import 'dart:convert';
import 'package:flutter/material.dart';
import '../../../models/statistics.dart';
import '../../../network/scrobbles_api.dart';
import '../../../ui/widgets/error.dart';
import '../../../ui/widgets/main_screen/statistics_content.dart';
class StatisticsCard extends StatelessWidget {
const StatisticsCard({super.key});
@override
Widget build(BuildContext context) {
late Future<StatisticsData> futureAlbum = ScrobblesApi.fetchStatistics();
return FutureBuilder<StatisticsData>(
future: futureAlbum,
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(12),
),
),
child: Padding(
padding: const EdgeInsets.all(12.0),
child: StatisticsContent(
statistics: snapshot.hasData
? StatisticsData.fromJson(jsonDecode(snapshot.data.toString()))
: StatisticsData.createEmpty(),
isLoading: !snapshot.hasData,
),
),
);
},
);
}
}
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import '../../../models/statistics.dart';
class StatisticsContent extends StatelessWidget {
final StatisticsData statistics;
final bool isLoading;
const StatisticsContent({super.key, required this.statistics, 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(
'global_statistics',
style: textTheme.titleLarge!.apply(fontWeightDelta: 2),
).tr(),
Text(
'statistics_total_scrobbles_count',
style: textTheme.bodyMedium,
).tr(
namedArgs: {
'count': this.isLoading ? placeholder : this.statistics.totalCount.toString(),
},
),
Text(
'statistics_last_scrobble',
style: textTheme.bodyMedium,
).tr(
namedArgs: {
'datetime': this.isLoading
? placeholder
: DateFormat().format(this.statistics.lastScrobble),
},
),
Text(
'statistics_selected_period',
style: textTheme.bodyMedium,
).tr(
namedArgs: {
'daysCount':
this.isLoading ? placeholder : this.statistics.selectedPeriod.toString(),
},
),
Text(
'statistics_recent_scrobbles_count',
style: textTheme.bodyMedium,
).tr(
namedArgs: {
'count': this.isLoading ? placeholder : this.statistics.recentCount.toString(),
},
),
Text(
'statistics_discoveries',
style: textTheme.bodyMedium,
).tr(
namedArgs: {
'artistsCount': this.isLoading
? placeholder
: this.statistics.firstPlayedArtistsCount.toString(),
'tracksCount': this.isLoading
? placeholder
: this.statistics.firstPlayedTracksCount.toString(),
},
),
],
);
}
}
...@@ -3,7 +3,7 @@ description: Display scrobbles data and charts ...@@ -3,7 +3,7 @@ description: Display scrobbles data and charts
publish_to: 'none' publish_to: 'none'
version: 0.0.5+5 version: 0.0.6+6
environment: environment:
sdk: '^3.0.0' sdk: '^3.0.0'
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment