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

Merge branch '65-normalize-game-architecture' into 'master'

Resolve "Normalize game architecture"

Closes #65

See merge request !61
parents 2fb921a6 4b567d90
No related branches found
No related tags found
1 merge request!61Resolve "Normalize game architecture"
Pipeline #5748 passed
Showing
with 440 additions and 63 deletions
......@@ -37,7 +37,7 @@ if (keystorePropertiesFile.exists()) {
}
android {
compileSdkVersion 33
compileSdkVersion 34
namespace "org.benoitharrault.scrobbles"
defaultConfig {
......
org.gradle.jvmargs=-Xmx1536M
android.useAndroidX=true
android.enableJetifier=true
app.versionName=0.0.57
app.versionCode=57
app.versionName=0.1.0
app.versionCode=58
{
"app_name": "Scrobbles",
"": "",
"bottom_nav_home": "Home",
"bottom_nav_discoveries": "Discoveries",
"bottom_nav_repartition": "Statistics",
"page_home": "Home",
"page_discoveries": "Discoveries",
"page_statistics": "Statistics",
"bottom_nav_settings": "Settings",
"about_title": "Informations",
"about_content": "Scrobbles",
"about_version": "Version: {version}",
"global_statistics": "Global statistics",
"statistics_total_scrobbles_count": "Total scrobbles count: {count}",
"statistics_last_scrobble": "Last scrobble: {datetime}",
......@@ -50,5 +53,7 @@
"THU": "THU",
"FRI": "FRI",
"SAT": "SAT",
"SUN": "SUN"
"SUN": "SUN",
"": ""
}
{
"app_name": "Scrobbles",
"": "",
"bottom_nav_home": "Accueil",
"bottom_nav_discoveries": "Découvertes",
"bottom_nav_repartition": "Statistiques",
"page_home": "Général",
"page_discoveries": "Découvertes",
"page_statistics": "Statistiques",
"bottom_nav_settings": "Paramètres",
"about_title": "Informations",
"about_content": "Scrobbles.",
"about_version": "Version : {version}",
"global_statistics": "Statistiques globales d'écoutes",
"statistics_total_scrobbles_count": "Nombre total d'écoutes : {count}",
"statistics_last_scrobble": "Dernière écoute : {datetime}",
......@@ -34,7 +37,7 @@
"settings_label_security_token": "Jeton de sécurité : ",
"settings_title_days_count": "Nombre de jours : ",
"settings_label_discoveries_days_count": "Découvertes : ",
"settings_label_distribution_days_count": "Répartitions (par jour/heure) : ",
"settings_label_distribution_days_count": "Répartitions par jour/heure : ",
"settings_label_statistics_recent_days_count": "Statistiques : ",
"settings_label_timeline_days_count": "Timeline globale : ",
"settings_label_top_artists_days_count": "Top Artistes : ",
......@@ -50,5 +53,7 @@
"THU": "JEU",
"FRI": "VEN",
"SAT": "SAM",
"SUN": "DIM"
"SUN": "DIM",
"": ""
}
Improve/normalize app architecture.
Amélioration/normalisation de l'architecture de l'application.
import 'package:flutter/material.dart';
import 'package:ionicons/ionicons.dart';
import 'package:scrobbles/ui/pages/discoveries.dart';
import 'package:scrobbles/ui/pages/home.dart';
import 'package:scrobbles/ui/pages/statistics.dart';
class ActivityPageItem {
final Icon icon;
final Widget page;
final String code;
const ActivityPageItem({
required this.icon,
required this.page,
required this.code,
});
}
class ActivityPage {
static const indexHome = 0;
static const pageHome = ActivityPageItem(
icon: Icon(Ionicons.home_outline),
page: PageHome(),
code: 'page_home',
);
static const indexDiscoveries = 1;
static const pageDiscoveries = ActivityPageItem(
icon: Icon(Ionicons.star_outline),
page: PageDiscoveries(),
code: 'page_discoveries',
);
static const indexStatistics = 2;
static const pageStatistics = ActivityPageItem(
icon: Icon(Ionicons.bar_chart_outline),
page: PageStatistics(),
code: 'page_statistics',
);
static Map<int, ActivityPageItem> items = {
indexHome: pageHome,
indexDiscoveries: pageDiscoveries,
indexStatistics: pageStatistics,
};
static bool isIndexAllowed(int pageIndex) {
return items.keys.contains(pageIndex);
}
static ActivityPageItem getPageItem(int pageIndex) {
return items[pageIndex] ?? pageHome;
}
static Widget getPageWidget(int pageIndex) {
return items[pageIndex]?.page ?? pageHome.page;
}
static int itemsCount = ActivityPage.items.length;
}
class DefaultSettings {
class DefaultGlobalSettings {
static const List<int> allowedDaysCountValues = [
7,
14,
......
import 'package:flutter/material.dart';
import 'package:unicons/unicons.dart';
import 'package:scrobbles/ui/screens/about.dart';
import 'package:scrobbles/ui/screens/activity.dart';
import 'package:scrobbles/ui/screens/settings.dart';
class ScreenItem {
final Icon icon;
final Widget screen;
final bool displayBottomNavBar;
const ScreenItem({
required this.icon,
required this.screen,
required this.displayBottomNavBar,
});
}
class Screen {
static const indexActivity = 0;
static const screenActivity = ScreenItem(
icon: Icon(UniconsLine.home),
screen: ScreenActivity(),
displayBottomNavBar: true,
);
static const indexSettings = 1;
static const screenSettings = ScreenItem(
icon: Icon(UniconsLine.setting),
screen: ScreenSettings(),
displayBottomNavBar: false,
);
static const indexAbout = 2;
static const screenAbout = ScreenItem(
icon: Icon(UniconsLine.info_circle),
screen: ScreenAbout(),
displayBottomNavBar: false,
);
static Map<int, ScreenItem> items = {
indexActivity: screenActivity,
indexSettings: screenSettings,
indexAbout: screenAbout,
};
static bool isIndexAllowed(int screenIndex) {
return items.keys.contains(screenIndex);
}
static Widget getWidget(int screenIndex) {
return items[screenIndex]?.screen ?? screenActivity.screen;
}
static bool displayBottomNavBar(int screenIndex) {
return items[screenIndex]?.displayBottomNavBar ?? screenActivity.displayBottomNavBar;
}
static int itemsCount = Screen.items.length;
}
......@@ -39,11 +39,9 @@ final ColorScheme lightColorScheme = ColorScheme.light(
secondary: primarySwatch.shade500,
onSecondary: Colors.white,
error: errorColor,
background: textSwatch.shade200,
onBackground: textSwatch.shade500,
onSurface: textSwatch.shade500,
surface: textSwatch.shade50,
surfaceVariant: Colors.white,
surfaceContainerHighest: Colors.white,
shadow: textSwatch.shade900.withOpacity(.1),
);
......@@ -52,11 +50,9 @@ final ColorScheme darkColorScheme = ColorScheme.dark(
secondary: primarySwatch.shade500,
onSecondary: Colors.white,
error: errorColor,
background: const Color(0xFF171724),
onBackground: textSwatch.shade400,
onSurface: textSwatch.shade300,
surface: const Color(0xFF262630),
surfaceVariant: const Color(0xFF282832),
surfaceContainerHighest: const Color(0xFF282832),
shadow: textSwatch.shade900.withOpacity(.2),
);
......
import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:hydrated_bloc/hydrated_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_heatmap_cubit.dart';
import 'package:scrobbles/cubit/data_new_artists_cubit.dart';
import 'package:scrobbles/cubit/data_new_tracks_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/activity/activity.dart';
part 'activity_state.dart';
class ActivityCubit extends HydratedCubit<ActivityState> {
ActivityCubit()
: super(ActivityState(
currentActivity: Activity.createNull(),
));
void updateState(Activity activity) {
emit(ActivityState(
currentActivity: activity,
));
}
void refresh(BuildContext context) {
BlocProvider.of<DataCountsByDayCubit>(context).refresh(context);
BlocProvider.of<DataCountsByHourCubit>(context).refresh(context);
BlocProvider.of<DataDiscoveriesCubit>(context).refresh(context);
BlocProvider.of<DataHeatmapCubit>(context).refresh(context);
BlocProvider.of<DataNewArtistsCubit>(context).refresh(context);
BlocProvider.of<DataNewTracksCubit>(context).refresh(context);
BlocProvider.of<DataStatisticsGlobalCubit>(context).refresh(context);
BlocProvider.of<DataStatisticsRecentCubit>(context).refresh(context);
BlocProvider.of<DataTimelineCubit>(context).refresh(context);
BlocProvider.of<DataTopArtistsCubit>(context).refresh(context);
}
@override
ActivityState? fromJson(Map<String, dynamic> json) {
final Activity currentActivity = json['currentActivity'] as Activity;
return ActivityState(
currentActivity: currentActivity,
);
}
@override
Map<String, dynamic>? toJson(ActivityState state) {
return <String, dynamic>{
'currentActivity': state.currentActivity.toJson(),
};
}
}
part of 'activity_cubit.dart';
@immutable
class ActivityState extends Equatable {
const ActivityState({
required this.currentActivity,
});
final Activity currentActivity;
@override
List<dynamic> get props => <dynamic>[
currentActivity,
];
}
import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:hydrated_bloc/hydrated_bloc.dart';
import 'package:scrobbles/models/counts_by_day.dart';
import 'package:scrobbles/cubit/settings_global_cubit.dart';
import 'package:scrobbles/models/data/counts_by_day.dart';
import 'package:scrobbles/network/scrobbles.dart';
part 'data_counts_by_day_state.dart';
class DataCountsByDayCubit extends HydratedCubit<DataCountsByDayState> {
DataCountsByDayCubit() : super(const DataCountsByDayState());
DataCountsByDayCubit()
: super(const DataCountsByDayState(
countsByDay: null,
status: '',
));
void getData(DataCountsByDayState state) {
emit(state);
void setLoading() {
emit(DataCountsByDayState(
countsByDay: state.countsByDay,
status: 'loading',
));
}
CountsByDayData? getValue() {
return state.countsByDay;
void setValue(CountsByDayData? countsByDay) {
emit(DataCountsByDayState(
countsByDay: countsByDay,
status: '',
));
}
void setFailed() {
emit(DataCountsByDayState(
countsByDay: state.countsByDay,
status: 'failed',
));
}
void setLoaded() {
emit(DataCountsByDayState(
countsByDay: state.countsByDay,
status: '',
));
}
void update(CountsByDayData? countsByDay) {
if ((countsByDay != null) && (state.countsByDay.toString() != countsByDay.toString())) {
setValue(countsByDay);
} else {
setLoaded();
}
}
void setValue(CountsByDayData? countsByDay) {
emit(DataCountsByDayState(
countsByDay: countsByDay,
));
void refresh(BuildContext context) async {
setLoading();
GlobalSettingsCubit settings = BlocProvider.of<GlobalSettingsCubit>(context);
final int daysCount = settings.getDistributionDaysCount();
final CountsByDayData? data = await ScrobblesApi.fetchCountsByDay(daysCount);
if (data != null) {
update(data);
} else {
setFailed();
}
}
@override
DataCountsByDayState? fromJson(Map<String, dynamic> json) {
return DataCountsByDayState(
countsByDay: CountsByDayData.fromJson(json['countsByDay']),
status: '',
);
}
......@@ -40,6 +78,7 @@ class DataCountsByDayCubit extends HydratedCubit<DataCountsByDayState> {
Map<String, Object?>? toJson(DataCountsByDayState state) {
return <String, Object?>{
'countsByDay': state.countsByDay?.toJson(),
'status': state.status,
};
}
}
......@@ -3,13 +3,16 @@ part of 'data_counts_by_day_cubit.dart';
@immutable
class DataCountsByDayState extends Equatable {
const DataCountsByDayState({
this.countsByDay,
required this.countsByDay,
required this.status,
});
final CountsByDayData? countsByDay;
final String status;
@override
List<Object?> get props => <Object?>[
countsByDay,
status,
];
}
import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:hydrated_bloc/hydrated_bloc.dart';
import 'package:scrobbles/models/counts_by_hour.dart';
import 'package:scrobbles/cubit/settings_global_cubit.dart';
import 'package:scrobbles/models/data/counts_by_hour.dart';
import 'package:scrobbles/network/scrobbles.dart';
part 'data_counts_by_hour_state.dart';
class DataCountsByHourCubit extends HydratedCubit<DataCountsByHourState> {
DataCountsByHourCubit() : super(const DataCountsByHourState());
DataCountsByHourCubit()
: super(const DataCountsByHourState(
countsByHour: null,
status: '',
));
void getData(DataCountsByHourState state) {
emit(state);
void setLoading() {
emit(DataCountsByHourState(
countsByHour: state.countsByHour,
status: 'loading',
));
}
CountsByHourData? getValue() {
return state.countsByHour;
void setValue(CountsByHourData? countsByHour) {
emit(DataCountsByHourState(
countsByHour: countsByHour,
status: '',
));
}
void setFailed() {
emit(DataCountsByHourState(
countsByHour: state.countsByHour,
status: 'failed',
));
}
void setLoaded() {
emit(DataCountsByHourState(
countsByHour: state.countsByHour,
status: '',
));
}
void update(CountsByHourData? countsByHour) {
if ((countsByHour != null) && (state.countsByHour.toString() != countsByHour.toString())) {
setValue(countsByHour);
} else {
setLoaded();
}
}
void setValue(CountsByHourData? countsByHour) {
emit(DataCountsByHourState(
countsByHour: countsByHour,
));
void refresh(BuildContext context) async {
setLoading();
GlobalSettingsCubit settings = BlocProvider.of<GlobalSettingsCubit>(context);
final int daysCount = settings.getDistributionDaysCount();
final CountsByHourData? data = await ScrobblesApi.fetchCountsByHour(daysCount);
if (data != null) {
update(data);
} else {
setFailed();
}
}
@override
DataCountsByHourState? fromJson(Map<String, dynamic> json) {
return DataCountsByHourState(
countsByHour: CountsByHourData.fromJson(json['countsByHour']),
status: '',
);
}
......@@ -40,6 +78,7 @@ class DataCountsByHourCubit extends HydratedCubit<DataCountsByHourState> {
Map<String, Object?>? toJson(DataCountsByHourState state) {
return <String, Object?>{
'countsByHour': state.countsByHour?.toJson(),
'status': state.status,
};
}
}
......@@ -3,13 +3,16 @@ part of 'data_counts_by_hour_cubit.dart';
@immutable
class DataCountsByHourState extends Equatable {
const DataCountsByHourState({
this.countsByHour,
required this.countsByHour,
required this.status,
});
final CountsByHourData? countsByHour;
final String status;
@override
List<Object?> get props => <Object?>[
countsByHour,
status,
];
}
import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:hydrated_bloc/hydrated_bloc.dart';
import 'package:scrobbles/models/discoveries.dart';
import 'package:scrobbles/cubit/settings_global_cubit.dart';
import 'package:scrobbles/models/data/discoveries.dart';
import 'package:scrobbles/network/scrobbles.dart';
part 'data_discoveries_state.dart';
class DataDiscoveriesCubit extends HydratedCubit<DataDiscoveriesState> {
DataDiscoveriesCubit() : super(const DataDiscoveriesState());
DataDiscoveriesCubit()
: super(const DataDiscoveriesState(
discoveries: null,
status: '',
));
void getData(DataDiscoveriesState state) {
emit(state);
void setLoading() {
emit(DataDiscoveriesState(
discoveries: state.discoveries,
status: 'loading',
));
}
DiscoveriesData? getValue() {
return state.discoveries;
void setValue(DiscoveriesData? discoveries) {
emit(DataDiscoveriesState(
discoveries: discoveries,
status: '',
));
}
void setFailed() {
emit(DataDiscoveriesState(
discoveries: state.discoveries,
status: 'failed',
));
}
void setLoaded() {
emit(DataDiscoveriesState(
discoveries: state.discoveries,
status: '',
));
}
void update(DiscoveriesData? discoveries) {
if ((discoveries != null) && (state.discoveries.toString() != discoveries.toString())) {
setValue(discoveries);
} else {
setLoaded();
}
}
void setValue(DiscoveriesData? discoveries) {
emit(DataDiscoveriesState(
discoveries: discoveries,
));
void refresh(BuildContext context) async {
setLoading();
GlobalSettingsCubit settings = BlocProvider.of<GlobalSettingsCubit>(context);
final int daysCount = settings.getDiscoveriesDaysCount();
final DiscoveriesData? data = await ScrobblesApi.fetchDiscoveries(daysCount);
if (data != null) {
update(data);
} else {
setFailed();
}
}
@override
DataDiscoveriesState? fromJson(Map<String, dynamic> json) {
return DataDiscoveriesState(
discoveries: DiscoveriesData.fromJson(json['discoveries']),
status: '',
);
}
......@@ -40,6 +78,7 @@ class DataDiscoveriesCubit extends HydratedCubit<DataDiscoveriesState> {
Map<String, Object?>? toJson(DataDiscoveriesState state) {
return <String, Object?>{
'discoveries': state.discoveries?.toJson(),
'status': state.status,
};
}
}
......@@ -3,13 +3,16 @@ part of 'data_discoveries_cubit.dart';
@immutable
class DataDiscoveriesState extends Equatable {
const DataDiscoveriesState({
this.discoveries,
required this.discoveries,
required this.status,
});
final DiscoveriesData? discoveries;
final String status;
@override
List<Object?> get props => <Object?>[
discoveries,
status,
];
}
import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:hydrated_bloc/hydrated_bloc.dart';
import 'package:scrobbles/models/heatmap.dart';
import 'package:scrobbles/cubit/settings_global_cubit.dart';
import 'package:scrobbles/models/data/heatmap.dart';
import 'package:scrobbles/network/scrobbles.dart';
part 'data_heatmap_state.dart';
class DataHeatmapCubit extends HydratedCubit<DataHeatmapState> {
DataHeatmapCubit() : super(const DataHeatmapState());
DataHeatmapCubit()
: super(const DataHeatmapState(
heatmap: null,
status: '',
));
void getData(DataHeatmapState state) {
emit(state);
void setLoading() {
emit(DataHeatmapState(
heatmap: state.heatmap,
status: 'loading',
));
}
void setValue(HeatmapData? heatmapData) {
emit(DataHeatmapState(
heatmap: heatmapData,
status: '',
));
}
void setFailed() {
emit(DataHeatmapState(
heatmap: state.heatmap,
status: 'failed',
));
}
void setLoaded() {
emit(DataHeatmapState(
heatmap: state.heatmap,
status: '',
));
}
void update(HeatmapData? heatmapData) {
if ((heatmapData != null) && (state.heatmap.toString() != heatmapData.toString())) {
setValue(heatmapData);
} else {
setLoaded();
}
}
void setValue(HeatmapData? heatmapData) {
emit(DataHeatmapState(
heatmap: heatmapData,
));
void refresh(BuildContext context) async {
setLoading();
GlobalSettingsCubit settings = BlocProvider.of<GlobalSettingsCubit>(context);
final int daysCount = settings.getDistributionDaysCount();
final HeatmapData? data = await ScrobblesApi.fetchHeatmap(daysCount);
if (data != null) {
update(data);
} else {
setFailed();
}
}
@override
DataHeatmapState? fromJson(Map<String, dynamic> json) {
return DataHeatmapState(
heatmap: HeatmapData.fromJson(json['heatmap']),
status: '',
);
}
......@@ -36,6 +78,7 @@ class DataHeatmapCubit extends HydratedCubit<DataHeatmapState> {
Map<String, Object?>? toJson(DataHeatmapState state) {
return <String, Object?>{
'heatmap': state.heatmap?.toJson(),
'status': state.status,
};
}
}
......@@ -3,13 +3,16 @@ part of 'data_heatmap_cubit.dart';
@immutable
class DataHeatmapState extends Equatable {
const DataHeatmapState({
this.heatmap,
required this.heatmap,
required this.status,
});
final HeatmapData? heatmap;
final String status;
@override
List<Object?> get props => <Object?>[
heatmap,
status,
];
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment