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

Merge branch '11-improve-global-statistics-widget' into 'master'

Resolve "Improve global statistics widget"

Closes #11

See merge request !7
parents 6f50801a 66edad8f
No related branches found
No related tags found
1 merge request!7Resolve "Improve global statistics widget"
Pipeline #4437 passed
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