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

Normalize app architecture

parent 64606b97
No related branches found
No related tags found
1 merge request!8Resolve "Normalize game architecture"
Pipeline #5733 passed
Showing
with 521 additions and 75 deletions
...@@ -37,7 +37,7 @@ if (keystorePropertiesFile.exists()) { ...@@ -37,7 +37,7 @@ if (keystorePropertiesFile.exists()) {
} }
android { android {
compileSdkVersion 33 compileSdkVersion 34
namespace "org.benoitharrault.stopmotion" namespace "org.benoitharrault.stopmotion"
defaultConfig { defaultConfig {
......
org.gradle.jvmargs=-Xmx1536M org.gradle.jvmargs=-Xmx1536M
android.useAndroidX=true android.useAndroidX=true
android.enableJetifier=true android.enableJetifier=true
app.versionName=0.0.7 app.versionName=0.0.8
app.versionCode=7 app.versionCode=8
{ {
"app_name": "Stop Motion assistant", "app_name": "Stop Motion",
"bottom_nav_home": "Home",
"bottom_nav_camera": "Camera",
"bottom_nav_settings": "Settings",
"settings_title": "Settings", "settings_title": "Settings",
"settings_title_global": "Global settings", "settings_label_theme": "Theme mode",
"settings_label_dummy_value": "Dummy parameter: ",
"about_title": "Informations",
"about_content": "MIDI synth",
"about_version": "Version: {version}",
"page_home": "Home",
"page_editor": "Editor",
"page_player": "Player",
"lang_prefix": "en" "": ""
} }
{ {
"app_name": "Assistant Stop Motion", "app_name": "Stop Motion",
"bottom_nav_home": "Accueil",
"bottom_nav_camera": "Caméra",
"bottom_nav_settings": "Réglages",
"settings_title": "Réglages", "settings_title": "Réglages",
"settings_title_global": "Réglages globaux", "settings_label_theme": "Thème de couleurs",
"settings_label_dummy_value": "Réglage bidon : ",
"about_title": "Informations",
"about_content": "MIDI synth.",
"about_version": "Version : {version}",
"page_home": "Accueil",
"page_editor": "Édition",
"page_player": "Lecture",
"lang_prefix": "fr" "": ""
} }
Improve/normalize app architecture.
Amélioration/normalisation de l'architecture de l'application.
import 'package:flutter/material.dart';
import 'package:unicons/unicons.dart';
import 'package:stopmotion/ui/pages/editor.dart';
import 'package:stopmotion/ui/pages/home.dart';
import 'package:stopmotion/ui/pages/player.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(UniconsLine.home),
page: PageHome(),
code: 'page_home',
);
static const indexEditor = 1;
static const pageEditor = ActivityPageItem(
icon: Icon(UniconsLine.setting),
page: PageEditor(),
code: 'page_editor',
);
static const indexPlayer = 2;
static const pagePlayer = ActivityPageItem(
icon: Icon(UniconsLine.info_circle),
page: PagePlayer(),
code: 'page_player',
);
static Map<int, ActivityPageItem> items = {
indexHome: pageHome,
indexEditor: pageEditor,
indexPlayer: pagePlayer,
};
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;
}
import 'package:stopmotion/utils/tools.dart';
class DefaultActivitySettings {
// available activity parameters codes
static const String parameterCodeMovieType = 'movieType';
static const List<String> availableParameters = [
parameterCodeMovieType,
];
// items count: available values
static const String movieTypeValueDefault = 'default';
static const List<String> allowedMovieTypeValues = [
movieTypeValueDefault,
];
// items count: default value
static const String defaultMovieTypeValue = movieTypeValueDefault;
// available values from parameter code
static List<String> getAvailableValues(String parameterCode) {
switch (parameterCode) {
case parameterCodeMovieType:
return DefaultActivitySettings.allowedMovieTypeValues;
}
printlog('Did not find any available value for activity parameter "$parameterCode".');
return [];
}
// parameters displayed with assets (instead of painter)
static List<String> displayedWithAssets = [
//
];
}
import 'package:stopmotion/utils/tools.dart';
class DefaultGlobalSettings {
// available global parameters codes
static const String parameterCodeSkin = 'skin';
static const List<String> availableParameters = [
parameterCodeSkin,
];
// skin: available values
static const String skinValueDefault = 'default';
static const List<String> allowedSkinValues = [
skinValueDefault,
];
// skin: default value
static const String defaultSkinValue = skinValueDefault;
// available values from parameter code
static List<String> getAvailableValues(String parameterCode) {
switch (parameterCode) {
case parameterCodeSkin:
return DefaultGlobalSettings.allowedSkinValues;
}
printlog('Did not find any available value for global parameter "$parameterCode".');
return [];
}
// parameters displayed with assets (instead of painter)
static List<String> displayedWithAssets = [
//
];
}
class DefaultSettings {
static const int defaultDummyValue = 20;
static const List<int> allowedDummyValues = [
10,
defaultDummyValue,
30,
];
}
import 'package:flutter/material.dart';
import 'package:unicons/unicons.dart';
import 'package:stopmotion/ui/screens/about.dart';
import 'package:stopmotion/ui/screens/activity.dart';
import 'package:stopmotion/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( ...@@ -39,11 +39,9 @@ final ColorScheme lightColorScheme = ColorScheme.light(
secondary: primarySwatch.shade500, secondary: primarySwatch.shade500,
onSecondary: Colors.white, onSecondary: Colors.white,
error: errorColor, error: errorColor,
background: textSwatch.shade200,
onBackground: textSwatch.shade500,
onSurface: textSwatch.shade500, onSurface: textSwatch.shade500,
surface: textSwatch.shade50, surface: textSwatch.shade50,
surfaceVariant: Colors.white, surfaceContainerHighest: Colors.white,
shadow: textSwatch.shade900.withOpacity(.1), shadow: textSwatch.shade900.withOpacity(.1),
); );
...@@ -52,11 +50,9 @@ final ColorScheme darkColorScheme = ColorScheme.dark( ...@@ -52,11 +50,9 @@ final ColorScheme darkColorScheme = ColorScheme.dark(
secondary: primarySwatch.shade500, secondary: primarySwatch.shade500,
onSecondary: Colors.white, onSecondary: Colors.white,
error: errorColor, error: errorColor,
background: const Color(0xFF171724),
onBackground: textSwatch.shade400,
onSurface: textSwatch.shade300, onSurface: textSwatch.shade300,
surface: const Color(0xFF262630), surface: const Color(0xFF262630),
surfaceVariant: const Color(0xFF282832), surfaceContainerHighest: const Color(0xFF282832),
shadow: textSwatch.shade900.withOpacity(.2), shadow: textSwatch.shade900.withOpacity(.2),
); );
...@@ -192,5 +188,3 @@ final ThemeData darkTheme = lightTheme.copyWith( ...@@ -192,5 +188,3 @@ final ThemeData darkTheme = lightTheme.copyWith(
), ),
), ),
); );
final ThemeData appTheme = darkTheme;
import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart';
import 'package:hydrated_bloc/hydrated_bloc.dart';
import 'package:stopmotion/models/activity/activity.dart';
import 'package:stopmotion/models/settings/settings_activity.dart';
import 'package:stopmotion/models/settings/settings_global.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() {
final Activity activity = Activity(
// Settings
activitySettings: state.currentActivity.activitySettings,
globalSettings: state.currentActivity.globalSettings,
// State
isRunning: state.currentActivity.isRunning,
isStarted: state.currentActivity.isStarted,
isFinished: state.currentActivity.isFinished,
animationInProgress: state.currentActivity.animationInProgress,
// Base data
pictures: state.currentActivity.pictures,
// Activity data
position: state.currentActivity.position,
);
// activity.dump();
updateState(activity);
}
void startNewActivity({
required ActivitySettings activitySettings,
required GlobalSettings globalSettings,
}) {
final Activity newActivity = Activity.createNew(
// Settings
activitySettings: activitySettings,
globalSettings: globalSettings,
);
newActivity.dump();
updateState(newActivity);
refresh();
}
void quitActivity() {
state.currentActivity.isRunning = false;
refresh();
}
void resumeSavedActivity() {
state.currentActivity.isRunning = true;
refresh();
}
void deleteSavedActivity() {
state.currentActivity.isRunning = false;
state.currentActivity.isFinished = true;
refresh();
}
@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:hydrated_bloc/hydrated_bloc.dart'; import 'package:hydrated_bloc/hydrated_bloc.dart';
class BottomNavCubit extends HydratedCubit<int> { import 'package:stopmotion/config/activity_page.dart';
BottomNavCubit() : super(0);
int pagesCount = 3; class NavCubitPage extends HydratedCubit<int> {
NavCubitPage() : super(0);
void updateIndex(int index) { void updateIndex(int index) {
if (isIndexAllowed(index)) { if (ActivityPage.isIndexAllowed(index)) {
emit(index); emit(index);
} else { } else {
goToHomePage(); emit(ActivityPage.indexHome);
} }
} }
bool isIndexAllowed(int index) {
return (index >= 0) && (index < pagesCount);
}
void goToHomePage() => emit(0);
@override @override
int? fromJson(Map<String, dynamic> json) { int fromJson(Map<String, dynamic> json) {
return 0; return ActivityPage.indexHome;
} }
@override @override
......
import 'package:hydrated_bloc/hydrated_bloc.dart';
import 'package:stopmotion/config/screen.dart';
class NavCubitScreen extends HydratedCubit<int> {
NavCubitScreen() : super(0);
void updateIndex(int index) {
if (Screen.isIndexAllowed(index)) {
emit(index);
} else {
goToActivityPage();
}
}
void goToActivityPage() {
emit(Screen.indexActivity);
}
void goToSettingsPage() {
emit(Screen.indexSettings);
}
void goToAboutPage() {
emit(Screen.indexAbout);
}
@override
int fromJson(Map<String, dynamic> json) {
return Screen.indexActivity;
}
@override
Map<String, dynamic>? toJson(int state) {
return <String, int>{'screenIndex': state};
}
}
import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart';
import 'package:hydrated_bloc/hydrated_bloc.dart';
import 'package:stopmotion/config/default_activity_settings.dart';
import 'package:stopmotion/models/settings/settings_activity.dart';
part 'settings_activity_state.dart';
class ActivitySettingsCubit extends HydratedCubit<ActivitySettingsState> {
ActivitySettingsCubit()
: super(ActivitySettingsState(settings: ActivitySettings.createDefault()));
void setValues({
String? movieType,
}) {
emit(
ActivitySettingsState(
settings: ActivitySettings(
movieType: movieType ?? state.settings.movieType,
),
),
);
}
String getParameterValue(String code) {
switch (code) {
case DefaultActivitySettings.parameterCodeMovieType:
return ActivitySettings.getMovieTypeValueFromUnsafe(state.settings.movieType);
}
return '';
}
void setParameterValue(String code, String value) {
final String movieType = code == DefaultActivitySettings.parameterCodeMovieType
? value
: getParameterValue(DefaultActivitySettings.parameterCodeMovieType);
setValues(
movieType: movieType,
);
}
@override
ActivitySettingsState? fromJson(Map<String, dynamic> json) {
final String movieType = json[DefaultActivitySettings.parameterCodeMovieType] as String;
return ActivitySettingsState(
settings: ActivitySettings(
movieType: movieType,
),
);
}
@override
Map<String, dynamic>? toJson(ActivitySettingsState state) {
return <String, dynamic>{
DefaultActivitySettings.parameterCodeMovieType: state.settings.movieType,
};
}
}
part of 'settings_activity_cubit.dart';
@immutable
class ActivitySettingsState extends Equatable {
const ActivitySettingsState({
required this.settings,
});
final ActivitySettings settings;
@override
List<dynamic> get props => <dynamic>[
settings,
];
}
import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart';
import 'package:hydrated_bloc/hydrated_bloc.dart';
import 'package:stopmotion/config/default_settings.dart';
part 'settings_state.dart';
class SettingsCubit extends HydratedCubit<SettingsState> {
SettingsCubit() : super(const SettingsState());
int getDummyValue() {
return state.dummyValue ?? DefaultSettings.defaultDummyValue;
}
void setValues({
int? dummyValue,
}) {
emit(SettingsState(
dummyValue: dummyValue ?? state.dummyValue,
));
}
@override
SettingsState? fromJson(Map<String, dynamic> json) {
int dummyValue = json['dummyValue'] as int;
return SettingsState(
dummyValue: dummyValue,
);
}
@override
Map<String, dynamic>? toJson(SettingsState state) {
return <String, dynamic>{
'dummyValue': state.dummyValue ?? DefaultSettings.defaultDummyValue,
};
}
}
import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart';
import 'package:hydrated_bloc/hydrated_bloc.dart';
import 'package:stopmotion/config/default_global_settings.dart';
import 'package:stopmotion/models/settings/settings_global.dart';
part 'settings_global_state.dart';
class GlobalSettingsCubit extends HydratedCubit<GlobalSettingsState> {
GlobalSettingsCubit() : super(GlobalSettingsState(settings: GlobalSettings.createDefault()));
void setValues({
String? skin,
}) {
emit(
GlobalSettingsState(
settings: GlobalSettings(
skin: skin ?? state.settings.skin,
),
),
);
}
String getParameterValue(String code) {
switch (code) {
case DefaultGlobalSettings.parameterCodeSkin:
return GlobalSettings.getSkinValueFromUnsafe(state.settings.skin);
}
return '';
}
void setParameterValue(String code, String value) {
final String skin = (code == DefaultGlobalSettings.parameterCodeSkin)
? value
: getParameterValue(DefaultGlobalSettings.parameterCodeSkin);
setValues(
skin: skin,
);
}
@override
GlobalSettingsState? fromJson(Map<String, dynamic> json) {
final String skin = json[DefaultGlobalSettings.parameterCodeSkin] as String;
return GlobalSettingsState(
settings: GlobalSettings(
skin: skin,
),
);
}
@override
Map<String, dynamic>? toJson(GlobalSettingsState state) {
return <String, dynamic>{
DefaultGlobalSettings.parameterCodeSkin: state.settings.skin,
};
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment