diff --git a/android/app/build.gradle b/android/app/build.gradle index 7e47b56357ab61b4f65d37b63a614ce814af536a..b66c7309008023fd1c5bbe9acda14bb0851f8780 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -37,7 +37,7 @@ if (keystorePropertiesFile.exists()) { } android { - compileSdkVersion 33 + compileSdkVersion 34 namespace "org.benoitharrault.stopmotion" defaultConfig { diff --git a/android/gradle.properties b/android/gradle.properties index 85b94f88ee157e1d1b3cec184c8948902443d36f..65eed6426393974efb5a056ec44936d42b5ef2a1 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.7 -app.versionCode=7 +app.versionName=0.0.8 +app.versionCode=8 diff --git a/assets/translations/en.json b/assets/translations/en.json index f53b1cdd7eb11b40a9bfa48b5ced2628de1cb912..2fbf22ada976732bc4ffb4752cb8bc0897c397b5 100644 --- a/assets/translations/en.json +++ b/assets/translations/en.json @@ -1,13 +1,16 @@ { - "app_name": "Stop Motion assistant", - - "bottom_nav_home": "Home", - "bottom_nav_camera": "Camera", - "bottom_nav_settings": "Settings", + "app_name": "Stop Motion", "settings_title": "Settings", - "settings_title_global": "Global settings", - "settings_label_dummy_value": "Dummy parameter: ", + "settings_label_theme": "Theme mode", + + "about_title": "Informations", + "about_content": "MIDI synth", + "about_version": "Version: {version}", + + "page_home": "Home", + "page_editor": "Editor", + "page_player": "Player", - "lang_prefix": "en" + "": "" } diff --git a/assets/translations/fr.json b/assets/translations/fr.json index 69be2063cc2af3de1d9ec30788c798a32313653c..770ad86a5155394806ef7408fc162ba8b602e01f 100644 --- a/assets/translations/fr.json +++ b/assets/translations/fr.json @@ -1,13 +1,16 @@ { - "app_name": "Assistant Stop Motion", - - "bottom_nav_home": "Accueil", - "bottom_nav_camera": "Caméra", - "bottom_nav_settings": "Réglages", + "app_name": "Stop Motion", "settings_title": "Réglages", - "settings_title_global": "Réglages globaux", - "settings_label_dummy_value": "Réglage bidon : ", + "settings_label_theme": "Thème de couleurs", + + "about_title": "Informations", + "about_content": "MIDI synth.", + "about_version": "Version : {version}", + + "page_home": "Accueil", + "page_editor": "Édition", + "page_player": "Lecture", - "lang_prefix": "fr" + "": "" } diff --git a/fastlane/metadata/android/en-US/changelogs/8.txt b/fastlane/metadata/android/en-US/changelogs/8.txt new file mode 100644 index 0000000000000000000000000000000000000000..060b202b87dcd33388eb8a9d1a45cbd276fc8ba3 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/8.txt @@ -0,0 +1 @@ +Improve/normalize app architecture. diff --git a/fastlane/metadata/android/fr-FR/changelogs/8.txt b/fastlane/metadata/android/fr-FR/changelogs/8.txt new file mode 100644 index 0000000000000000000000000000000000000000..3cab228cbe7443782c4b187cbe805e4d0ba8e71a --- /dev/null +++ b/fastlane/metadata/android/fr-FR/changelogs/8.txt @@ -0,0 +1 @@ +Amélioration/normalisation de l'architecture de l'application. diff --git a/lib/config/activity_page.dart b/lib/config/activity_page.dart new file mode 100644 index 0000000000000000000000000000000000000000..29314379fa159675e4c47fa91ce6eb19063d9854 --- /dev/null +++ b/lib/config/activity_page.dart @@ -0,0 +1,61 @@ +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; +} diff --git a/lib/config/default_activity_settings.dart b/lib/config/default_activity_settings.dart new file mode 100644 index 0000000000000000000000000000000000000000..23b9a5c4b13be14661db04285a7525cf1bf14539 --- /dev/null +++ b/lib/config/default_activity_settings.dart @@ -0,0 +1,33 @@ +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 = [ + // + ]; +} diff --git a/lib/config/default_global_settings.dart b/lib/config/default_global_settings.dart new file mode 100644 index 0000000000000000000000000000000000000000..b40decad910ede779fb5be49b0cda80812682e4d --- /dev/null +++ b/lib/config/default_global_settings.dart @@ -0,0 +1,33 @@ +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 = [ + // + ]; +} diff --git a/lib/config/default_settings.dart b/lib/config/default_settings.dart deleted file mode 100644 index 751fd3c28a8cc6bcec81285d504621896da998d0..0000000000000000000000000000000000000000 --- a/lib/config/default_settings.dart +++ /dev/null @@ -1,9 +0,0 @@ -class DefaultSettings { - static const int defaultDummyValue = 20; - - static const List<int> allowedDummyValues = [ - 10, - defaultDummyValue, - 30, - ]; -} diff --git a/lib/config/screen.dart b/lib/config/screen.dart new file mode 100644 index 0000000000000000000000000000000000000000..46382ae9824be4b247aff08f051634a591a23287 --- /dev/null +++ b/lib/config/screen.dart @@ -0,0 +1,61 @@ +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; +} diff --git a/lib/config/theme.dart b/lib/config/theme.dart index be390348c7868e7c63387df13e13c46de43f8a23..74f532fd5abf693979118609564d29167e902009 100644 --- a/lib/config/theme.dart +++ b/lib/config/theme.dart @@ -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), ); @@ -192,5 +188,3 @@ final ThemeData darkTheme = lightTheme.copyWith( ), ), ); - -final ThemeData appTheme = darkTheme; diff --git a/lib/cubit/activity_cubit.dart b/lib/cubit/activity_cubit.dart new file mode 100644 index 0000000000000000000000000000000000000000..9ab361adcac13a9b1562fee1723dd22593b08d66 --- /dev/null +++ b/lib/cubit/activity_cubit.dart @@ -0,0 +1,90 @@ +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(), + }; + } +} diff --git a/lib/cubit/activity_state.dart b/lib/cubit/activity_state.dart new file mode 100644 index 0000000000000000000000000000000000000000..887b45e4255fd7de1cc7744569d82a38a66602f2 --- /dev/null +++ b/lib/cubit/activity_state.dart @@ -0,0 +1,15 @@ +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, + ]; +} diff --git a/lib/cubit/bottom_nav_cubit.dart b/lib/cubit/bottom_nav_cubit.dart deleted file mode 100644 index 8753255ac7acba27b594ea5cfb5b46aafee31625..0000000000000000000000000000000000000000 --- a/lib/cubit/bottom_nav_cubit.dart +++ /dev/null @@ -1,31 +0,0 @@ -import 'package:hydrated_bloc/hydrated_bloc.dart'; - -class BottomNavCubit extends HydratedCubit<int> { - BottomNavCubit() : super(0); - - int pagesCount = 3; - - void updateIndex(int index) { - if (isIndexAllowed(index)) { - emit(index); - } else { - goToHomePage(); - } - } - - bool isIndexAllowed(int index) { - return (index >= 0) && (index < pagesCount); - } - - void goToHomePage() => emit(0); - - @override - int? fromJson(Map<String, dynamic> json) { - return 0; - } - - @override - Map<String, dynamic>? toJson(int state) { - return <String, int>{'pageIndex': state}; - } -} diff --git a/lib/cubit/nav_cubit_pages.dart b/lib/cubit/nav_cubit_pages.dart new file mode 100644 index 0000000000000000000000000000000000000000..e64bc1139f40c761eea2fba07f80ce0c496c464e --- /dev/null +++ b/lib/cubit/nav_cubit_pages.dart @@ -0,0 +1,25 @@ +import 'package:hydrated_bloc/hydrated_bloc.dart'; + +import 'package:stopmotion/config/activity_page.dart'; + +class NavCubitPage extends HydratedCubit<int> { + NavCubitPage() : super(0); + + void updateIndex(int index) { + if (ActivityPage.isIndexAllowed(index)) { + emit(index); + } else { + emit(ActivityPage.indexHome); + } + } + + @override + int fromJson(Map<String, dynamic> json) { + return ActivityPage.indexHome; + } + + @override + Map<String, dynamic>? toJson(int state) { + return <String, int>{'pageIndex': state}; + } +} diff --git a/lib/cubit/nav_cubit_screens.dart b/lib/cubit/nav_cubit_screens.dart new file mode 100644 index 0000000000000000000000000000000000000000..ca76f548b52c21b221e53f6b565c4efa0b52773a --- /dev/null +++ b/lib/cubit/nav_cubit_screens.dart @@ -0,0 +1,37 @@ +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}; + } +} diff --git a/lib/cubit/settings_activity_cubit.dart b/lib/cubit/settings_activity_cubit.dart new file mode 100644 index 0000000000000000000000000000000000000000..f0e460d7bcfbcc83b9ce009ada99f5ecceeb4090 --- /dev/null +++ b/lib/cubit/settings_activity_cubit.dart @@ -0,0 +1,62 @@ +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, + }; + } +} diff --git a/lib/cubit/settings_activity_state.dart b/lib/cubit/settings_activity_state.dart new file mode 100644 index 0000000000000000000000000000000000000000..2b2de42011634e81ae9e6f8bcaa1577f239c778b --- /dev/null +++ b/lib/cubit/settings_activity_state.dart @@ -0,0 +1,15 @@ +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, + ]; +} diff --git a/lib/cubit/settings_cubit.dart b/lib/cubit/settings_cubit.dart deleted file mode 100644 index 0c681feef3211012fa516631ef2b079365856206..0000000000000000000000000000000000000000 --- a/lib/cubit/settings_cubit.dart +++ /dev/null @@ -1,39 +0,0 @@ -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, - }; - } -} diff --git a/lib/cubit/settings_global_cubit.dart b/lib/cubit/settings_global_cubit.dart new file mode 100644 index 0000000000000000000000000000000000000000..f5b2f0667916c5144243eec7532a795e80a523e7 --- /dev/null +++ b/lib/cubit/settings_global_cubit.dart @@ -0,0 +1,60 @@ +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, + }; + } +} diff --git a/lib/cubit/settings_global_state.dart b/lib/cubit/settings_global_state.dart new file mode 100644 index 0000000000000000000000000000000000000000..ebcddd700f252257223ca8e16c85202b04f3ff24 --- /dev/null +++ b/lib/cubit/settings_global_state.dart @@ -0,0 +1,15 @@ +part of 'settings_global_cubit.dart'; + +@immutable +class GlobalSettingsState extends Equatable { + const GlobalSettingsState({ + required this.settings, + }); + + final GlobalSettings settings; + + @override + List<dynamic> get props => <dynamic>[ + settings, + ]; +} diff --git a/lib/cubit/settings_state.dart b/lib/cubit/settings_state.dart deleted file mode 100644 index 33953d6aada4d1aa30273543f91660cbcdd9c341..0000000000000000000000000000000000000000 --- a/lib/cubit/settings_state.dart +++ /dev/null @@ -1,19 +0,0 @@ -part of 'settings_cubit.dart'; - -@immutable -class SettingsState extends Equatable { - const SettingsState({ - this.dummyValue, - }); - - final int? dummyValue; - - @override - List<dynamic> get props => <dynamic>[ - dummyValue, - ]; - - Map<String, dynamic> get values => <String, dynamic>{ - 'dummyValue': dummyValue, - }; -} diff --git a/lib/cubit/theme_cubit.dart b/lib/cubit/theme_cubit.dart new file mode 100644 index 0000000000000000000000000000000000000000..b793e895dbb0c672d451cd403e0036c3d9ac9b42 --- /dev/null +++ b/lib/cubit/theme_cubit.dart @@ -0,0 +1,31 @@ +import 'package:equatable/equatable.dart'; +import 'package:flutter/material.dart'; +import 'package:hydrated_bloc/hydrated_bloc.dart'; + +part 'theme_state.dart'; + +class ThemeCubit extends HydratedCubit<ThemeModeState> { + ThemeCubit() : super(const ThemeModeState()); + + void getTheme(ThemeModeState state) { + emit(state); + } + + @override + ThemeModeState? fromJson(Map<String, dynamic> json) { + switch (json['themeMode']) { + case 'ThemeMode.dark': + return const ThemeModeState(themeMode: ThemeMode.dark); + case 'ThemeMode.light': + return const ThemeModeState(themeMode: ThemeMode.light); + case 'ThemeMode.system': + default: + return const ThemeModeState(themeMode: ThemeMode.system); + } + } + + @override + Map<String, String>? toJson(ThemeModeState state) { + return <String, String>{'themeMode': state.themeMode.toString()}; + } +} diff --git a/lib/cubit/theme_state.dart b/lib/cubit/theme_state.dart new file mode 100644 index 0000000000000000000000000000000000000000..e479a50f12fe72a35a1fd1722ff72afbb692a136 --- /dev/null +++ b/lib/cubit/theme_state.dart @@ -0,0 +1,15 @@ +part of 'theme_cubit.dart'; + +@immutable +class ThemeModeState extends Equatable { + const ThemeModeState({ + this.themeMode, + }); + + final ThemeMode? themeMode; + + @override + List<Object?> get props => <Object?>[ + themeMode, + ]; +} diff --git a/lib/main.dart b/lib/main.dart index 7ce98c62d7c9ae45735ede3e07a831da6a6e0308..042dbd65e41f6c10c4b6f947f51d0fc07c62b534 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -2,20 +2,24 @@ import 'dart:io'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:hive/hive.dart'; import 'package:hydrated_bloc/hydrated_bloc.dart'; import 'package:path_provider/path_provider.dart'; import 'package:stopmotion/config/theme.dart'; -import 'package:stopmotion/cubit/bottom_nav_cubit.dart'; -import 'package:stopmotion/cubit/settings_cubit.dart'; +import 'package:stopmotion/cubit/activity_cubit.dart'; +import 'package:stopmotion/cubit/nav_cubit_pages.dart'; +import 'package:stopmotion/cubit/nav_cubit_screens.dart'; +import 'package:stopmotion/cubit/settings_global_cubit.dart'; +import 'package:stopmotion/cubit/settings_activity_cubit.dart'; +import 'package:stopmotion/cubit/theme_cubit.dart'; import 'package:stopmotion/ui/skeleton.dart'; void main() async { - /// Initialize packages + // Initialize packages WidgetsFlutterBinding.ensureInitialized(); - await EasyLocalization.ensureInitialized(); final Directory tmpDir = await getTemporaryDirectory(); Hive.init(tmpDir.toString()); @@ -23,18 +27,17 @@ void main() async { storageDirectory: tmpDir, ); - runApp( - EasyLocalization( - path: 'assets/translations', - supportedLocales: const <Locale>[ - Locale('en'), - Locale('fr'), - ], - fallbackLocale: const Locale('en'), - useFallbackTranslations: true, - child: const MyApp(), - ), - ); + SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]) + .then((value) => runApp(EasyLocalization( + path: 'assets/translations', + supportedLocales: const <Locale>[ + Locale('en'), + Locale('fr'), + ], + fallbackLocale: const Locale('en'), + useFallbackTranslations: true, + child: const MyApp(), + ))); } class MyApp extends StatelessWidget { @@ -44,19 +47,31 @@ class MyApp extends StatelessWidget { Widget build(BuildContext context) { return MultiBlocProvider( providers: [ - BlocProvider<BottomNavCubit>(create: (context) => BottomNavCubit()), - BlocProvider<SettingsCubit>(create: (context) => SettingsCubit()), + BlocProvider<NavCubitPage>(create: (context) => NavCubitPage()), + BlocProvider<NavCubitScreen>(create: (context) => NavCubitScreen()), + BlocProvider<ThemeCubit>(create: (context) => ThemeCubit()), + BlocProvider<ActivityCubit>(create: (context) => ActivityCubit()), + BlocProvider<GlobalSettingsCubit>(create: (context) => GlobalSettingsCubit()), + BlocProvider<ActivitySettingsCubit>(create: (context) => ActivitySettingsCubit()), ], - child: MaterialApp( - title: 'Stop Motion', - theme: appTheme, - home: const SkeletonScreen(), - - // Localization stuff - localizationsDelegates: context.localizationDelegates, - supportedLocales: context.supportedLocales, - locale: context.locale, - debugShowCheckedModeBanner: false, + child: BlocBuilder<ThemeCubit, ThemeModeState>( + builder: (BuildContext context, ThemeModeState state) { + return MaterialApp( + title: 'Stop Motion', + home: const SkeletonScreen(), + + // Theme stuff + theme: lightTheme, + darkTheme: darkTheme, + themeMode: state.themeMode, + + // Localization stuff + localizationsDelegates: context.localizationDelegates, + supportedLocales: context.supportedLocales, + locale: context.locale, + debugShowCheckedModeBanner: false, + ); + }, ), ); } diff --git a/lib/models/activity/activity.dart b/lib/models/activity/activity.dart new file mode 100644 index 0000000000000000000000000000000000000000..6b778cb963c164c320d4ffee4327db0ee239806b --- /dev/null +++ b/lib/models/activity/activity.dart @@ -0,0 +1,113 @@ +import 'package:stopmotion/models/data/picture.dart'; +import 'package:stopmotion/models/settings/settings_activity.dart'; +import 'package:stopmotion/models/settings/settings_global.dart'; +import 'package:stopmotion/utils/tools.dart'; + +class Activity { + Activity({ + // Settings + required this.activitySettings, + required this.globalSettings, + + // State + this.isRunning = false, + this.isStarted = false, + this.isFinished = false, + this.animationInProgress = false, + + // Base data + this.pictures = const [], + + // Activity data + this.position = 1, + }); + + // Settings + final ActivitySettings activitySettings; + final GlobalSettings globalSettings; + + // State + bool isRunning; + bool isStarted; + bool isFinished; + bool animationInProgress; + + // Base data + List<Picture> pictures; + + // Activity data + int position; + + factory Activity.createNull() { + return Activity( + // Settings + activitySettings: ActivitySettings.createDefault(), + globalSettings: GlobalSettings.createDefault(), + // Base data + pictures: [], + ); + } + + factory Activity.createNew({ + ActivitySettings? activitySettings, + GlobalSettings? globalSettings, + }) { + final ActivitySettings newActivitySettings = + activitySettings ?? ActivitySettings.createDefault(); + final GlobalSettings newGlobalSettings = globalSettings ?? GlobalSettings.createDefault(); + + return Activity( + // Settings + activitySettings: newActivitySettings, + globalSettings: newGlobalSettings, + // State + isRunning: true, + // Base data + pictures: [], + ); + } + + bool get canBeResumed => isStarted && !isFinished; + + void dump() { + printlog(''); + printlog('## Current activity dump:'); + printlog(''); + printlog('$Activity:'); + printlog(' Settings'); + activitySettings.dump(); + globalSettings.dump(); + printlog(' State'); + printlog(' isRunning: $isRunning'); + printlog(' isStarted: $isStarted'); + printlog(' isFinished: $isFinished'); + printlog(' animationInProgress: $animationInProgress'); + printlog(' Base data'); + printlog(' pictures: $pictures'); + printlog(' Activity data'); + printlog(' position: $position'); + printlog(''); + } + + @override + String toString() { + return '$Activity(${toJson()})'; + } + + Map<String, dynamic>? toJson() { + return <String, dynamic>{ + // Settings + 'activitySettings': activitySettings.toJson(), + 'globalSettings': globalSettings.toJson(), + // State + 'isRunning': isRunning, + 'isStarted': isStarted, + 'isFinished': isFinished, + 'animationInProgress': animationInProgress, + // Base data + 'pictures': pictures, + // Activity data + 'position': position, + }; + } +} diff --git a/lib/models/data/picture.dart b/lib/models/data/picture.dart new file mode 100644 index 0000000000000000000000000000000000000000..73df607fab99cde1d5a68a37f7869211f952c288 --- /dev/null +++ b/lib/models/data/picture.dart @@ -0,0 +1,21 @@ +class Picture { + final String key; + final String file; + + const Picture({ + required this.key, + required this.file, + }); + + @override + String toString() { + return '$Picture(${toJson()})'; + } + + Map<String, dynamic> toJson() { + return { + 'key': key, + 'file': file, + }; + } +} diff --git a/lib/models/settings/settings_activity.dart b/lib/models/settings/settings_activity.dart new file mode 100644 index 0000000000000000000000000000000000000000..434ea010e783c23838485ca0b7c0186295803eaa --- /dev/null +++ b/lib/models/settings/settings_activity.dart @@ -0,0 +1,41 @@ +import 'package:stopmotion/config/default_activity_settings.dart'; +import 'package:stopmotion/utils/tools.dart'; + +class ActivitySettings { + final String movieType; + + ActivitySettings({ + required this.movieType, + }); + + static String getMovieTypeValueFromUnsafe(String movieType) { + if (DefaultActivitySettings.allowedMovieTypeValues.contains(movieType)) { + return movieType; + } + + return DefaultActivitySettings.defaultMovieTypeValue; + } + + factory ActivitySettings.createDefault() { + return ActivitySettings( + movieType: DefaultActivitySettings.defaultMovieTypeValue, + ); + } + + void dump() { + printlog('$ActivitySettings:'); + printlog(' ${DefaultActivitySettings.parameterCodeMovieType}: $movieType'); + printlog(''); + } + + @override + String toString() { + return '$ActivitySettings(${toJson()})'; + } + + Map<String, dynamic>? toJson() { + return <String, dynamic>{ + DefaultActivitySettings.parameterCodeMovieType: movieType, + }; + } +} diff --git a/lib/models/settings/settings_global.dart b/lib/models/settings/settings_global.dart new file mode 100644 index 0000000000000000000000000000000000000000..060d7d49a494c6ec9b1dbf01d9572d8dbe676ab6 --- /dev/null +++ b/lib/models/settings/settings_global.dart @@ -0,0 +1,41 @@ +import 'package:stopmotion/config/default_global_settings.dart'; +import 'package:stopmotion/utils/tools.dart'; + +class GlobalSettings { + String skin; + + GlobalSettings({ + required this.skin, + }); + + static String getSkinValueFromUnsafe(String skin) { + if (DefaultGlobalSettings.allowedSkinValues.contains(skin)) { + return skin; + } + + return DefaultGlobalSettings.defaultSkinValue; + } + + factory GlobalSettings.createDefault() { + return GlobalSettings( + skin: DefaultGlobalSettings.defaultSkinValue, + ); + } + + void dump() { + printlog('$GlobalSettings:'); + printlog(' ${DefaultGlobalSettings.parameterCodeSkin}: $skin'); + printlog(''); + } + + @override + String toString() { + return '$GlobalSettings(${toJson()})'; + } + + Map<String, dynamic>? toJson() { + return <String, dynamic>{ + DefaultGlobalSettings.parameterCodeSkin: skin, + }; + } +} diff --git a/lib/ui/widgets/app_titles.dart b/lib/ui/helpers/app_titles.dart similarity index 52% rename from lib/ui/widgets/app_titles.dart rename to lib/ui/helpers/app_titles.dart index 93541243613b0f20e76485520a275d1527a6fcc9..b98107b12fabc3114ebfbec994166b588abcf1ad 100644 --- a/lib/ui/widgets/app_titles.dart +++ b/lib/ui/helpers/app_titles.dart @@ -1,8 +1,8 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; -class AppTitle extends StatelessWidget { - const AppTitle({super.key, required this.text}); +class AppHeader extends StatelessWidget { + const AppHeader({super.key, required this.text}); final String text; @@ -11,37 +11,22 @@ class AppTitle extends StatelessWidget { return Text( tr(text), textAlign: TextAlign.start, - style: Theme.of(context).textTheme.headlineLarge!.apply(fontWeightDelta: 2), + style: Theme.of(context).textTheme.headlineMedium!.apply(fontWeightDelta: 2), ); } } -class AppTitle1 extends StatelessWidget { - const AppTitle1({super.key, required this.text}); +class AppTitle extends StatelessWidget { + const AppTitle({super.key, required this.text}); final String text; @override Widget build(BuildContext context) { return Text( - text, + tr(text), textAlign: TextAlign.start, style: Theme.of(context).textTheme.titleLarge!.apply(fontWeightDelta: 2), ); } } - -class AppTitle2 extends StatelessWidget { - const AppTitle2({super.key, required this.text}); - - final String text; - - @override - Widget build(BuildContext context) { - return Text( - text, - textAlign: TextAlign.start, - style: Theme.of(context).textTheme.titleMedium!.apply(fontWeightDelta: 2), - ); - } -} diff --git a/lib/ui/helpers/outlined_text_widget.dart b/lib/ui/helpers/outlined_text_widget.dart new file mode 100644 index 0000000000000000000000000000000000000000..e8cbb93a282c081d59cc9b0963dd9cf3554b0860 --- /dev/null +++ b/lib/ui/helpers/outlined_text_widget.dart @@ -0,0 +1,51 @@ +import 'package:flutter/material.dart'; + +import 'package:stopmotion/utils/color_extensions.dart'; + +class OutlinedText extends StatelessWidget { + const OutlinedText({ + super.key, + required this.text, + required this.fontSize, + required this.textColor, + this.outlineColor, + }); + + final String text; + final double fontSize; + final Color textColor; + final Color? outlineColor; + + @override + Widget build(BuildContext context) { + final double delta = fontSize / 30; + + return Text( + text, + style: TextStyle( + inherit: true, + fontSize: fontSize, + fontWeight: FontWeight.w600, + color: textColor, + shadows: [ + Shadow( + offset: Offset(-delta, -delta), + color: outlineColor ?? textColor.darken(), + ), + Shadow( + offset: Offset(delta, -delta), + color: outlineColor ?? textColor.darken(), + ), + Shadow( + offset: Offset(delta, delta), + color: outlineColor ?? textColor.darken(), + ), + Shadow( + offset: Offset(-delta, delta), + color: outlineColor ?? textColor.darken(), + ), + ], + ), + ); + } +} diff --git a/lib/ui/widgets/bottom_nav_bar.dart b/lib/ui/nav/bottom_nav_bar.dart similarity index 51% rename from lib/ui/widgets/bottom_nav_bar.dart rename to lib/ui/nav/bottom_nav_bar.dart index 9ce8d67088e14107d2d8b2c3082355e5b4de322d..fb30fdec3daadf1d86a603f22ec58103d6160f77 100644 --- a/lib/ui/widgets/bottom_nav_bar.dart +++ b/lib/ui/nav/bottom_nav_bar.dart @@ -2,10 +2,8 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:stopmotion/cubit/bottom_nav_cubit.dart'; -import 'package:stopmotion/ui/screens/camera.dart'; -import 'package:stopmotion/ui/screens/settings.dart'; -import 'package:stopmotion/ui/screens/home.dart'; +import 'package:stopmotion/config/activity_page.dart'; +import 'package:stopmotion/cubit/nav_cubit_pages.dart'; class BottomNavBar extends StatelessWidget { const BottomNavBar({super.key}); @@ -16,36 +14,35 @@ class BottomNavBar extends StatelessWidget { margin: const EdgeInsets.only(top: 1, right: 4, left: 4), elevation: 4, shadowColor: Theme.of(context).colorScheme.shadow, - color: Theme.of(context).colorScheme.surfaceVariant, + color: Theme.of(context).colorScheme.surfaceContainerHighest, shape: const RoundedRectangleBorder( borderRadius: BorderRadius.only( topLeft: Radius.circular(16), topRight: Radius.circular(16), ), ), - child: BlocBuilder<BottomNavCubit, int>(builder: (BuildContext context, int state) { + child: BlocBuilder<NavCubitPage, int>(builder: (BuildContext context, int state) { + final List<ActivityPageItem> pageItems = [ + ActivityPage.pageHome, + ActivityPage.pageEditor, + ActivityPage.pagePlayer, + ]; + final List<BottomNavigationBarItem> items = pageItems.map((ActivityPageItem item) { + return BottomNavigationBarItem( + icon: item.icon, + label: tr(item.code), + ); + }).toList(); + return BottomNavigationBar( currentIndex: state, - onTap: (int index) => context.read<BottomNavCubit>().updateIndex(index), + onTap: (int index) => context.read<NavCubitPage>().updateIndex(index), type: BottomNavigationBarType.fixed, elevation: 0, backgroundColor: Colors.transparent, selectedItemColor: Theme.of(context).colorScheme.primary, unselectedItemColor: Theme.of(context).textTheme.bodySmall!.color, - items: <BottomNavigationBarItem>[ - BottomNavigationBarItem( - icon: ScreenHome.navBarIcon, - label: tr(ScreenHome.navBarText), - ), - BottomNavigationBarItem( - icon: ScreenCamera.navBarIcon, - label: tr(ScreenCamera.navBarText), - ), - BottomNavigationBarItem( - icon: ScreenSettings.navBarIcon, - label: tr(ScreenSettings.navBarText), - ), - ], + items: items, ); }), ); diff --git a/lib/ui/nav/global_app_bar.dart b/lib/ui/nav/global_app_bar.dart new file mode 100644 index 0000000000000000000000000000000000000000..0590d1dfaf047967ee80c1d750909f1553dc0cf8 --- /dev/null +++ b/lib/ui/nav/global_app_bar.dart @@ -0,0 +1,67 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +import 'package:stopmotion/config/screen.dart'; +import 'package:stopmotion/cubit/activity_cubit.dart'; +import 'package:stopmotion/cubit/nav_cubit_screens.dart'; +import 'package:stopmotion/ui/helpers/app_titles.dart'; + +class GlobalAppBar extends StatelessWidget implements PreferredSizeWidget { + const GlobalAppBar({super.key}); + + @override + Widget build(BuildContext context) { + return BlocBuilder<ActivityCubit, ActivityState>( + builder: (BuildContext context, ActivityState activityState) { + return BlocBuilder<NavCubitScreen, int>( + builder: (BuildContext context, int screenIndex) { + final List<Widget> menuActions = []; + + if (screenIndex == Screen.indexActivity) { + // go to Settings page + menuActions.add(ElevatedButton( + onPressed: () { + context.read<NavCubitScreen>().goToSettingsPage(); + }, + style: ElevatedButton.styleFrom( + shape: const CircleBorder(), + ), + child: Screen.screenSettings.icon, + )); + + // go to About page + menuActions.add(ElevatedButton( + onPressed: () { + context.read<NavCubitScreen>().goToAboutPage(); + }, + style: ElevatedButton.styleFrom( + shape: const CircleBorder(), + ), + child: Screen.screenAbout.icon, + )); + } else { + // back to Home page + menuActions.add(ElevatedButton( + onPressed: () { + context.read<NavCubitScreen>().goToActivityPage(); + }, + style: ElevatedButton.styleFrom( + shape: const CircleBorder(), + ), + child: Screen.screenActivity.icon, + )); + } + + return AppBar( + title: const AppHeader(text: 'app_name'), + actions: menuActions, + ); + }, + ); + }, + ); + } + + @override + Size get preferredSize => const Size.fromHeight(50); +} diff --git a/lib/ui/pages/editor.dart b/lib/ui/pages/editor.dart new file mode 100644 index 0000000000000000000000000000000000000000..2a0648fdbd1d3d593547e6865afe430d5674f857 --- /dev/null +++ b/lib/ui/pages/editor.dart @@ -0,0 +1,26 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +import 'package:stopmotion/cubit/activity_cubit.dart'; +import 'package:stopmotion/ui/widgets/take_picture_widget.dart'; + +class PageEditor extends StatelessWidget { + const PageEditor({super.key}); + + @override + Widget build(BuildContext context) { + return BlocBuilder<ActivityCubit, ActivityState>( + builder: (BuildContext context, ActivityState activityState) { + return const Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, + children: <Widget>[ + SizedBox(height: 8), + Text('[editor]'), + TakePictureWidget(), + ], + ); + }, + ); + } +} diff --git a/lib/ui/pages/home.dart b/lib/ui/pages/home.dart new file mode 100644 index 0000000000000000000000000000000000000000..ffe31c447aa85a04b6bc1a9dc0a7d92b8e96062c --- /dev/null +++ b/lib/ui/pages/home.dart @@ -0,0 +1,35 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +import 'package:stopmotion/cubit/activity_cubit.dart'; +import 'package:stopmotion/models/activity/activity.dart'; +import 'package:stopmotion/ui/helpers/outlined_text_widget.dart'; +import 'package:stopmotion/utils/color_extensions.dart'; + +class PageHome extends StatelessWidget { + const PageHome({super.key}); + + @override + Widget build(BuildContext context) { + return BlocBuilder<ActivityCubit, ActivityState>( + builder: (BuildContext context, ActivityState activityState) { + final Activity currentActivity = activityState.currentActivity; + + return Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, + children: <Widget>[ + const SizedBox(height: 8), + OutlinedText( + text: '[home]', + fontSize: 50, + textColor: Colors.blueAccent, + outlineColor: Colors.blueAccent.lighten(20), + ), + Text(currentActivity.toString()), + ], + ); + }, + ); + } +} diff --git a/lib/ui/pages/player.dart b/lib/ui/pages/player.dart new file mode 100644 index 0000000000000000000000000000000000000000..5171cfc87c7e1465881c7150d9df5c81c1a8111e --- /dev/null +++ b/lib/ui/pages/player.dart @@ -0,0 +1,35 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +import 'package:stopmotion/cubit/activity_cubit.dart'; +import 'package:stopmotion/models/activity/activity.dart'; +import 'package:stopmotion/ui/helpers/outlined_text_widget.dart'; +import 'package:stopmotion/utils/color_extensions.dart'; + +class PagePlayer extends StatelessWidget { + const PagePlayer({super.key}); + + @override + Widget build(BuildContext context) { + return BlocBuilder<ActivityCubit, ActivityState>( + builder: (BuildContext context, ActivityState activityState) { + final Activity currentActivity = activityState.currentActivity; + + return Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, + children: <Widget>[ + const SizedBox(height: 8), + OutlinedText( + text: '[player]', + fontSize: 50, + textColor: Colors.blueAccent, + outlineColor: Colors.blueAccent.lighten(20), + ), + Text(currentActivity.toString()), + ], + ); + }, + ); + } +} diff --git a/lib/ui/screens/about.dart b/lib/ui/screens/about.dart new file mode 100644 index 0000000000000000000000000000000000000000..ec183f054b2c033fbc535ba80266bcb6fbcff0ba --- /dev/null +++ b/lib/ui/screens/about.dart @@ -0,0 +1,41 @@ +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:package_info_plus/package_info_plus.dart'; + +import 'package:stopmotion/ui/helpers/app_titles.dart'; + +class ScreenAbout extends StatelessWidget { + const ScreenAbout({super.key}); + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 8), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: <Widget>[ + const SizedBox(height: 8), + const AppTitle(text: 'about_title'), + const Text('about_content').tr(), + FutureBuilder<PackageInfo>( + future: PackageInfo.fromPlatform(), + builder: (context, snapshot) { + switch (snapshot.connectionState) { + case ConnectionState.done: + return const Text('about_version').tr( + namedArgs: { + 'version': snapshot.data!.version, + }, + ); + default: + return const SizedBox(); + } + }, + ), + ], + ), + ); + } +} diff --git a/lib/ui/screens/activity.dart b/lib/ui/screens/activity.dart new file mode 100644 index 0000000000000000000000000000000000000000..c4a4697a2a279942f72a2ff69773f1152c1c6d3f --- /dev/null +++ b/lib/ui/screens/activity.dart @@ -0,0 +1,18 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +import 'package:stopmotion/config/activity_page.dart'; +import 'package:stopmotion/cubit/nav_cubit_pages.dart'; + +class ScreenActivity extends StatelessWidget { + const ScreenActivity({super.key}); + + @override + Widget build(BuildContext context) { + return BlocBuilder<NavCubitPage, int>( + builder: (BuildContext context, int pageIndex) { + return ActivityPage.getPageWidget(pageIndex); + }, + ); + } +} diff --git a/lib/ui/screens/camera.dart b/lib/ui/screens/camera.dart deleted file mode 100644 index 00278434f60bdad03f093efd3c1ea7a88c7fd8cf..0000000000000000000000000000000000000000 --- a/lib/ui/screens/camera.dart +++ /dev/null @@ -1,26 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:unicons/unicons.dart'; - -import 'package:stopmotion/ui/widgets/take_picture_widget.dart'; - -class ScreenCamera extends StatelessWidget { - const ScreenCamera({super.key}); - - static Icon navBarIcon = const Icon(UniconsLine.camera); - static String navBarText = 'bottom_nav_camera'; - - @override - Widget build(BuildContext context) { - return Material( - color: Theme.of(context).colorScheme.background, - child: const Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.center, - children: <Widget>[ - SizedBox(height: 8), - TakePictureWidget(), - ], - ), - ); - } -} diff --git a/lib/ui/screens/home.dart b/lib/ui/screens/home.dart deleted file mode 100644 index c9c537457b02275095311939873152e0bfded8c3..0000000000000000000000000000000000000000 --- a/lib/ui/screens/home.dart +++ /dev/null @@ -1,25 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:unicons/unicons.dart'; - -class ScreenHome extends StatelessWidget { - const ScreenHome({super.key}); - - static Icon navBarIcon = const Icon(UniconsLine.home); - static String navBarText = 'bottom_nav_home'; - - @override - Widget build(BuildContext context) { - return Material( - color: Theme.of(context).colorScheme.background, - child: ListView( - padding: const EdgeInsets.symmetric(horizontal: 4), - physics: const BouncingScrollPhysics(), - children: const <Widget>[ - SizedBox(height: 8), - Text('CONTENT'), - SizedBox(height: 36), - ], - ), - ); - } -} diff --git a/lib/ui/screens/settings.dart b/lib/ui/screens/settings.dart index db2e9214cf474767b2d5d66e89db18fde70aec42..d08b042e201531509d7d7ac81a41610b66259905 100644 --- a/lib/ui/screens/settings.dart +++ b/lib/ui/screens/settings.dart @@ -1,27 +1,24 @@ -import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; -import 'package:stopmotion/ui/widgets/app_titles.dart'; -import 'package:stopmotion/ui/widgets/settings_form.dart'; -import 'package:unicons/unicons.dart'; +import 'package:stopmotion/ui/settings/settings_form.dart'; +import 'package:stopmotion/ui/helpers/app_titles.dart'; class ScreenSettings extends StatelessWidget { const ScreenSettings({super.key}); - static Icon navBarIcon = const Icon(UniconsLine.setting); - static String navBarText = 'bottom_nav_settings'; - @override Widget build(BuildContext context) { - return Material( - color: Theme.of(context).colorScheme.background, - child: ListView( - padding: const EdgeInsets.symmetric(horizontal: 4), - physics: const BouncingScrollPhysics(), + return const Padding( + padding: EdgeInsets.symmetric(horizontal: 8), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.max, children: <Widget>[ - const SizedBox(height: 8), - AppTitle1(text: tr('settings_title')), - const SettingsForm(), + SizedBox(height: 8), + AppTitle(text: 'settings_title'), + SizedBox(height: 8), + SettingsForm(), ], ), ); diff --git a/lib/ui/settings/settings_form.dart b/lib/ui/settings/settings_form.dart new file mode 100644 index 0000000000000000000000000000000000000000..e9106fb751d10a80642254bc7c471bd59bd52cb3 --- /dev/null +++ b/lib/ui/settings/settings_form.dart @@ -0,0 +1,63 @@ +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:unicons/unicons.dart'; + +import 'package:stopmotion/ui/settings/theme_card.dart'; + +class SettingsForm extends StatefulWidget { + const SettingsForm({super.key}); + + @override + State<SettingsForm> createState() => _SettingsFormState(); +} + +class _SettingsFormState extends State<SettingsForm> { + @override + void dispose() { + super.dispose(); + } + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + } + + @override + Widget build(BuildContext context) { + return Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + children: <Widget>[ + // Light/dark theme + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.center, + children: <Widget>[ + const Text('settings_label_theme').tr(), + const Row( + mainAxisAlignment: MainAxisAlignment.end, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + ThemeCard( + mode: ThemeMode.system, + icon: UniconsLine.cog, + ), + ThemeCard( + mode: ThemeMode.light, + icon: UniconsLine.sun, + ), + ThemeCard( + mode: ThemeMode.dark, + icon: UniconsLine.moon, + ) + ], + ), + ], + ), + + const SizedBox(height: 16), + ], + ); + } +} diff --git a/lib/ui/settings/theme_card.dart b/lib/ui/settings/theme_card.dart new file mode 100644 index 0000000000000000000000000000000000000000..74351a20082666571f8bcec4f320a74139683e55 --- /dev/null +++ b/lib/ui/settings/theme_card.dart @@ -0,0 +1,47 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +import 'package:stopmotion/cubit/theme_cubit.dart'; + +class ThemeCard extends StatelessWidget { + const ThemeCard({ + super.key, + required this.mode, + required this.icon, + }); + + final IconData icon; + final ThemeMode mode; + + @override + Widget build(BuildContext context) { + return BlocBuilder<ThemeCubit, ThemeModeState>( + builder: (BuildContext context, ThemeModeState state) { + return Card( + elevation: 2, + shadowColor: Theme.of(context).colorScheme.shadow, + color: state.themeMode == mode + ? Theme.of(context).colorScheme.primary + : Theme.of(context).colorScheme.surface, + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(12)), + ), + margin: const EdgeInsets.all(5), + child: InkWell( + onTap: () => BlocProvider.of<ThemeCubit>(context).getTheme( + ThemeModeState(themeMode: mode), + ), + borderRadius: const BorderRadius.all(Radius.circular(12)), + child: Icon( + icon, + size: 32, + color: state.themeMode != mode + ? Theme.of(context).colorScheme.primary + : Colors.white, + ), + ), + ); + }, + ); + } +} diff --git a/lib/ui/skeleton.dart b/lib/ui/skeleton.dart index 16d65ec2c7efc08ef3d6484b46f1c3df225945ab..8da2685aadfc2b261e682ded04aa4a38c14d9180 100644 --- a/lib/ui/skeleton.dart +++ b/lib/ui/skeleton.dart @@ -1,42 +1,37 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:stopmotion/cubit/bottom_nav_cubit.dart'; -import 'package:stopmotion/ui/screens/camera.dart'; -import 'package:stopmotion/ui/screens/home.dart'; -import 'package:stopmotion/ui/screens/settings.dart'; -import 'package:stopmotion/ui/widgets/app_bar.dart'; -import 'package:stopmotion/ui/widgets/bottom_nav_bar.dart'; +import 'package:stopmotion/config/screen.dart'; +import 'package:stopmotion/cubit/nav_cubit_screens.dart'; +import 'package:stopmotion/ui/nav/global_app_bar.dart'; +import 'package:stopmotion/ui/nav/bottom_nav_bar.dart'; -class SkeletonScreen extends StatefulWidget { +class SkeletonScreen extends StatelessWidget { const SkeletonScreen({super.key}); - @override - State<SkeletonScreen> createState() => _SkeletonScreenState(); -} - -class _SkeletonScreenState extends State<SkeletonScreen> { @override Widget build(BuildContext context) { - List<Widget> pageNavigation = <Widget>[ - const ScreenHome(), - const ScreenCamera(), - const ScreenSettings(), - ]; - - return Scaffold( - appBar: const StandardAppBar(), - extendBodyBehindAppBar: false, - body: BlocBuilder<BottomNavCubit, int>( - builder: (BuildContext context, int state) { - return AnimatedSwitcher( - duration: const Duration(milliseconds: 300), - child: pageNavigation.elementAt(state), - ); - }, - ), - backgroundColor: Theme.of(context).colorScheme.background, - bottomNavigationBar: const BottomNavBar(), + return BlocBuilder<NavCubitScreen, int>( + builder: (BuildContext context, int screenIndex) { + return Scaffold( + appBar: const GlobalAppBar(), + extendBodyBehindAppBar: false, + body: Material( + color: Theme.of(context).colorScheme.surface, + child: Padding( + padding: const EdgeInsets.only( + top: 8, + left: 2, + right: 2, + ), + child: Screen.getWidget(screenIndex), + ), + ), + backgroundColor: Theme.of(context).colorScheme.surface, + bottomNavigationBar: + Screen.displayBottomNavBar(screenIndex) ? const BottomNavBar() : null, + ); + }, ); } } diff --git a/lib/ui/widgets/app_bar.dart b/lib/ui/widgets/app_bar.dart deleted file mode 100644 index 35094c7252b900686a3d0b3b567636740b38ac08..0000000000000000000000000000000000000000 --- a/lib/ui/widgets/app_bar.dart +++ /dev/null @@ -1,18 +0,0 @@ -import 'package:flutter/material.dart'; - -import 'package:stopmotion/ui/widgets/app_titles.dart'; - -class StandardAppBar extends StatelessWidget implements PreferredSizeWidget { - const StandardAppBar({super.key}); - - @override - Widget build(BuildContext context) { - return AppBar( - title: const AppTitle(text: 'app_name'), - actions: const [], - ); - } - - @override - Size get preferredSize => const Size.fromHeight(50); -} diff --git a/lib/ui/widgets/settings_form.dart b/lib/ui/widgets/settings_form.dart deleted file mode 100644 index d527702b672d6d2306827910ad4cacc4cef87f57..0000000000000000000000000000000000000000 --- a/lib/ui/widgets/settings_form.dart +++ /dev/null @@ -1,81 +0,0 @@ -import 'package:easy_localization/easy_localization.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; - -import 'package:stopmotion/config/default_settings.dart'; -import 'package:stopmotion/cubit/settings_cubit.dart'; -import 'package:stopmotion/ui/widgets/app_titles.dart'; - -class SettingsForm extends StatefulWidget { - const SettingsForm({super.key}); - - @override - State<SettingsForm> createState() => _SettingsFormState(); -} - -class _SettingsFormState extends State<SettingsForm> { - int dummyValue = DefaultSettings.defaultDummyValue; - - List<bool> _selectedDummyValue = []; - - @override - void didChangeDependencies() { - SettingsCubit settings = BlocProvider.of<SettingsCubit>(context); - - dummyValue = settings.getDummyValue(); - - _selectedDummyValue = - DefaultSettings.allowedDummyValues.map((e) => (e == dummyValue)).toList(); - - super.didChangeDependencies(); - } - - @override - void dispose() { - super.dispose(); - } - - @override - Widget build(BuildContext context) { - void saveSettings() { - BlocProvider.of<SettingsCubit>(context).setValues( - dummyValue: dummyValue, - ); - } - - return Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.max, - children: <Widget>[ - const SizedBox(height: 8), - AppTitle2(text: tr('settings_title_global')), - - // Dummy value - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - const Text('settings_label_dummy_value').tr(), - ToggleButtons( - onPressed: (int index) { - setState(() { - dummyValue = DefaultSettings.allowedDummyValues[index]; - for (int i = 0; i < _selectedDummyValue.length; i++) { - _selectedDummyValue[i] = i == index; - } - }); - saveSettings(); - }, - borderRadius: const BorderRadius.all(Radius.circular(8)), - constraints: const BoxConstraints(minHeight: 30.0, minWidth: 30.0), - isSelected: _selectedDummyValue, - children: - DefaultSettings.allowedDummyValues.map((e) => Text(e.toString())).toList(), - ), - ], - ), - ], - ); - } -} diff --git a/pubspec.lock b/pubspec.lock index 03fa8f88b17c79c6bba02eb84694453caa60e662..8c9e1fe3d069efaa7820da53174ab15e7b9adaaf 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,42 +5,50 @@ packages: dependency: transitive description: name: args - sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596 + sha256: "7cf60b9f0cc88203c5a190b4cd62a99feea42759a7fa695010eb5de1c0b2252a" url: "https://pub.dev" source: hosted - version: "2.4.2" + version: "2.5.0" + async: + dependency: transitive + description: + name: async + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + url: "https://pub.dev" + source: hosted + version: "2.11.0" bloc: dependency: transitive description: name: bloc - sha256: f53a110e3b48dcd78136c10daa5d51512443cea5e1348c9d80a320095fa2db9e + sha256: "106842ad6569f0b60297619e9e0b1885c2fb9bf84812935490e6c5275777804e" url: "https://pub.dev" source: hosted - version: "8.1.3" + version: "8.1.4" camera: dependency: "direct main" description: name: camera - sha256: "9499cbc2e51d8eb0beadc158b288380037618ce4e30c9acbc4fae1ac3ecb5797" + sha256: "2170a943dcb67be2af2c6bcda8775e74b41d4c02d6a4eb10bdc832ee185c4eea" url: "https://pub.dev" source: hosted - version: "0.10.5+9" - camera_android: + version: "0.11.0+1" + camera_android_camerax: dependency: transitive description: - name: camera_android - sha256: "351429510121d179b9aac5a2e8cb525c3cd6c39f4d709c5f72dfb21726e52371" + name: camera_android_camerax + sha256: "7abb0faddbf103c59365e805ad9a30ab4d602b2eb7a8de469697945fd4a69daa" url: "https://pub.dev" source: hosted - version: "0.10.8+16" + version: "0.6.5+6" camera_avfoundation: dependency: transitive description: name: camera_avfoundation - sha256: "7d0763dfcbf060f56aa254a68c103210280bee9e97bbe4fdef23e257a4f70ab9" + sha256: "7d021e8cd30d9b71b8b92b4ad669e80af432d722d18d6aac338572754a786c15" url: "https://pub.dev" source: hosted - version: "0.9.14" + version: "0.9.16" camera_platform_interface: dependency: transitive description: @@ -53,10 +61,10 @@ packages: dependency: transitive description: name: camera_web - sha256: f18ccfb33b2a7c49a52ad5aa3f07330b7422faaecbdfd9b9fe8e51182f6ad67d + sha256: "9e9aba2fbab77ce2472924196ff8ac4dd8f9126c4f9a3096171cd1d870d6b26c" url: "https://pub.dev" source: hosted - version: "0.3.2+4" + version: "0.3.3" characters: dependency: transitive description: @@ -101,10 +109,10 @@ packages: dependency: "direct main" description: name: easy_localization - sha256: c145aeb6584aedc7c862ab8c737c3277788f47488bfdf9bae0fe112bd0a4789c + sha256: fa59bcdbbb911a764aa6acf96bbb6fa7a5cf8234354fc45ec1a43a0349ef0201 url: "https://pub.dev" source: hosted - version: "3.0.5" + version: "3.0.7" easy_logger: dependency: transitive description: @@ -146,18 +154,18 @@ packages: dependency: "direct main" description: name: flutter_bloc - sha256: "87325da1ac757fcc4813e6b34ed5dd61169973871fdf181d6c2109dd6935ece1" + sha256: b594505eac31a0518bdcb4b5b79573b8d9117b193cc80cc12e17d639b10aa27a url: "https://pub.dev" source: hosted - version: "8.1.4" + version: "8.1.6" flutter_lints: dependency: "direct dev" description: name: flutter_lints - sha256: e2a421b7e59244faef694ba7b30562e489c2b489866e505074eb005cd7060db7 + sha256: "3f41d009ba7172d5ff9be5f6e6e6abb4300e263aab8866d2a0842ed2a70f8f0c" url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "4.0.0" flutter_localizations: dependency: transitive description: flutter @@ -167,10 +175,10 @@ packages: dependency: transitive description: name: flutter_plugin_android_lifecycle - sha256: b068ffc46f82a55844acfa4fdbb61fad72fa2aef0905548419d97f0f95c456da + sha256: c6b0b4c05c458e1c01ad9bcc14041dd7b1f6783d487be4386f793f47a8a4d03e url: "https://pub.dev" source: hosted - version: "2.0.17" + version: "2.0.20" flutter_web_plugins: dependency: transitive description: flutter @@ -184,30 +192,46 @@ packages: url: "https://pub.dev" source: hosted version: "2.2.3" + http: + dependency: transitive + description: + name: http + sha256: "761a297c042deedc1ffbb156d6e2af13886bb305c2a343a4d972504cd67dd938" + url: "https://pub.dev" + source: hosted + version: "1.2.1" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + url: "https://pub.dev" + source: hosted + version: "4.0.2" hydrated_bloc: dependency: "direct main" description: name: hydrated_bloc - sha256: "00a2099680162e74b5a836b8a7f446e478520a9cae9f6032e028ad8129f4432d" + sha256: af35b357739fe41728df10bec03aad422cdc725a1e702e03af9d2a41ea05160c url: "https://pub.dev" source: hosted - version: "9.1.4" + version: "9.1.5" intl: dependency: transitive description: name: intl - sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d" + sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf url: "https://pub.dev" source: hosted - version: "0.18.1" + version: "0.19.0" lints: dependency: transitive description: name: lints - sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290 + sha256: "976c774dd944a42e83e2467f4cc670daef7eed6295b10b36ae8c85bcbf828235" url: "https://pub.dev" source: hosted - version: "3.0.0" + version: "4.0.0" material_color_utilities: dependency: transitive description: @@ -220,10 +244,10 @@ packages: dependency: transitive description: name: meta - sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 + sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136" url: "https://pub.dev" source: hosted - version: "1.11.0" + version: "1.12.0" nested: dependency: transitive description: @@ -232,6 +256,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.0" + package_info_plus: + dependency: "direct main" + description: + name: package_info_plus + sha256: b93d8b4d624b4ea19b0a5a208b2d6eff06004bc3ce74c06040b120eeadd00ce0 + url: "https://pub.dev" + source: hosted + version: "8.0.0" + package_info_plus_platform_interface: + dependency: transitive + description: + name: package_info_plus_platform_interface + sha256: f49918f3433a3146047372f9d4f1f847511f2acd5cd030e1f44fe5a50036b70e + url: "https://pub.dev" + source: hosted + version: "3.0.0" path: dependency: "direct main" description: @@ -244,26 +284,26 @@ packages: dependency: "direct main" description: name: path_provider - sha256: b27217933eeeba8ff24845c34003b003b2b22151de3c908d0e679e8fe1aa078b + sha256: c9e7d3a4cd1410877472158bee69963a4579f78b68c65a2b7d40d1a7a88bb161 url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.3" path_provider_android: dependency: transitive description: name: path_provider_android - sha256: "477184d672607c0a3bf68fbbf601805f92ef79c82b64b4d6eb318cbca4c48668" + sha256: bca87b0165ffd7cdb9cad8edd22d18d2201e886d9a9f19b4fb3452ea7df3a72a url: "https://pub.dev" source: hosted - version: "2.2.2" + version: "2.2.6" path_provider_foundation: dependency: transitive description: name: path_provider_foundation - sha256: "5a7999be66e000916500be4f15a3633ebceb8302719b47b9cc49ce924125350f" + sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16 url: "https://pub.dev" source: hosted - version: "2.3.2" + version: "2.4.0" path_provider_linux: dependency: transitive description: @@ -292,10 +332,10 @@ packages: dependency: transitive description: name: platform - sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec" + sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65" url: "https://pub.dev" source: hosted - version: "3.1.4" + version: "3.1.5" plugin_platform_interface: dependency: transitive description: @@ -316,26 +356,26 @@ packages: dependency: transitive description: name: shared_preferences - sha256: "81429e4481e1ccfb51ede496e916348668fd0921627779233bd24cc3ff6abd02" + sha256: d3bbe5553a986e83980916ded2f0b435ef2e1893dfaa29d5a7a790d0eca12180 url: "https://pub.dev" source: hosted - version: "2.2.2" + version: "2.2.3" shared_preferences_android: dependency: transitive description: name: shared_preferences_android - sha256: "8568a389334b6e83415b6aae55378e158fbc2314e074983362d20c562780fb06" + sha256: "93d0ec9dd902d85f326068e6a899487d1f65ffcd5798721a95330b26c8131577" url: "https://pub.dev" source: hosted - version: "2.2.1" + version: "2.2.3" shared_preferences_foundation: dependency: transitive description: name: shared_preferences_foundation - sha256: "7708d83064f38060c7b39db12aefe449cb8cdc031d6062280087bc4cdb988f5c" + sha256: "0a8a893bf4fd1152f93fec03a415d11c27c74454d96e2318a7ac38dd18683ab7" url: "https://pub.dev" source: hosted - version: "2.3.5" + version: "2.4.0" shared_preferences_linux: dependency: transitive description: @@ -373,6 +413,14 @@ packages: description: flutter source: sdk version: "0.0.99" + source_span: + dependency: transitive + description: + name: source_span + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" + url: "https://pub.dev" + source: hosted + version: "1.10.0" stream_transform: dependency: transitive description: @@ -381,6 +429,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.0" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" + source: hosted + version: "1.2.0" synchronized: dependency: transitive description: @@ -389,6 +445,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.1.0+1" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" + source: hosted + version: "1.2.1" typed_data: dependency: transitive description: @@ -401,10 +465,10 @@ packages: dependency: "direct main" description: name: unicons - sha256: dbfcf93ff4d4ea19b324113857e358e4882115ab85db04417a4ba1c72b17a670 + sha256: "1cca7462df18ff191b7e41b52f747d08854916531d1d7ab7cec0552095995206" url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" vector_math: dependency: transitive description: @@ -417,18 +481,18 @@ packages: dependency: transitive description: name: web - sha256: "1d9158c616048c38f712a6646e317a3426da10e884447626167240d45209cbad" + sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27" url: "https://pub.dev" source: hosted - version: "0.5.0" + version: "0.5.1" win32: dependency: transitive description: name: win32 - sha256: "464f5674532865248444b4c3daca12bd9bf2d7c47f759ce2617986e7229494a8" + sha256: a79dbe579cb51ecd6d30b17e0cae4e0ea15e2c0e66f69ad4198f22a6789e94f4 url: "https://pub.dev" source: hosted - version: "5.2.0" + version: "5.5.1" xdg_directories: dependency: transitive description: @@ -438,5 +502,5 @@ packages: source: hosted version: "1.0.4" sdks: - dart: ">=3.3.0 <4.0.0" - flutter: ">=3.19.0" + dart: ">=3.4.0 <4.0.0" + flutter: ">=3.22.0" diff --git a/pubspec.yaml b/pubspec.yaml index c7072694801d238b5b613a59ac10a399a4bdf81b..6d5d0df0a506b04477ff181e66529cfc303ee0be 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,32 +1,36 @@ name: stopmotion description: stop motion assistant -publish_to: 'none' +publish_to: "none" -version: 0.0.7+7 +version: 0.0.8+8 environment: - sdk: '^3.0.0' + sdk: "^3.0.0" dependencies: flutter: sdk: flutter - camera: ^0.10.5+8 + # base easy_localization: ^3.0.1 equatable: ^2.0.5 flutter_bloc: ^8.1.1 hive: ^2.2.3 hydrated_bloc: ^9.0.0 - path: ^1.8.3 - path_provider: ^2.1.1 + package_info_plus: ^8.0.0 + path_provider: ^2.0.11 unicons: ^2.1.1 + # specific + camera: ^0.11.0+1 + path: ^1.8.3 + dev_dependencies: - flutter_lints: ^3.0.1 + flutter_lints: ^4.0.0 flutter: - uses-material-design: false + uses-material-design: true assets: - assets/translations/ @@ -41,3 +45,4 @@ flutter: weight: 400 - asset: assets/fonts/Nunito-Light.ttf weight: 300 + diff --git a/icons/build_repository_icons.sh b/resources/app/build_application_resources.sh similarity index 98% rename from icons/build_repository_icons.sh rename to resources/app/build_application_resources.sh index 27dbe2647fe4e6d562fbd99451716d1b7d448570..6d67b8f4f9eca701d1aed7331ef41dfb0bd44f20 100755 --- a/icons/build_repository_icons.sh +++ b/resources/app/build_application_resources.sh @@ -6,7 +6,7 @@ command -v scour >/dev/null 2>&1 || { echo >&2 "I require scour but it's not ins command -v optipng >/dev/null 2>&1 || { echo >&2 "I require optipng but it's not installed. Aborting."; exit 1; } CURRENT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)" -BASE_DIR="$(dirname "${CURRENT_DIR}")" +BASE_DIR="$(dirname "$(dirname "${CURRENT_DIR}")")" SOURCE_ICON="${CURRENT_DIR}/icon.svg" SOURCE_FASTLANE="${CURRENT_DIR}/featureGraphic.svg" diff --git a/icons/featureGraphic.svg b/resources/app/featureGraphic.svg similarity index 100% rename from icons/featureGraphic.svg rename to resources/app/featureGraphic.svg diff --git a/icons/icon.svg b/resources/app/icon.svg similarity index 100% rename from icons/icon.svg rename to resources/app/icon.svg diff --git a/resources/build_resources.sh b/resources/build_resources.sh new file mode 100755 index 0000000000000000000000000000000000000000..8d5848a985ed1068f6e6226379a9cedb69c3fa15 --- /dev/null +++ b/resources/build_resources.sh @@ -0,0 +1,6 @@ +#! /bin/bash + +CURRENT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)" + +${CURRENT_DIR}/app/build_application_resources.sh +