save
This commit is contained in:
Generated
+3
-3
@@ -1,3 +1,3 @@
|
|||||||
# Default ignored files
|
# Default ignored files
|
||||||
/shelf/
|
/shelf/
|
||||||
/workspace.xml
|
/workspace.xml
|
||||||
|
|||||||
Generated
+51
-51
@@ -1,52 +1,52 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<module type="JAVA_MODULE" version="4">
|
<module type="JAVA_MODULE" version="4">
|
||||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||||
<exclude-output />
|
<exclude-output />
|
||||||
<content url="file://$MODULE_DIR$">
|
<content url="file://$MODULE_DIR$">
|
||||||
<excludeFolder url="file://$MODULE_DIR$/mobile/.dart_tool" />
|
<excludeFolder url="file://$MODULE_DIR$/mobile/.dart_tool" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/mobile/.pub" />
|
<excludeFolder url="file://$MODULE_DIR$/mobile/.pub" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/mobile/build" />
|
<excludeFolder url="file://$MODULE_DIR$/mobile/build" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/mobile/linux/flutter/ephemeral/.plugin_symlinks/flutter_secure_storage_linux/.dart_tool" />
|
<excludeFolder url="file://$MODULE_DIR$/mobile/linux/flutter/ephemeral/.plugin_symlinks/flutter_secure_storage_linux/.dart_tool" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/mobile/linux/flutter/ephemeral/.plugin_symlinks/flutter_secure_storage_linux/.pub" />
|
<excludeFolder url="file://$MODULE_DIR$/mobile/linux/flutter/ephemeral/.plugin_symlinks/flutter_secure_storage_linux/.pub" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/mobile/linux/flutter/ephemeral/.plugin_symlinks/flutter_secure_storage_linux/build" />
|
<excludeFolder url="file://$MODULE_DIR$/mobile/linux/flutter/ephemeral/.plugin_symlinks/flutter_secure_storage_linux/build" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/mobile/linux/flutter/ephemeral/.plugin_symlinks/jni/.dart_tool" />
|
<excludeFolder url="file://$MODULE_DIR$/mobile/linux/flutter/ephemeral/.plugin_symlinks/jni/.dart_tool" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/mobile/linux/flutter/ephemeral/.plugin_symlinks/jni/.pub" />
|
<excludeFolder url="file://$MODULE_DIR$/mobile/linux/flutter/ephemeral/.plugin_symlinks/jni/.pub" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/mobile/linux/flutter/ephemeral/.plugin_symlinks/jni/build" />
|
<excludeFolder url="file://$MODULE_DIR$/mobile/linux/flutter/ephemeral/.plugin_symlinks/jni/build" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/mobile/linux/flutter/ephemeral/.plugin_symlinks/jni/example/.dart_tool" />
|
<excludeFolder url="file://$MODULE_DIR$/mobile/linux/flutter/ephemeral/.plugin_symlinks/jni/example/.dart_tool" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/mobile/linux/flutter/ephemeral/.plugin_symlinks/jni/example/.pub" />
|
<excludeFolder url="file://$MODULE_DIR$/mobile/linux/flutter/ephemeral/.plugin_symlinks/jni/example/.pub" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/mobile/linux/flutter/ephemeral/.plugin_symlinks/jni/example/build" />
|
<excludeFolder url="file://$MODULE_DIR$/mobile/linux/flutter/ephemeral/.plugin_symlinks/jni/example/build" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/mobile/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/.dart_tool" />
|
<excludeFolder url="file://$MODULE_DIR$/mobile/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/.dart_tool" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/mobile/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/.pub" />
|
<excludeFolder url="file://$MODULE_DIR$/mobile/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/.pub" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/mobile/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/build" />
|
<excludeFolder url="file://$MODULE_DIR$/mobile/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/build" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/mobile/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/example/.dart_tool" />
|
<excludeFolder url="file://$MODULE_DIR$/mobile/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/example/.dart_tool" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/mobile/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/example/.pub" />
|
<excludeFolder url="file://$MODULE_DIR$/mobile/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/example/.pub" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/mobile/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/example/build" />
|
<excludeFolder url="file://$MODULE_DIR$/mobile/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux/example/build" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/mobile/windows/flutter/ephemeral/.plugin_symlinks/flutter_secure_storage_windows/.dart_tool" />
|
<excludeFolder url="file://$MODULE_DIR$/mobile/windows/flutter/ephemeral/.plugin_symlinks/flutter_secure_storage_windows/.dart_tool" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/mobile/windows/flutter/ephemeral/.plugin_symlinks/flutter_secure_storage_windows/.pub" />
|
<excludeFolder url="file://$MODULE_DIR$/mobile/windows/flutter/ephemeral/.plugin_symlinks/flutter_secure_storage_windows/.pub" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/mobile/windows/flutter/ephemeral/.plugin_symlinks/flutter_secure_storage_windows/build" />
|
<excludeFolder url="file://$MODULE_DIR$/mobile/windows/flutter/ephemeral/.plugin_symlinks/flutter_secure_storage_windows/build" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/mobile/windows/flutter/ephemeral/.plugin_symlinks/flutter_secure_storage_windows/example/.dart_tool" />
|
<excludeFolder url="file://$MODULE_DIR$/mobile/windows/flutter/ephemeral/.plugin_symlinks/flutter_secure_storage_windows/example/.dart_tool" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/mobile/windows/flutter/ephemeral/.plugin_symlinks/flutter_secure_storage_windows/example/.pub" />
|
<excludeFolder url="file://$MODULE_DIR$/mobile/windows/flutter/ephemeral/.plugin_symlinks/flutter_secure_storage_windows/example/.pub" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/mobile/windows/flutter/ephemeral/.plugin_symlinks/flutter_secure_storage_windows/example/build" />
|
<excludeFolder url="file://$MODULE_DIR$/mobile/windows/flutter/ephemeral/.plugin_symlinks/flutter_secure_storage_windows/example/build" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/mobile/windows/flutter/ephemeral/.plugin_symlinks/jni/.dart_tool" />
|
<excludeFolder url="file://$MODULE_DIR$/mobile/windows/flutter/ephemeral/.plugin_symlinks/jni/.dart_tool" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/mobile/windows/flutter/ephemeral/.plugin_symlinks/jni/.pub" />
|
<excludeFolder url="file://$MODULE_DIR$/mobile/windows/flutter/ephemeral/.plugin_symlinks/jni/.pub" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/mobile/windows/flutter/ephemeral/.plugin_symlinks/jni/build" />
|
<excludeFolder url="file://$MODULE_DIR$/mobile/windows/flutter/ephemeral/.plugin_symlinks/jni/build" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/mobile/windows/flutter/ephemeral/.plugin_symlinks/jni/example/.dart_tool" />
|
<excludeFolder url="file://$MODULE_DIR$/mobile/windows/flutter/ephemeral/.plugin_symlinks/jni/example/.dart_tool" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/mobile/windows/flutter/ephemeral/.plugin_symlinks/jni/example/.pub" />
|
<excludeFolder url="file://$MODULE_DIR$/mobile/windows/flutter/ephemeral/.plugin_symlinks/jni/example/.pub" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/mobile/windows/flutter/ephemeral/.plugin_symlinks/jni/example/build" />
|
<excludeFolder url="file://$MODULE_DIR$/mobile/windows/flutter/ephemeral/.plugin_symlinks/jni/example/build" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/mobile/windows/flutter/ephemeral/.plugin_symlinks/path_provider_windows/.dart_tool" />
|
<excludeFolder url="file://$MODULE_DIR$/mobile/windows/flutter/ephemeral/.plugin_symlinks/path_provider_windows/.dart_tool" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/mobile/windows/flutter/ephemeral/.plugin_symlinks/path_provider_windows/.pub" />
|
<excludeFolder url="file://$MODULE_DIR$/mobile/windows/flutter/ephemeral/.plugin_symlinks/path_provider_windows/.pub" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/mobile/windows/flutter/ephemeral/.plugin_symlinks/path_provider_windows/build" />
|
<excludeFolder url="file://$MODULE_DIR$/mobile/windows/flutter/ephemeral/.plugin_symlinks/path_provider_windows/build" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/mobile/windows/flutter/ephemeral/.plugin_symlinks/path_provider_windows/example/.dart_tool" />
|
<excludeFolder url="file://$MODULE_DIR$/mobile/windows/flutter/ephemeral/.plugin_symlinks/path_provider_windows/example/.dart_tool" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/mobile/windows/flutter/ephemeral/.plugin_symlinks/path_provider_windows/example/.pub" />
|
<excludeFolder url="file://$MODULE_DIR$/mobile/windows/flutter/ephemeral/.plugin_symlinks/path_provider_windows/example/.pub" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/mobile/windows/flutter/ephemeral/.plugin_symlinks/path_provider_windows/example/build" />
|
<excludeFolder url="file://$MODULE_DIR$/mobile/windows/flutter/ephemeral/.plugin_symlinks/path_provider_windows/example/build" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/mobile/windows/flutter/ephemeral/.plugin_symlinks/permission_handler_windows/.dart_tool" />
|
<excludeFolder url="file://$MODULE_DIR$/mobile/windows/flutter/ephemeral/.plugin_symlinks/permission_handler_windows/.dart_tool" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/mobile/windows/flutter/ephemeral/.plugin_symlinks/permission_handler_windows/.pub" />
|
<excludeFolder url="file://$MODULE_DIR$/mobile/windows/flutter/ephemeral/.plugin_symlinks/permission_handler_windows/.pub" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/mobile/windows/flutter/ephemeral/.plugin_symlinks/permission_handler_windows/build" />
|
<excludeFolder url="file://$MODULE_DIR$/mobile/windows/flutter/ephemeral/.plugin_symlinks/permission_handler_windows/build" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/mobile/windows/flutter/ephemeral/.plugin_symlinks/permission_handler_windows/example/.dart_tool" />
|
<excludeFolder url="file://$MODULE_DIR$/mobile/windows/flutter/ephemeral/.plugin_symlinks/permission_handler_windows/example/.dart_tool" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/mobile/windows/flutter/ephemeral/.plugin_symlinks/permission_handler_windows/example/.pub" />
|
<excludeFolder url="file://$MODULE_DIR$/mobile/windows/flutter/ephemeral/.plugin_symlinks/permission_handler_windows/example/.pub" />
|
||||||
<excludeFolder url="file://$MODULE_DIR$/mobile/windows/flutter/ephemeral/.plugin_symlinks/permission_handler_windows/example/build" />
|
<excludeFolder url="file://$MODULE_DIR$/mobile/windows/flutter/ephemeral/.plugin_symlinks/permission_handler_windows/example/build" />
|
||||||
</content>
|
</content>
|
||||||
<orderEntry type="inheritedJdk" />
|
<orderEntry type="inheritedJdk" />
|
||||||
<orderEntry type="sourceFolder" forTests="false" />
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
</component>
|
</component>
|
||||||
</module>
|
</module>
|
||||||
Generated
+1
-1
@@ -1781,4 +1781,4 @@
|
|||||||
</list>
|
</list>
|
||||||
</option>
|
</option>
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
Generated
+10
-10
@@ -1,11 +1,11 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="deploymentTargetSelector">
|
<component name="deploymentTargetSelector">
|
||||||
<selectionStates>
|
<selectionStates>
|
||||||
<SelectionState runConfigName="Wear App">
|
<SelectionState runConfigName="Wear App">
|
||||||
<option name="selectionMode" value="DROPDOWN" />
|
<option name="selectionMode" value="DROPDOWN" />
|
||||||
<DialogSelection />
|
<DialogSelection />
|
||||||
</SelectionState>
|
</SelectionState>
|
||||||
</selectionStates>
|
</selectionStates>
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
Generated
+7
-7
@@ -1,8 +1,8 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="MarkdownSettings">
|
<component name="MarkdownSettings">
|
||||||
<option name="previewPanelProviderInfo">
|
<option name="previewPanelProviderInfo">
|
||||||
<ProviderInfo name="Compose (experimental)" className="com.intellij.markdown.compose.preview.ComposePanelProvider" />
|
<ProviderInfo name="Compose (experimental)" className="com.intellij.markdown.compose.preview.ComposePanelProvider" />
|
||||||
</option>
|
</option>
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
Generated
+7
-7
@@ -1,8 +1,8 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="ProjectModuleManager">
|
<component name="ProjectModuleManager">
|
||||||
<modules>
|
<modules>
|
||||||
<module fileurl="file://$PROJECT_DIR$/.idea/CESIZen.iml" filepath="$PROJECT_DIR$/.idea/CESIZen.iml" />
|
<module fileurl="file://$PROJECT_DIR$/.idea/CESIZen.iml" filepath="$PROJECT_DIR$/.idea/CESIZen.iml" />
|
||||||
</modules>
|
</modules>
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
+7
-7
@@ -1,7 +1,7 @@
|
|||||||
<component name="ProjectRunConfigurationManager">
|
<component name="ProjectRunConfigurationManager">
|
||||||
<configuration default="false" name="Launch All (Mobile & Wear)" type="CompoundRunConfigurationType">
|
<configuration default="false" name="Launch All (Mobile & Wear)" type="CompoundRunConfigurationType">
|
||||||
<toRun name="Mobile App" type="FlutterRunConfigurationType" />
|
<toRun name="Mobile App" type="FlutterRunConfigurationType" />
|
||||||
<toRun name="Wear App" type="AndroidRunConfigurationType" />
|
<toRun name="Wear App" type="AndroidRunConfigurationType" />
|
||||||
<method v="2" />
|
<method v="2" />
|
||||||
</configuration>
|
</configuration>
|
||||||
</component>
|
</component>
|
||||||
|
|||||||
Generated
+7
-7
@@ -1,7 +1,7 @@
|
|||||||
<component name="ProjectRunConfigurationManager">
|
<component name="ProjectRunConfigurationManager">
|
||||||
<configuration default="false" name="Mobile App" type="FlutterRunConfigurationType" factoryName="Flutter">
|
<configuration default="false" name="Mobile App" type="FlutterRunConfigurationType" factoryName="Flutter">
|
||||||
<option name="filePath" value="$PROJECT_DIR$/mobile/lib/main.dart" />
|
<option name="filePath" value="$PROJECT_DIR$/mobile/lib/main.dart" />
|
||||||
<option name="additionalArgs" value="-d PV5HRKVCJVKZ9DOB" />
|
<option name="additionalArgs" value="-d PV5HRKVCJVKZ9DOB" />
|
||||||
<method v="2" />
|
<method v="2" />
|
||||||
</configuration>
|
</configuration>
|
||||||
</component>
|
</component>
|
||||||
|
|||||||
Generated
+68
-68
@@ -1,68 +1,68 @@
|
|||||||
<component name="ProjectRunConfigurationManager">
|
<component name="ProjectRunConfigurationManager">
|
||||||
<configuration default="false" name="Wear App" type="AndroidRunConfigurationType" factoryName="Android App">
|
<configuration default="false" name="Wear App" type="AndroidRunConfigurationType" factoryName="Android App">
|
||||||
<module name="CESIZen.Wear.app.main" />
|
<module name="CESIZen.Wear.app.main" />
|
||||||
<option name="DEPLOY" value="true" />
|
<option name="DEPLOY" value="true" />
|
||||||
<option name="DEPLOY_APK_FROM_BUNDLE" value="false" />
|
<option name="DEPLOY_APK_FROM_BUNDLE" value="false" />
|
||||||
<option name="DEPLOY_AS_INSTANT" value="false" />
|
<option name="DEPLOY_AS_INSTANT" value="false" />
|
||||||
<option name="ARTIFACT_NAME" value="" />
|
<option name="ARTIFACT_NAME" value="" />
|
||||||
<option name="PM_INSTALL_OPTIONS" value="" />
|
<option name="PM_INSTALL_OPTIONS" value="" />
|
||||||
<option name="ALL_USERS" value="false" />
|
<option name="ALL_USERS" value="false" />
|
||||||
<option name="ALWAYS_INSTALL_WITH_PM" value="false" />
|
<option name="ALWAYS_INSTALL_WITH_PM" value="false" />
|
||||||
<option name="CLEAR_APP_STORAGE" value="false" />
|
<option name="CLEAR_APP_STORAGE" value="false" />
|
||||||
<option name="DYNAMIC_FEATURES_DISABLED_LIST" value="" />
|
<option name="DYNAMIC_FEATURES_DISABLED_LIST" value="" />
|
||||||
<option name="ACTIVITY_EXTRA_FLAGS" value="" />
|
<option name="ACTIVITY_EXTRA_FLAGS" value="" />
|
||||||
<option name="MODE" value="default_activity" />
|
<option name="MODE" value="default_activity" />
|
||||||
<option name="CLEAR_LOGCAT" value="false" />
|
<option name="CLEAR_LOGCAT" value="false" />
|
||||||
<option name="SHOW_LOGCAT_AUTOMATICALLY" value="false" />
|
<option name="SHOW_LOGCAT_AUTOMATICALLY" value="false" />
|
||||||
<option name="INSPECTION_WITHOUT_ACTIVITY_RESTART" value="false" />
|
<option name="INSPECTION_WITHOUT_ACTIVITY_RESTART" value="false" />
|
||||||
<option name="TARGET_SELECTION_MODE" value="DEVICE_AND_SNAPSHOT_COMBO_BOX" />
|
<option name="TARGET_SELECTION_MODE" value="DEVICE_AND_SNAPSHOT_COMBO_BOX" />
|
||||||
<option name="PREFERRED_AVD" value="" />
|
<option name="PREFERRED_AVD" value="" />
|
||||||
<option name="SELECTED_DEVICE_ID" value="adb-d76a0274-X63ZH9 (2)._adb-tls-connect._tcp" />
|
<option name="SELECTED_DEVICE_ID" value="adb-d76a0274-X63ZH9 (2)._adb-tls-connect._tcp" />
|
||||||
<option name="SELECTED_CLOUD_MATRIX_CONFIGURATION_ID" value="-1" />
|
<option name="SELECTED_CLOUD_MATRIX_CONFIGURATION_ID" value="-1" />
|
||||||
<option name="SELECTED_CLOUD_MATRIX_PROJECT_ID" value="" />
|
<option name="SELECTED_CLOUD_MATRIX_PROJECT_ID" value="" />
|
||||||
<option name="DEBUGGER_TYPE" value="Auto" />
|
<option name="DEBUGGER_TYPE" value="Auto" />
|
||||||
<Auto>
|
<Auto>
|
||||||
<option name="USE_JAVA_AWARE_DEBUGGER" value="false" />
|
<option name="USE_JAVA_AWARE_DEBUGGER" value="false" />
|
||||||
<option name="SHOW_STATIC_VARS" value="true" />
|
<option name="SHOW_STATIC_VARS" value="true" />
|
||||||
<option name="WORKING_DIR" value="" />
|
<option name="WORKING_DIR" value="" />
|
||||||
<option name="TARGET_LOGGING_CHANNELS" value="lldb process:gdb-remote packets" />
|
<option name="TARGET_LOGGING_CHANNELS" value="lldb process:gdb-remote packets" />
|
||||||
<option name="SHOW_OPTIMIZED_WARNING" value="true" />
|
<option name="SHOW_OPTIMIZED_WARNING" value="true" />
|
||||||
<option name="ATTACH_ON_WAIT_FOR_DEBUGGER" value="false" />
|
<option name="ATTACH_ON_WAIT_FOR_DEBUGGER" value="false" />
|
||||||
<option name="DEBUG_SANDBOX_SDK" value="false" />
|
<option name="DEBUG_SANDBOX_SDK" value="false" />
|
||||||
</Auto>
|
</Auto>
|
||||||
<Hybrid>
|
<Hybrid>
|
||||||
<option name="USE_JAVA_AWARE_DEBUGGER" value="false" />
|
<option name="USE_JAVA_AWARE_DEBUGGER" value="false" />
|
||||||
<option name="SHOW_STATIC_VARS" value="true" />
|
<option name="SHOW_STATIC_VARS" value="true" />
|
||||||
<option name="WORKING_DIR" value="" />
|
<option name="WORKING_DIR" value="" />
|
||||||
<option name="TARGET_LOGGING_CHANNELS" value="lldb process:gdb-remote packets" />
|
<option name="TARGET_LOGGING_CHANNELS" value="lldb process:gdb-remote packets" />
|
||||||
<option name="SHOW_OPTIMIZED_WARNING" value="true" />
|
<option name="SHOW_OPTIMIZED_WARNING" value="true" />
|
||||||
<option name="ATTACH_ON_WAIT_FOR_DEBUGGER" value="false" />
|
<option name="ATTACH_ON_WAIT_FOR_DEBUGGER" value="false" />
|
||||||
<option name="DEBUG_SANDBOX_SDK" value="false" />
|
<option name="DEBUG_SANDBOX_SDK" value="false" />
|
||||||
</Hybrid>
|
</Hybrid>
|
||||||
<Java>
|
<Java>
|
||||||
<option name="ATTACH_ON_WAIT_FOR_DEBUGGER" value="false" />
|
<option name="ATTACH_ON_WAIT_FOR_DEBUGGER" value="false" />
|
||||||
<option name="DEBUG_SANDBOX_SDK" value="false" />
|
<option name="DEBUG_SANDBOX_SDK" value="false" />
|
||||||
</Java>
|
</Java>
|
||||||
<Native>
|
<Native>
|
||||||
<option name="USE_JAVA_AWARE_DEBUGGER" value="false" />
|
<option name="USE_JAVA_AWARE_DEBUGGER" value="false" />
|
||||||
<option name="SHOW_STATIC_VARS" value="true" />
|
<option name="SHOW_STATIC_VARS" value="true" />
|
||||||
<option name="WORKING_DIR" value="" />
|
<option name="WORKING_DIR" value="" />
|
||||||
<option name="TARGET_LOGGING_CHANNELS" value="lldb process:gdb-remote packets" />
|
<option name="TARGET_LOGGING_CHANNELS" value="lldb process:gdb-remote packets" />
|
||||||
<option name="SHOW_OPTIMIZED_WARNING" value="true" />
|
<option name="SHOW_OPTIMIZED_WARNING" value="true" />
|
||||||
<option name="ATTACH_ON_WAIT_FOR_DEBUGGER" value="false" />
|
<option name="ATTACH_ON_WAIT_FOR_DEBUGGER" value="false" />
|
||||||
<option name="DEBUG_SANDBOX_SDK" value="false" />
|
<option name="DEBUG_SANDBOX_SDK" value="false" />
|
||||||
</Native>
|
</Native>
|
||||||
<Profilers>
|
<Profilers>
|
||||||
<option name="ADVANCED_PROFILING_ENABLED" value="false" />
|
<option name="ADVANCED_PROFILING_ENABLED" value="false" />
|
||||||
<option name="STARTUP_PROFILING_ENABLED" value="false" />
|
<option name="STARTUP_PROFILING_ENABLED" value="false" />
|
||||||
<option name="DETAILED_REPORT_APP_STARTUP_PROFILING_ENABLED" value="false" />
|
<option name="DETAILED_REPORT_APP_STARTUP_PROFILING_ENABLED" value="false" />
|
||||||
</Profilers>
|
</Profilers>
|
||||||
<option name="DEEP_LINK" value="" />
|
<option name="DEEP_LINK" value="" />
|
||||||
<option name="ACTIVITY_CLASS" value="" />
|
<option name="ACTIVITY_CLASS" value="" />
|
||||||
<option name="SEARCH_ACTIVITY_IN_GLOBAL_SCOPE" value="false" />
|
<option name="SEARCH_ACTIVITY_IN_GLOBAL_SCOPE" value="false" />
|
||||||
<option name="SKIP_ACTIVITY_VALIDATION" value="false" />
|
<option name="SKIP_ACTIVITY_VALIDATION" value="false" />
|
||||||
<method v="2">
|
<method v="2">
|
||||||
<option name="Android.Gradle.BeforeRunTask" enabled="true" />
|
<option name="Android.Gradle.BeforeRunTask" enabled="true" />
|
||||||
</method>
|
</method>
|
||||||
</configuration>
|
</configuration>
|
||||||
</component>
|
</component>
|
||||||
|
|||||||
Generated
+5
-5
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="VcsDirectoryMappings">
|
<component name="VcsDirectoryMappings">
|
||||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
<mapping directory="$PROJECT_DIR$/" vcs="Git" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
@@ -1,85 +1,85 @@
|
|||||||
# 🌿 CESIZen - Écosystème de Bien-être Unifié
|
# 🌿 CESIZen - Écosystème de Bien-être Unifié
|
||||||
|
|
||||||
CESIZen est une solution complète de gestion du stress et du bien-être, composée d'une plateforme web, d'une application mobile et d'une application pour montre connectée (Wear OS).
|
CESIZen est une solution complète de gestion du stress et du bien-être, composée d'une plateforme web, d'une application mobile et d'une application pour montre connectée (Wear OS).
|
||||||
|
|
||||||
## 🚀 Structure du Projet
|
## 🚀 Structure du Projet
|
||||||
|
|
||||||
- **/WEB** : API et interface d'administration/diagnostic (Laravel 10, DSFR, Alpine.js).
|
- **/WEB** : API et interface d'administration/diagnostic (Laravel 10, DSFR, Alpine.js).
|
||||||
- **/mobile** : Application compagnon pour le suivi et les exercices (Flutter).
|
- **/mobile** : Application compagnon pour le suivi et les exercices (Flutter).
|
||||||
- **/Wear** : Application de montre pour le tracking rapide de l'humeur (Android Wear OS, Kotlin/Compose).
|
- **/Wear** : Application de montre pour le tracking rapide de l'humeur (Android Wear OS, Kotlin/Compose).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🛠 Installation & Configuration
|
## 🛠 Installation & Configuration
|
||||||
|
|
||||||
### 1. Backend & Web (Laravel)
|
### 1. Backend & Web (Laravel)
|
||||||
Le serveur central gère l'authentification (Sanctum) et la persistance des données.
|
Le serveur central gère l'authentification (Sanctum) et la persistance des données.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd WEB
|
cd WEB
|
||||||
composer install
|
composer install
|
||||||
npm install
|
npm install
|
||||||
cp .env.example .env # Configurez votre base de données et l'URL du serveur
|
cp .env.example .env # Configurez votre base de données et l'URL du serveur
|
||||||
php artisan key:generate
|
php artisan key:generate
|
||||||
php artisan migrate --seed
|
php artisan migrate --seed
|
||||||
php artisan serve
|
php artisan serve
|
||||||
```
|
```
|
||||||
*Note : Assurez-vous que l'IP de votre serveur est accessible par votre téléphone/émulateur pour la synchronisation.*
|
*Note : Assurez-vous que l'IP de votre serveur est accessible par votre téléphone/émulateur pour la synchronisation.*
|
||||||
|
|
||||||
### 2. Application Mobile (Flutter)
|
### 2. Application Mobile (Flutter)
|
||||||
L'application mobile se connecte à l'API Laravel.
|
L'application mobile se connecte à l'API Laravel.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd mobile
|
cd mobile
|
||||||
flutter pub get
|
flutter pub get
|
||||||
# Modifiez l'URL de l'API dans lib/features/auth/services/auth_service.dart si nécessaire
|
# Modifiez l'URL de l'API dans lib/features/auth/services/auth_service.dart si nécessaire
|
||||||
flutter run
|
flutter run
|
||||||
```
|
```
|
||||||
|
|
||||||
### 3. Application Montre (Wear OS)
|
### 3. Application Montre (Wear OS)
|
||||||
La montre communique avec le téléphone via le **Google Wearable Data Layer**.
|
La montre communique avec le téléphone via le **Google Wearable Data Layer**.
|
||||||
|
|
||||||
1. Ouvrez le dossier `/Wear` dans **Android Studio**.
|
1. Ouvrez le dossier `/Wear` dans **Android Studio**.
|
||||||
2. Compilez et installez l'APK sur une montre (ou émulateur) Wear OS.
|
2. Compilez et installez l'APK sur une montre (ou émulateur) Wear OS.
|
||||||
3. Assurez-vous que le téléphone appairé possède également l'application mobile CESIZen installée.
|
3. Assurez-vous que le téléphone appairé possède également l'application mobile CESIZen installée.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 📱 Utilisation & Fonctionnalités
|
## 📱 Utilisation & Fonctionnalités
|
||||||
|
|
||||||
### 🖥️ Plateforme Web
|
### 🖥️ Plateforme Web
|
||||||
- **Tableau de bord** : Visualisation des statistiques de stress.
|
- **Tableau de bord** : Visualisation des statistiques de stress.
|
||||||
- **Détente interactive** : Module de respiration guidée (méthode DSFR) avec 3 modes (Sommeil, Cohérence, Anxiété).
|
- **Détente interactive** : Module de respiration guidée (méthode DSFR) avec 3 modes (Sommeil, Cohérence, Anxiété).
|
||||||
- **Diagnostics** : Historique détaillé des relevés émotionnels.
|
- **Diagnostics** : Historique détaillé des relevés émotionnels.
|
||||||
|
|
||||||
### 🤳 Application Mobile
|
### 🤳 Application Mobile
|
||||||
- **Authentification** : Connexion sécurisée avec persistance de session.
|
- **Authentification** : Connexion sécurisée avec persistance de session.
|
||||||
- **Tracker** : Enregistrement quotidien de l'état émotionnel.
|
- **Tracker** : Enregistrement quotidien de l'état émotionnel.
|
||||||
- **Exercices** : Respiration guidée avec animation synchronisée du logo CESIZen.
|
- **Exercices** : Respiration guidée avec animation synchronisée du logo CESIZen.
|
||||||
- **Sync Montre** : Envoi automatique de la date et réception des humeurs capturées sur la montre.
|
- **Sync Montre** : Envoi automatique de la date et réception des humeurs capturées sur la montre.
|
||||||
|
|
||||||
### ⌚ Application Wear OS
|
### ⌚ Application Wear OS
|
||||||
- **Quick Mood** : Sélectionnez votre humeur en un clic parmi 5 niveaux.
|
- **Quick Mood** : Sélectionnez votre humeur en un clic parmi 5 niveaux.
|
||||||
- **Smart Reset** : L'humeur est automatiquement réinitialisée à minuit chaque jour grâce à la synchronisation bidirectionnelle avec le mobile.
|
- **Smart Reset** : L'humeur est automatiquement réinitialisée à minuit chaque jour grâce à la synchronisation bidirectionnelle avec le mobile.
|
||||||
- **Indicateur visuel** : Confirmation visuelle immédiate de l'enregistrement.
|
- **Indicateur visuel** : Confirmation visuelle immédiate de l'enregistrement.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🔗 Synchronisation Bidirectionnelle
|
## 🔗 Synchronisation Bidirectionnelle
|
||||||
- **Mobile -> Montre** : Envoie la `date du jour` pour synchroniser le cycle quotidien.
|
- **Mobile -> Montre** : Envoie la `date du jour` pour synchroniser le cycle quotidien.
|
||||||
- **Montre -> Mobile** : Envoie l'émotion sélectionnée via le `Data Layer` (`/daily_mood`).
|
- **Montre -> Mobile** : Envoie l'émotion sélectionnée via le `Data Layer` (`/daily_mood`).
|
||||||
- **Mobile -> Web** : Synchronise les données finales vers la base de données Laravel pour analyse.
|
- **Mobile -> Web** : Synchronise les données finales vers la base de données Laravel pour analyse.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🎨 Identité Visuelle
|
## 🎨 Identité Visuelle
|
||||||
L'ensemble de l'écosystème utilise la charte graphique **CesiZen** :
|
L'ensemble de l'écosystème utilise la charte graphique **CesiZen** :
|
||||||
- **Couleur Primaire** : Bleu Marine (`#000080`)
|
- **Couleur Primaire** : Bleu Marine (`#000080`)
|
||||||
- **Couleur Accent** : Orange (`#FFCC80`)
|
- **Couleur Accent** : Orange (`#FFCC80`)
|
||||||
- **Typographie** : Marianne (standard DSFR)
|
- **Typographie** : Marianne (standard DSFR)
|
||||||
- **Logo** : Point central de l'animation de respiration.
|
- **Logo** : Point central de l'animation de respiration.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 📄 Licence
|
## 📄 Licence
|
||||||
Projet réalisé dans le cadre de la formation CDA CESI.
|
Projet réalisé dans le cadre de la formation CDA CESI.
|
||||||
|
|||||||
@@ -1,41 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace Tests\Unit;
|
|
||||||
|
|
||||||
use Tests\TestCase;
|
|
||||||
use App\Models\User;
|
|
||||||
use App\Models\StressEvent;
|
|
||||||
use App\Models\ResultatDiag;
|
|
||||||
use Illuminate\Foundation.Testing.RefreshDatabase;
|
|
||||||
|
|
||||||
class DiagnosticTest extends TestCase
|
|
||||||
{
|
|
||||||
use RefreshDatabase;
|
|
||||||
|
|
||||||
public function test_diagnostic_score_calculation_and_storage()
|
|
||||||
{
|
|
||||||
// Créer un utilisateur
|
|
||||||
$user = User::factory()->create();
|
|
||||||
|
|
||||||
// Créer des événements de stress
|
|
||||||
$event1 = StressEvent::create(['event_name' => 'Event 1', 'points' => 100]);
|
|
||||||
$event2 = StressEvent::create(['event_name' => 'Event 2', 'points' => 60]);
|
|
||||||
|
|
||||||
// Simuler une requête de diagnostic
|
|
||||||
$response = $this->actingAs($user)
|
|
||||||
->post(route('diagnostics.store'), [
|
|
||||||
'events' => [$event1->id, $event2->id]
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Vérifier la redirection et le score en session
|
|
||||||
$response->assertStatus(302);
|
|
||||||
$response->assertSessionHas('score', 160);
|
|
||||||
|
|
||||||
// Vérifier l'enregistrement en base de données
|
|
||||||
$this->assertDatabaseHas('resultat_diags', [
|
|
||||||
'id_user' => $user->id,
|
|
||||||
'score_total' => 160,
|
|
||||||
'niveau_stress' => 'Modéré'
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Generated
+3
-3
@@ -1,3 +1,3 @@
|
|||||||
# Default ignored files
|
# Default ignored files
|
||||||
/shelf/
|
/shelf/
|
||||||
/workspace.xml
|
/workspace.xml
|
||||||
|
|||||||
Generated
+5
-5
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="AndroidProjectSystem">
|
<component name="AndroidProjectSystem">
|
||||||
<option name="providerId" value="com.android.tools.idea.GradleProjectSystem" />
|
<option name="providerId" value="com.android.tools.idea.GradleProjectSystem" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
Generated
+5
-5
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="CompilerConfiguration">
|
<component name="CompilerConfiguration">
|
||||||
<bytecodeTargetLevel target="21" />
|
<bytecodeTargetLevel target="21" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
Generated
+17
-17
@@ -1,18 +1,18 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="deploymentTargetSelector">
|
<component name="deploymentTargetSelector">
|
||||||
<selectionStates>
|
<selectionStates>
|
||||||
<SelectionState runConfigName="app">
|
<SelectionState runConfigName="app">
|
||||||
<option name="selectionMode" value="DROPDOWN" />
|
<option name="selectionMode" value="DROPDOWN" />
|
||||||
<DropdownSelection timestamp="2026-04-21T21:27:34.624668600Z">
|
<DropdownSelection timestamp="2026-04-21T21:27:34.624668600Z">
|
||||||
<Target type="DEFAULT_BOOT">
|
<Target type="DEFAULT_BOOT">
|
||||||
<handle>
|
<handle>
|
||||||
<DeviceId pluginId="PhysicalDevice" identifier="serial=d76a0274" />
|
<DeviceId pluginId="PhysicalDevice" identifier="serial=d76a0274" />
|
||||||
</handle>
|
</handle>
|
||||||
</Target>
|
</Target>
|
||||||
</DropdownSelection>
|
</DropdownSelection>
|
||||||
<DialogSelection />
|
<DialogSelection />
|
||||||
</SelectionState>
|
</SelectionState>
|
||||||
</selectionStates>
|
</selectionStates>
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
Generated
+17
-17
@@ -1,18 +1,18 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="GradleMigrationSettings" migrationVersion="1" />
|
<component name="GradleMigrationSettings" migrationVersion="1" />
|
||||||
<component name="GradleSettings">
|
<component name="GradleSettings">
|
||||||
<option name="linkedExternalProjectsSettings">
|
<option name="linkedExternalProjectsSettings">
|
||||||
<GradleProjectSettings>
|
<GradleProjectSettings>
|
||||||
<option name="testRunner" value="CHOOSE_PER_TEST" />
|
<option name="testRunner" value="CHOOSE_PER_TEST" />
|
||||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||||
<option name="modules">
|
<option name="modules">
|
||||||
<set>
|
<set>
|
||||||
<option value="$PROJECT_DIR$" />
|
<option value="$PROJECT_DIR$" />
|
||||||
<option value="$PROJECT_DIR$/app" />
|
<option value="$PROJECT_DIR$/app" />
|
||||||
</set>
|
</set>
|
||||||
</option>
|
</option>
|
||||||
</GradleProjectSettings>
|
</GradleProjectSettings>
|
||||||
</option>
|
</option>
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
Generated
+16
-16
@@ -1,17 +1,17 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="RunConfigurationProducerService">
|
<component name="RunConfigurationProducerService">
|
||||||
<option name="ignoredProducers">
|
<option name="ignoredProducers">
|
||||||
<set>
|
<set>
|
||||||
<option value="com.intellij.execution.junit.AbstractAllInDirectoryConfigurationProducer" />
|
<option value="com.intellij.execution.junit.AbstractAllInDirectoryConfigurationProducer" />
|
||||||
<option value="com.intellij.execution.junit.AllInPackageConfigurationProducer" />
|
<option value="com.intellij.execution.junit.AllInPackageConfigurationProducer" />
|
||||||
<option value="com.intellij.execution.junit.PatternConfigurationProducer" />
|
<option value="com.intellij.execution.junit.PatternConfigurationProducer" />
|
||||||
<option value="com.intellij.execution.junit.TestInClassConfigurationProducer" />
|
<option value="com.intellij.execution.junit.TestInClassConfigurationProducer" />
|
||||||
<option value="com.intellij.execution.junit.UniqueIdConfigurationProducer" />
|
<option value="com.intellij.execution.junit.UniqueIdConfigurationProducer" />
|
||||||
<option value="com.intellij.execution.junit.testDiscovery.JUnitTestDiscoveryConfigurationProducer" />
|
<option value="com.intellij.execution.junit.testDiscovery.JUnitTestDiscoveryConfigurationProducer" />
|
||||||
<option value="org.jetbrains.kotlin.idea.junit.KotlinJUnitRunConfigurationProducer" />
|
<option value="org.jetbrains.kotlin.idea.junit.KotlinJUnitRunConfigurationProducer" />
|
||||||
<option value="org.jetbrains.kotlin.idea.junit.KotlinPatternConfigurationProducer" />
|
<option value="org.jetbrains.kotlin.idea.junit.KotlinPatternConfigurationProducer" />
|
||||||
</set>
|
</set>
|
||||||
</option>
|
</option>
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
Generated
+5
-5
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="VcsDirectoryMappings">
|
<component name="VcsDirectoryMappings">
|
||||||
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
|
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
@@ -1,50 +1,50 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||||
|
|
||||||
<uses-feature android:name="android.hardware.type.watch" />
|
<uses-feature android:name="android.hardware.type.watch" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@android:style/Theme.DeviceDefault">
|
android:theme="@android:style/Theme.DeviceDefault">
|
||||||
<uses-library
|
<uses-library
|
||||||
android:name="com.google.android.wearable"
|
android:name="com.google.android.wearable"
|
||||||
android:required="true" />
|
android:required="true" />
|
||||||
<uses-library
|
<uses-library
|
||||||
android:name="wear-sdk"
|
android:name="wear-sdk"
|
||||||
android:required="false" />
|
android:required="false" />
|
||||||
|
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
Set to true if your app is Standalone, that is, it does not require the handheld
|
Set to true if your app is Standalone, that is, it does not require the handheld
|
||||||
app to run.
|
app to run.
|
||||||
-->
|
-->
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="com.google.android.gms.wearable.standalone"
|
android:name="com.google.android.gms.wearable.standalone"
|
||||||
android:value="true" />
|
android:value="true" />
|
||||||
|
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="com.google.android.gms.wearable.capabilities"
|
android:name="com.google.android.gms.wearable.capabilities"
|
||||||
android:resource="@xml/wearable_app_values" />
|
android:resource="@xml/wearable_app_values" />
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name="com.cesizen.app.MainActivity"
|
android:name="com.cesizen.app.MainActivity"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:taskAffinity=""
|
android:taskAffinity=""
|
||||||
android:theme="@style/MainActivityTheme.Starting">
|
android:theme="@style/MainActivityTheme.Starting">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
@@ -1,282 +1,282 @@
|
|||||||
package com.cesizen.app
|
package com.cesizen.app
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
import androidx.activity.compose.setContent
|
import androidx.activity.compose.setContent
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.layout.*
|
import androidx.compose.foundation.layout.*
|
||||||
import androidx.compose.foundation.shape.CircleShape
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Brush
|
import androidx.compose.ui.graphics.Brush
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import androidx.wear.compose.foundation.lazy.TransformingLazyColumn
|
import androidx.wear.compose.foundation.lazy.TransformingLazyColumn
|
||||||
import androidx.wear.compose.foundation.lazy.rememberTransformingLazyColumnState
|
import androidx.wear.compose.foundation.lazy.rememberTransformingLazyColumnState
|
||||||
import androidx.wear.compose.material3.*
|
import androidx.wear.compose.material3.*
|
||||||
import com.cesizen.app.presentation.theme.MyApplicationTheme
|
import com.cesizen.app.presentation.theme.MyApplicationTheme
|
||||||
import com.google.android.gms.tasks.Tasks
|
import com.google.android.gms.tasks.Tasks
|
||||||
import com.google.android.gms.wearable.*
|
import com.google.android.gms.wearable.*
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import android.net.ConnectivityManager
|
import android.net.ConnectivityManager
|
||||||
import android.net.Network
|
import android.net.Network
|
||||||
import android.net.NetworkCapabilities
|
import android.net.NetworkCapabilities
|
||||||
import android.net.NetworkRequest
|
import android.net.NetworkRequest
|
||||||
|
|
||||||
class MainActivity : ComponentActivity(), DataClient.OnDataChangedListener {
|
class MainActivity : ComponentActivity(), DataClient.OnDataChangedListener {
|
||||||
|
|
||||||
|
|
||||||
private var userName by mutableStateOf<String?>(null)
|
private var userName by mutableStateOf<String?>(null)
|
||||||
private var currentMood by mutableStateOf<String?>(null)
|
private var currentMood by mutableStateOf<String?>(null)
|
||||||
private var isRefreshing by mutableStateOf(false)
|
private var isRefreshing by mutableStateOf(false)
|
||||||
private val TAG = "CESIZen_Watch"
|
private val TAG = "CESIZen_Watch"
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
Wearable.getDataClient(this).addListener(this)
|
Wearable.getDataClient(this).addListener(this)
|
||||||
refreshData()
|
refreshData()
|
||||||
|
|
||||||
val connectivityManager = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
|
val connectivityManager = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
|
||||||
|
|
||||||
val request = NetworkRequest.Builder()
|
val request = NetworkRequest.Builder()
|
||||||
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
|
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
|
||||||
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI) // Priorité Wi-Fi
|
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI) // Priorité Wi-Fi
|
||||||
.addTransportType(NetworkCapabilities.TRANSPORT_BLUETOOTH) // Secours Bluetooth
|
.addTransportType(NetworkCapabilities.TRANSPORT_BLUETOOTH) // Secours Bluetooth
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
connectivityManager.requestNetwork(request, object : ConnectivityManager.NetworkCallback() {
|
connectivityManager.requestNetwork(request, object : ConnectivityManager.NetworkCallback() {
|
||||||
override fun onAvailable(network: Network) {
|
override fun onAvailable(network: Network) {
|
||||||
// Le système a trouvé soit du Wi-Fi, soit le pont Bluetooth du téléphone
|
// Le système a trouvé soit du Wi-Fi, soit le pont Bluetooth du téléphone
|
||||||
connectivityManager.bindProcessToNetwork(network)
|
connectivityManager.bindProcessToNetwork(network)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
setContent {
|
setContent {
|
||||||
WearApp(
|
WearApp(
|
||||||
userName = userName,
|
userName = userName,
|
||||||
currentMood = currentMood,
|
currentMood = currentMood,
|
||||||
isRefreshing = isRefreshing,
|
isRefreshing = isRefreshing,
|
||||||
onRefresh = { refreshData() },
|
onRefresh = { refreshData() },
|
||||||
onMoodSelected = { mood -> sendMoodToPhone(mood) }
|
onMoodSelected = { mood -> sendMoodToPhone(mood) }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun refreshData() {
|
private fun refreshData() {
|
||||||
if (isRefreshing) return
|
if (isRefreshing) return
|
||||||
isRefreshing = true
|
isRefreshing = true
|
||||||
|
|
||||||
val today = java.text.SimpleDateFormat("yyyy-MM-dd", java.util.Locale.getDefault()).format(java.util.Date())
|
val today = java.text.SimpleDateFormat("yyyy-MM-dd", java.util.Locale.getDefault()).format(java.util.Date())
|
||||||
|
|
||||||
Wearable.getDataClient(this).dataItems.addOnSuccessListener { items ->
|
Wearable.getDataClient(this).dataItems.addOnSuccessListener { items ->
|
||||||
for (item in items) {
|
for (item in items) {
|
||||||
if (item.uri.path == "/auth_status") {
|
if (item.uri.path == "/auth_status") {
|
||||||
val dataMap = DataMapItem.fromDataItem(item).dataMap
|
val dataMap = DataMapItem.fromDataItem(item).dataMap
|
||||||
userName = if (dataMap.getString("status") == "authenticated") dataMap.getString("userName") else null
|
userName = if (dataMap.getString("status") == "authenticated") dataMap.getString("userName") else null
|
||||||
} else if (item.uri.path == "/daily_mood") {
|
} else if (item.uri.path == "/daily_mood") {
|
||||||
val dataMap = DataMapItem.fromDataItem(item).dataMap
|
val dataMap = DataMapItem.fromDataItem(item).dataMap
|
||||||
val moodDate = dataMap.getString("date")
|
val moodDate = dataMap.getString("date")
|
||||||
|
|
||||||
if (moodDate == today) {
|
if (moodDate == today) {
|
||||||
currentMood = dataMap.getString("mood")
|
currentMood = dataMap.getString("mood")
|
||||||
} else {
|
} else {
|
||||||
currentMood = null
|
currentMood = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
isRefreshing = false
|
isRefreshing = false
|
||||||
}
|
}
|
||||||
|
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
try {
|
try {
|
||||||
val nodes = Tasks.await(Wearable.getNodeClient(this@MainActivity).connectedNodes)
|
val nodes = Tasks.await(Wearable.getNodeClient(this@MainActivity).connectedNodes)
|
||||||
for (node in nodes) {
|
for (node in nodes) {
|
||||||
val payload = JSONObject().apply { put("command", "get_sync_data") }.toString().toByteArray()
|
val payload = JSONObject().apply { put("command", "get_sync_data") }.toString().toByteArray()
|
||||||
Wearable.getMessageClient(this@MainActivity).sendMessage(node.id, "/wearable_communication", payload)
|
Wearable.getMessageClient(this@MainActivity).sendMessage(node.id, "/wearable_communication", payload)
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e(TAG, "Error sync nodes", e)
|
Log.e(TAG, "Error sync nodes", e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun sendMoodToPhone(mood: String) {
|
private fun sendMoodToPhone(mood: String) {
|
||||||
currentMood = mood
|
currentMood = mood
|
||||||
if (mood.isEmpty()) {
|
if (mood.isEmpty()) {
|
||||||
// Reset mood locally to show the selection again
|
// Reset mood locally to show the selection again
|
||||||
currentMood = null
|
currentMood = null
|
||||||
}
|
}
|
||||||
|
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
try {
|
try {
|
||||||
val nodes = Tasks.await(Wearable.getNodeClient(this@MainActivity).connectedNodes)
|
val nodes = Tasks.await(Wearable.getNodeClient(this@MainActivity).connectedNodes)
|
||||||
for (node in nodes) {
|
for (node in nodes) {
|
||||||
val payload = JSONObject().apply {
|
val payload = JSONObject().apply {
|
||||||
put("command", "save_mood")
|
put("command", "save_mood")
|
||||||
put("mood", mood)
|
put("mood", mood)
|
||||||
}.toString().toByteArray()
|
}.toString().toByteArray()
|
||||||
Wearable.getMessageClient(this@MainActivity).sendMessage(node.id, "/wearable_communication", payload)
|
Wearable.getMessageClient(this@MainActivity).sendMessage(node.id, "/wearable_communication", payload)
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e(TAG, "Error sending mood", e)
|
Log.e(TAG, "Error sending mood", e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDataChanged(dataEvents: DataEventBuffer) {
|
override fun onDataChanged(dataEvents: DataEventBuffer) {
|
||||||
val today = java.text.SimpleDateFormat("yyyy-MM-dd", java.util.Locale.getDefault()).format(java.util.Date())
|
val today = java.text.SimpleDateFormat("yyyy-MM-dd", java.util.Locale.getDefault()).format(java.util.Date())
|
||||||
|
|
||||||
for (event in dataEvents) {
|
for (event in dataEvents) {
|
||||||
val dataMap = DataMapItem.fromDataItem(event.dataItem).dataMap
|
val dataMap = DataMapItem.fromDataItem(event.dataItem).dataMap
|
||||||
if (event.dataItem.uri.path == "/auth_status") {
|
if (event.dataItem.uri.path == "/auth_status") {
|
||||||
userName = if (dataMap.getString("status") == "authenticated") dataMap.getString("userName") else null
|
userName = if (dataMap.getString("status") == "authenticated") dataMap.getString("userName") else null
|
||||||
} else if (event.dataItem.uri.path == "/daily_mood") {
|
} else if (event.dataItem.uri.path == "/daily_mood") {
|
||||||
val moodDate = dataMap.getString("date")
|
val moodDate = dataMap.getString("date")
|
||||||
if (moodDate == today) {
|
if (moodDate == today) {
|
||||||
currentMood = dataMap.getString("mood")
|
currentMood = dataMap.getString("mood")
|
||||||
} else {
|
} else {
|
||||||
currentMood = null
|
currentMood = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun WearApp(userName: String?, currentMood: String?, isRefreshing: Boolean, onRefresh: () -> Unit, onMoodSelected: (String) -> Unit) {
|
fun WearApp(userName: String?, currentMood: String?, isRefreshing: Boolean, onRefresh: () -> Unit, onMoodSelected: (String) -> Unit) {
|
||||||
val cesiBlue = Color(0xFF000091)
|
val cesiBlue = Color(0xFF000091)
|
||||||
|
|
||||||
MyApplicationTheme {
|
MyApplicationTheme {
|
||||||
AppScaffold {
|
AppScaffold {
|
||||||
val listState = rememberTransformingLazyColumnState()
|
val listState = rememberTransformingLazyColumnState()
|
||||||
ScreenScaffold(scrollState = listState) { contentPadding ->
|
ScreenScaffold(scrollState = listState) { contentPadding ->
|
||||||
TransformingLazyColumn(
|
TransformingLazyColumn(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.background(Brush.verticalGradient(listOf(Color.Black, Color(0xFF000022)))),
|
.background(Brush.verticalGradient(listOf(Color.Black, Color(0xFF000022)))),
|
||||||
contentPadding = contentPadding,
|
contentPadding = contentPadding,
|
||||||
state = listState,
|
state = listState,
|
||||||
horizontalAlignment = Alignment.CenterHorizontally
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
) {
|
) {
|
||||||
// Header
|
// Header
|
||||||
item {
|
item {
|
||||||
Column(
|
Column(
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
modifier = Modifier.padding(bottom = 12.dp)
|
modifier = Modifier.padding(bottom = 12.dp)
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
"CESIZen",
|
"CESIZen",
|
||||||
color = cesiBlue,
|
color = cesiBlue,
|
||||||
style = MaterialTheme.typography.labelMedium,
|
style = MaterialTheme.typography.labelMedium,
|
||||||
fontWeight = FontWeight.Bold
|
fontWeight = FontWeight.Bold
|
||||||
)
|
)
|
||||||
Spacer(modifier = Modifier.height(4.dp))
|
Spacer(modifier = Modifier.height(4.dp))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (userName == null) {
|
if (userName == null) {
|
||||||
item {
|
item {
|
||||||
TitleCard(
|
TitleCard(
|
||||||
onClick = onRefresh,
|
onClick = onRefresh,
|
||||||
title = { Text("Connexion requise", textAlign = TextAlign.Center) },
|
title = { Text("Connexion requise", textAlign = TextAlign.Center) },
|
||||||
subtitle = { Text("Ouvrez l'app sur votre téléphone", textAlign = TextAlign.Center, fontSize = 12.sp) },
|
subtitle = { Text("Ouvrez l'app sur votre téléphone", textAlign = TextAlign.Center, fontSize = 12.sp) },
|
||||||
modifier = Modifier.padding(horizontal = 8.dp)
|
modifier = Modifier.padding(horizontal = 8.dp)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// User Status
|
// User Status
|
||||||
item {
|
item {
|
||||||
val displayName = userName.split(" ").firstOrNull() ?: "Zen"
|
val displayName = userName.split(" ").firstOrNull() ?: "Zen"
|
||||||
Text(
|
Text(
|
||||||
"Bonjour $displayName",
|
"Bonjour $displayName",
|
||||||
style = MaterialTheme.typography.titleMedium,
|
style = MaterialTheme.typography.titleMedium,
|
||||||
textAlign = TextAlign.Center
|
textAlign = TextAlign.Center
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentMood.isNullOrEmpty()) {
|
if (currentMood.isNullOrEmpty()) {
|
||||||
item {
|
item {
|
||||||
Text(
|
Text(
|
||||||
"Comment allez-vous ?",
|
"Comment allez-vous ?",
|
||||||
style = MaterialTheme.typography.bodySmall,
|
style = MaterialTheme.typography.bodySmall,
|
||||||
color = Color.LightGray,
|
color = Color.LightGray,
|
||||||
modifier = Modifier.padding(vertical = 8.dp)
|
modifier = Modifier.padding(vertical = 8.dp)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
val moods = listOf(
|
val moods = listOf(
|
||||||
MoodItem("Très bien", "😊", Color(0xFF4CAF50)),
|
MoodItem("Très bien", "😊", Color(0xFF4CAF50)),
|
||||||
MoodItem("Bien", "🙂", Color(0xFF8BC34A)),
|
MoodItem("Bien", "🙂", Color(0xFF8BC34A)),
|
||||||
MoodItem("Neutre", "😐", Color(0xFFFFC107)),
|
MoodItem("Neutre", "😐", Color(0xFFFFC107)),
|
||||||
MoodItem("Pas top", "🙁", Color(0xFFFF9800)),
|
MoodItem("Pas top", "🙁", Color(0xFFFF9800)),
|
||||||
MoodItem("Stressé", "😫", Color(0xFFF44336))
|
MoodItem("Stressé", "😫", Color(0xFFF44336))
|
||||||
)
|
)
|
||||||
|
|
||||||
moods.forEach { mood ->
|
moods.forEach { mood ->
|
||||||
item {
|
item {
|
||||||
FilledTonalButton(
|
FilledTonalButton(
|
||||||
onClick = { onMoodSelected(mood.label) },
|
onClick = { onMoodSelected(mood.label) },
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(vertical = 2.dp, horizontal = 16.dp),
|
.padding(vertical = 2.dp, horizontal = 16.dp),
|
||||||
colors = ButtonDefaults.filledTonalButtonColors(
|
colors = ButtonDefaults.filledTonalButtonColors(
|
||||||
containerColor = mood.color.copy(alpha = 0.2f),
|
containerColor = mood.color.copy(alpha = 0.2f),
|
||||||
contentColor = Color.White
|
contentColor = Color.White
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
verticalAlignment = Alignment.CenterVertically
|
verticalAlignment = Alignment.CenterVertically
|
||||||
) {
|
) {
|
||||||
Text(mood.emoji, fontSize = 20.sp)
|
Text(mood.emoji, fontSize = 20.sp)
|
||||||
Spacer(modifier = Modifier.width(12.dp))
|
Spacer(modifier = Modifier.width(12.dp))
|
||||||
Text(mood.label, style = MaterialTheme.typography.labelLarge)
|
Text(mood.label, style = MaterialTheme.typography.labelLarge)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
item {
|
item {
|
||||||
Card(
|
Card(
|
||||||
onClick = { onMoodSelected("") },
|
onClick = { onMoodSelected("") },
|
||||||
modifier = Modifier.padding(16.dp),
|
modifier = Modifier.padding(16.dp),
|
||||||
colors = CardDefaults.cardColors(containerColor = cesiBlue.copy(alpha = 0.3f))
|
colors = CardDefaults.cardColors(containerColor = cesiBlue.copy(alpha = 0.3f))
|
||||||
) {
|
) {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier.fillMaxWidth().padding(8.dp),
|
modifier = Modifier.fillMaxWidth().padding(8.dp),
|
||||||
horizontalAlignment = Alignment.CenterHorizontally
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
) {
|
) {
|
||||||
Text("Humeur enregistrée", style = MaterialTheme.typography.labelSmall)
|
Text("Humeur enregistrée", style = MaterialTheme.typography.labelSmall)
|
||||||
Spacer(modifier = Modifier.height(8.dp))
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
Text(currentMood, style = MaterialTheme.typography.titleLarge, fontWeight = FontWeight.Bold)
|
Text(currentMood, style = MaterialTheme.typography.titleLarge, fontWeight = FontWeight.Bold)
|
||||||
Spacer(modifier = Modifier.height(8.dp))
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
Text("Tapoter pour changer", fontSize = 10.sp, color = Color.LightGray)
|
Text("Tapoter pour changer", fontSize = 10.sp, color = Color.LightGray)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bottom Spacer
|
// Bottom Spacer
|
||||||
item {
|
item {
|
||||||
Spacer(modifier = Modifier.height(20.dp))
|
Spacer(modifier = Modifier.height(20.dp))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data class MoodItem(val label: String, val emoji: String, val color: Color)
|
data class MoodItem(val label: String, val emoji: String, val color: Color)
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
package com.cesizen.app.presentation.theme
|
package com.cesizen.app.presentation.theme
|
||||||
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.wear.compose.material3.MaterialTheme
|
import androidx.wear.compose.material3.MaterialTheme
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun MyApplicationTheme(
|
fun MyApplicationTheme(
|
||||||
content: @Composable () -> Unit
|
content: @Composable () -> Unit
|
||||||
) {
|
) {
|
||||||
MaterialTheme(
|
MaterialTheme(
|
||||||
content = content
|
content = content
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<capability name="cesizen_wear_app" />
|
<capability name="cesizen_wear_app" />
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
+9
-9
@@ -1,9 +1,9 @@
|
|||||||
#Tue Apr 21 22:42:57 CEST 2026
|
#Tue Apr 21 22:42:57 CEST 2026
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionSha256Sum=b266d5ff6b90eada6dc3b20cb090e3731302e553a27c5d3e4df1f0d76beaff06
|
distributionSha256Sum=b266d5ff6b90eada6dc3b20cb090e3731302e553a27c5d3e4df1f0d76beaff06
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.1-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.1-bin.zip
|
||||||
networkTimeout=10000
|
networkTimeout=10000
|
||||||
validateDistributionUrl=true
|
validateDistributionUrl=true
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
|||||||
Vendored
+94
-94
@@ -1,94 +1,94 @@
|
|||||||
@rem
|
@rem
|
||||||
@rem Copyright 2015 the original author or authors.
|
@rem Copyright 2015 the original author or authors.
|
||||||
@rem
|
@rem
|
||||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@rem you may not use this file except in compliance with the License.
|
@rem you may not use this file except in compliance with the License.
|
||||||
@rem You may obtain a copy of the License at
|
@rem You may obtain a copy of the License at
|
||||||
@rem
|
@rem
|
||||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||||
@rem
|
@rem
|
||||||
@rem Unless required by applicable law or agreed to in writing, software
|
@rem Unless required by applicable law or agreed to in writing, software
|
||||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
@rem See the License for the specific language governing permissions and
|
@rem See the License for the specific language governing permissions and
|
||||||
@rem limitations under the License.
|
@rem limitations under the License.
|
||||||
@rem
|
@rem
|
||||||
@rem SPDX-License-Identifier: Apache-2.0
|
@rem SPDX-License-Identifier: Apache-2.0
|
||||||
@rem
|
@rem
|
||||||
|
|
||||||
@if "%DEBUG%"=="" @echo off
|
@if "%DEBUG%"=="" @echo off
|
||||||
@rem ##########################################################################
|
@rem ##########################################################################
|
||||||
@rem
|
@rem
|
||||||
@rem Gradle startup script for Windows
|
@rem Gradle startup script for Windows
|
||||||
@rem
|
@rem
|
||||||
@rem ##########################################################################
|
@rem ##########################################################################
|
||||||
|
|
||||||
@rem Set local scope for the variables with windows NT shell
|
@rem Set local scope for the variables with windows NT shell
|
||||||
if "%OS%"=="Windows_NT" setlocal
|
if "%OS%"=="Windows_NT" setlocal
|
||||||
|
|
||||||
set DIRNAME=%~dp0
|
set DIRNAME=%~dp0
|
||||||
if "%DIRNAME%"=="" set DIRNAME=.
|
if "%DIRNAME%"=="" set DIRNAME=.
|
||||||
@rem This is normally unused
|
@rem This is normally unused
|
||||||
set APP_BASE_NAME=%~n0
|
set APP_BASE_NAME=%~n0
|
||||||
set APP_HOME=%DIRNAME%
|
set APP_HOME=%DIRNAME%
|
||||||
|
|
||||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||||
|
|
||||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||||
|
|
||||||
@rem Find java.exe
|
@rem Find java.exe
|
||||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||||
|
|
||||||
set JAVA_EXE=java.exe
|
set JAVA_EXE=java.exe
|
||||||
%JAVA_EXE% -version >NUL 2>&1
|
%JAVA_EXE% -version >NUL 2>&1
|
||||||
if %ERRORLEVEL% equ 0 goto execute
|
if %ERRORLEVEL% equ 0 goto execute
|
||||||
|
|
||||||
echo. 1>&2
|
echo. 1>&2
|
||||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
||||||
echo. 1>&2
|
echo. 1>&2
|
||||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||||
echo location of your Java installation. 1>&2
|
echo location of your Java installation. 1>&2
|
||||||
|
|
||||||
goto fail
|
goto fail
|
||||||
|
|
||||||
:findJavaFromJavaHome
|
:findJavaFromJavaHome
|
||||||
set JAVA_HOME=%JAVA_HOME:"=%
|
set JAVA_HOME=%JAVA_HOME:"=%
|
||||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||||
|
|
||||||
if exist "%JAVA_EXE%" goto execute
|
if exist "%JAVA_EXE%" goto execute
|
||||||
|
|
||||||
echo. 1>&2
|
echo. 1>&2
|
||||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
||||||
echo. 1>&2
|
echo. 1>&2
|
||||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||||
echo location of your Java installation. 1>&2
|
echo location of your Java installation. 1>&2
|
||||||
|
|
||||||
goto fail
|
goto fail
|
||||||
|
|
||||||
:execute
|
:execute
|
||||||
@rem Setup the command line
|
@rem Setup the command line
|
||||||
|
|
||||||
set CLASSPATH=
|
set CLASSPATH=
|
||||||
|
|
||||||
|
|
||||||
@rem Execute Gradle
|
@rem Execute Gradle
|
||||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
|
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
|
||||||
|
|
||||||
:end
|
:end
|
||||||
@rem End local scope for the variables with windows NT shell
|
@rem End local scope for the variables with windows NT shell
|
||||||
if %ERRORLEVEL% equ 0 goto mainEnd
|
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||||
|
|
||||||
:fail
|
:fail
|
||||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||||
rem the _cmd.exe /c_ return code!
|
rem the _cmd.exe /c_ return code!
|
||||||
set EXIT_CODE=%ERRORLEVEL%
|
set EXIT_CODE=%ERRORLEVEL%
|
||||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||||
exit /b %EXIT_CODE%
|
exit /b %EXIT_CODE%
|
||||||
|
|
||||||
:mainEnd
|
:mainEnd
|
||||||
if "%OS%"=="Windows_NT" endlocal
|
if "%OS%"=="Windows_NT" endlocal
|
||||||
|
|
||||||
:omega
|
:omega
|
||||||
|
|||||||
+45
-45
@@ -1,45 +1,45 @@
|
|||||||
# Miscellaneous
|
# Miscellaneous
|
||||||
*.class
|
*.class
|
||||||
*.log
|
*.log
|
||||||
*.pyc
|
*.pyc
|
||||||
*.swp
|
*.swp
|
||||||
.DS_Store
|
.DS_Store
|
||||||
.atom/
|
.atom/
|
||||||
.build/
|
.build/
|
||||||
.buildlog/
|
.buildlog/
|
||||||
.history
|
.history
|
||||||
.svn/
|
.svn/
|
||||||
.swiftpm/
|
.swiftpm/
|
||||||
migrate_working_dir/
|
migrate_working_dir/
|
||||||
|
|
||||||
# IntelliJ related
|
# IntelliJ related
|
||||||
*.iml
|
*.iml
|
||||||
*.ipr
|
*.ipr
|
||||||
*.iws
|
*.iws
|
||||||
.idea/
|
.idea/
|
||||||
|
|
||||||
# The .vscode folder contains launch configuration and tasks you configure in
|
# The .vscode folder contains launch configuration and tasks you configure in
|
||||||
# VS Code which you may wish to be included in version control, so this line
|
# VS Code which you may wish to be included in version control, so this line
|
||||||
# is commented out by default.
|
# is commented out by default.
|
||||||
#.vscode/
|
#.vscode/
|
||||||
|
|
||||||
# Flutter/Dart/Pub related
|
# Flutter/Dart/Pub related
|
||||||
**/doc/api/
|
**/doc/api/
|
||||||
**/ios/Flutter/.last_build_id
|
**/ios/Flutter/.last_build_id
|
||||||
.dart_tool/
|
.dart_tool/
|
||||||
.flutter-plugins-dependencies
|
.flutter-plugins-dependencies
|
||||||
.pub-cache/
|
.pub-cache/
|
||||||
.pub/
|
.pub/
|
||||||
/build/
|
/build/
|
||||||
/coverage/
|
/coverage/
|
||||||
|
|
||||||
# Symbolication related
|
# Symbolication related
|
||||||
app.*.symbols
|
app.*.symbols
|
||||||
|
|
||||||
# Obfuscation related
|
# Obfuscation related
|
||||||
app.*.map.json
|
app.*.map.json
|
||||||
|
|
||||||
# Android Studio will place build artifacts here
|
# Android Studio will place build artifacts here
|
||||||
/android/app/debug
|
/android/app/debug
|
||||||
/android/app/profile
|
/android/app/profile
|
||||||
/android/app/release
|
/android/app/release
|
||||||
|
|||||||
+84
-84
@@ -1,84 +1,84 @@
|
|||||||
# CESIZen - Application Mobile (Flutter)
|
# CESIZen - Application Mobile (Flutter)
|
||||||
|
|
||||||
CESIZen est une application de gestion de la santé mentale développée avec Flutter. Elle permet aux utilisateurs de suivre leur état émotionnel, de réaliser des diagnostics de stress et de pratiquer des exercices de relaxation.
|
CESIZen est une application de gestion de la santé mentale développée avec Flutter. Elle permet aux utilisateurs de suivre leur état émotionnel, de réaliser des diagnostics de stress et de pratiquer des exercices de relaxation.
|
||||||
|
|
||||||
## 🚀 Fonctionnalités
|
## 🚀 Fonctionnalités
|
||||||
|
|
||||||
- **Authentification Sécurisée** : Connexion et inscription via une API Laravel (JWT).
|
- **Authentification Sécurisée** : Connexion et inscription via une API Laravel (JWT).
|
||||||
- **Espace Santé Personnel** : Modification du profil (Nom, Email, Mot de passe).
|
- **Espace Santé Personnel** : Modification du profil (Nom, Email, Mot de passe).
|
||||||
- **Diagnostic de Stress** : Basé sur l'échelle de **Holmes et Rahe** (données dynamiques via API).
|
- **Diagnostic de Stress** : Basé sur l'échelle de **Holmes et Rahe** (données dynamiques via API).
|
||||||
- **Tracker d'Émotions** : Journal de bord complet (CRUD) pour suivre son humeur.
|
- **Tracker d'Émotions** : Journal de bord complet (CRUD) pour suivre son humeur.
|
||||||
- **Cohérence Cardiaque** : Exercice de respiration guidé (5s inspiration / 5s expiration).
|
- **Cohérence Cardiaque** : Exercice de respiration guidé (5s inspiration / 5s expiration).
|
||||||
- **Catalogue Détente** : Activités de relaxation (Méditation, Musique) filtrables par catégorie.
|
- **Catalogue Détente** : Activités de relaxation (Méditation, Musique) filtrables par catégorie.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🛠️ Installation et Lancement
|
## 🛠️ Installation et Lancement
|
||||||
|
|
||||||
### 1. Prérequis
|
### 1. Prérequis
|
||||||
- [Flutter SDK](https://docs.flutter.dev/get-started/install) (dernière version stable recommandée).
|
- [Flutter SDK](https://docs.flutter.dev/get-started/install) (dernière version stable recommandée).
|
||||||
- [Android Studio](https://developer.android.com/studio) ou [VS Code](https://code.visualstudio.com/).
|
- [Android Studio](https://developer.android.com/studio) ou [VS Code](https://code.visualstudio.com/).
|
||||||
- Un émulateur Android ou un appareil physique avec le débogage USB activé.
|
- Un émulateur Android ou un appareil physique avec le débogage USB activé.
|
||||||
|
|
||||||
### 2. Récupération du projet
|
### 2. Récupération du projet
|
||||||
```bash
|
```bash
|
||||||
git clone <url-du-depot>
|
git clone <url-du-depot>
|
||||||
cd CESIZen/mobile
|
cd CESIZen/mobile
|
||||||
```
|
```
|
||||||
|
|
||||||
### 3. Installation des dépendances
|
### 3. Installation des dépendances
|
||||||
```bash
|
```bash
|
||||||
flutter pub get
|
flutter pub get
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🌐 Configuration de l'API
|
## 🌐 Configuration de l'API
|
||||||
|
|
||||||
L'application communique avec un backend Laravel.
|
L'application communique avec un backend Laravel.
|
||||||
|
|
||||||
### URL de l'API
|
### URL de l'API
|
||||||
La configuration se trouve dans `lib/core/network/dio_client.dart`.
|
La configuration se trouve dans `lib/core/network/dio_client.dart`.
|
||||||
- **URL actuelle** : `https://apicesizen.sam-coffre.duckdns.org/api`
|
- **URL actuelle** : `https://apicesizen.sam-coffre.duckdns.org/api`
|
||||||
|
|
||||||
### Compatibilité et Sécurité (SSL Bypass)
|
### Compatibilité et Sécurité (SSL Bypass)
|
||||||
Pour faciliter le développement sur des serveurs avec des certificats auto-signés ou en cours de configuration, le client `Dio` est configuré pour **ignorer les erreurs de certificat SSL**.
|
Pour faciliter le développement sur des serveurs avec des certificats auto-signés ou en cours de configuration, le client `Dio` est configuré pour **ignorer les erreurs de certificat SSL**.
|
||||||
|
|
||||||
Dans `lib/core/network/dio_client.dart` :
|
Dans `lib/core/network/dio_client.dart` :
|
||||||
```dart
|
```dart
|
||||||
// Le code inclut un SecurityContext qui accepte tous les certificats
|
// Le code inclut un SecurityContext qui accepte tous les certificats
|
||||||
(dio.httpClientAdapter as IOHttpClientAdapter).createHttpClient = () {
|
(dio.httpClientAdapter as IOHttpClientAdapter).createHttpClient = () {
|
||||||
final client = HttpClient();
|
final client = HttpClient();
|
||||||
client.badCertificateCallback = (X509Certificate cert, String host, int port) => true;
|
client.badCertificateCallback = (X509Certificate cert, String host, int port) => true;
|
||||||
return client;
|
return client;
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
**Note importante :** Sur Android, assurez-vous que `android:usesCleartextTraffic="true"` est bien présent dans le `AndroidManifest.xml` si vous repassez en HTTP simple.
|
**Note importante :** Sur Android, assurez-vous que `android:usesCleartextTraffic="true"` est bien présent dans le `AndroidManifest.xml` si vous repassez en HTTP simple.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🏃 Lancer l'application
|
## 🏃 Lancer l'application
|
||||||
|
|
||||||
Pour lancer l'application en mode debug :
|
Pour lancer l'application en mode debug :
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
flutter run
|
flutter run
|
||||||
```
|
```
|
||||||
|
|
||||||
Pour générer un APK de test :
|
Pour générer un APK de test :
|
||||||
```bash
|
```bash
|
||||||
flutter build apk --debug
|
flutter build apk --debug
|
||||||
```
|
```
|
||||||
|
|
||||||
## 📂 Structure du Projet
|
## 📂 Structure du Projet
|
||||||
|
|
||||||
- `lib/core/` : Configuration réseau (Dio) et thèmes.
|
- `lib/core/` : Configuration réseau (Dio) et thèmes.
|
||||||
- `lib/features/auth/` : Gestion de l'authentification et du profil.
|
- `lib/features/auth/` : Gestion de l'authentification et du profil.
|
||||||
- `lib/features/diagnostics/` : Logique du questionnaire Holmes & Rahe.
|
- `lib/features/diagnostics/` : Logique du questionnaire Holmes & Rahe.
|
||||||
- `lib/features/tracker/` : Journal des émotions (CRUD).
|
- `lib/features/tracker/` : Journal des émotions (CRUD).
|
||||||
- `lib/features/exercises/` : Exercice de cohérence cardiaque.
|
- `lib/features/exercises/` : Exercice de cohérence cardiaque.
|
||||||
- `lib/features/relaxation/` : Catalogue d'activités de détente.
|
- `lib/features/relaxation/` : Catalogue d'activités de détente.
|
||||||
|
|
||||||
---
|
---
|
||||||
© 2024 CESIZen - Projet CDA
|
© 2024 CESIZen - Projet CDA
|
||||||
|
|||||||
@@ -1,28 +1,28 @@
|
|||||||
# This file configures the analyzer, which statically analyzes Dart code to
|
# This file configures the analyzer, which statically analyzes Dart code to
|
||||||
# check for errors, warnings, and lints.
|
# check for errors, warnings, and lints.
|
||||||
#
|
#
|
||||||
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
|
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
|
||||||
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
|
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
|
||||||
# invoked from the command line by running `flutter analyze`.
|
# invoked from the command line by running `flutter analyze`.
|
||||||
|
|
||||||
# The following line activates a set of recommended lints for Flutter apps,
|
# The following line activates a set of recommended lints for Flutter apps,
|
||||||
# packages, and plugins designed to encourage good coding practices.
|
# packages, and plugins designed to encourage good coding practices.
|
||||||
include: package:flutter_lints/flutter.yaml
|
include: package:flutter_lints/flutter.yaml
|
||||||
|
|
||||||
linter:
|
linter:
|
||||||
# The lint rules applied to this project can be customized in the
|
# The lint rules applied to this project can be customized in the
|
||||||
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
|
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
|
||||||
# included above or to enable additional rules. A list of all available lints
|
# included above or to enable additional rules. A list of all available lints
|
||||||
# and their documentation is published at https://dart.dev/lints.
|
# and their documentation is published at https://dart.dev/lints.
|
||||||
#
|
#
|
||||||
# Instead of disabling a lint rule for the entire project in the
|
# Instead of disabling a lint rule for the entire project in the
|
||||||
# section below, it can also be suppressed for a single line of code
|
# section below, it can also be suppressed for a single line of code
|
||||||
# or a specific dart file by using the `// ignore: name_of_lint` and
|
# or a specific dart file by using the `// ignore: name_of_lint` and
|
||||||
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
|
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
|
||||||
# producing the lint.
|
# producing the lint.
|
||||||
rules:
|
rules:
|
||||||
# avoid_print: false # Uncomment to disable the `avoid_print` rule
|
# avoid_print: false # Uncomment to disable the `avoid_print` rule
|
||||||
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
|
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
|
||||||
|
|
||||||
# Additional information about this file can be found at
|
# Additional information about this file can be found at
|
||||||
# https://dart.dev/guides/language/analysis-options
|
# https://dart.dev/guides/language/analysis-options
|
||||||
|
|||||||
+14
-14
@@ -1,14 +1,14 @@
|
|||||||
gradle-wrapper.jar
|
gradle-wrapper.jar
|
||||||
/.gradle
|
/.gradle
|
||||||
/captures/
|
/captures/
|
||||||
/gradlew
|
/gradlew
|
||||||
/gradlew.bat
|
/gradlew.bat
|
||||||
/local.properties
|
/local.properties
|
||||||
GeneratedPluginRegistrant.java
|
GeneratedPluginRegistrant.java
|
||||||
.cxx/
|
.cxx/
|
||||||
|
|
||||||
# Remember to never publicly share your keystore.
|
# Remember to never publicly share your keystore.
|
||||||
# See https://flutter.dev/to/reference-keystore
|
# See https://flutter.dev/to/reference-keystore
|
||||||
key.properties
|
key.properties
|
||||||
**/*.keystore
|
**/*.keystore
|
||||||
**/*.jks
|
**/*.jks
|
||||||
|
|||||||
@@ -1,47 +1,47 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id("com.android.application")
|
id("com.android.application")
|
||||||
id("kotlin-android")
|
id("kotlin-android")
|
||||||
// The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
|
// The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
|
||||||
id("dev.flutter.flutter-gradle-plugin")
|
id("dev.flutter.flutter-gradle-plugin")
|
||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
namespace = "com.cesizen.app"
|
namespace = "com.cesizen.app"
|
||||||
compileSdk = flutter.compileSdkVersion
|
compileSdk = flutter.compileSdkVersion
|
||||||
ndkVersion = flutter.ndkVersion
|
ndkVersion = flutter.ndkVersion
|
||||||
|
|
||||||
compileOptions {
|
compileOptions {
|
||||||
sourceCompatibility = JavaVersion.VERSION_17
|
sourceCompatibility = JavaVersion.VERSION_17
|
||||||
targetCompatibility = JavaVersion.VERSION_17
|
targetCompatibility = JavaVersion.VERSION_17
|
||||||
}
|
}
|
||||||
|
|
||||||
kotlinOptions {
|
kotlinOptions {
|
||||||
jvmTarget = JavaVersion.VERSION_17.toString()
|
jvmTarget = JavaVersion.VERSION_17.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId = "com.cesizen.app"
|
applicationId = "com.cesizen.app"
|
||||||
// You can update the following values to match your application needs.
|
// You can update the following values to match your application needs.
|
||||||
// For more information, see: https://flutter.dev/to/review-gradle-config.
|
// For more information, see: https://flutter.dev/to/review-gradle-config.
|
||||||
minSdk = flutter.minSdkVersion
|
minSdk = flutter.minSdkVersion
|
||||||
targetSdk = flutter.targetSdkVersion
|
targetSdk = flutter.targetSdkVersion
|
||||||
versionCode = flutter.versionCode
|
versionCode = flutter.versionCode
|
||||||
versionName = flutter.versionName
|
versionName = flutter.versionName
|
||||||
}
|
}
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
release {
|
release {
|
||||||
// TODO: Add your own signing config for the release build.
|
// TODO: Add your own signing config for the release build.
|
||||||
// Signing with the debug keys for now, so `flutter run --release` works.
|
// Signing with the debug keys for now, so `flutter run --release` works.
|
||||||
signingConfig = signingConfigs.getByName("debug")
|
signingConfig = signingConfigs.getByName("debug")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation("com.google.android.gms:play-services-wearable:18.0.0")
|
implementation("com.google.android.gms:play-services-wearable:18.0.0")
|
||||||
}
|
}
|
||||||
|
|
||||||
flutter {
|
flutter {
|
||||||
source = "../.."
|
source = "../.."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<!-- The INTERNET permission is required for development. Specifically,
|
<!-- The INTERNET permission is required for development. Specifically,
|
||||||
the Flutter tool needs it to communicate with the running application
|
the Flutter tool needs it to communicate with the running application
|
||||||
to allow setting breakpoints, to provide hot reload, etc.
|
to allow setting breakpoints, to provide hot reload, etc.
|
||||||
-->
|
-->
|
||||||
<uses-permission android:name="android.permission.INTERNET"/>
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|||||||
@@ -1,55 +1,55 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
|
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
|
||||||
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
|
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
|
||||||
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
|
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:label="CESIZen"
|
android:label="CESIZen"
|
||||||
android:name="${applicationName}"
|
android:name="${applicationName}"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
android:usesCleartextTraffic="true">
|
android:usesCleartextTraffic="true">
|
||||||
<activity
|
<activity
|
||||||
android:name="com.cesizen.app.MainActivity"
|
android:name="com.cesizen.app.MainActivity"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:launchMode="singleTop"
|
android:launchMode="singleTop"
|
||||||
android:taskAffinity=""
|
android:taskAffinity=""
|
||||||
android:theme="@style/LaunchTheme"
|
android:theme="@style/LaunchTheme"
|
||||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
||||||
android:hardwareAccelerated="true"
|
android:hardwareAccelerated="true"
|
||||||
android:windowSoftInputMode="adjustResize">
|
android:windowSoftInputMode="adjustResize">
|
||||||
<!-- Specifies an Android theme to apply to this Activity as soon as
|
<!-- Specifies an Android theme to apply to this Activity as soon as
|
||||||
the Android process has started. This theme is visible to the user
|
the Android process has started. This theme is visible to the user
|
||||||
while the Flutter UI initializes. After that, this theme continues
|
while the Flutter UI initializes. After that, this theme continues
|
||||||
to determine the Window background behind the Flutter UI. -->
|
to determine the Window background behind the Flutter UI. -->
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="io.flutter.embedding.android.NormalTheme"
|
android:name="io.flutter.embedding.android.NormalTheme"
|
||||||
android:resource="@style/NormalTheme"
|
android:resource="@style/NormalTheme"
|
||||||
/>
|
/>
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN"/>
|
<action android:name="android.intent.action.MAIN"/>
|
||||||
<category android:name="android.intent.category.LAUNCHER"/>
|
<category android:name="android.intent.category.LAUNCHER"/>
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="com.google.android.gms.wearable.capabilities"
|
android:name="com.google.android.gms.wearable.capabilities"
|
||||||
android:resource="@xml/wearable_app_values" />
|
android:resource="@xml/wearable_app_values" />
|
||||||
|
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="flutterEmbedding"
|
android:name="flutterEmbedding"
|
||||||
android:value="2" />
|
android:value="2" />
|
||||||
</application>
|
</application>
|
||||||
<!-- Required to query activities that can process text, see:
|
<!-- Required to query activities that can process text, see:
|
||||||
https://developer.android.com/training/package-visibility and
|
https://developer.android.com/training/package-visibility and
|
||||||
https://developer.android.com/reference/android/content/Intent#ACTION_PROCESS_TEXT.
|
https://developer.android.com/reference/android/content/Intent#ACTION_PROCESS_TEXT.
|
||||||
|
|
||||||
In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. -->
|
In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. -->
|
||||||
<queries>
|
<queries>
|
||||||
<package android:name="com.google.android.wearable.app" />
|
<package android:name="com.google.android.wearable.app" />
|
||||||
<package android:name="com.cesizen.app" />
|
<package android:name="com.cesizen.app" />
|
||||||
<intent>
|
<intent>
|
||||||
<action android:name="android.intent.action.PROCESS_TEXT"/>
|
<action android:name="android.intent.action.PROCESS_TEXT"/>
|
||||||
<data android:mimeType="text/plain"/>
|
<data android:mimeType="text/plain"/>
|
||||||
</intent>
|
</intent>
|
||||||
</queries>
|
</queries>
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|||||||
@@ -1,108 +1,108 @@
|
|||||||
package com.cesizen.app
|
package com.cesizen.app
|
||||||
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import io.flutter.embedding.android.FlutterActivity
|
import io.flutter.embedding.android.FlutterActivity
|
||||||
import io.flutter.embedding.engine.FlutterEngine
|
import io.flutter.embedding.engine.FlutterEngine
|
||||||
import io.flutter.plugin.common.MethodChannel
|
import io.flutter.plugin.common.MethodChannel
|
||||||
import com.google.android.gms.wearable.Wearable
|
import com.google.android.gms.wearable.Wearable
|
||||||
import com.google.android.gms.wearable.PutDataMapRequest
|
import com.google.android.gms.wearable.PutDataMapRequest
|
||||||
import com.google.android.gms.wearable.CapabilityClient
|
import com.google.android.gms.wearable.CapabilityClient
|
||||||
import com.google.android.gms.tasks.Tasks
|
import com.google.android.gms.tasks.Tasks
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
class MainActivity : FlutterActivity() {
|
class MainActivity : FlutterActivity() {
|
||||||
private val CHANNEL = "com.cesizen/wearable"
|
private val CHANNEL = "com.cesizen/wearable"
|
||||||
private val TAG = "CESIZen_Mobile_Native"
|
private val TAG = "CESIZen_Mobile_Native"
|
||||||
|
|
||||||
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
|
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
|
||||||
super.configureFlutterEngine(flutterEngine)
|
super.configureFlutterEngine(flutterEngine)
|
||||||
|
|
||||||
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result ->
|
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result ->
|
||||||
when (call.method) {
|
when (call.method) {
|
||||||
"sendAuthStatus" -> {
|
"sendAuthStatus" -> {
|
||||||
val status = call.argument<String>("status")
|
val status = call.argument<String>("status")
|
||||||
val userName = call.argument<String>("userName")
|
val userName = call.argument<String>("userName")
|
||||||
updateWearDataLayer(status, userName)
|
updateWearDataLayer(status, userName)
|
||||||
result.success(true)
|
result.success(true)
|
||||||
}
|
}
|
||||||
"syncMood" -> {
|
"syncMood" -> {
|
||||||
val mood = call.argument<String>("mood")
|
val mood = call.argument<String>("mood")
|
||||||
updateMoodDataLayer(mood)
|
updateMoodDataLayer(mood)
|
||||||
result.success(true)
|
result.success(true)
|
||||||
}
|
}
|
||||||
"isWatchNearby" -> {
|
"isWatchNearby" -> {
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
try {
|
try {
|
||||||
val capabilityInfo = Tasks.await(
|
val capabilityInfo = Tasks.await(
|
||||||
Wearable.getCapabilityClient(this@MainActivity)
|
Wearable.getCapabilityClient(this@MainActivity)
|
||||||
.getCapability("cesizen_wear_app", CapabilityClient.FILTER_ALL)
|
.getCapability("cesizen_wear_app", CapabilityClient.FILTER_ALL)
|
||||||
)
|
)
|
||||||
val isNearby = capabilityInfo.nodes.isNotEmpty()
|
val isNearby = capabilityInfo.nodes.isNotEmpty()
|
||||||
runOnUiThread { result.success(isNearby) }
|
runOnUiThread { result.success(isNearby) }
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
runOnUiThread { result.success(false) }
|
runOnUiThread { result.success(false) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
result.notImplemented()
|
result.notImplemented()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Écouter les messages de la montre
|
// Écouter les messages de la montre
|
||||||
Wearable.getMessageClient(this).addListener { messageEvent ->
|
Wearable.getMessageClient(this).addListener { messageEvent ->
|
||||||
Log.d(TAG, "Message received from watch: ${messageEvent.path}")
|
Log.d(TAG, "Message received from watch: ${messageEvent.path}")
|
||||||
if (messageEvent.path == "/wearable_communication") {
|
if (messageEvent.path == "/wearable_communication") {
|
||||||
try {
|
try {
|
||||||
val dataString = String(messageEvent.data)
|
val dataString = String(messageEvent.data)
|
||||||
Log.d(TAG, "Payload: $dataString")
|
Log.d(TAG, "Payload: $dataString")
|
||||||
val json = JSONObject(dataString)
|
val json = JSONObject(dataString)
|
||||||
val command = json.optString("command")
|
val command = json.optString("command")
|
||||||
|
|
||||||
runOnUiThread {
|
runOnUiThread {
|
||||||
val messenger = flutterEngine.dartExecutor.binaryMessenger
|
val messenger = flutterEngine.dartExecutor.binaryMessenger
|
||||||
when (command) {
|
when (command) {
|
||||||
"get_sync_data" -> {
|
"get_sync_data" -> {
|
||||||
Log.d(TAG, "Command: get_sync_data -> calling requestStatusUpdate")
|
Log.d(TAG, "Command: get_sync_data -> calling requestStatusUpdate")
|
||||||
MethodChannel(messenger, CHANNEL).invokeMethod("requestStatusUpdate", null)
|
MethodChannel(messenger, CHANNEL).invokeMethod("requestStatusUpdate", null)
|
||||||
}
|
}
|
||||||
"save_mood" -> {
|
"save_mood" -> {
|
||||||
val mood = json.optString("mood")
|
val mood = json.optString("mood")
|
||||||
Log.d(TAG, "Command: save_mood ($mood) -> calling saveMoodFromWear")
|
Log.d(TAG, "Command: save_mood ($mood) -> calling saveMoodFromWear")
|
||||||
MethodChannel(messenger, CHANNEL).invokeMethod("saveMoodFromWear", mapOf("mood" to mood))
|
MethodChannel(messenger, CHANNEL).invokeMethod("saveMoodFromWear", mapOf("mood" to mood))
|
||||||
updateMoodDataLayer(mood)
|
updateMoodDataLayer(mood)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e(TAG, "Error processing message", e)
|
Log.e(TAG, "Error processing message", e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateWearDataLayer(status: String?, userName: String?) {
|
private fun updateWearDataLayer(status: String?, userName: String?) {
|
||||||
val request = PutDataMapRequest.create("/auth_status")
|
val request = PutDataMapRequest.create("/auth_status")
|
||||||
request.dataMap.putString("status", status ?: "unauthenticated")
|
request.dataMap.putString("status", status ?: "unauthenticated")
|
||||||
request.dataMap.putString("userName", userName ?: "")
|
request.dataMap.putString("userName", userName ?: "")
|
||||||
request.dataMap.putLong("timestamp", System.currentTimeMillis())
|
request.dataMap.putLong("timestamp", System.currentTimeMillis())
|
||||||
val putDataRequest = request.asPutDataRequest().setUrgent()
|
val putDataRequest = request.asPutDataRequest().setUrgent()
|
||||||
Wearable.getDataClient(this).putDataItem(putDataRequest)
|
Wearable.getDataClient(this).putDataItem(putDataRequest)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateMoodDataLayer(mood: String?) {
|
private fun updateMoodDataLayer(mood: String?) {
|
||||||
val request = PutDataMapRequest.create("/daily_mood")
|
val request = PutDataMapRequest.create("/daily_mood")
|
||||||
val today = java.text.SimpleDateFormat("yyyy-MM-dd", java.util.Locale.getDefault()).format(java.util.Date())
|
val today = java.text.SimpleDateFormat("yyyy-MM-dd", java.util.Locale.getDefault()).format(java.util.Date())
|
||||||
|
|
||||||
request.dataMap.putString("mood", mood ?: "")
|
request.dataMap.putString("mood", mood ?: "")
|
||||||
request.dataMap.putString("date", today)
|
request.dataMap.putString("date", today)
|
||||||
request.dataMap.putLong("timestamp", System.currentTimeMillis())
|
request.dataMap.putLong("timestamp", System.currentTimeMillis())
|
||||||
|
|
||||||
val putDataRequest = request.asPutDataRequest().setUrgent()
|
val putDataRequest = request.asPutDataRequest().setUrgent()
|
||||||
Wearable.getDataClient(this).putDataItem(putDataRequest)
|
Wearable.getDataClient(this).putDataItem(putDataRequest)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Modify this file to customize your launch splash screen -->
|
<!-- Modify this file to customize your launch splash screen -->
|
||||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<item android:drawable="?android:colorBackground" />
|
<item android:drawable="?android:colorBackground" />
|
||||||
|
|
||||||
<!-- You can insert your own image assets here -->
|
<!-- You can insert your own image assets here -->
|
||||||
<!-- <item>
|
<!-- <item>
|
||||||
<bitmap
|
<bitmap
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:src="@mipmap/launch_image" />
|
android:src="@mipmap/launch_image" />
|
||||||
</item> -->
|
</item> -->
|
||||||
</layer-list>
|
</layer-list>
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!-- Modify this file to customize your launch splash screen -->
|
<!-- Modify this file to customize your launch splash screen -->
|
||||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<item android:drawable="@android:color/white" />
|
<item android:drawable="@android:color/white" />
|
||||||
|
|
||||||
<!-- You can insert your own image assets here -->
|
<!-- You can insert your own image assets here -->
|
||||||
<!-- <item>
|
<!-- <item>
|
||||||
<bitmap
|
<bitmap
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:src="@mipmap/launch_image" />
|
android:src="@mipmap/launch_image" />
|
||||||
</item> -->
|
</item> -->
|
||||||
</layer-list>
|
</layer-list>
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
|
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
|
||||||
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||||
<!-- Show a splash screen on the activity. Automatically removed when
|
<!-- Show a splash screen on the activity. Automatically removed when
|
||||||
the Flutter engine draws its first frame -->
|
the Flutter engine draws its first frame -->
|
||||||
<item name="android:windowBackground">@drawable/launch_background</item>
|
<item name="android:windowBackground">@drawable/launch_background</item>
|
||||||
</style>
|
</style>
|
||||||
<!-- Theme applied to the Android Window as soon as the process has started.
|
<!-- Theme applied to the Android Window as soon as the process has started.
|
||||||
This theme determines the color of the Android Window while your
|
This theme determines the color of the Android Window while your
|
||||||
Flutter UI initializes, as well as behind your Flutter UI while its
|
Flutter UI initializes, as well as behind your Flutter UI while its
|
||||||
running.
|
running.
|
||||||
|
|
||||||
This Theme is only used starting with V2 of Flutter's Android embedding. -->
|
This Theme is only used starting with V2 of Flutter's Android embedding. -->
|
||||||
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
|
||||||
<item name="android:windowBackground">?android:colorBackground</item>
|
<item name="android:windowBackground">?android:colorBackground</item>
|
||||||
</style>
|
</style>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
|
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
|
||||||
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
|
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
|
||||||
<!-- Show a splash screen on the activity. Automatically removed when
|
<!-- Show a splash screen on the activity. Automatically removed when
|
||||||
the Flutter engine draws its first frame -->
|
the Flutter engine draws its first frame -->
|
||||||
<item name="android:windowBackground">@drawable/launch_background</item>
|
<item name="android:windowBackground">@drawable/launch_background</item>
|
||||||
</style>
|
</style>
|
||||||
<!-- Theme applied to the Android Window as soon as the process has started.
|
<!-- Theme applied to the Android Window as soon as the process has started.
|
||||||
This theme determines the color of the Android Window while your
|
This theme determines the color of the Android Window while your
|
||||||
Flutter UI initializes, as well as behind your Flutter UI while its
|
Flutter UI initializes, as well as behind your Flutter UI while its
|
||||||
running.
|
running.
|
||||||
|
|
||||||
This Theme is only used starting with V2 of Flutter's Android embedding. -->
|
This Theme is only used starting with V2 of Flutter's Android embedding. -->
|
||||||
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
|
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
|
||||||
<item name="android:windowBackground">?android:colorBackground</item>
|
<item name="android:windowBackground">?android:colorBackground</item>
|
||||||
</style>
|
</style>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<capability name="cesizen_handheld_app" />
|
<capability name="cesizen_handheld_app" />
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<!-- The INTERNET permission is required for development. Specifically,
|
<!-- The INTERNET permission is required for development. Specifically,
|
||||||
the Flutter tool needs it to communicate with the running application
|
the Flutter tool needs it to communicate with the running application
|
||||||
to allow setting breakpoints, to provide hot reload, etc.
|
to allow setting breakpoints, to provide hot reload, etc.
|
||||||
-->
|
-->
|
||||||
<uses-permission android:name="android.permission.INTERNET"/>
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|||||||
@@ -1,24 +1,24 @@
|
|||||||
allprojects {
|
allprojects {
|
||||||
repositories {
|
repositories {
|
||||||
google()
|
google()
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val newBuildDir: Directory =
|
val newBuildDir: Directory =
|
||||||
rootProject.layout.buildDirectory
|
rootProject.layout.buildDirectory
|
||||||
.dir("../../build")
|
.dir("../../build")
|
||||||
.get()
|
.get()
|
||||||
rootProject.layout.buildDirectory.value(newBuildDir)
|
rootProject.layout.buildDirectory.value(newBuildDir)
|
||||||
|
|
||||||
subprojects {
|
subprojects {
|
||||||
val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name)
|
val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name)
|
||||||
project.layout.buildDirectory.value(newSubprojectBuildDir)
|
project.layout.buildDirectory.value(newSubprojectBuildDir)
|
||||||
}
|
}
|
||||||
subprojects {
|
subprojects {
|
||||||
project.evaluationDependsOn(":app")
|
project.evaluationDependsOn(":app")
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.register<Delete>("clean") {
|
tasks.register<Delete>("clean") {
|
||||||
delete(rootProject.layout.buildDirectory)
|
delete(rootProject.layout.buildDirectory)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError
|
org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError
|
||||||
android.useAndroidX=true
|
android.useAndroidX=true
|
||||||
|
|||||||
+5
-5
@@ -1,5 +1,5 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-all.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-all.zip
|
||||||
|
|||||||
@@ -1,26 +1,26 @@
|
|||||||
pluginManagement {
|
pluginManagement {
|
||||||
val flutterSdkPath =
|
val flutterSdkPath =
|
||||||
run {
|
run {
|
||||||
val properties = java.util.Properties()
|
val properties = java.util.Properties()
|
||||||
file("local.properties").inputStream().use { properties.load(it) }
|
file("local.properties").inputStream().use { properties.load(it) }
|
||||||
val flutterSdkPath = properties.getProperty("flutter.sdk")
|
val flutterSdkPath = properties.getProperty("flutter.sdk")
|
||||||
require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" }
|
require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" }
|
||||||
flutterSdkPath
|
flutterSdkPath
|
||||||
}
|
}
|
||||||
|
|
||||||
includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
|
includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
google()
|
google()
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
gradlePluginPortal()
|
gradlePluginPortal()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("dev.flutter.flutter-plugin-loader") version "1.0.0"
|
id("dev.flutter.flutter-plugin-loader") version "1.0.0"
|
||||||
id("com.android.application") version "8.11.1" apply false
|
id("com.android.application") version "8.11.1" apply false
|
||||||
id("org.jetbrains.kotlin.android") version "2.2.20" apply false
|
id("org.jetbrains.kotlin.android") version "2.2.20" apply false
|
||||||
}
|
}
|
||||||
|
|
||||||
include(":app")
|
include(":app")
|
||||||
|
|||||||
+34
-34
@@ -1,34 +1,34 @@
|
|||||||
**/dgph
|
**/dgph
|
||||||
*.mode1v3
|
*.mode1v3
|
||||||
*.mode2v3
|
*.mode2v3
|
||||||
*.moved-aside
|
*.moved-aside
|
||||||
*.pbxuser
|
*.pbxuser
|
||||||
*.perspectivev3
|
*.perspectivev3
|
||||||
**/*sync/
|
**/*sync/
|
||||||
.sconsign.dblite
|
.sconsign.dblite
|
||||||
.tags*
|
.tags*
|
||||||
**/.vagrant/
|
**/.vagrant/
|
||||||
**/DerivedData/
|
**/DerivedData/
|
||||||
Icon?
|
Icon?
|
||||||
**/Pods/
|
**/Pods/
|
||||||
**/.symlinks/
|
**/.symlinks/
|
||||||
profile
|
profile
|
||||||
xcuserdata
|
xcuserdata
|
||||||
**/.generated/
|
**/.generated/
|
||||||
Flutter/App.framework
|
Flutter/App.framework
|
||||||
Flutter/Flutter.framework
|
Flutter/Flutter.framework
|
||||||
Flutter/Flutter.podspec
|
Flutter/Flutter.podspec
|
||||||
Flutter/Generated.xcconfig
|
Flutter/Generated.xcconfig
|
||||||
Flutter/ephemeral/
|
Flutter/ephemeral/
|
||||||
Flutter/app.flx
|
Flutter/app.flx
|
||||||
Flutter/app.zip
|
Flutter/app.zip
|
||||||
Flutter/flutter_assets/
|
Flutter/flutter_assets/
|
||||||
Flutter/flutter_export_environment.sh
|
Flutter/flutter_export_environment.sh
|
||||||
ServiceDefinitions.json
|
ServiceDefinitions.json
|
||||||
Runner/GeneratedPluginRegistrant.*
|
Runner/GeneratedPluginRegistrant.*
|
||||||
|
|
||||||
# Exceptions to above rules.
|
# Exceptions to above rules.
|
||||||
!default.mode1v3
|
!default.mode1v3
|
||||||
!default.mode2v3
|
!default.mode2v3
|
||||||
!default.pbxuser
|
!default.pbxuser
|
||||||
!default.perspectivev3
|
!default.perspectivev3
|
||||||
|
|||||||
@@ -1,24 +1,24 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict>
|
<dict>
|
||||||
<key>CFBundleDevelopmentRegion</key>
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
<string>en</string>
|
<string>en</string>
|
||||||
<key>CFBundleExecutable</key>
|
<key>CFBundleExecutable</key>
|
||||||
<string>App</string>
|
<string>App</string>
|
||||||
<key>CFBundleIdentifier</key>
|
<key>CFBundleIdentifier</key>
|
||||||
<string>io.flutter.flutter.app</string>
|
<string>io.flutter.flutter.app</string>
|
||||||
<key>CFBundleInfoDictionaryVersion</key>
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
<string>6.0</string>
|
<string>6.0</string>
|
||||||
<key>CFBundleName</key>
|
<key>CFBundleName</key>
|
||||||
<string>App</string>
|
<string>App</string>
|
||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>FMWK</string>
|
<string>FMWK</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>1.0</string>
|
<string>1.0</string>
|
||||||
<key>CFBundleSignature</key>
|
<key>CFBundleSignature</key>
|
||||||
<string>????</string>
|
<string>????</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>1.0</string>
|
<string>1.0</string>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
#include "Generated.xcconfig"
|
#include "Generated.xcconfig"
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
#include "Generated.xcconfig"
|
#include "Generated.xcconfig"
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<Workspace
|
<Workspace
|
||||||
version = "1.0">
|
version = "1.0">
|
||||||
<FileRef
|
<FileRef
|
||||||
location = "self:">
|
location = "self:">
|
||||||
</FileRef>
|
</FileRef>
|
||||||
</Workspace>
|
</Workspace>
|
||||||
|
|||||||
+8
-8
@@ -1,8 +1,8 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict>
|
<dict>
|
||||||
<key>IDEDidComputeMac32BitWarning</key>
|
<key>IDEDidComputeMac32BitWarning</key>
|
||||||
<true/>
|
<true/>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|||||||
+8
-8
@@ -1,8 +1,8 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict>
|
<dict>
|
||||||
<key>PreviewsEnabled</key>
|
<key>PreviewsEnabled</key>
|
||||||
<false/>
|
<false/>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|||||||
@@ -1,101 +1,101 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<Scheme
|
<Scheme
|
||||||
LastUpgradeVersion = "1510"
|
LastUpgradeVersion = "1510"
|
||||||
version = "1.3">
|
version = "1.3">
|
||||||
<BuildAction
|
<BuildAction
|
||||||
parallelizeBuildables = "YES"
|
parallelizeBuildables = "YES"
|
||||||
buildImplicitDependencies = "YES">
|
buildImplicitDependencies = "YES">
|
||||||
<BuildActionEntries>
|
<BuildActionEntries>
|
||||||
<BuildActionEntry
|
<BuildActionEntry
|
||||||
buildForTesting = "YES"
|
buildForTesting = "YES"
|
||||||
buildForRunning = "YES"
|
buildForRunning = "YES"
|
||||||
buildForProfiling = "YES"
|
buildForProfiling = "YES"
|
||||||
buildForArchiving = "YES"
|
buildForArchiving = "YES"
|
||||||
buildForAnalyzing = "YES">
|
buildForAnalyzing = "YES">
|
||||||
<BuildableReference
|
<BuildableReference
|
||||||
BuildableIdentifier = "primary"
|
BuildableIdentifier = "primary"
|
||||||
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
||||||
BuildableName = "Runner.app"
|
BuildableName = "Runner.app"
|
||||||
BlueprintName = "Runner"
|
BlueprintName = "Runner"
|
||||||
ReferencedContainer = "container:Runner.xcodeproj">
|
ReferencedContainer = "container:Runner.xcodeproj">
|
||||||
</BuildableReference>
|
</BuildableReference>
|
||||||
</BuildActionEntry>
|
</BuildActionEntry>
|
||||||
</BuildActionEntries>
|
</BuildActionEntries>
|
||||||
</BuildAction>
|
</BuildAction>
|
||||||
<TestAction
|
<TestAction
|
||||||
buildConfiguration = "Debug"
|
buildConfiguration = "Debug"
|
||||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"
|
customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"
|
||||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||||
<MacroExpansion>
|
<MacroExpansion>
|
||||||
<BuildableReference
|
<BuildableReference
|
||||||
BuildableIdentifier = "primary"
|
BuildableIdentifier = "primary"
|
||||||
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
||||||
BuildableName = "Runner.app"
|
BuildableName = "Runner.app"
|
||||||
BlueprintName = "Runner"
|
BlueprintName = "Runner"
|
||||||
ReferencedContainer = "container:Runner.xcodeproj">
|
ReferencedContainer = "container:Runner.xcodeproj">
|
||||||
</BuildableReference>
|
</BuildableReference>
|
||||||
</MacroExpansion>
|
</MacroExpansion>
|
||||||
<Testables>
|
<Testables>
|
||||||
<TestableReference
|
<TestableReference
|
||||||
skipped = "NO"
|
skipped = "NO"
|
||||||
parallelizable = "YES">
|
parallelizable = "YES">
|
||||||
<BuildableReference
|
<BuildableReference
|
||||||
BuildableIdentifier = "primary"
|
BuildableIdentifier = "primary"
|
||||||
BlueprintIdentifier = "331C8080294A63A400263BE5"
|
BlueprintIdentifier = "331C8080294A63A400263BE5"
|
||||||
BuildableName = "RunnerTests.xctest"
|
BuildableName = "RunnerTests.xctest"
|
||||||
BlueprintName = "RunnerTests"
|
BlueprintName = "RunnerTests"
|
||||||
ReferencedContainer = "container:Runner.xcodeproj">
|
ReferencedContainer = "container:Runner.xcodeproj">
|
||||||
</BuildableReference>
|
</BuildableReference>
|
||||||
</TestableReference>
|
</TestableReference>
|
||||||
</Testables>
|
</Testables>
|
||||||
</TestAction>
|
</TestAction>
|
||||||
<LaunchAction
|
<LaunchAction
|
||||||
buildConfiguration = "Debug"
|
buildConfiguration = "Debug"
|
||||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"
|
customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"
|
||||||
launchStyle = "0"
|
launchStyle = "0"
|
||||||
useCustomWorkingDirectory = "NO"
|
useCustomWorkingDirectory = "NO"
|
||||||
ignoresPersistentStateOnLaunch = "NO"
|
ignoresPersistentStateOnLaunch = "NO"
|
||||||
debugDocumentVersioning = "YES"
|
debugDocumentVersioning = "YES"
|
||||||
debugServiceExtension = "internal"
|
debugServiceExtension = "internal"
|
||||||
enableGPUValidationMode = "1"
|
enableGPUValidationMode = "1"
|
||||||
allowLocationSimulation = "YES">
|
allowLocationSimulation = "YES">
|
||||||
<BuildableProductRunnable
|
<BuildableProductRunnable
|
||||||
runnableDebuggingMode = "0">
|
runnableDebuggingMode = "0">
|
||||||
<BuildableReference
|
<BuildableReference
|
||||||
BuildableIdentifier = "primary"
|
BuildableIdentifier = "primary"
|
||||||
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
||||||
BuildableName = "Runner.app"
|
BuildableName = "Runner.app"
|
||||||
BlueprintName = "Runner"
|
BlueprintName = "Runner"
|
||||||
ReferencedContainer = "container:Runner.xcodeproj">
|
ReferencedContainer = "container:Runner.xcodeproj">
|
||||||
</BuildableReference>
|
</BuildableReference>
|
||||||
</BuildableProductRunnable>
|
</BuildableProductRunnable>
|
||||||
</LaunchAction>
|
</LaunchAction>
|
||||||
<ProfileAction
|
<ProfileAction
|
||||||
buildConfiguration = "Profile"
|
buildConfiguration = "Profile"
|
||||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||||
savedToolIdentifier = ""
|
savedToolIdentifier = ""
|
||||||
useCustomWorkingDirectory = "NO"
|
useCustomWorkingDirectory = "NO"
|
||||||
debugDocumentVersioning = "YES">
|
debugDocumentVersioning = "YES">
|
||||||
<BuildableProductRunnable
|
<BuildableProductRunnable
|
||||||
runnableDebuggingMode = "0">
|
runnableDebuggingMode = "0">
|
||||||
<BuildableReference
|
<BuildableReference
|
||||||
BuildableIdentifier = "primary"
|
BuildableIdentifier = "primary"
|
||||||
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
||||||
BuildableName = "Runner.app"
|
BuildableName = "Runner.app"
|
||||||
BlueprintName = "Runner"
|
BlueprintName = "Runner"
|
||||||
ReferencedContainer = "container:Runner.xcodeproj">
|
ReferencedContainer = "container:Runner.xcodeproj">
|
||||||
</BuildableReference>
|
</BuildableReference>
|
||||||
</BuildableProductRunnable>
|
</BuildableProductRunnable>
|
||||||
</ProfileAction>
|
</ProfileAction>
|
||||||
<AnalyzeAction
|
<AnalyzeAction
|
||||||
buildConfiguration = "Debug">
|
buildConfiguration = "Debug">
|
||||||
</AnalyzeAction>
|
</AnalyzeAction>
|
||||||
<ArchiveAction
|
<ArchiveAction
|
||||||
buildConfiguration = "Release"
|
buildConfiguration = "Release"
|
||||||
revealArchiveInOrganizer = "YES">
|
revealArchiveInOrganizer = "YES">
|
||||||
</ArchiveAction>
|
</ArchiveAction>
|
||||||
</Scheme>
|
</Scheme>
|
||||||
|
|||||||
+7
-7
@@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<Workspace
|
<Workspace
|
||||||
version = "1.0">
|
version = "1.0">
|
||||||
<FileRef
|
<FileRef
|
||||||
location = "group:Runner.xcodeproj">
|
location = "group:Runner.xcodeproj">
|
||||||
</FileRef>
|
</FileRef>
|
||||||
</Workspace>
|
</Workspace>
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict>
|
<dict>
|
||||||
<key>IDEDidComputeMac32BitWarning</key>
|
<key>IDEDidComputeMac32BitWarning</key>
|
||||||
<true/>
|
<true/>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict>
|
<dict>
|
||||||
<key>PreviewsEnabled</key>
|
<key>PreviewsEnabled</key>
|
||||||
<false/>
|
<false/>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
import Flutter
|
import Flutter
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
@main
|
@main
|
||||||
@objc class AppDelegate: FlutterAppDelegate, FlutterImplicitEngineDelegate {
|
@objc class AppDelegate: FlutterAppDelegate, FlutterImplicitEngineDelegate {
|
||||||
override func application(
|
override func application(
|
||||||
_ application: UIApplication,
|
_ application: UIApplication,
|
||||||
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
|
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
|
||||||
) -> Bool {
|
) -> Bool {
|
||||||
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
|
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
|
||||||
}
|
}
|
||||||
|
|
||||||
func didInitializeImplicitFlutterEngine(_ engineBridge: FlutterImplicitEngineBridge) {
|
func didInitializeImplicitFlutterEngine(_ engineBridge: FlutterImplicitEngineBridge) {
|
||||||
GeneratedPluginRegistrant.register(with: engineBridge.pluginRegistry)
|
GeneratedPluginRegistrant.register(with: engineBridge.pluginRegistry)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,122 +1,122 @@
|
|||||||
{
|
{
|
||||||
"images" : [
|
"images" : [
|
||||||
{
|
{
|
||||||
"size" : "20x20",
|
"size" : "20x20",
|
||||||
"idiom" : "iphone",
|
"idiom" : "iphone",
|
||||||
"filename" : "Icon-App-20x20@2x.png",
|
"filename" : "Icon-App-20x20@2x.png",
|
||||||
"scale" : "2x"
|
"scale" : "2x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"size" : "20x20",
|
"size" : "20x20",
|
||||||
"idiom" : "iphone",
|
"idiom" : "iphone",
|
||||||
"filename" : "Icon-App-20x20@3x.png",
|
"filename" : "Icon-App-20x20@3x.png",
|
||||||
"scale" : "3x"
|
"scale" : "3x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"size" : "29x29",
|
"size" : "29x29",
|
||||||
"idiom" : "iphone",
|
"idiom" : "iphone",
|
||||||
"filename" : "Icon-App-29x29@1x.png",
|
"filename" : "Icon-App-29x29@1x.png",
|
||||||
"scale" : "1x"
|
"scale" : "1x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"size" : "29x29",
|
"size" : "29x29",
|
||||||
"idiom" : "iphone",
|
"idiom" : "iphone",
|
||||||
"filename" : "Icon-App-29x29@2x.png",
|
"filename" : "Icon-App-29x29@2x.png",
|
||||||
"scale" : "2x"
|
"scale" : "2x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"size" : "29x29",
|
"size" : "29x29",
|
||||||
"idiom" : "iphone",
|
"idiom" : "iphone",
|
||||||
"filename" : "Icon-App-29x29@3x.png",
|
"filename" : "Icon-App-29x29@3x.png",
|
||||||
"scale" : "3x"
|
"scale" : "3x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"size" : "40x40",
|
"size" : "40x40",
|
||||||
"idiom" : "iphone",
|
"idiom" : "iphone",
|
||||||
"filename" : "Icon-App-40x40@2x.png",
|
"filename" : "Icon-App-40x40@2x.png",
|
||||||
"scale" : "2x"
|
"scale" : "2x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"size" : "40x40",
|
"size" : "40x40",
|
||||||
"idiom" : "iphone",
|
"idiom" : "iphone",
|
||||||
"filename" : "Icon-App-40x40@3x.png",
|
"filename" : "Icon-App-40x40@3x.png",
|
||||||
"scale" : "3x"
|
"scale" : "3x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"size" : "60x60",
|
"size" : "60x60",
|
||||||
"idiom" : "iphone",
|
"idiom" : "iphone",
|
||||||
"filename" : "Icon-App-60x60@2x.png",
|
"filename" : "Icon-App-60x60@2x.png",
|
||||||
"scale" : "2x"
|
"scale" : "2x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"size" : "60x60",
|
"size" : "60x60",
|
||||||
"idiom" : "iphone",
|
"idiom" : "iphone",
|
||||||
"filename" : "Icon-App-60x60@3x.png",
|
"filename" : "Icon-App-60x60@3x.png",
|
||||||
"scale" : "3x"
|
"scale" : "3x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"size" : "20x20",
|
"size" : "20x20",
|
||||||
"idiom" : "ipad",
|
"idiom" : "ipad",
|
||||||
"filename" : "Icon-App-20x20@1x.png",
|
"filename" : "Icon-App-20x20@1x.png",
|
||||||
"scale" : "1x"
|
"scale" : "1x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"size" : "20x20",
|
"size" : "20x20",
|
||||||
"idiom" : "ipad",
|
"idiom" : "ipad",
|
||||||
"filename" : "Icon-App-20x20@2x.png",
|
"filename" : "Icon-App-20x20@2x.png",
|
||||||
"scale" : "2x"
|
"scale" : "2x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"size" : "29x29",
|
"size" : "29x29",
|
||||||
"idiom" : "ipad",
|
"idiom" : "ipad",
|
||||||
"filename" : "Icon-App-29x29@1x.png",
|
"filename" : "Icon-App-29x29@1x.png",
|
||||||
"scale" : "1x"
|
"scale" : "1x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"size" : "29x29",
|
"size" : "29x29",
|
||||||
"idiom" : "ipad",
|
"idiom" : "ipad",
|
||||||
"filename" : "Icon-App-29x29@2x.png",
|
"filename" : "Icon-App-29x29@2x.png",
|
||||||
"scale" : "2x"
|
"scale" : "2x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"size" : "40x40",
|
"size" : "40x40",
|
||||||
"idiom" : "ipad",
|
"idiom" : "ipad",
|
||||||
"filename" : "Icon-App-40x40@1x.png",
|
"filename" : "Icon-App-40x40@1x.png",
|
||||||
"scale" : "1x"
|
"scale" : "1x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"size" : "40x40",
|
"size" : "40x40",
|
||||||
"idiom" : "ipad",
|
"idiom" : "ipad",
|
||||||
"filename" : "Icon-App-40x40@2x.png",
|
"filename" : "Icon-App-40x40@2x.png",
|
||||||
"scale" : "2x"
|
"scale" : "2x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"size" : "76x76",
|
"size" : "76x76",
|
||||||
"idiom" : "ipad",
|
"idiom" : "ipad",
|
||||||
"filename" : "Icon-App-76x76@1x.png",
|
"filename" : "Icon-App-76x76@1x.png",
|
||||||
"scale" : "1x"
|
"scale" : "1x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"size" : "76x76",
|
"size" : "76x76",
|
||||||
"idiom" : "ipad",
|
"idiom" : "ipad",
|
||||||
"filename" : "Icon-App-76x76@2x.png",
|
"filename" : "Icon-App-76x76@2x.png",
|
||||||
"scale" : "2x"
|
"scale" : "2x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"size" : "83.5x83.5",
|
"size" : "83.5x83.5",
|
||||||
"idiom" : "ipad",
|
"idiom" : "ipad",
|
||||||
"filename" : "Icon-App-83.5x83.5@2x.png",
|
"filename" : "Icon-App-83.5x83.5@2x.png",
|
||||||
"scale" : "2x"
|
"scale" : "2x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"size" : "1024x1024",
|
"size" : "1024x1024",
|
||||||
"idiom" : "ios-marketing",
|
"idiom" : "ios-marketing",
|
||||||
"filename" : "Icon-App-1024x1024@1x.png",
|
"filename" : "Icon-App-1024x1024@1x.png",
|
||||||
"scale" : "1x"
|
"scale" : "1x"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"info" : {
|
"info" : {
|
||||||
"version" : 1,
|
"version" : 1,
|
||||||
"author" : "xcode"
|
"author" : "xcode"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,23 +1,23 @@
|
|||||||
{
|
{
|
||||||
"images" : [
|
"images" : [
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"filename" : "LaunchImage.png",
|
"filename" : "LaunchImage.png",
|
||||||
"scale" : "1x"
|
"scale" : "1x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"filename" : "LaunchImage@2x.png",
|
"filename" : "LaunchImage@2x.png",
|
||||||
"scale" : "2x"
|
"scale" : "2x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"filename" : "LaunchImage@3x.png",
|
"filename" : "LaunchImage@3x.png",
|
||||||
"scale" : "3x"
|
"scale" : "3x"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"info" : {
|
"info" : {
|
||||||
"version" : 1,
|
"version" : 1,
|
||||||
"author" : "xcode"
|
"author" : "xcode"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Launch Screen Assets
|
# Launch Screen Assets
|
||||||
|
|
||||||
You can customize the launch screen with your own desired assets by replacing the image files in this directory.
|
You can customize the launch screen with your own desired assets by replacing the image files in this directory.
|
||||||
|
|
||||||
You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
|
You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
|
||||||
@@ -1,37 +1,37 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12121" systemVersion="16G29" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12121" systemVersion="16G29" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<deployment identifier="iOS"/>
|
<deployment identifier="iOS"/>
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/>
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<scenes>
|
<scenes>
|
||||||
<!--View Controller-->
|
<!--View Controller-->
|
||||||
<scene sceneID="EHf-IW-A2E">
|
<scene sceneID="EHf-IW-A2E">
|
||||||
<objects>
|
<objects>
|
||||||
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
|
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
|
||||||
<layoutGuides>
|
<layoutGuides>
|
||||||
<viewControllerLayoutGuide type="top" id="Ydg-fD-yQy"/>
|
<viewControllerLayoutGuide type="top" id="Ydg-fD-yQy"/>
|
||||||
<viewControllerLayoutGuide type="bottom" id="xbc-2k-c8Z"/>
|
<viewControllerLayoutGuide type="bottom" id="xbc-2k-c8Z"/>
|
||||||
</layoutGuides>
|
</layoutGuides>
|
||||||
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
|
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" image="LaunchImage" translatesAutoresizingMaskIntoConstraints="NO" id="YRO-k0-Ey4">
|
<imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" image="LaunchImage" translatesAutoresizingMaskIntoConstraints="NO" id="YRO-k0-Ey4">
|
||||||
</imageView>
|
</imageView>
|
||||||
</subviews>
|
</subviews>
|
||||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerX" secondItem="Ze5-6b-2t3" secondAttribute="centerX" id="1a2-6s-vTC"/>
|
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerX" secondItem="Ze5-6b-2t3" secondAttribute="centerX" id="1a2-6s-vTC"/>
|
||||||
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="centerY" id="4X2-HB-R7a"/>
|
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="centerY" id="4X2-HB-R7a"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
</view>
|
</view>
|
||||||
</viewController>
|
</viewController>
|
||||||
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||||
</objects>
|
</objects>
|
||||||
<point key="canvasLocation" x="53" y="375"/>
|
<point key="canvasLocation" x="53" y="375"/>
|
||||||
</scene>
|
</scene>
|
||||||
</scenes>
|
</scenes>
|
||||||
<resources>
|
<resources>
|
||||||
<image name="LaunchImage" width="168" height="185"/>
|
<image name="LaunchImage" width="168" height="185"/>
|
||||||
</resources>
|
</resources>
|
||||||
</document>
|
</document>
|
||||||
|
|||||||
@@ -1,26 +1,26 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<deployment identifier="iOS"/>
|
<deployment identifier="iOS"/>
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<scenes>
|
<scenes>
|
||||||
<!--Flutter View Controller-->
|
<!--Flutter View Controller-->
|
||||||
<scene sceneID="tne-QT-ifu">
|
<scene sceneID="tne-QT-ifu">
|
||||||
<objects>
|
<objects>
|
||||||
<viewController id="BYZ-38-t0r" customClass="FlutterViewController" sceneMemberID="viewController">
|
<viewController id="BYZ-38-t0r" customClass="FlutterViewController" sceneMemberID="viewController">
|
||||||
<layoutGuides>
|
<layoutGuides>
|
||||||
<viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
|
<viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
|
||||||
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
|
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
|
||||||
</layoutGuides>
|
</layoutGuides>
|
||||||
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
|
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
|
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
|
||||||
</view>
|
</view>
|
||||||
</viewController>
|
</viewController>
|
||||||
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
|
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
|
||||||
</objects>
|
</objects>
|
||||||
</scene>
|
</scene>
|
||||||
</scenes>
|
</scenes>
|
||||||
</document>
|
</document>
|
||||||
|
|||||||
@@ -1,70 +1,70 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict>
|
<dict>
|
||||||
<key>CADisableMinimumFrameDurationOnPhone</key>
|
<key>CADisableMinimumFrameDurationOnPhone</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>CFBundleDevelopmentRegion</key>
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||||
<key>CFBundleDisplayName</key>
|
<key>CFBundleDisplayName</key>
|
||||||
<string>Mobile</string>
|
<string>Mobile</string>
|
||||||
<key>CFBundleExecutable</key>
|
<key>CFBundleExecutable</key>
|
||||||
<string>$(EXECUTABLE_NAME)</string>
|
<string>$(EXECUTABLE_NAME)</string>
|
||||||
<key>CFBundleIdentifier</key>
|
<key>CFBundleIdentifier</key>
|
||||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||||
<key>CFBundleInfoDictionaryVersion</key>
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
<string>6.0</string>
|
<string>6.0</string>
|
||||||
<key>CFBundleName</key>
|
<key>CFBundleName</key>
|
||||||
<string>mobile</string>
|
<string>mobile</string>
|
||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>APPL</string>
|
<string>APPL</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>$(FLUTTER_BUILD_NAME)</string>
|
<string>$(FLUTTER_BUILD_NAME)</string>
|
||||||
<key>CFBundleSignature</key>
|
<key>CFBundleSignature</key>
|
||||||
<string>????</string>
|
<string>????</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>$(FLUTTER_BUILD_NUMBER)</string>
|
<string>$(FLUTTER_BUILD_NUMBER)</string>
|
||||||
<key>LSRequiresIPhoneOS</key>
|
<key>LSRequiresIPhoneOS</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>UIApplicationSceneManifest</key>
|
<key>UIApplicationSceneManifest</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>UIApplicationSupportsMultipleScenes</key>
|
<key>UIApplicationSupportsMultipleScenes</key>
|
||||||
<false/>
|
<false/>
|
||||||
<key>UISceneConfigurations</key>
|
<key>UISceneConfigurations</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>UIWindowSceneSessionRoleApplication</key>
|
<key>UIWindowSceneSessionRoleApplication</key>
|
||||||
<array>
|
<array>
|
||||||
<dict>
|
<dict>
|
||||||
<key>UISceneClassName</key>
|
<key>UISceneClassName</key>
|
||||||
<string>UIWindowScene</string>
|
<string>UIWindowScene</string>
|
||||||
<key>UISceneConfigurationName</key>
|
<key>UISceneConfigurationName</key>
|
||||||
<string>flutter</string>
|
<string>flutter</string>
|
||||||
<key>UISceneDelegateClassName</key>
|
<key>UISceneDelegateClassName</key>
|
||||||
<string>$(PRODUCT_MODULE_NAME).SceneDelegate</string>
|
<string>$(PRODUCT_MODULE_NAME).SceneDelegate</string>
|
||||||
<key>UISceneStoryboardFile</key>
|
<key>UISceneStoryboardFile</key>
|
||||||
<string>Main</string>
|
<string>Main</string>
|
||||||
</dict>
|
</dict>
|
||||||
</array>
|
</array>
|
||||||
</dict>
|
</dict>
|
||||||
</dict>
|
</dict>
|
||||||
<key>UIApplicationSupportsIndirectInputEvents</key>
|
<key>UIApplicationSupportsIndirectInputEvents</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>UILaunchStoryboardName</key>
|
<key>UILaunchStoryboardName</key>
|
||||||
<string>LaunchScreen</string>
|
<string>LaunchScreen</string>
|
||||||
<key>UIMainStoryboardFile</key>
|
<key>UIMainStoryboardFile</key>
|
||||||
<string>Main</string>
|
<string>Main</string>
|
||||||
<key>UISupportedInterfaceOrientations</key>
|
<key>UISupportedInterfaceOrientations</key>
|
||||||
<array>
|
<array>
|
||||||
<string>UIInterfaceOrientationPortrait</string>
|
<string>UIInterfaceOrientationPortrait</string>
|
||||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||||
</array>
|
</array>
|
||||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||||
<array>
|
<array>
|
||||||
<string>UIInterfaceOrientationPortrait</string>
|
<string>UIInterfaceOrientationPortrait</string>
|
||||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||||
</array>
|
</array>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
#import "GeneratedPluginRegistrant.h"
|
#import "GeneratedPluginRegistrant.h"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import Flutter
|
import Flutter
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
class SceneDelegate: FlutterSceneDelegate {
|
class SceneDelegate: FlutterSceneDelegate {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import Flutter
|
import Flutter
|
||||||
import UIKit
|
import UIKit
|
||||||
import XCTest
|
import XCTest
|
||||||
|
|
||||||
class RunnerTests: XCTestCase {
|
class RunnerTests: XCTestCase {
|
||||||
|
|
||||||
func testExample() {
|
func testExample() {
|
||||||
// If you add code to the Runner application, consider adding tests here.
|
// If you add code to the Runner application, consider adding tests here.
|
||||||
// See https://developer.apple.com/documentation/xctest for more information about using XCTest.
|
// See https://developer.apple.com/documentation/xctest for more information about using XCTest.
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,44 +1,44 @@
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
import 'package:dio/io.dart';
|
import 'package:dio/io.dart';
|
||||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||||
|
|
||||||
class DioClient {
|
class DioClient {
|
||||||
final Dio _dio = Dio();
|
final Dio _dio = Dio();
|
||||||
final FlutterSecureStorage _storage = const FlutterSecureStorage();
|
final FlutterSecureStorage _storage = const FlutterSecureStorage();
|
||||||
|
|
||||||
DioClient() {
|
DioClient() {
|
||||||
// On enlève le slash final ici
|
// On enlève le slash final ici
|
||||||
_dio.options.baseUrl = "https://apicesizen.sam-coffre.duckdns.org/api";
|
_dio.options.baseUrl = "https://apicesizen.sam-coffre.duckdns.org/api";
|
||||||
_dio.options.connectTimeout = const Duration(seconds: 10);
|
_dio.options.connectTimeout = const Duration(seconds: 10);
|
||||||
_dio.options.receiveTimeout = const Duration(seconds: 10);
|
_dio.options.receiveTimeout = const Duration(seconds: 10);
|
||||||
_dio.options.headers = {
|
_dio.options.headers = {
|
||||||
'Accept': 'application/json',
|
'Accept': 'application/json',
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
};
|
};
|
||||||
|
|
||||||
// Bypass SSL pour éviter l'erreur "unknown" sur certains certificats DuckDNS/Let's Encrypt
|
// Bypass SSL pour éviter l'erreur "unknown" sur certains certificats DuckDNS/Let's Encrypt
|
||||||
_dio.httpClientAdapter = IOHttpClientAdapter(
|
_dio.httpClientAdapter = IOHttpClientAdapter(
|
||||||
createHttpClient: () {
|
createHttpClient: () {
|
||||||
final client = HttpClient();
|
final client = HttpClient();
|
||||||
client.badCertificateCallback = (X509Certificate cert, String host, int port) => true;
|
client.badCertificateCallback = (X509Certificate cert, String host, int port) => true;
|
||||||
return client;
|
return client;
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
_dio.interceptors.add(InterceptorsWrapper(
|
_dio.interceptors.add(InterceptorsWrapper(
|
||||||
onRequest: (options, handler) async {
|
onRequest: (options, handler) async {
|
||||||
String? token = await _storage.read(key: 'token');
|
String? token = await _storage.read(key: 'token');
|
||||||
if (token != null) {
|
if (token != null) {
|
||||||
options.headers['Authorization'] = 'Bearer $token';
|
options.headers['Authorization'] = 'Bearer $token';
|
||||||
}
|
}
|
||||||
return handler.next(options);
|
return handler.next(options);
|
||||||
},
|
},
|
||||||
onError: (DioException e, handler) {
|
onError: (DioException e, handler) {
|
||||||
return handler.next(e);
|
return handler.next(e);
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
Dio get dio => _dio;
|
Dio get dio => _dio;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,27 +1,27 @@
|
|||||||
class User {
|
class User {
|
||||||
final int id;
|
final int id;
|
||||||
final String name;
|
final String name;
|
||||||
final String email;
|
final String email;
|
||||||
|
|
||||||
User({
|
User({
|
||||||
required this.id,
|
required this.id,
|
||||||
required this.name,
|
required this.name,
|
||||||
required this.email,
|
required this.email,
|
||||||
});
|
});
|
||||||
|
|
||||||
factory User.fromJson(Map<String, dynamic> json) {
|
factory User.fromJson(Map<String, dynamic> json) {
|
||||||
return User(
|
return User(
|
||||||
id: json['id'],
|
id: json['id'],
|
||||||
name: json['name'],
|
name: json['name'],
|
||||||
email: json['email'],
|
email: json['email'],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() {
|
||||||
return {
|
return {
|
||||||
'id': id,
|
'id': id,
|
||||||
'name': name,
|
'name': name,
|
||||||
'email': email,
|
'email': email,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,127 +1,127 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import '../models/user.dart';
|
import '../models/user.dart';
|
||||||
import '../services/auth_service.dart';
|
import '../services/auth_service.dart';
|
||||||
|
|
||||||
class AuthProvider with ChangeNotifier {
|
class AuthProvider with ChangeNotifier {
|
||||||
final AuthService _authService = AuthService();
|
final AuthService _authService = AuthService();
|
||||||
static const _platform = MethodChannel('com.cesizen/wearable');
|
static const _platform = MethodChannel('com.cesizen/wearable');
|
||||||
|
|
||||||
User? _user;
|
User? _user;
|
||||||
bool _isLoading = false;
|
bool _isLoading = false;
|
||||||
String? _errorMessage;
|
String? _errorMessage;
|
||||||
|
|
||||||
AuthProvider() {
|
AuthProvider() {
|
||||||
// Écouter les demandes de mise à jour venant de la couche native (montre -> téléphone)
|
// Écouter les demandes de mise à jour venant de la couche native (montre -> téléphone)
|
||||||
_platform.setMethodCallHandler((call) async {
|
_platform.setMethodCallHandler((call) async {
|
||||||
if (call.method == "requestStatusUpdate") {
|
if (call.method == "requestStatusUpdate") {
|
||||||
_syncWithWear();
|
_syncWithWear();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Tenter de restaurer la session au lancement
|
// Tenter de restaurer la session au lancement
|
||||||
_checkInitialAuth();
|
_checkInitialAuth();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _checkInitialAuth() async {
|
Future<void> _checkInitialAuth() async {
|
||||||
_isLoading = true;
|
_isLoading = true;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
|
|
||||||
final result = await _authService.getProfile();
|
final result = await _authService.getProfile();
|
||||||
if (result['status'] == 'success') {
|
if (result['status'] == 'success') {
|
||||||
_user = result['user'];
|
_user = result['user'];
|
||||||
_syncWithWear();
|
_syncWithWear();
|
||||||
}
|
}
|
||||||
|
|
||||||
_isLoading = false;
|
_isLoading = false;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
User? get user => _user;
|
User? get user => _user;
|
||||||
bool get isLoading => _isLoading;
|
bool get isLoading => _isLoading;
|
||||||
String? get errorMessage => _errorMessage;
|
String? get errorMessage => _errorMessage;
|
||||||
bool get isAuthenticated => _user != null;
|
bool get isAuthenticated => _user != null;
|
||||||
|
|
||||||
void _syncWithWear() {
|
void _syncWithWear() {
|
||||||
try {
|
try {
|
||||||
_platform.invokeMethod('sendAuthStatus', {
|
_platform.invokeMethod('sendAuthStatus', {
|
||||||
'status': isAuthenticated ? 'authenticated' : 'unauthenticated',
|
'status': isAuthenticated ? 'authenticated' : 'unauthenticated',
|
||||||
'userName': _user?.name ?? '',
|
'userName': _user?.name ?? '',
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Échec silencieux si pas d'appareil Wear OS à proximité
|
// Échec silencieux si pas d'appareil Wear OS à proximité
|
||||||
debugPrint("Wear OS sync failed: $e");
|
debugPrint("Wear OS sync failed: $e");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> login(String email, String password) async {
|
Future<bool> login(String email, String password) async {
|
||||||
_isLoading = true;
|
_isLoading = true;
|
||||||
_errorMessage = null;
|
_errorMessage = null;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
|
|
||||||
final result = await _authService.login(email, password);
|
final result = await _authService.login(email, password);
|
||||||
|
|
||||||
_isLoading = false;
|
_isLoading = false;
|
||||||
if (result['status'] == 'success') {
|
if (result['status'] == 'success') {
|
||||||
_user = result['user'];
|
_user = result['user'];
|
||||||
_syncWithWear();
|
_syncWithWear();
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
_errorMessage = result['message'];
|
_errorMessage = result['message'];
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> register(String name, String email, String password, String passwordConfirmation) async {
|
Future<bool> register(String name, String email, String password, String passwordConfirmation) async {
|
||||||
_isLoading = true;
|
_isLoading = true;
|
||||||
_errorMessage = null;
|
_errorMessage = null;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
|
|
||||||
final result = await _authService.register(name, email, password, passwordConfirmation);
|
final result = await _authService.register(name, email, password, passwordConfirmation);
|
||||||
|
|
||||||
_isLoading = false;
|
_isLoading = false;
|
||||||
if (result['status'] == 'success') {
|
if (result['status'] == 'success') {
|
||||||
_user = result['user'];
|
_user = result['user'];
|
||||||
_syncWithWear();
|
_syncWithWear();
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
if (result['errors'] is Map) {
|
if (result['errors'] is Map) {
|
||||||
_errorMessage = (result['errors'] as Map).values.first[0];
|
_errorMessage = (result['errors'] as Map).values.first[0];
|
||||||
} else {
|
} else {
|
||||||
_errorMessage = result['errors'].toString();
|
_errorMessage = result['errors'].toString();
|
||||||
}
|
}
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> logout() async {
|
Future<void> logout() async {
|
||||||
await _authService.logout();
|
await _authService.logout();
|
||||||
_user = null;
|
_user = null;
|
||||||
_syncWithWear();
|
_syncWithWear();
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> updateProfile(String name, String email, {String? password}) async {
|
Future<bool> updateProfile(String name, String email, {String? password}) async {
|
||||||
_isLoading = true;
|
_isLoading = true;
|
||||||
_errorMessage = null;
|
_errorMessage = null;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
|
|
||||||
final result = await _authService.updateProfile(name, email, password: password);
|
final result = await _authService.updateProfile(name, email, password: password);
|
||||||
|
|
||||||
_isLoading = false;
|
_isLoading = false;
|
||||||
if (result['status'] == 'success') {
|
if (result['status'] == 'success') {
|
||||||
_user = result['user'];
|
_user = result['user'];
|
||||||
_syncWithWear();
|
_syncWithWear();
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
_errorMessage = result['message'];
|
_errorMessage = result['message'];
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,124 +1,124 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import '../providers/auth_provider.dart';
|
import '../providers/auth_provider.dart';
|
||||||
import 'register_screen.dart';
|
import 'register_screen.dart';
|
||||||
|
|
||||||
class LoginScreen extends StatefulWidget {
|
class LoginScreen extends StatefulWidget {
|
||||||
const LoginScreen({super.key});
|
const LoginScreen({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<LoginScreen> createState() => _LoginScreenState();
|
State<LoginScreen> createState() => _LoginScreenState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _LoginScreenState extends State<LoginScreen> {
|
class _LoginScreenState extends State<LoginScreen> {
|
||||||
final _formKey = GlobalKey<FormState>();
|
final _formKey = GlobalKey<FormState>();
|
||||||
final _emailController = TextEditingController();
|
final _emailController = TextEditingController();
|
||||||
final _passwordController = TextEditingController();
|
final _passwordController = TextEditingController();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
_emailController.dispose();
|
_emailController.dispose();
|
||||||
_passwordController.dispose();
|
_passwordController.dispose();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
void _login() async {
|
void _login() async {
|
||||||
if (_formKey.currentState!.validate()) {
|
if (_formKey.currentState!.validate()) {
|
||||||
final authProvider = Provider.of<AuthProvider>(context, listen: false);
|
final authProvider = Provider.of<AuthProvider>(context, listen: false);
|
||||||
final success = await authProvider.login(
|
final success = await authProvider.login(
|
||||||
_emailController.text,
|
_emailController.text,
|
||||||
_passwordController.text,
|
_passwordController.text,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
// Rediriger vers l'accueil ou le dashboard
|
// Rediriger vers l'accueil ou le dashboard
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
const SnackBar(content: Text('Connexion réussie')),
|
const SnackBar(content: Text('Connexion réussie')),
|
||||||
);
|
);
|
||||||
Navigator.of(context).pop(); // Retourne à l'écran précédent (HomeScreen)
|
Navigator.of(context).pop(); // Retourne à l'écran précédent (HomeScreen)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
SnackBar(content: Text(authProvider.errorMessage ?? 'Échec de la connexion')),
|
SnackBar(content: Text(authProvider.errorMessage ?? 'Échec de la connexion')),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(title: const Text('Connexion CESIZen')),
|
appBar: AppBar(title: const Text('Connexion CESIZen')),
|
||||||
body: Padding(
|
body: Padding(
|
||||||
padding: const EdgeInsets.all(16.0),
|
padding: const EdgeInsets.all(16.0),
|
||||||
child: Form(
|
child: Form(
|
||||||
key: _formKey,
|
key: _formKey,
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
const Text(
|
const Text(
|
||||||
'Bienvenue sur CESIZen',
|
'Bienvenue sur CESIZen',
|
||||||
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
|
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 32),
|
const SizedBox(height: 32),
|
||||||
TextFormField(
|
TextFormField(
|
||||||
controller: _emailController,
|
controller: _emailController,
|
||||||
decoration: const InputDecoration(
|
decoration: const InputDecoration(
|
||||||
labelText: 'Email',
|
labelText: 'Email',
|
||||||
border: OutlineInputBorder(),
|
border: OutlineInputBorder(),
|
||||||
prefixIcon: Icon(Icons.email),
|
prefixIcon: Icon(Icons.email),
|
||||||
),
|
),
|
||||||
keyboardType: TextInputType.emailAddress,
|
keyboardType: TextInputType.emailAddress,
|
||||||
validator: (value) {
|
validator: (value) {
|
||||||
if (value == null || value.isEmpty) return 'Veuillez entrer votre email';
|
if (value == null || value.isEmpty) return 'Veuillez entrer votre email';
|
||||||
if (!value.contains('@')) return 'Email invalide';
|
if (!value.contains('@')) return 'Email invalide';
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
TextFormField(
|
TextFormField(
|
||||||
controller: _passwordController,
|
controller: _passwordController,
|
||||||
decoration: const InputDecoration(
|
decoration: const InputDecoration(
|
||||||
labelText: 'Mot de passe',
|
labelText: 'Mot de passe',
|
||||||
border: OutlineInputBorder(),
|
border: OutlineInputBorder(),
|
||||||
prefixIcon: Icon(Icons.lock),
|
prefixIcon: Icon(Icons.lock),
|
||||||
),
|
),
|
||||||
obscureText: true,
|
obscureText: true,
|
||||||
validator: (value) {
|
validator: (value) {
|
||||||
if (value == null || value.isEmpty) return 'Veuillez entrer votre mot de passe';
|
if (value == null || value.isEmpty) return 'Veuillez entrer votre mot de passe';
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
const SizedBox(height: 24),
|
const SizedBox(height: 24),
|
||||||
Consumer<AuthProvider>(
|
Consumer<AuthProvider>(
|
||||||
builder: (context, auth, child) {
|
builder: (context, auth, child) {
|
||||||
return auth.isLoading
|
return auth.isLoading
|
||||||
? const CircularProgressIndicator()
|
? const CircularProgressIndicator()
|
||||||
: ElevatedButton(
|
: ElevatedButton(
|
||||||
onPressed: _login,
|
onPressed: _login,
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
minimumSize: const Size.fromHeight(50),
|
minimumSize: const Size.fromHeight(50),
|
||||||
),
|
),
|
||||||
child: const Text('Se connecter'),
|
child: const Text('Se connecter'),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.push(
|
Navigator.push(
|
||||||
context,
|
context,
|
||||||
MaterialPageRoute(builder: (context) => const RegisterScreen()),
|
MaterialPageRoute(builder: (context) => const RegisterScreen()),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
child: const Text("Pas encore de compte ? S'inscrire"),
|
child: const Text("Pas encore de compte ? S'inscrire"),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,267 +1,267 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import '../providers/auth_provider.dart';
|
import '../providers/auth_provider.dart';
|
||||||
import '../../tracker/providers/emotion_provider.dart';
|
import '../../tracker/providers/emotion_provider.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
|
|
||||||
class ProfileScreen extends StatefulWidget {
|
class ProfileScreen extends StatefulWidget {
|
||||||
const ProfileScreen({super.key});
|
const ProfileScreen({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<ProfileScreen> createState() => _ProfileScreenState();
|
State<ProfileScreen> createState() => _ProfileScreenState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _ProfileScreenState extends State<ProfileScreen> {
|
class _ProfileScreenState extends State<ProfileScreen> {
|
||||||
final _formKey = GlobalKey<FormState>();
|
final _formKey = GlobalKey<FormState>();
|
||||||
late TextEditingController _nameController;
|
late TextEditingController _nameController;
|
||||||
late TextEditingController _emailController;
|
late TextEditingController _emailController;
|
||||||
late TextEditingController _passwordController;
|
late TextEditingController _passwordController;
|
||||||
late String _currentEmail;
|
late String _currentEmail;
|
||||||
bool _isEditing = false;
|
bool _isEditing = false;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
final user = Provider.of<AuthProvider>(context, listen: false).user;
|
final user = Provider.of<AuthProvider>(context, listen: false).user;
|
||||||
_currentEmail = user?.email ?? '';
|
_currentEmail = user?.email ?? '';
|
||||||
_nameController = TextEditingController(text: user?.name);
|
_nameController = TextEditingController(text: user?.name);
|
||||||
_emailController = TextEditingController(text: _currentEmail);
|
_emailController = TextEditingController(text: _currentEmail);
|
||||||
_passwordController = TextEditingController();
|
_passwordController = TextEditingController();
|
||||||
|
|
||||||
_emailController.addListener(() {
|
_emailController.addListener(() {
|
||||||
if (mounted) setState(() {});
|
if (mounted) setState(() {});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Charger les émotions pour le journal
|
// Charger les émotions pour le journal
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
Provider.of<EmotionProvider>(context, listen: false).loadEmotions();
|
Provider.of<EmotionProvider>(context, listen: false).loadEmotions();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
_nameController.dispose();
|
_nameController.dispose();
|
||||||
_emailController.dispose();
|
_emailController.dispose();
|
||||||
_passwordController.dispose();
|
_passwordController.dispose();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
void _submitUpdate() async {
|
void _submitUpdate() async {
|
||||||
if (_formKey.currentState!.validate()) {
|
if (_formKey.currentState!.validate()) {
|
||||||
final authProvider = Provider.of<AuthProvider>(context, listen: false);
|
final authProvider = Provider.of<AuthProvider>(context, listen: false);
|
||||||
|
|
||||||
final String newName = _nameController.text.trim();
|
final String newName = _nameController.text.trim();
|
||||||
final String newEmail = _emailController.text.trim();
|
final String newEmail = _emailController.text.trim();
|
||||||
final String? newPassword = _passwordController.text.isNotEmpty ? _passwordController.text : null;
|
final String? newPassword = _passwordController.text.isNotEmpty ? _passwordController.text : null;
|
||||||
|
|
||||||
final success = await authProvider.updateProfile(
|
final success = await authProvider.updateProfile(
|
||||||
newName,
|
newName,
|
||||||
newEmail,
|
newEmail,
|
||||||
password: newPassword,
|
password: newPassword,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
if (success) {
|
if (success) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
const SnackBar(content: Text('Profil mis à jour avec succès')),
|
const SnackBar(content: Text('Profil mis à jour avec succès')),
|
||||||
);
|
);
|
||||||
setState(() {
|
setState(() {
|
||||||
_isEditing = false;
|
_isEditing = false;
|
||||||
_currentEmail = newEmail;
|
_currentEmail = newEmail;
|
||||||
_passwordController.clear();
|
_passwordController.clear();
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
SnackBar(content: Text(authProvider.errorMessage ?? 'Erreur lors de la mise à jour')),
|
SnackBar(content: Text(authProvider.errorMessage ?? 'Erreur lors de la mise à jour')),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final authProvider = Provider.of<AuthProvider>(context);
|
final authProvider = Provider.of<AuthProvider>(context);
|
||||||
final emotionProvider = Provider.of<EmotionProvider>(context);
|
final emotionProvider = Provider.of<EmotionProvider>(context);
|
||||||
final user = authProvider.user;
|
final user = authProvider.user;
|
||||||
final bool emailChanged = _emailController.text.trim() != _currentEmail.trim();
|
final bool emailChanged = _emailController.text.trim() != _currentEmail.trim();
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: const Text('Mon Espace Santé'),
|
title: const Text('Mon Espace Santé'),
|
||||||
backgroundColor: Colors.white,
|
backgroundColor: Colors.white,
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
actions: [
|
actions: [
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: Icon(_isEditing ? Icons.close : Icons.edit),
|
icon: Icon(_isEditing ? Icons.close : Icons.edit),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
setState(() {
|
setState(() {
|
||||||
_isEditing = !_isEditing;
|
_isEditing = !_isEditing;
|
||||||
if (!_isEditing) {
|
if (!_isEditing) {
|
||||||
_nameController.text = user?.name ?? '';
|
_nameController.text = user?.name ?? '';
|
||||||
_emailController.text = user?.email ?? '';
|
_emailController.text = user?.email ?? '';
|
||||||
_passwordController.clear();
|
_passwordController.clear();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
body: SingleChildScrollView(
|
body: SingleChildScrollView(
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
// Section Profil
|
// Section Profil
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(24.0),
|
padding: const EdgeInsets.all(24.0),
|
||||||
child: Form(
|
child: Form(
|
||||||
key: _formKey,
|
key: _formKey,
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
const CircleAvatar(
|
const CircleAvatar(
|
||||||
radius: 50,
|
radius: 50,
|
||||||
backgroundColor: Color(0xFF000080),
|
backgroundColor: Color(0xFF000080),
|
||||||
child: Icon(Icons.person, size: 50, color: Colors.white),
|
child: Icon(Icons.person, size: 50, color: Colors.white),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
TextFormField(
|
TextFormField(
|
||||||
controller: _nameController,
|
controller: _nameController,
|
||||||
enabled: _isEditing,
|
enabled: _isEditing,
|
||||||
decoration: const InputDecoration(
|
decoration: const InputDecoration(
|
||||||
labelText: 'Nom',
|
labelText: 'Nom',
|
||||||
prefixIcon: Icon(Icons.person_outline),
|
prefixIcon: Icon(Icons.person_outline),
|
||||||
border: OutlineInputBorder(),
|
border: OutlineInputBorder(),
|
||||||
),
|
),
|
||||||
validator: (value) => (value == null || value.trim().isEmpty) ? 'Veuillez entrer un nom' : null,
|
validator: (value) => (value == null || value.trim().isEmpty) ? 'Veuillez entrer un nom' : null,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 15),
|
const SizedBox(height: 15),
|
||||||
TextFormField(
|
TextFormField(
|
||||||
controller: _emailController,
|
controller: _emailController,
|
||||||
enabled: _isEditing,
|
enabled: _isEditing,
|
||||||
decoration: const InputDecoration(
|
decoration: const InputDecoration(
|
||||||
labelText: 'Email',
|
labelText: 'Email',
|
||||||
prefixIcon: Icon(Icons.email_outlined),
|
prefixIcon: Icon(Icons.email_outlined),
|
||||||
border: OutlineInputBorder(),
|
border: OutlineInputBorder(),
|
||||||
),
|
),
|
||||||
validator: (value) {
|
validator: (value) {
|
||||||
final email = value?.trim() ?? '';
|
final email = value?.trim() ?? '';
|
||||||
if (email.isEmpty) return 'Veuillez entrer un email';
|
if (email.isEmpty) return 'Veuillez entrer un email';
|
||||||
if (!email.contains('@')) return 'Email invalide';
|
if (!email.contains('@')) return 'Email invalide';
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
if (_isEditing) ...[
|
if (_isEditing) ...[
|
||||||
const SizedBox(height: 15),
|
const SizedBox(height: 15),
|
||||||
TextFormField(
|
TextFormField(
|
||||||
controller: _passwordController,
|
controller: _passwordController,
|
||||||
obscureText: true,
|
obscureText: true,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
labelText: emailChanged ? 'Mot de passe requis' : 'Nouveau mot de passe',
|
labelText: emailChanged ? 'Mot de passe requis' : 'Nouveau mot de passe',
|
||||||
prefixIcon: const Icon(Icons.lock_outline),
|
prefixIcon: const Icon(Icons.lock_outline),
|
||||||
border: const OutlineInputBorder(),
|
border: const OutlineInputBorder(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
onPressed: authProvider.isLoading ? null : _submitUpdate,
|
onPressed: authProvider.isLoading ? null : _submitUpdate,
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
backgroundColor: const Color(0xFF000080),
|
backgroundColor: const Color(0xFF000080),
|
||||||
foregroundColor: Colors.white,
|
foregroundColor: Colors.white,
|
||||||
minimumSize: const Size.fromHeight(50),
|
minimumSize: const Size.fromHeight(50),
|
||||||
),
|
),
|
||||||
child: const Text('ENREGISTRER'),
|
child: const Text('ENREGISTRER'),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
// Section Journal Émotionnel (Le "Journal Santé")
|
// Section Journal Émotionnel (Le "Journal Santé")
|
||||||
Container(
|
Container(
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16),
|
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 16),
|
||||||
color: Colors.grey.shade50,
|
color: Colors.grey.shade50,
|
||||||
child: const Column(
|
child: const Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'Journal Émotionnel',
|
'Journal Émotionnel',
|
||||||
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold, color: Color(0xFF000080)),
|
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold, color: Color(0xFF000080)),
|
||||||
),
|
),
|
||||||
Text('Historique de vos saisies (Mobile & Montre)', style: TextStyle(color: Colors.grey, fontSize: 12)),
|
Text('Historique de vos saisies (Mobile & Montre)', style: TextStyle(color: Colors.grey, fontSize: 12)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
if (emotionProvider.isLoading)
|
if (emotionProvider.isLoading)
|
||||||
const Padding(
|
const Padding(
|
||||||
padding: EdgeInsets.all(20.0),
|
padding: EdgeInsets.all(20.0),
|
||||||
child: CircularProgressIndicator(),
|
child: CircularProgressIndicator(),
|
||||||
)
|
)
|
||||||
else if (emotionProvider.entries.isEmpty)
|
else if (emotionProvider.entries.isEmpty)
|
||||||
const Padding(
|
const Padding(
|
||||||
padding: EdgeInsets.all(40.0),
|
padding: EdgeInsets.all(40.0),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
Icon(Icons.history, size: 48, color: Colors.grey),
|
Icon(Icons.history, size: 48, color: Colors.grey),
|
||||||
SizedBox(height: 10),
|
SizedBox(height: 10),
|
||||||
Text('Aucun historique pour le moment.', style: TextStyle(color: Colors.grey)),
|
Text('Aucun historique pour le moment.', style: TextStyle(color: Colors.grey)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
ListView.separated(
|
ListView.separated(
|
||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
itemCount: emotionProvider.entries.length,
|
itemCount: emotionProvider.entries.length,
|
||||||
separatorBuilder: (context, index) => const Divider(height: 1),
|
separatorBuilder: (context, index) => const Divider(height: 1),
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
final entry = emotionProvider.entries[index];
|
final entry = emotionProvider.entries[index];
|
||||||
final dateStr = DateFormat('dd/MM/yyyy HH:mm').format(entry.createdAt);
|
final dateStr = DateFormat('dd/MM/yyyy HH:mm').format(entry.createdAt);
|
||||||
return ListTile(
|
return ListTile(
|
||||||
leading: _getMoodEmoji(entry.emotion),
|
leading: _getMoodEmoji(entry.emotion),
|
||||||
title: Text(entry.emotion, style: const TextStyle(fontWeight: FontWeight.bold)),
|
title: Text(entry.emotion, style: const TextStyle(fontWeight: FontWeight.bold)),
|
||||||
subtitle: Text(entry.note ?? 'Saisie rapide'),
|
subtitle: Text(entry.note ?? 'Saisie rapide'),
|
||||||
trailing: Text(dateStr, style: const TextStyle(fontSize: 11, color: Colors.grey)),
|
trailing: Text(dateStr, style: const TextStyle(fontSize: 11, color: Colors.grey)),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|
||||||
const SizedBox(height: 100), // Espace pour le scroll
|
const SizedBox(height: 100), // Espace pour le scroll
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _getMoodEmoji(String mood) {
|
Widget _getMoodEmoji(String mood) {
|
||||||
String emoji = "😐";
|
String emoji = "😐";
|
||||||
Color color = Colors.grey;
|
Color color = Colors.grey;
|
||||||
switch (mood) {
|
switch (mood) {
|
||||||
case 'Très bien':
|
case 'Très bien':
|
||||||
emoji = "😊";
|
emoji = "😊";
|
||||||
color = const Color(0xFF4CAF50);
|
color = const Color(0xFF4CAF50);
|
||||||
break;
|
break;
|
||||||
case 'Bien':
|
case 'Bien':
|
||||||
emoji = "🙂";
|
emoji = "🙂";
|
||||||
color = const Color(0xFF8BC34A);
|
color = const Color(0xFF8BC34A);
|
||||||
break;
|
break;
|
||||||
case 'Neutre':
|
case 'Neutre':
|
||||||
emoji = "😐";
|
emoji = "😐";
|
||||||
color = const Color(0xFFFFC107);
|
color = const Color(0xFFFFC107);
|
||||||
break;
|
break;
|
||||||
case 'Pas top':
|
case 'Pas top':
|
||||||
emoji = "🙁";
|
emoji = "🙁";
|
||||||
color = const Color(0xFFFF9800);
|
color = const Color(0xFFFF9800);
|
||||||
break;
|
break;
|
||||||
case 'Stressé':
|
case 'Stressé':
|
||||||
emoji = "😫";
|
emoji = "😫";
|
||||||
color = const Color(0xFFF44336);
|
color = const Color(0xFFF44336);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return CircleAvatar(
|
return CircleAvatar(
|
||||||
backgroundColor: color.withOpacity(0.1),
|
backgroundColor: color.withOpacity(0.1),
|
||||||
child: Text(emoji, style: const TextStyle(fontSize: 20)),
|
child: Text(emoji, style: const TextStyle(fontSize: 20)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,132 +1,132 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import '../providers/auth_provider.dart';
|
import '../providers/auth_provider.dart';
|
||||||
|
|
||||||
class RegisterScreen extends StatefulWidget {
|
class RegisterScreen extends StatefulWidget {
|
||||||
const RegisterScreen({super.key});
|
const RegisterScreen({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<RegisterScreen> createState() => _RegisterScreenState();
|
State<RegisterScreen> createState() => _RegisterScreenState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _RegisterScreenState extends State<RegisterScreen> {
|
class _RegisterScreenState extends State<RegisterScreen> {
|
||||||
final _formKey = GlobalKey<FormState>();
|
final _formKey = GlobalKey<FormState>();
|
||||||
final _nameController = TextEditingController();
|
final _nameController = TextEditingController();
|
||||||
final _emailController = TextEditingController();
|
final _emailController = TextEditingController();
|
||||||
final _passwordController = TextEditingController();
|
final _passwordController = TextEditingController();
|
||||||
final _confirmPasswordController = TextEditingController();
|
final _confirmPasswordController = TextEditingController();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
_nameController.dispose();
|
_nameController.dispose();
|
||||||
_emailController.dispose();
|
_emailController.dispose();
|
||||||
_passwordController.dispose();
|
_passwordController.dispose();
|
||||||
_confirmPasswordController.dispose();
|
_confirmPasswordController.dispose();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
void _register() async {
|
void _register() async {
|
||||||
if (_formKey.currentState!.validate()) {
|
if (_formKey.currentState!.validate()) {
|
||||||
final authProvider = Provider.of<AuthProvider>(context, listen: false);
|
final authProvider = Provider.of<AuthProvider>(context, listen: false);
|
||||||
final success = await authProvider.register(
|
final success = await authProvider.register(
|
||||||
_nameController.text,
|
_nameController.text,
|
||||||
_emailController.text,
|
_emailController.text,
|
||||||
_passwordController.text,
|
_passwordController.text,
|
||||||
_confirmPasswordController.text,
|
_confirmPasswordController.text,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
const SnackBar(content: Text('Compte créé avec succès !')),
|
const SnackBar(content: Text('Compte créé avec succès !')),
|
||||||
);
|
);
|
||||||
// On vide la pile et on retourne au menu principal (HomeScreen)
|
// On vide la pile et on retourne au menu principal (HomeScreen)
|
||||||
Navigator.of(context).popUntil((route) => route.isFirst);
|
Navigator.of(context).popUntil((route) => route.isFirst);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
SnackBar(content: Text(authProvider.errorMessage ?? 'Échec de l\'inscription')),
|
SnackBar(content: Text(authProvider.errorMessage ?? 'Échec de l\'inscription')),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(title: const Text('Inscription CESIZen')),
|
appBar: AppBar(title: const Text('Inscription CESIZen')),
|
||||||
body: SingleChildScrollView(
|
body: SingleChildScrollView(
|
||||||
padding: const EdgeInsets.all(16.0),
|
padding: const EdgeInsets.all(16.0),
|
||||||
child: Form(
|
child: Form(
|
||||||
key: _formKey,
|
key: _formKey,
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
TextFormField(
|
TextFormField(
|
||||||
controller: _nameController,
|
controller: _nameController,
|
||||||
decoration: const InputDecoration(
|
decoration: const InputDecoration(
|
||||||
labelText: 'Nom complet',
|
labelText: 'Nom complet',
|
||||||
border: OutlineInputBorder(),
|
border: OutlineInputBorder(),
|
||||||
prefixIcon: Icon(Icons.person),
|
prefixIcon: Icon(Icons.person),
|
||||||
),
|
),
|
||||||
validator: (value) => value == null || value.isEmpty ? 'Entrez votre nom' : null,
|
validator: (value) => value == null || value.isEmpty ? 'Entrez votre nom' : null,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
TextFormField(
|
TextFormField(
|
||||||
controller: _emailController,
|
controller: _emailController,
|
||||||
decoration: const InputDecoration(
|
decoration: const InputDecoration(
|
||||||
labelText: 'Email',
|
labelText: 'Email',
|
||||||
border: OutlineInputBorder(),
|
border: OutlineInputBorder(),
|
||||||
prefixIcon: Icon(Icons.email),
|
prefixIcon: Icon(Icons.email),
|
||||||
),
|
),
|
||||||
keyboardType: TextInputType.emailAddress,
|
keyboardType: TextInputType.emailAddress,
|
||||||
validator: (value) => value == null || !value.contains('@') ? 'Email invalide' : null,
|
validator: (value) => value == null || !value.contains('@') ? 'Email invalide' : null,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
TextFormField(
|
TextFormField(
|
||||||
controller: _passwordController,
|
controller: _passwordController,
|
||||||
decoration: const InputDecoration(
|
decoration: const InputDecoration(
|
||||||
labelText: 'Mot de passe',
|
labelText: 'Mot de passe',
|
||||||
border: OutlineInputBorder(),
|
border: OutlineInputBorder(),
|
||||||
prefixIcon: Icon(Icons.lock),
|
prefixIcon: Icon(Icons.lock),
|
||||||
),
|
),
|
||||||
obscureText: true,
|
obscureText: true,
|
||||||
validator: (value) => value == null || value.length < 8 ? '8 caractères minimum' : null,
|
validator: (value) => value == null || value.length < 8 ? '8 caractères minimum' : null,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
TextFormField(
|
TextFormField(
|
||||||
controller: _confirmPasswordController,
|
controller: _confirmPasswordController,
|
||||||
decoration: const InputDecoration(
|
decoration: const InputDecoration(
|
||||||
labelText: 'Confirmer le mot de passe',
|
labelText: 'Confirmer le mot de passe',
|
||||||
border: OutlineInputBorder(),
|
border: OutlineInputBorder(),
|
||||||
prefixIcon: Icon(Icons.lock_outline),
|
prefixIcon: Icon(Icons.lock_outline),
|
||||||
),
|
),
|
||||||
obscureText: true,
|
obscureText: true,
|
||||||
validator: (value) {
|
validator: (value) {
|
||||||
if (value != _passwordController.text) return 'Les mots de passe ne correspondent pas';
|
if (value != _passwordController.text) return 'Les mots de passe ne correspondent pas';
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
const SizedBox(height: 24),
|
const SizedBox(height: 24),
|
||||||
Consumer<AuthProvider>(
|
Consumer<AuthProvider>(
|
||||||
builder: (context, auth, child) {
|
builder: (context, auth, child) {
|
||||||
return auth.isLoading
|
return auth.isLoading
|
||||||
? const CircularProgressIndicator()
|
? const CircularProgressIndicator()
|
||||||
: ElevatedButton(
|
: ElevatedButton(
|
||||||
onPressed: _register,
|
onPressed: _register,
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
minimumSize: const Size.fromHeight(50),
|
minimumSize: const Size.fromHeight(50),
|
||||||
),
|
),
|
||||||
child: const Text('S\'inscrire'),
|
child: const Text('S\'inscrire'),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,130 +1,130 @@
|
|||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||||
import '../../../core/network/dio_client.dart';
|
import '../../../core/network/dio_client.dart';
|
||||||
import '../models/user.dart';
|
import '../models/user.dart';
|
||||||
|
|
||||||
class AuthService {
|
class AuthService {
|
||||||
final Dio _dio = DioClient().dio;
|
final Dio _dio = DioClient().dio;
|
||||||
final FlutterSecureStorage _storage = const FlutterSecureStorage();
|
final FlutterSecureStorage _storage = const FlutterSecureStorage();
|
||||||
|
|
||||||
Future<Map<String, dynamic>> login(String email, String password) async {
|
Future<Map<String, dynamic>> login(String email, String password) async {
|
||||||
try {
|
try {
|
||||||
final response = await _dio.post('/login', data: {
|
final response = await _dio.post('/login', data: {
|
||||||
'email': email,
|
'email': email,
|
||||||
'password': password,
|
'password': password,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
String token = response.data['token'];
|
String token = response.data['token'];
|
||||||
await _storage.write(key: 'token', value: token);
|
await _storage.write(key: 'token', value: token);
|
||||||
return {
|
return {
|
||||||
'status': 'success',
|
'status': 'success',
|
||||||
'user': User.fromJson(response.data['user']),
|
'user': User.fromJson(response.data['user']),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return {'status': 'error', 'message': 'Erreur inconnue'};
|
return {'status': 'error', 'message': 'Erreur inconnue'};
|
||||||
} on DioException catch (e) {
|
} on DioException catch (e) {
|
||||||
return {
|
return {
|
||||||
'status': 'error',
|
'status': 'error',
|
||||||
'message': e.response?.data['message'] ?? 'Erreur de connexion'
|
'message': e.response?.data['message'] ?? 'Erreur de connexion'
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Map<String, dynamic>> register(String name, String email, String password, String passwordConfirmation) async {
|
Future<Map<String, dynamic>> register(String name, String email, String password, String passwordConfirmation) async {
|
||||||
try {
|
try {
|
||||||
final response = await _dio.post('/register', data: {
|
final response = await _dio.post('/register', data: {
|
||||||
'name': name,
|
'name': name,
|
||||||
'email': email,
|
'email': email,
|
||||||
'password': password,
|
'password': password,
|
||||||
'password_confirmation': passwordConfirmation,
|
'password_confirmation': passwordConfirmation,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (response.statusCode == 201) {
|
if (response.statusCode == 201) {
|
||||||
String token = response.data['token'];
|
String token = response.data['token'];
|
||||||
await _storage.write(key: 'token', value: token);
|
await _storage.write(key: 'token', value: token);
|
||||||
return {
|
return {
|
||||||
'status': 'success',
|
'status': 'success',
|
||||||
'user': User.fromJson(response.data['user']),
|
'user': User.fromJson(response.data['user']),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return {'status': 'error', 'message': 'Erreur inconnue'};
|
return {'status': 'error', 'message': 'Erreur inconnue'};
|
||||||
} on DioException catch (e) {
|
} on DioException catch (e) {
|
||||||
return {
|
return {
|
||||||
'status': 'error',
|
'status': 'error',
|
||||||
'errors': e.response?.data['errors'] ?? 'Erreur lors de l\'inscription'
|
'errors': e.response?.data['errors'] ?? 'Erreur lors de l\'inscription'
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Map<String, dynamic>> updateProfile(String name, String email, {String? password}) async {
|
Future<Map<String, dynamic>> updateProfile(String name, String email, {String? password}) async {
|
||||||
try {
|
try {
|
||||||
String? token = await getToken();
|
String? token = await getToken();
|
||||||
|
|
||||||
final Map<String, dynamic> data = {
|
final Map<String, dynamic> data = {
|
||||||
'name': name,
|
'name': name,
|
||||||
'email': email,
|
'email': email,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (password != null && password.isNotEmpty) {
|
if (password != null && password.isNotEmpty) {
|
||||||
data['current_password'] = password;
|
data['current_password'] = password;
|
||||||
data['password'] = password;
|
data['password'] = password;
|
||||||
data['password_confirmation'] = password;
|
data['password_confirmation'] = password;
|
||||||
}
|
}
|
||||||
|
|
||||||
final response = await _dio.post(
|
final response = await _dio.post(
|
||||||
'/update-profile',
|
'/update-profile',
|
||||||
data: data,
|
data: data,
|
||||||
options: Options(
|
options: Options(
|
||||||
headers: {
|
headers: {
|
||||||
'Authorization': 'Bearer $token',
|
'Authorization': 'Bearer $token',
|
||||||
'Accept': 'application/json',
|
'Accept': 'application/json',
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
return {
|
return {
|
||||||
'status': 'success',
|
'status': 'success',
|
||||||
'user': User.fromJson(response.data['user']),
|
'user': User.fromJson(response.data['user']),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return {'status': 'error', 'message': 'Erreur lors de la mise à jour'};
|
return {'status': 'error', 'message': 'Erreur lors de la mise à jour'};
|
||||||
} on DioException catch (e) {
|
} on DioException catch (e) {
|
||||||
return {
|
return {
|
||||||
'status': 'error',
|
'status': 'error',
|
||||||
'message': e.response?.data['message'] ?? 'Erreur lors de la modification du profil'
|
'message': e.response?.data['message'] ?? 'Erreur lors de la modification du profil'
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Map<String, dynamic>> getProfile() async {
|
Future<Map<String, dynamic>> getProfile() async {
|
||||||
try {
|
try {
|
||||||
String? token = await getToken();
|
String? token = await getToken();
|
||||||
if (token == null) return {'status': 'error', 'message': 'No token'};
|
if (token == null) return {'status': 'error', 'message': 'No token'};
|
||||||
|
|
||||||
final response = await _dio.get('/profile', options: Options(
|
final response = await _dio.get('/profile', options: Options(
|
||||||
headers: {'Authorization': 'Bearer $token'}
|
headers: {'Authorization': 'Bearer $token'}
|
||||||
));
|
));
|
||||||
|
|
||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
return {
|
return {
|
||||||
'status': 'success',
|
'status': 'success',
|
||||||
'user': User.fromJson(response.data),
|
'user': User.fromJson(response.data),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return {'status': 'error', 'message': 'Session expirée'};
|
return {'status': 'error', 'message': 'Session expirée'};
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return {'status': 'error', 'message': e.toString()};
|
return {'status': 'error', 'message': e.toString()};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> logout() async {
|
Future<void> logout() async {
|
||||||
await _storage.delete(key: 'token');
|
await _storage.delete(key: 'token');
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<String?> getToken() async {
|
Future<String?> getToken() async {
|
||||||
return await _storage.read(key: 'token');
|
return await _storage.read(key: 'token');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
class Question {
|
class Question {
|
||||||
final String text;
|
final String text;
|
||||||
final List<Option> options;
|
final List<Option> options;
|
||||||
|
|
||||||
Question({required this.text, required this.options});
|
Question({required this.text, required this.options});
|
||||||
}
|
}
|
||||||
|
|
||||||
class Option {
|
class Option {
|
||||||
final String text;
|
final String text;
|
||||||
final int points;
|
final int points;
|
||||||
|
|
||||||
Option({required this.text, required this.points});
|
Option({required this.text, required this.points});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,65 +1,65 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import '../models/question.dart';
|
import '../models/question.dart';
|
||||||
import '../services/diagnostic_service.dart';
|
import '../services/diagnostic_service.dart';
|
||||||
|
|
||||||
class DiagnosticProvider with ChangeNotifier {
|
class DiagnosticProvider with ChangeNotifier {
|
||||||
final DiagnosticService _service = DiagnosticService();
|
final DiagnosticService _service = DiagnosticService();
|
||||||
List<Question> _questions = [];
|
List<Question> _questions = [];
|
||||||
int _currentQuestionIndex = 0;
|
int _currentQuestionIndex = 0;
|
||||||
int _totalScore = 0;
|
int _totalScore = 0;
|
||||||
bool _isFinished = false;
|
bool _isFinished = false;
|
||||||
bool _isLoading = true;
|
bool _isLoading = true;
|
||||||
|
|
||||||
List<Question> get questions => _questions;
|
List<Question> get questions => _questions;
|
||||||
int get currentQuestionIndex => _currentQuestionIndex;
|
int get currentQuestionIndex => _currentQuestionIndex;
|
||||||
int get totalScore => _totalScore;
|
int get totalScore => _totalScore;
|
||||||
bool get isFinished => _isFinished;
|
bool get isFinished => _isFinished;
|
||||||
bool get isLoading => _isLoading;
|
bool get isLoading => _isLoading;
|
||||||
|
|
||||||
DiagnosticProvider() {
|
DiagnosticProvider() {
|
||||||
loadQuestions();
|
loadQuestions();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> loadQuestions() async {
|
Future<void> loadQuestions() async {
|
||||||
_isLoading = true;
|
_isLoading = true;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
|
|
||||||
_questions = await _service.fetchStressEvents();
|
_questions = await _service.fetchStressEvents();
|
||||||
|
|
||||||
_isLoading = false;
|
_isLoading = false;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
void answerQuestion(int points) {
|
void answerQuestion(int points) {
|
||||||
_totalScore += points;
|
_totalScore += points;
|
||||||
if (_currentQuestionIndex < _questions.length - 1) {
|
if (_currentQuestionIndex < _questions.length - 1) {
|
||||||
_currentQuestionIndex++;
|
_currentQuestionIndex++;
|
||||||
} else {
|
} else {
|
||||||
_isFinished = true;
|
_isFinished = true;
|
||||||
}
|
}
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
void reset() {
|
void reset() {
|
||||||
_currentQuestionIndex = 0;
|
_currentQuestionIndex = 0;
|
||||||
_totalScore = 0;
|
_totalScore = 0;
|
||||||
_isFinished = false;
|
_isFinished = false;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
String get stressLevel {
|
String get stressLevel {
|
||||||
if (_totalScore < 150) return "Risque Faible";
|
if (_totalScore < 150) return "Risque Faible";
|
||||||
if (_totalScore < 300) return "Risque Modéré (50%)";
|
if (_totalScore < 300) return "Risque Modéré (50%)";
|
||||||
return "Risque Élevé (80%)";
|
return "Risque Élevé (80%)";
|
||||||
}
|
}
|
||||||
|
|
||||||
String get advice {
|
String get advice {
|
||||||
if (_totalScore < 150) {
|
if (_totalScore < 150) {
|
||||||
return "Votre niveau de changement de vie est gérable. Continuez à maintenir votre équilibre actuel.";
|
return "Votre niveau de changement de vie est gérable. Continuez à maintenir votre équilibre actuel.";
|
||||||
}
|
}
|
||||||
if (_totalScore < 300) {
|
if (_totalScore < 300) {
|
||||||
return "Vous avez vécu beaucoup de changements. Il y a un risque modéré que cela affecte votre santé. Prenez du temps pour vous reposer.";
|
return "Vous avez vécu beaucoup de changements. Il y a un risque modéré que cela affecte votre santé. Prenez du temps pour vous reposer.";
|
||||||
}
|
}
|
||||||
return "Attention : Votre score est très élevé. L'accumulation de stress lié à ces changements majeurs pourrait sérieusement impacter votre santé. Il est recommandé de consulter un professionnel.";
|
return "Attention : Votre score est très élevé. L'accumulation de stress lié à ces changements majeurs pourrait sérieusement impacter votre santé. Il est recommandé de consulter un professionnel.";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,122 +1,122 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import '../providers/diagnostic_provider.dart';
|
import '../providers/diagnostic_provider.dart';
|
||||||
|
|
||||||
class DiagnosticScreen extends StatelessWidget {
|
class DiagnosticScreen extends StatelessWidget {
|
||||||
const DiagnosticScreen({super.key});
|
const DiagnosticScreen({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ChangeNotifierProvider(
|
return ChangeNotifierProvider(
|
||||||
create: (_) => DiagnosticProvider(),
|
create: (_) => DiagnosticProvider(),
|
||||||
child: const _DiagnosticView(),
|
child: const _DiagnosticView(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _DiagnosticView extends StatelessWidget {
|
class _DiagnosticView extends StatelessWidget {
|
||||||
const _DiagnosticView();
|
const _DiagnosticView();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final provider = Provider.of<DiagnosticProvider>(context);
|
final provider = Provider.of<DiagnosticProvider>(context);
|
||||||
|
|
||||||
if (provider.isLoading) {
|
if (provider.isLoading) {
|
||||||
return const Scaffold(
|
return const Scaffold(
|
||||||
body: Center(child: CircularProgressIndicator()),
|
body: Center(child: CircularProgressIndicator()),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (provider.questions.isEmpty) {
|
if (provider.questions.isEmpty) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(title: const Text('Diagnostic')),
|
appBar: AppBar(title: const Text('Diagnostic')),
|
||||||
body: const Center(child: Text('Aucun événement trouvé.')),
|
body: const Center(child: Text('Aucun événement trouvé.')),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
final question = provider.questions[provider.currentQuestionIndex];
|
final question = provider.questions[provider.currentQuestionIndex];
|
||||||
|
|
||||||
if (provider.isFinished) {
|
if (provider.isFinished) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(title: const Text('Résultat du Diagnostic')),
|
appBar: AppBar(title: const Text('Résultat du Diagnostic')),
|
||||||
body: Center(
|
body: Center(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(24.0),
|
padding: const EdgeInsets.all(24.0),
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
const Text('Votre niveau de stress est :', style: TextStyle(fontSize: 18)),
|
const Text('Votre niveau de stress est :', style: TextStyle(fontSize: 18)),
|
||||||
const SizedBox(height: 10),
|
const SizedBox(height: 10),
|
||||||
Text(
|
Text(
|
||||||
provider.stressLevel,
|
provider.stressLevel,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 32,
|
fontSize: 32,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
color: _getColorForLevel(provider.stressLevel),
|
color: _getColorForLevel(provider.stressLevel),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
Text(
|
Text(
|
||||||
provider.advice,
|
provider.advice,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: const TextStyle(fontSize: 16, fontStyle: FontStyle.italic),
|
style: const TextStyle(fontSize: 16, fontStyle: FontStyle.italic),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 40),
|
const SizedBox(height: 40),
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
onPressed: () => Navigator.pop(context),
|
onPressed: () => Navigator.pop(context),
|
||||||
child: const Text('Retour à l\'accueil'),
|
child: const Text('Retour à l\'accueil'),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text('Question ${provider.currentQuestionIndex + 1}/${provider.questions.length}'),
|
title: Text('Question ${provider.currentQuestionIndex + 1}/${provider.questions.length}'),
|
||||||
),
|
),
|
||||||
body: Padding(
|
body: Padding(
|
||||||
padding: const EdgeInsets.all(20.0),
|
padding: const EdgeInsets.all(20.0),
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
children: [
|
children: [
|
||||||
LinearProgressIndicator(
|
LinearProgressIndicator(
|
||||||
value: (provider.currentQuestionIndex + 1) / provider.questions.length,
|
value: (provider.currentQuestionIndex + 1) / provider.questions.length,
|
||||||
backgroundColor: Colors.grey.shade200,
|
backgroundColor: Colors.grey.shade200,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 40),
|
const SizedBox(height: 40),
|
||||||
Text(
|
Text(
|
||||||
question.text,
|
question.text,
|
||||||
style: const TextStyle(fontSize: 20, fontWeight: FontWeight.w500),
|
style: const TextStyle(fontSize: 20, fontWeight: FontWeight.w500),
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 40),
|
const SizedBox(height: 40),
|
||||||
...question.options.map((option) => Padding(
|
...question.options.map((option) => Padding(
|
||||||
padding: const EdgeInsets.only(bottom: 12.0),
|
padding: const EdgeInsets.only(bottom: 12.0),
|
||||||
child: ElevatedButton(
|
child: ElevatedButton(
|
||||||
onPressed: () => provider.answerQuestion(option.points),
|
onPressed: () => provider.answerQuestion(option.points),
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 15),
|
padding: const EdgeInsets.symmetric(vertical: 15),
|
||||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
|
||||||
),
|
),
|
||||||
child: Text(option.text),
|
child: Text(option.text),
|
||||||
),
|
),
|
||||||
)),
|
)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Color _getColorForLevel(String level) {
|
Color _getColorForLevel(String level) {
|
||||||
switch (level) {
|
switch (level) {
|
||||||
case "Faible": return Colors.green;
|
case "Faible": return Colors.green;
|
||||||
case "Modéré": return Colors.orange;
|
case "Modéré": return Colors.orange;
|
||||||
case "Élevé": return Colors.red;
|
case "Élevé": return Colors.red;
|
||||||
case "Très élevé": return Colors.red.shade900;
|
case "Très élevé": return Colors.red.shade900;
|
||||||
default: return Colors.black;
|
default: return Colors.black;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,30 +1,30 @@
|
|||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
import '../../../core/network/dio_client.dart';
|
import '../../../core/network/dio_client.dart';
|
||||||
import '../models/question.dart';
|
import '../models/question.dart';
|
||||||
|
|
||||||
class DiagnosticService {
|
class DiagnosticService {
|
||||||
final Dio _dio = DioClient().dio;
|
final Dio _dio = DioClient().dio;
|
||||||
|
|
||||||
Future<List<Question>> fetchStressEvents() async {
|
Future<List<Question>> fetchStressEvents() async {
|
||||||
try {
|
try {
|
||||||
final response = await _dio.get('/stress-events');
|
final response = await _dio.get('/stress-events');
|
||||||
|
|
||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
List<dynamic> data = response.data;
|
List<dynamic> data = response.data;
|
||||||
return data.map((item) {
|
return data.map((item) {
|
||||||
return Question(
|
return Question(
|
||||||
text: "Avez-vous vécu : ${item['event_name']} ?",
|
text: "Avez-vous vécu : ${item['event_name']} ?",
|
||||||
options: [
|
options: [
|
||||||
Option(text: "Oui", points: int.parse(item['points'].toString())),
|
Option(text: "Oui", points: int.parse(item['points'].toString())),
|
||||||
Option(text: "Non", points: 0),
|
Option(text: "Non", points: 0),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}).toList();
|
}).toList();
|
||||||
}
|
}
|
||||||
return [];
|
return [];
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print("Erreur lors de la récupération des événements : $e");
|
print("Erreur lors de la récupération des événements : $e");
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,307 +1,307 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class BreathingMode {
|
class BreathingMode {
|
||||||
final String name;
|
final String name;
|
||||||
final String description;
|
final String description;
|
||||||
final int inhale;
|
final int inhale;
|
||||||
final int hold;
|
final int hold;
|
||||||
final int exhale;
|
final int exhale;
|
||||||
final Color color;
|
final Color color;
|
||||||
|
|
||||||
BreathingMode({
|
BreathingMode({
|
||||||
required this.name,
|
required this.name,
|
||||||
required this.description,
|
required this.description,
|
||||||
required this.inhale,
|
required this.inhale,
|
||||||
required this.hold,
|
required this.hold,
|
||||||
required this.exhale,
|
required this.exhale,
|
||||||
required this.color,
|
required this.color,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
class BreathingScreen extends StatefulWidget {
|
class BreathingScreen extends StatefulWidget {
|
||||||
const BreathingScreen({super.key});
|
const BreathingScreen({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<BreathingScreen> createState() => _BreathingScreenState();
|
State<BreathingScreen> createState() => _BreathingScreenState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _BreathingScreenState extends State<BreathingScreen> with TickerProviderStateMixin {
|
class _BreathingScreenState extends State<BreathingScreen> with TickerProviderStateMixin {
|
||||||
late AnimationController _controller;
|
late AnimationController _controller;
|
||||||
late Animation<double> _animation;
|
late Animation<double> _animation;
|
||||||
|
|
||||||
final List<BreathingMode> _modes = [
|
final List<BreathingMode> _modes = [
|
||||||
BreathingMode(
|
BreathingMode(
|
||||||
name: "7-4-8",
|
name: "7-4-8",
|
||||||
description: "Sommeil & Détente profonde",
|
description: "Sommeil & Détente profonde",
|
||||||
inhale: 7,
|
inhale: 7,
|
||||||
hold: 4,
|
hold: 4,
|
||||||
exhale: 8,
|
exhale: 8,
|
||||||
color: Colors.indigo,
|
color: Colors.indigo,
|
||||||
),
|
),
|
||||||
BreathingMode(
|
BreathingMode(
|
||||||
name: "5-5",
|
name: "5-5",
|
||||||
description: "Cohérence Cardiaque classique",
|
description: "Cohérence Cardiaque classique",
|
||||||
inhale: 5,
|
inhale: 5,
|
||||||
hold: 0,
|
hold: 0,
|
||||||
exhale: 5,
|
exhale: 5,
|
||||||
color: Colors.teal,
|
color: Colors.teal,
|
||||||
),
|
),
|
||||||
BreathingMode(
|
BreathingMode(
|
||||||
name: "4-6",
|
name: "4-6",
|
||||||
description: "Réduction rapide du stress",
|
description: "Réduction rapide du stress",
|
||||||
inhale: 4,
|
inhale: 4,
|
||||||
hold: 0,
|
hold: 0,
|
||||||
exhale: 6,
|
exhale: 6,
|
||||||
color: Colors.orange,
|
color: Colors.orange,
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
late BreathingMode _selectedMode;
|
late BreathingMode _selectedMode;
|
||||||
bool _isStarted = false;
|
bool _isStarted = false;
|
||||||
String _actionText = "Prêt ?";
|
String _actionText = "Prêt ?";
|
||||||
int _secondsRemaining = 0;
|
int _secondsRemaining = 0;
|
||||||
Timer? _timer;
|
Timer? _timer;
|
||||||
int _phaseSecondsRemaining = 0;
|
int _phaseSecondsRemaining = 0;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
_selectedMode = _modes[1]; // 5-5 par défaut
|
_selectedMode = _modes[1]; // 5-5 par défaut
|
||||||
_setupController();
|
_setupController();
|
||||||
}
|
}
|
||||||
|
|
||||||
void _setupController() {
|
void _setupController() {
|
||||||
_controller = AnimationController(vsync: this);
|
_controller = AnimationController(vsync: this);
|
||||||
_animation = Tween<double>(begin: 0.6, end: 1.0).animate(
|
_animation = Tween<double>(begin: 0.6, end: 1.0).animate(
|
||||||
CurvedAnimation(parent: _controller, curve: Curves.easeInOut),
|
CurvedAnimation(parent: _controller, curve: Curves.easeInOut),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _runExercise() async {
|
Future<void> _runExercise() async {
|
||||||
while (_isStarted && _secondsRemaining > 0) {
|
while (_isStarted && _secondsRemaining > 0) {
|
||||||
// Phase 1 : Inspiration
|
// Phase 1 : Inspiration
|
||||||
if (!_isStarted) break;
|
if (!_isStarted) break;
|
||||||
setState(() => _actionText = "Inspirez");
|
setState(() => _actionText = "Inspirez");
|
||||||
_controller.duration = Duration(seconds: _selectedMode.inhale);
|
_controller.duration = Duration(seconds: _selectedMode.inhale);
|
||||||
_controller.forward();
|
_controller.forward();
|
||||||
await _waitForPhase(_selectedMode.inhale);
|
await _waitForPhase(_selectedMode.inhale);
|
||||||
|
|
||||||
// Phase 2 : Apnée (Hold)
|
// Phase 2 : Apnée (Hold)
|
||||||
if (!_isStarted) break;
|
if (!_isStarted) break;
|
||||||
if (_selectedMode.hold > 0) {
|
if (_selectedMode.hold > 0) {
|
||||||
setState(() => _actionText = "Bloquez");
|
setState(() => _actionText = "Bloquez");
|
||||||
await _waitForPhase(_selectedMode.hold);
|
await _waitForPhase(_selectedMode.hold);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Phase 3 : Expiration
|
// Phase 3 : Expiration
|
||||||
if (!_isStarted) break;
|
if (!_isStarted) break;
|
||||||
setState(() => _actionText = "Expirez");
|
setState(() => _actionText = "Expirez");
|
||||||
_controller.duration = Duration(seconds: _selectedMode.exhale);
|
_controller.duration = Duration(seconds: _selectedMode.exhale);
|
||||||
_controller.reverse();
|
_controller.reverse();
|
||||||
await _waitForPhase(_selectedMode.exhale);
|
await _waitForPhase(_selectedMode.exhale);
|
||||||
}
|
}
|
||||||
if (_isStarted) _stopExercise();
|
if (_isStarted) _stopExercise();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _waitForPhase(int seconds) async {
|
Future<void> _waitForPhase(int seconds) async {
|
||||||
_phaseSecondsRemaining = seconds;
|
_phaseSecondsRemaining = seconds;
|
||||||
for (int i = 0; i < seconds; i++) {
|
for (int i = 0; i < seconds; i++) {
|
||||||
if (!_isStarted) return;
|
if (!_isStarted) return;
|
||||||
await Future.delayed(const Duration(seconds: 1));
|
await Future.delayed(const Duration(seconds: 1));
|
||||||
if (mounted) setState(() => _phaseSecondsRemaining--);
|
if (mounted) setState(() => _phaseSecondsRemaining--);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _startExercise() {
|
void _startExercise() {
|
||||||
setState(() {
|
setState(() {
|
||||||
_isStarted = true;
|
_isStarted = true;
|
||||||
_secondsRemaining = 300; // 5 minutes
|
_secondsRemaining = 300; // 5 minutes
|
||||||
});
|
});
|
||||||
|
|
||||||
_timer = Timer.periodic(const Duration(seconds: 1), (timer) {
|
_timer = Timer.periodic(const Duration(seconds: 1), (timer) {
|
||||||
if (_secondsRemaining > 0) {
|
if (_secondsRemaining > 0) {
|
||||||
setState(() => _secondsRemaining--);
|
setState(() => _secondsRemaining--);
|
||||||
} else {
|
} else {
|
||||||
_stopExercise();
|
_stopExercise();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
_runExercise();
|
_runExercise();
|
||||||
}
|
}
|
||||||
|
|
||||||
void _stopExercise() {
|
void _stopExercise() {
|
||||||
_timer?.cancel();
|
_timer?.cancel();
|
||||||
_controller.stop();
|
_controller.stop();
|
||||||
_controller.reset();
|
_controller.reset();
|
||||||
setState(() {
|
setState(() {
|
||||||
_isStarted = false;
|
_isStarted = false;
|
||||||
_actionText = "Prêt ?";
|
_actionText = "Prêt ?";
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
_timer?.cancel();
|
_timer?.cancel();
|
||||||
_controller.dispose();
|
_controller.dispose();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
String _formatTime(int seconds) {
|
String _formatTime(int seconds) {
|
||||||
int mins = seconds ~/ 60;
|
int mins = seconds ~/ 60;
|
||||||
int secs = seconds % 60;
|
int secs = seconds % 60;
|
||||||
return "$mins:${secs.toString().padLeft(2, '0')}";
|
return "$mins:${secs.toString().padLeft(2, '0')}";
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: Colors.white,
|
backgroundColor: Colors.white,
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: const Text('Respiration Guidée', style: TextStyle(fontWeight: FontWeight.bold)),
|
title: const Text('Respiration Guidée', style: TextStyle(fontWeight: FontWeight.bold)),
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
backgroundColor: Colors.white,
|
backgroundColor: Colors.white,
|
||||||
),
|
),
|
||||||
body: Container(
|
body: Container(
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 24),
|
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
if (!_isStarted) ...[
|
if (!_isStarted) ...[
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
const Text(
|
const Text(
|
||||||
"Choisissez votre exercice",
|
"Choisissez votre exercice",
|
||||||
style: TextStyle(fontSize: 18, color: Colors.grey),
|
style: TextStyle(fontSize: 18, color: Colors.grey),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
..._modes.map((mode) => _buildModeCard(mode)).toList(),
|
..._modes.map((mode) => _buildModeCard(mode)).toList(),
|
||||||
] else ...[
|
] else ...[
|
||||||
const SizedBox(height: 40),
|
const SizedBox(height: 40),
|
||||||
Text(
|
Text(
|
||||||
_formatTime(_secondsRemaining),
|
_formatTime(_secondsRemaining),
|
||||||
style: const TextStyle(fontSize: 32, fontWeight: FontWeight.bold, letterSpacing: 2),
|
style: const TextStyle(fontSize: 32, fontWeight: FontWeight.bold, letterSpacing: 2),
|
||||||
),
|
),
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
_buildAnimatedCircle(),
|
_buildAnimatedCircle(),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
if (_phaseSecondsRemaining > 0)
|
if (_phaseSecondsRemaining > 0)
|
||||||
Text(
|
Text(
|
||||||
"$_phaseSecondsRemaining",
|
"$_phaseSecondsRemaining",
|
||||||
style: TextStyle(fontSize: 40, fontWeight: FontWeight.w300, color: _selectedMode.color),
|
style: TextStyle(fontSize: 40, fontWeight: FontWeight.w300, color: _selectedMode.color),
|
||||||
),
|
),
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
onPressed: _stopExercise,
|
onPressed: _stopExercise,
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
backgroundColor: Colors.red.shade50,
|
backgroundColor: Colors.red.shade50,
|
||||||
foregroundColor: Colors.red,
|
foregroundColor: Colors.red,
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 50, vertical: 15),
|
padding: const EdgeInsets.symmetric(horizontal: 50, vertical: 15),
|
||||||
),
|
),
|
||||||
child: const Text("ARRÊTER LA SESSION", style: TextStyle(fontWeight: FontWeight.bold)),
|
child: const Text("ARRÊTER LA SESSION", style: TextStyle(fontWeight: FontWeight.bold)),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 40),
|
const SizedBox(height: 40),
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildModeCard(BreathingMode mode) {
|
Widget _buildModeCard(BreathingMode mode) {
|
||||||
final isSelected = _selectedMode == mode;
|
final isSelected = _selectedMode == mode;
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: () => setState(() => _selectedMode = mode),
|
onTap: () => setState(() => _selectedMode = mode),
|
||||||
child: Container(
|
child: Container(
|
||||||
margin: const EdgeInsets.only(bottom: 16),
|
margin: const EdgeInsets.only(bottom: 16),
|
||||||
padding: const EdgeInsets.all(20),
|
padding: const EdgeInsets.all(20),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: isSelected ? mode.color.withOpacity(0.05) : Colors.white,
|
color: isSelected ? mode.color.withOpacity(0.05) : Colors.white,
|
||||||
borderRadius: BorderRadius.circular(20),
|
borderRadius: BorderRadius.circular(20),
|
||||||
border: Border.all(
|
border: Border.all(
|
||||||
color: isSelected ? mode.color : Colors.grey.shade200,
|
color: isSelected ? mode.color : Colors.grey.shade200,
|
||||||
width: isSelected ? 2 : 1,
|
width: isSelected ? 2 : 1,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Container(
|
Container(
|
||||||
padding: const EdgeInsets.all(12),
|
padding: const EdgeInsets.all(12),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: mode.color.withOpacity(0.1),
|
color: mode.color.withOpacity(0.1),
|
||||||
shape: BoxShape.circle,
|
shape: BoxShape.circle,
|
||||||
),
|
),
|
||||||
child: Icon(Icons.air, color: mode.color),
|
child: Icon(Icons.air, color: mode.color),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 20),
|
const SizedBox(width: 20),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(mode.name, style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
|
Text(mode.name, style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
|
||||||
Text(mode.description, style: TextStyle(color: Colors.grey.shade600, fontSize: 13)),
|
Text(mode.description, style: TextStyle(color: Colors.grey.shade600, fontSize: 13)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (isSelected)
|
if (isSelected)
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
onPressed: _startExercise,
|
onPressed: _startExercise,
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
backgroundColor: mode.color,
|
backgroundColor: mode.color,
|
||||||
foregroundColor: Colors.white,
|
foregroundColor: Colors.white,
|
||||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
|
||||||
),
|
),
|
||||||
child: const Text("GO"),
|
child: const Text("GO"),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildAnimatedCircle() {
|
Widget _buildAnimatedCircle() {
|
||||||
return ScaleTransition(
|
return ScaleTransition(
|
||||||
scale: _animation,
|
scale: _animation,
|
||||||
child: Container(
|
child: Container(
|
||||||
width: 250,
|
width: 250,
|
||||||
height: 250,
|
height: 250,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
shape: BoxShape.circle,
|
shape: BoxShape.circle,
|
||||||
gradient: RadialGradient(
|
gradient: RadialGradient(
|
||||||
colors: [
|
colors: [
|
||||||
_selectedMode.color.withOpacity(0.2),
|
_selectedMode.color.withOpacity(0.2),
|
||||||
_selectedMode.color.withOpacity(0.05),
|
_selectedMode.color.withOpacity(0.05),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
border: Border.all(color: _selectedMode.color.withOpacity(0.3), width: 8),
|
border: Border.all(color: _selectedMode.color.withOpacity(0.3), width: 8),
|
||||||
),
|
),
|
||||||
child: Stack(
|
child: Stack(
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
children: [
|
children: [
|
||||||
// Logo de méditation en fond
|
// Logo de méditation en fond
|
||||||
Opacity(
|
Opacity(
|
||||||
opacity: 0.1,
|
opacity: 0.1,
|
||||||
child: Image.asset(
|
child: Image.asset(
|
||||||
'assets/images/CesiZen logo.png',
|
'assets/images/CesiZen logo.png',
|
||||||
width: 150,
|
width: 150,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Column(
|
Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
_actionText,
|
_actionText,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 28,
|
fontSize: 28,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
color: _selectedMode.color,
|
color: _selectedMode.color,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,28 +1,28 @@
|
|||||||
class Activity {
|
class Activity {
|
||||||
final int id;
|
final int id;
|
||||||
final String title;
|
final String title;
|
||||||
final String description;
|
final String description;
|
||||||
final String category; // 'Méditation', 'Musique', 'Respiration', etc.
|
final String category; // 'Méditation', 'Musique', 'Respiration', etc.
|
||||||
final String? imageUrl;
|
final String? imageUrl;
|
||||||
final String? videoUrl;
|
final String? videoUrl;
|
||||||
|
|
||||||
Activity({
|
Activity({
|
||||||
required this.id,
|
required this.id,
|
||||||
required this.title,
|
required this.title,
|
||||||
required this.description,
|
required this.description,
|
||||||
required this.category,
|
required this.category,
|
||||||
this.imageUrl,
|
this.imageUrl,
|
||||||
this.videoUrl,
|
this.videoUrl,
|
||||||
});
|
});
|
||||||
|
|
||||||
factory Activity.fromJson(Map<String, dynamic> json) {
|
factory Activity.fromJson(Map<String, dynamic> json) {
|
||||||
return Activity(
|
return Activity(
|
||||||
id: json['id'],
|
id: json['id'],
|
||||||
title: json['title'] ?? '',
|
title: json['title'] ?? '',
|
||||||
description: json['description'] ?? '',
|
description: json['description'] ?? '',
|
||||||
category: json['category'] ?? 'Détente',
|
category: json['category'] ?? 'Détente',
|
||||||
imageUrl: json['image_url'],
|
imageUrl: json['image_url'],
|
||||||
videoUrl: json['video_url'],
|
videoUrl: json['video_url'],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,31 +1,31 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import '../models/activity.dart';
|
import '../models/activity.dart';
|
||||||
import '../services/relaxation_service.dart';
|
import '../services/relaxation_service.dart';
|
||||||
|
|
||||||
class RelaxationProvider with ChangeNotifier {
|
class RelaxationProvider with ChangeNotifier {
|
||||||
final RelaxationService _service = RelaxationService();
|
final RelaxationService _service = RelaxationService();
|
||||||
List<Activity> _activities = [];
|
List<Activity> _activities = [];
|
||||||
bool _isLoading = false;
|
bool _isLoading = false;
|
||||||
String _selectedCategory = 'Toutes';
|
String _selectedCategory = 'Toutes';
|
||||||
|
|
||||||
List<Activity> get activities {
|
List<Activity> get activities {
|
||||||
if (_selectedCategory == 'Toutes') return _activities;
|
if (_selectedCategory == 'Toutes') return _activities;
|
||||||
return _activities.where((a) => a.category == _selectedCategory).toList();
|
return _activities.where((a) => a.category == _selectedCategory).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool get isLoading => _isLoading;
|
bool get isLoading => _isLoading;
|
||||||
String get selectedCategory => _selectedCategory;
|
String get selectedCategory => _selectedCategory;
|
||||||
|
|
||||||
Future<void> loadActivities() async {
|
Future<void> loadActivities() async {
|
||||||
_isLoading = true;
|
_isLoading = true;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
_activities = await _service.fetchActivities();
|
_activities = await _service.fetchActivities();
|
||||||
_isLoading = false;
|
_isLoading = false;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
void setCategory(String category) {
|
void setCategory(String category) {
|
||||||
_selectedCategory = category;
|
_selectedCategory = category;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,131 +1,131 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import '../providers/relaxation_provider.dart';
|
import '../providers/relaxation_provider.dart';
|
||||||
|
|
||||||
class RelaxationScreen extends StatefulWidget {
|
class RelaxationScreen extends StatefulWidget {
|
||||||
const RelaxationScreen({super.key});
|
const RelaxationScreen({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<RelaxationScreen> createState() => _RelaxationScreenState();
|
State<RelaxationScreen> createState() => _RelaxationScreenState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _RelaxationScreenState extends State<RelaxationScreen> {
|
class _RelaxationScreenState extends State<RelaxationScreen> {
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
Future.microtask(() =>
|
Future.microtask(() =>
|
||||||
Provider.of<RelaxationProvider>(context, listen: false).loadActivities());
|
Provider.of<RelaxationProvider>(context, listen: false).loadActivities());
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final provider = Provider.of<RelaxationProvider>(context);
|
final provider = Provider.of<RelaxationProvider>(context);
|
||||||
final categories = ['Toutes', 'Méditation', 'Musique', 'Lecture', 'Sport'];
|
final categories = ['Toutes', 'Méditation', 'Musique', 'Lecture', 'Sport'];
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: const Text('Espace Détente'),
|
title: const Text('Espace Détente'),
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
),
|
),
|
||||||
body: Column(
|
body: Column(
|
||||||
children: [
|
children: [
|
||||||
// Barre de catégories
|
// Barre de catégories
|
||||||
Container(
|
Container(
|
||||||
height: 60,
|
height: 60,
|
||||||
padding: const EdgeInsets.symmetric(vertical: 10),
|
padding: const EdgeInsets.symmetric(vertical: 10),
|
||||||
child: ListView.builder(
|
child: ListView.builder(
|
||||||
scrollDirection: Axis.horizontal,
|
scrollDirection: Axis.horizontal,
|
||||||
itemCount: categories.length,
|
itemCount: categories.length,
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
final cat = categories[index];
|
final cat = categories[index];
|
||||||
final isSelected = provider.selectedCategory == cat;
|
final isSelected = provider.selectedCategory == cat;
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.only(right: 10),
|
padding: const EdgeInsets.only(right: 10),
|
||||||
child: FilterChip(
|
child: FilterChip(
|
||||||
label: Text(cat),
|
label: Text(cat),
|
||||||
selected: isSelected,
|
selected: isSelected,
|
||||||
onSelected: (_) => provider.setCategory(cat),
|
onSelected: (_) => provider.setCategory(cat),
|
||||||
selectedColor: const Color(0xFF000080).withOpacity(0.2),
|
selectedColor: const Color(0xFF000080).withOpacity(0.2),
|
||||||
checkmarkColor: const Color(0xFF000080),
|
checkmarkColor: const Color(0xFF000080),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
// Liste des activités
|
// Liste des activités
|
||||||
Expanded(
|
Expanded(
|
||||||
child: provider.isLoading
|
child: provider.isLoading
|
||||||
? const Center(child: CircularProgressIndicator())
|
? const Center(child: CircularProgressIndicator())
|
||||||
: provider.activities.isEmpty
|
: provider.activities.isEmpty
|
||||||
? const Center(child: Text('Aucune activité trouvée.'))
|
? const Center(child: Text('Aucune activité trouvée.'))
|
||||||
: ListView.builder(
|
: ListView.builder(
|
||||||
itemCount: provider.activities.length,
|
itemCount: provider.activities.length,
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
final activity = provider.activities[index];
|
final activity = provider.activities[index];
|
||||||
return Card(
|
return Card(
|
||||||
margin: const EdgeInsets.only(bottom: 16),
|
margin: const EdgeInsets.only(bottom: 16),
|
||||||
clipBehavior: Clip.antiAlias,
|
clipBehavior: Clip.antiAlias,
|
||||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15)),
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15)),
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
if (activity.imageUrl != null)
|
if (activity.imageUrl != null)
|
||||||
Image.network(
|
Image.network(
|
||||||
activity.imageUrl!,
|
activity.imageUrl!,
|
||||||
height: 150,
|
height: 150,
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
fit: BoxFit.cover,
|
fit: BoxFit.cover,
|
||||||
errorBuilder: (_, __, ___) => Container(
|
errorBuilder: (_, __, ___) => Container(
|
||||||
height: 150,
|
height: 150,
|
||||||
color: Colors.grey.shade200,
|
color: Colors.grey.shade200,
|
||||||
child: const Icon(Icons.image_not_supported),
|
child: const Icon(Icons.image_not_supported),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
activity.category,
|
activity.category,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.orange.shade700,
|
color: Colors.orange.shade700,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (activity.videoUrl != null)
|
if (activity.videoUrl != null)
|
||||||
const Icon(Icons.play_circle_fill, color: Color(0xFF000080)),
|
const Icon(Icons.play_circle_fill, color: Color(0xFF000080)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
Text(
|
Text(
|
||||||
activity.title,
|
activity.title,
|
||||||
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
Text(
|
Text(
|
||||||
activity.description,
|
activity.description,
|
||||||
style: const TextStyle(color: Colors.grey),
|
style: const TextStyle(color: Colors.grey),
|
||||||
maxLines: 2,
|
maxLines: 2,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
import '../../../core/network/dio_client.dart';
|
import '../../../core/network/dio_client.dart';
|
||||||
import '../models/activity.dart';
|
import '../models/activity.dart';
|
||||||
|
|
||||||
class RelaxationService {
|
class RelaxationService {
|
||||||
final Dio _dio = DioClient().dio;
|
final Dio _dio = DioClient().dio;
|
||||||
|
|
||||||
Future<List<Activity>> fetchActivities() async {
|
Future<List<Activity>> fetchActivities() async {
|
||||||
try {
|
try {
|
||||||
final response = await _dio.get('/activities');
|
final response = await _dio.get('/activities');
|
||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
List<dynamic> data = response.data;
|
List<dynamic> data = response.data;
|
||||||
return data.map((item) => Activity.fromJson(item)).toList();
|
return data.map((item) => Activity.fromJson(item)).toList();
|
||||||
}
|
}
|
||||||
return [];
|
return [];
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print("Erreur fetchActivities: $e");
|
print("Erreur fetchActivities: $e");
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,29 +1,29 @@
|
|||||||
class EmotionEntry {
|
class EmotionEntry {
|
||||||
final int? id;
|
final int? id;
|
||||||
final String emotion; // ex: 'Heureux', 'Triste', 'Stressé'
|
final String emotion; // ex: 'Heureux', 'Triste', 'Stressé'
|
||||||
final String? note;
|
final String? note;
|
||||||
final DateTime createdAt;
|
final DateTime createdAt;
|
||||||
|
|
||||||
EmotionEntry({
|
EmotionEntry({
|
||||||
this.id,
|
this.id,
|
||||||
required this.emotion,
|
required this.emotion,
|
||||||
this.note,
|
this.note,
|
||||||
required this.createdAt,
|
required this.createdAt,
|
||||||
});
|
});
|
||||||
|
|
||||||
factory EmotionEntry.fromJson(Map<String, dynamic> json) {
|
factory EmotionEntry.fromJson(Map<String, dynamic> json) {
|
||||||
return EmotionEntry(
|
return EmotionEntry(
|
||||||
id: json['id'],
|
id: json['id'],
|
||||||
emotion: json['emotion_name'] ?? json['emotion'] ?? '',
|
emotion: json['emotion_name'] ?? json['emotion'] ?? '',
|
||||||
note: json['note'],
|
note: json['note'],
|
||||||
createdAt: DateTime.parse(json['created_at']),
|
createdAt: DateTime.parse(json['created_at']),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() {
|
||||||
return {
|
return {
|
||||||
'emotion_name': emotion,
|
'emotion_name': emotion,
|
||||||
'note': note,
|
'note': note,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,39 +1,39 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import '../models/emotion_entry.dart';
|
import '../models/emotion_entry.dart';
|
||||||
import '../services/emotion_service.dart';
|
import '../services/emotion_service.dart';
|
||||||
|
|
||||||
class EmotionProvider with ChangeNotifier {
|
class EmotionProvider with ChangeNotifier {
|
||||||
final EmotionService _service = EmotionService();
|
final EmotionService _service = EmotionService();
|
||||||
List<EmotionEntry> _entries = [];
|
List<EmotionEntry> _entries = [];
|
||||||
bool _isLoading = false;
|
bool _isLoading = false;
|
||||||
|
|
||||||
List<EmotionEntry> get entries => _entries;
|
List<EmotionEntry> get entries => _entries;
|
||||||
bool get isLoading => _isLoading;
|
bool get isLoading => _isLoading;
|
||||||
|
|
||||||
Future<void> loadEmotions() async {
|
Future<void> loadEmotions() async {
|
||||||
_isLoading = true;
|
_isLoading = true;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
_entries = await _service.fetchEmotions();
|
_entries = await _service.fetchEmotions();
|
||||||
// Trier par date décroissante (plus récent en haut)
|
// Trier par date décroissante (plus récent en haut)
|
||||||
_entries.sort((a, b) => b.createdAt.compareTo(a.createdAt));
|
_entries.sort((a, b) => b.createdAt.compareTo(a.createdAt));
|
||||||
_isLoading = false;
|
_isLoading = false;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> addEmotion(String emotion, String note) async {
|
Future<bool> addEmotion(String emotion, String note) async {
|
||||||
final success = await _service.addEmotion(emotion, note);
|
final success = await _service.addEmotion(emotion, note);
|
||||||
if (success) {
|
if (success) {
|
||||||
await loadEmotions();
|
await loadEmotions();
|
||||||
}
|
}
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> deleteEmotion(int id) async {
|
Future<bool> deleteEmotion(int id) async {
|
||||||
final success = await _service.deleteEmotion(id);
|
final success = await _service.deleteEmotion(id);
|
||||||
if (success) {
|
if (success) {
|
||||||
_entries.removeWhere((entry) => entry.id == id);
|
_entries.removeWhere((entry) => entry.id == id);
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,168 +1,168 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import '../providers/emotion_provider.dart';
|
import '../providers/emotion_provider.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
|
|
||||||
class TrackerScreen extends StatefulWidget {
|
class TrackerScreen extends StatefulWidget {
|
||||||
const TrackerScreen({super.key});
|
const TrackerScreen({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<TrackerScreen> createState() => _TrackerScreenState();
|
State<TrackerScreen> createState() => _TrackerScreenState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _TrackerScreenState extends State<TrackerScreen> {
|
class _TrackerScreenState extends State<TrackerScreen> {
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
Future.microtask(() =>
|
Future.microtask(() =>
|
||||||
Provider.of<EmotionProvider>(context, listen: false).loadEmotions());
|
Provider.of<EmotionProvider>(context, listen: false).loadEmotions());
|
||||||
}
|
}
|
||||||
|
|
||||||
void _showAddEmotionDialog() {
|
void _showAddEmotionDialog() {
|
||||||
String selectedEmotion = 'Bien';
|
String selectedEmotion = 'Bien';
|
||||||
final noteController = TextEditingController();
|
final noteController = TextEditingController();
|
||||||
final emotions = ['Très bien', 'Bien', 'Neutre', 'Pas top', 'Stressé'];
|
final emotions = ['Très bien', 'Bien', 'Neutre', 'Pas top', 'Stressé'];
|
||||||
|
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) => StatefulBuilder(
|
builder: (context) => StatefulBuilder(
|
||||||
builder: (context, setDialogState) => AlertDialog(
|
builder: (context, setDialogState) => AlertDialog(
|
||||||
title: const Text('Comment vous sentez-vous ?'),
|
title: const Text('Comment vous sentez-vous ?'),
|
||||||
content: Column(
|
content: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
DropdownButton<String>(
|
DropdownButton<String>(
|
||||||
value: selectedEmotion,
|
value: selectedEmotion,
|
||||||
isExpanded: true,
|
isExpanded: true,
|
||||||
items: emotions.map((String value) {
|
items: emotions.map((String value) {
|
||||||
return DropdownMenuItem<String>(
|
return DropdownMenuItem<String>(
|
||||||
value: value,
|
value: value,
|
||||||
child: Text(value),
|
child: Text(value),
|
||||||
);
|
);
|
||||||
}).toList(),
|
}).toList(),
|
||||||
onChanged: (newValue) {
|
onChanged: (newValue) {
|
||||||
setDialogState(() => selectedEmotion = newValue!);
|
setDialogState(() => selectedEmotion = newValue!);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
TextField(
|
TextField(
|
||||||
controller: noteController,
|
controller: noteController,
|
||||||
decoration: const InputDecoration(
|
decoration: const InputDecoration(
|
||||||
labelText: 'Note (optionnel)',
|
labelText: 'Note (optionnel)',
|
||||||
border: OutlineInputBorder(),
|
border: OutlineInputBorder(),
|
||||||
),
|
),
|
||||||
maxLines: 3,
|
maxLines: 3,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () => Navigator.pop(context),
|
onPressed: () => Navigator.pop(context),
|
||||||
child: const Text('ANNULER'),
|
child: const Text('ANNULER'),
|
||||||
),
|
),
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
final success = await Provider.of<EmotionProvider>(context, listen: false)
|
final success = await Provider.of<EmotionProvider>(context, listen: false)
|
||||||
.addEmotion(selectedEmotion, noteController.text);
|
.addEmotion(selectedEmotion, noteController.text);
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
if (!success) {
|
if (!success) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
const SnackBar(content: Text('Erreur lors de l\'ajout')),
|
const SnackBar(content: Text('Erreur lors de l\'ajout')),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
child: const Text('ENREGISTRER'),
|
child: const Text('ENREGISTRER'),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final provider = Provider.of<EmotionProvider>(context);
|
final provider = Provider.of<EmotionProvider>(context);
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(title: const Text('Journal des Émotions')),
|
appBar: AppBar(title: const Text('Journal des Émotions')),
|
||||||
body: provider.isLoading
|
body: provider.isLoading
|
||||||
? const Center(child: CircularProgressIndicator())
|
? const Center(child: CircularProgressIndicator())
|
||||||
: provider.entries.isEmpty
|
: provider.entries.isEmpty
|
||||||
? const Center(child: Text('Aucune entrée pour le moment.'))
|
? const Center(child: Text('Aucune entrée pour le moment.'))
|
||||||
: ListView.builder(
|
: ListView.builder(
|
||||||
itemCount: provider.entries.length,
|
itemCount: provider.entries.length,
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
final entry = provider.entries[index];
|
final entry = provider.entries[index];
|
||||||
return Card(
|
return Card(
|
||||||
margin: const EdgeInsets.only(bottom: 12),
|
margin: const EdgeInsets.only(bottom: 12),
|
||||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15)),
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15)),
|
||||||
child: ListTile(
|
child: ListTile(
|
||||||
leading: _getEmotionIcon(entry.emotion),
|
leading: _getEmotionIcon(entry.emotion),
|
||||||
title: Text(
|
title: Text(
|
||||||
entry.emotion,
|
entry.emotion,
|
||||||
style: const TextStyle(fontWeight: FontWeight.bold),
|
style: const TextStyle(fontWeight: FontWeight.bold),
|
||||||
),
|
),
|
||||||
subtitle: Column(
|
subtitle: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
if (entry.note != null && entry.note!.isNotEmpty)
|
if (entry.note != null && entry.note!.isNotEmpty)
|
||||||
Text(entry.note!),
|
Text(entry.note!),
|
||||||
Text(
|
Text(
|
||||||
DateFormat('dd/MM/yyyy HH:mm').format(entry.createdAt),
|
DateFormat('dd/MM/yyyy HH:mm').format(entry.createdAt),
|
||||||
style: const TextStyle(fontSize: 12, color: Colors.grey),
|
style: const TextStyle(fontSize: 12, color: Colors.grey),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
trailing: IconButton(
|
trailing: IconButton(
|
||||||
icon: const Icon(Icons.delete_outline, color: Colors.red),
|
icon: const Icon(Icons.delete_outline, color: Colors.red),
|
||||||
onPressed: () => provider.deleteEmotion(entry.id!),
|
onPressed: () => provider.deleteEmotion(entry.id!),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
floatingActionButton: FloatingActionButton(
|
floatingActionButton: FloatingActionButton(
|
||||||
onPressed: _showAddEmotionDialog,
|
onPressed: _showAddEmotionDialog,
|
||||||
backgroundColor: const Color(0xFF000080),
|
backgroundColor: const Color(0xFF000080),
|
||||||
child: const Icon(Icons.add, color: Colors.white),
|
child: const Icon(Icons.add, color: Colors.white),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _getEmotionIcon(String emotion) {
|
Widget _getEmotionIcon(String emotion) {
|
||||||
IconData icon;
|
IconData icon;
|
||||||
Color color;
|
Color color;
|
||||||
switch (emotion) {
|
switch (emotion) {
|
||||||
case 'Très bien':
|
case 'Très bien':
|
||||||
icon = Icons.sentiment_very_satisfied;
|
icon = Icons.sentiment_very_satisfied;
|
||||||
color = const Color(0xFF4CAF50);
|
color = const Color(0xFF4CAF50);
|
||||||
break;
|
break;
|
||||||
case 'Bien':
|
case 'Bien':
|
||||||
icon = Icons.sentiment_satisfied;
|
icon = Icons.sentiment_satisfied;
|
||||||
color = const Color(0xFF8BC34A);
|
color = const Color(0xFF8BC34A);
|
||||||
break;
|
break;
|
||||||
case 'Neutre':
|
case 'Neutre':
|
||||||
icon = Icons.sentiment_neutral;
|
icon = Icons.sentiment_neutral;
|
||||||
color = const Color(0xFFFFC107);
|
color = const Color(0xFFFFC107);
|
||||||
break;
|
break;
|
||||||
case 'Pas top':
|
case 'Pas top':
|
||||||
icon = Icons.sentiment_dissatisfied;
|
icon = Icons.sentiment_dissatisfied;
|
||||||
color = const Color(0xFFFF9800);
|
color = const Color(0xFFFF9800);
|
||||||
break;
|
break;
|
||||||
case 'Stressé':
|
case 'Stressé':
|
||||||
icon = Icons.sentiment_very_dissatisfied;
|
icon = Icons.sentiment_very_dissatisfied;
|
||||||
color = const Color(0xFFF44336);
|
color = const Color(0xFFF44336);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
icon = Icons.sentiment_neutral;
|
icon = Icons.sentiment_neutral;
|
||||||
color = Colors.grey;
|
color = Colors.grey;
|
||||||
}
|
}
|
||||||
return CircleAvatar(
|
return CircleAvatar(
|
||||||
backgroundColor: color.withOpacity(0.1),
|
backgroundColor: color.withOpacity(0.1),
|
||||||
child: Icon(icon, color: color),
|
child: Icon(icon, color: color),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,69 +1,69 @@
|
|||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
import '../../../core/network/dio_client.dart';
|
import '../../../core/network/dio_client.dart';
|
||||||
import '../../auth/services/auth_service.dart';
|
import '../../auth/services/auth_service.dart';
|
||||||
import '../models/emotion_entry.dart';
|
import '../models/emotion_entry.dart';
|
||||||
|
|
||||||
class EmotionService {
|
class EmotionService {
|
||||||
final Dio _dio = DioClient().dio;
|
final Dio _dio = DioClient().dio;
|
||||||
final AuthService _authService = AuthService();
|
final AuthService _authService = AuthService();
|
||||||
|
|
||||||
Future<List<EmotionEntry>> fetchEmotions() async {
|
Future<List<EmotionEntry>> fetchEmotions() async {
|
||||||
try {
|
try {
|
||||||
String? token = await _authService.getToken();
|
String? token = await _authService.getToken();
|
||||||
final response = await _dio.get(
|
final response = await _dio.get(
|
||||||
'/emotions',
|
'/emotions',
|
||||||
options: Options(headers: {
|
options: Options(headers: {
|
||||||
'Authorization': 'Bearer $token',
|
'Authorization': 'Bearer $token',
|
||||||
'Accept': 'application/json',
|
'Accept': 'application/json',
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
List<dynamic> data = response.data;
|
List<dynamic> data = response.data;
|
||||||
return data.map((item) => EmotionEntry.fromJson(item)).toList();
|
return data.map((item) => EmotionEntry.fromJson(item)).toList();
|
||||||
}
|
}
|
||||||
return [];
|
return [];
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print("Erreur fetchEmotions: $e");
|
print("Erreur fetchEmotions: $e");
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> addEmotion(String emotion, String note) async {
|
Future<bool> addEmotion(String emotion, String note) async {
|
||||||
try {
|
try {
|
||||||
String? token = await _authService.getToken();
|
String? token = await _authService.getToken();
|
||||||
final response = await _dio.post(
|
final response = await _dio.post(
|
||||||
'/emotions',
|
'/emotions',
|
||||||
data: {
|
data: {
|
||||||
'emotion_name': emotion,
|
'emotion_name': emotion,
|
||||||
'note': note,
|
'note': note,
|
||||||
},
|
},
|
||||||
options: Options(headers: {
|
options: Options(headers: {
|
||||||
'Authorization': 'Bearer $token',
|
'Authorization': 'Bearer $token',
|
||||||
'Accept': 'application/json',
|
'Accept': 'application/json',
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
return response.statusCode == 201 || response.statusCode == 200;
|
return response.statusCode == 201 || response.statusCode == 200;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print("Erreur addEmotion: $e");
|
print("Erreur addEmotion: $e");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> deleteEmotion(int id) async {
|
Future<bool> deleteEmotion(int id) async {
|
||||||
try {
|
try {
|
||||||
String? token = await _authService.getToken();
|
String? token = await _authService.getToken();
|
||||||
final response = await _dio.delete(
|
final response = await _dio.delete(
|
||||||
'/emotions/$id',
|
'/emotions/$id',
|
||||||
options: Options(headers: {
|
options: Options(headers: {
|
||||||
'Authorization': 'Bearer $token',
|
'Authorization': 'Bearer $token',
|
||||||
'Accept': 'application/json',
|
'Accept': 'application/json',
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
return response.statusCode == 200 || response.statusCode == 204;
|
return response.statusCode == 200 || response.statusCode == 204;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print("Erreur deleteEmotion: $e");
|
print("Erreur deleteEmotion: $e");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,74 +1,74 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:permission_handler/permission_handler.dart';
|
import 'package:permission_handler/permission_handler.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import '../tracker/providers/emotion_provider.dart';
|
import '../tracker/providers/emotion_provider.dart';
|
||||||
|
|
||||||
class WearSyncService {
|
class WearSyncService {
|
||||||
static const _platform = MethodChannel('com.cesizen/wearable');
|
static const _platform = MethodChannel('com.cesizen/wearable');
|
||||||
|
|
||||||
static void initialize(BuildContext context) {
|
static void initialize(BuildContext context) {
|
||||||
_platform.setMethodCallHandler((call) async {
|
_platform.setMethodCallHandler((call) async {
|
||||||
switch (call.method) {
|
switch (call.method) {
|
||||||
case "requestStatusUpdate":
|
case "requestStatusUpdate":
|
||||||
// On peut forcer un rafraîchissement des données ici si besoin
|
// On peut forcer un rafraîchissement des données ici si besoin
|
||||||
break;
|
break;
|
||||||
case "saveMoodFromWear":
|
case "saveMoodFromWear":
|
||||||
final String mood = call.arguments['mood'];
|
final String mood = call.arguments['mood'];
|
||||||
print("DEBUG FLUTTER: Message saveMoodFromWear reçu pour '$mood'");
|
print("DEBUG FLUTTER: Message saveMoodFromWear reçu pour '$mood'");
|
||||||
if (mood.isNotEmpty) {
|
if (mood.isNotEmpty) {
|
||||||
// UTILISATION DU PROVIDER : C'est la clé pour que le token soit inclus
|
// UTILISATION DU PROVIDER : C'est la clé pour que le token soit inclus
|
||||||
try {
|
try {
|
||||||
final emotionProvider = Provider.of<EmotionProvider>(context, listen: false);
|
final emotionProvider = Provider.of<EmotionProvider>(context, listen: false);
|
||||||
await emotionProvider.addEmotion(mood, "Enregistré depuis la montre");
|
await emotionProvider.addEmotion(mood, "Enregistré depuis la montre");
|
||||||
print("DEBUG: Humeur '$mood' envoyée à l'API via Provider");
|
print("DEBUG: Humeur '$mood' envoyée à l'API via Provider");
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print("DEBUG ERROR: Impossible d'accéder au Provider: $e");
|
print("DEBUG ERROR: Impossible d'accéder au Provider: $e");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<void> syncMoodToWatch(String mood) async {
|
static Future<void> syncMoodToWatch(String mood) async {
|
||||||
await _platform.invokeMethod('syncMood', {'mood': mood});
|
await _platform.invokeMethod('syncMood', {'mood': mood});
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<void> checkAndPromptWearSync(BuildContext context, String? userName) async {
|
static Future<void> checkAndPromptWearSync(BuildContext context, String? userName) async {
|
||||||
if (await Permission.bluetoothConnect.request().isGranted) {
|
if (await Permission.bluetoothConnect.request().isGranted) {
|
||||||
final bool? isWatchNearby = await _platform.invokeMethod('isWatchNearby');
|
final bool? isWatchNearby = await _platform.invokeMethod('isWatchNearby');
|
||||||
|
|
||||||
if (isWatchNearby == true && context.mounted) {
|
if (isWatchNearby == true && context.mounted) {
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
title: const Text("Montre connectée détectée"),
|
title: const Text("Montre connectée détectée"),
|
||||||
content: const Text(
|
content: const Text(
|
||||||
"Souhaitez-vous lier CESIZen à votre montre pour suivre votre état émotionnel au poignet ?"
|
"Souhaitez-vous lier CESIZen à votre montre pour suivre votre état émotionnel au poignet ?"
|
||||||
),
|
),
|
||||||
actions: [
|
actions: [
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () => Navigator.pop(context),
|
onPressed: () => Navigator.pop(context),
|
||||||
child: const Text("PLUS TARD", style: TextStyle(color: Colors.grey)),
|
child: const Text("PLUS TARD", style: TextStyle(color: Colors.grey)),
|
||||||
),
|
),
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
await _platform.invokeMethod('sendAuthStatus', {
|
await _platform.invokeMethod('sendAuthStatus', {
|
||||||
'status': userName != null ? 'authenticated' : 'unauthenticated',
|
'status': userName != null ? 'authenticated' : 'unauthenticated',
|
||||||
'userName': userName ?? '',
|
'userName': userName ?? '',
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
style: ElevatedButton.styleFrom(backgroundColor: const Color(0xFF000091)),
|
style: ElevatedButton.styleFrom(backgroundColor: const Color(0xFF000091)),
|
||||||
child: const Text("ACTIVER LA LIAISON", style: TextStyle(color: Colors.white)),
|
child: const Text("ACTIVER LA LIAISON", style: TextStyle(color: Colors.white)),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+372
-372
@@ -1,372 +1,372 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/rendering.dart';
|
import 'package:flutter/rendering.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'features/auth/providers/auth_provider.dart';
|
import 'features/auth/providers/auth_provider.dart';
|
||||||
import 'features/diagnostics/providers/diagnostic_provider.dart';
|
import 'features/diagnostics/providers/diagnostic_provider.dart';
|
||||||
import 'features/tracker/providers/emotion_provider.dart';
|
import 'features/tracker/providers/emotion_provider.dart';
|
||||||
import 'features/relaxation/providers/relaxation_provider.dart';
|
import 'features/relaxation/providers/relaxation_provider.dart';
|
||||||
import 'features/auth/screens/login_screen.dart';
|
import 'features/auth/screens/login_screen.dart';
|
||||||
import 'features/auth/screens/profile_screen.dart';
|
import 'features/auth/screens/profile_screen.dart';
|
||||||
import 'features/diagnostics/screens/diagnostic_screen.dart';
|
import 'features/diagnostics/screens/diagnostic_screen.dart';
|
||||||
import 'features/exercises/screens/breathing_screen.dart';
|
import 'features/exercises/screens/breathing_screen.dart';
|
||||||
import 'features/informations/screens/info_screen.dart';
|
import 'features/informations/screens/info_screen.dart';
|
||||||
import 'features/informations/providers/information_provider.dart';
|
import 'features/informations/providers/information_provider.dart';
|
||||||
import 'features/tracker/screens/tracker_screen.dart';
|
import 'features/tracker/screens/tracker_screen.dart';
|
||||||
import 'features/relaxation/screens/relaxation_screen.dart';
|
import 'features/relaxation/screens/relaxation_screen.dart';
|
||||||
import 'features/wear/wear_sync_service.dart';
|
import 'features/wear/wear_sync_service.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
runApp(
|
runApp(
|
||||||
MultiProvider(
|
MultiProvider(
|
||||||
providers: [
|
providers: [
|
||||||
ChangeNotifierProvider(create: (_) => AuthProvider()),
|
ChangeNotifierProvider(create: (_) => AuthProvider()),
|
||||||
ChangeNotifierProvider(create: (_) => DiagnosticProvider()),
|
ChangeNotifierProvider(create: (_) => DiagnosticProvider()),
|
||||||
ChangeNotifierProvider(create: (_) => EmotionProvider()),
|
ChangeNotifierProvider(create: (_) => EmotionProvider()),
|
||||||
ChangeNotifierProvider(create: (_) => RelaxationProvider()),
|
ChangeNotifierProvider(create: (_) => RelaxationProvider()),
|
||||||
ChangeNotifierProvider(create: (_) => InformationProvider()),
|
ChangeNotifierProvider(create: (_) => InformationProvider()),
|
||||||
],
|
],
|
||||||
child: const MyApp(),
|
child: const MyApp(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
class MyApp extends StatelessWidget {
|
class MyApp extends StatelessWidget {
|
||||||
const MyApp({super.key});
|
const MyApp({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return MaterialApp(
|
return MaterialApp(
|
||||||
title: 'CESIZen',
|
title: 'CESIZen',
|
||||||
debugShowCheckedModeBanner: false,
|
debugShowCheckedModeBanner: false,
|
||||||
theme: ThemeData(
|
theme: ThemeData(
|
||||||
colorScheme: ColorScheme.fromSeed(seedColor: const Color(0xFF000080)),
|
colorScheme: ColorScheme.fromSeed(seedColor: const Color(0xFF000080)),
|
||||||
useMaterial3: true,
|
useMaterial3: true,
|
||||||
scaffoldBackgroundColor: Colors.white,
|
scaffoldBackgroundColor: Colors.white,
|
||||||
),
|
),
|
||||||
home: const HomeScreen(),
|
home: const HomeScreen(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class HomeScreen extends StatefulWidget {
|
class HomeScreen extends StatefulWidget {
|
||||||
const HomeScreen({super.key});
|
const HomeScreen({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<HomeScreen> createState() => _HomeScreenState();
|
State<HomeScreen> createState() => _HomeScreenState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _HomeScreenState extends State<HomeScreen> {
|
class _HomeScreenState extends State<HomeScreen> {
|
||||||
final ScrollController _scrollController = ScrollController();
|
final ScrollController _scrollController = ScrollController();
|
||||||
bool _isFabExpanded = true;
|
bool _isFabExpanded = true;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
_scrollController.addListener(_onScroll);
|
_scrollController.addListener(_onScroll);
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
WearSyncService.initialize(context);
|
WearSyncService.initialize(context);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
_scrollController.removeListener(_onScroll);
|
_scrollController.removeListener(_onScroll);
|
||||||
_scrollController.dispose();
|
_scrollController.dispose();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onScroll() {
|
void _onScroll() {
|
||||||
if (_scrollController.position.userScrollDirection == ScrollDirection.reverse) {
|
if (_scrollController.position.userScrollDirection == ScrollDirection.reverse) {
|
||||||
if (_isFabExpanded) {
|
if (_isFabExpanded) {
|
||||||
setState(() => _isFabExpanded = false);
|
setState(() => _isFabExpanded = false);
|
||||||
}
|
}
|
||||||
} else if (_scrollController.position.userScrollDirection == ScrollDirection.forward) {
|
} else if (_scrollController.position.userScrollDirection == ScrollDirection.forward) {
|
||||||
if (!_isFabExpanded) {
|
if (!_isFabExpanded) {
|
||||||
setState(() => _isFabExpanded = true);
|
setState(() => _isFabExpanded = true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final authProvider = Provider.of<AuthProvider>(context);
|
final authProvider = Provider.of<AuthProvider>(context);
|
||||||
|
|
||||||
if (authProvider.isLoading && authProvider.user == null) {
|
if (authProvider.isLoading && authProvider.user == null) {
|
||||||
return const Scaffold(
|
return const Scaffold(
|
||||||
body: Center(
|
body: Center(
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
CircularProgressIndicator(color: Color(0xFF000080)),
|
CircularProgressIndicator(color: Color(0xFF000080)),
|
||||||
SizedBox(height: 20),
|
SizedBox(height: 20),
|
||||||
Text("Synchronisation en cours...", style: TextStyle(color: Color(0xFF000080), fontWeight: FontWeight.bold)),
|
Text("Synchronisation en cours...", style: TextStyle(color: Color(0xFF000080), fontWeight: FontWeight.bold)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
final bool isLoggedIn = authProvider.isAuthenticated;
|
final bool isLoggedIn = authProvider.isAuthenticated;
|
||||||
final String userName = isLoggedIn ? (authProvider.user?.name ?? 'Utilisateur') : 'Visiteur';
|
final String userName = isLoggedIn ? (authProvider.user?.name ?? 'Utilisateur') : 'Visiteur';
|
||||||
|
|
||||||
if (isLoggedIn) {
|
if (isLoggedIn) {
|
||||||
WearSyncService.checkAndPromptWearSync(context, authProvider.user?.name);
|
WearSyncService.checkAndPromptWearSync(context, authProvider.user?.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
body: SafeArea(
|
body: SafeArea(
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
// HEADER FIXE (Logos + Bonjour + Message)
|
// HEADER FIXE (Logos + Bonjour + Message)
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.fromLTRB(24, 20, 24, 20),
|
padding: const EdgeInsets.fromLTRB(24, 20, 24, 20),
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Image.asset('assets/images/ministere.png', height: 60),
|
Image.asset('assets/images/ministere.png', height: 60),
|
||||||
Image.asset('assets/images/CesiZen.png', height: 40),
|
Image.asset('assets/images/CesiZen.png', height: 40),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(height: 30),
|
const SizedBox(height: 30),
|
||||||
const Text('Bonjour,', style: TextStyle(fontSize: 18, color: Colors.grey)),
|
const Text('Bonjour,', style: TextStyle(fontSize: 18, color: Colors.grey)),
|
||||||
Text(
|
Text(
|
||||||
userName,
|
userName,
|
||||||
style: const TextStyle(fontSize: 32, fontWeight: FontWeight.bold),
|
style: const TextStyle(fontSize: 32, fontWeight: FontWeight.bold),
|
||||||
),
|
),
|
||||||
Container(
|
Container(
|
||||||
margin: const EdgeInsets.only(top: 8, bottom: 20),
|
margin: const EdgeInsets.only(top: 8, bottom: 20),
|
||||||
width: 40,
|
width: 40,
|
||||||
height: 4,
|
height: 4,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.orange.shade300,
|
color: Colors.orange.shade300,
|
||||||
borderRadius: BorderRadius.circular(2),
|
borderRadius: BorderRadius.circular(2),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Container(
|
Container(
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
padding: const EdgeInsets.all(20),
|
padding: const EdgeInsets.all(20),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
borderRadius: BorderRadius.circular(20),
|
borderRadius: BorderRadius.circular(20),
|
||||||
boxShadow: [
|
boxShadow: [
|
||||||
BoxShadow(
|
BoxShadow(
|
||||||
color: Colors.black.withOpacity(0.05),
|
color: Colors.black.withOpacity(0.05),
|
||||||
blurRadius: 10,
|
blurRadius: 10,
|
||||||
offset: const Offset(0, 4),
|
offset: const Offset(0, 4),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
border: Border.all(color: Colors.grey.shade100),
|
border: Border.all(color: Colors.grey.shade100),
|
||||||
),
|
),
|
||||||
child: const Column(
|
child: const Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'Prenez soin de vous',
|
'Prenez soin de vous',
|
||||||
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold, color: Color(0xFF000080)),
|
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold, color: Color(0xFF000080)),
|
||||||
),
|
),
|
||||||
SizedBox(height: 8),
|
SizedBox(height: 8),
|
||||||
Text(
|
Text(
|
||||||
'Retrouvez vos outils de suivi et de détente.',
|
'Retrouvez vos outils de suivi et de détente.',
|
||||||
style: TextStyle(color: Colors.grey),
|
style: TextStyle(color: Colors.grey),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
// ZONE SCROLLABLE (UNIQUEMENT LES BOUTONS)
|
// ZONE SCROLLABLE (UNIQUEMENT LES BOUTONS)
|
||||||
Expanded(
|
Expanded(
|
||||||
child: GridView.count(
|
child: GridView.count(
|
||||||
controller: _scrollController,
|
controller: _scrollController,
|
||||||
padding: const EdgeInsets.fromLTRB(24, 0, 24, 100),
|
padding: const EdgeInsets.fromLTRB(24, 0, 24, 100),
|
||||||
crossAxisCount: 2,
|
crossAxisCount: 2,
|
||||||
crossAxisSpacing: 20,
|
crossAxisSpacing: 20,
|
||||||
mainAxisSpacing: 20,
|
mainAxisSpacing: 20,
|
||||||
children: [
|
children: [
|
||||||
_buildMenuCard(
|
_buildMenuCard(
|
||||||
context,
|
context,
|
||||||
'Tracker',
|
'Tracker',
|
||||||
Icons.access_time,
|
Icons.access_time,
|
||||||
Colors.teal.shade300,
|
Colors.teal.shade300,
|
||||||
isLocked: !isLoggedIn,
|
isLocked: !isLoggedIn,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Navigator.push(context, MaterialPageRoute(builder: (_) => const TrackerScreen()));
|
Navigator.push(context, MaterialPageRoute(builder: (_) => const TrackerScreen()));
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
_buildMenuCard(
|
_buildMenuCard(
|
||||||
context,
|
context,
|
||||||
'Diagnostics',
|
'Diagnostics',
|
||||||
Icons.analytics_outlined,
|
Icons.analytics_outlined,
|
||||||
Colors.orange.shade200,
|
Colors.orange.shade200,
|
||||||
isLocked: !isLoggedIn,
|
isLocked: !isLoggedIn,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Navigator.push(context, MaterialPageRoute(builder: (_) => const DiagnosticScreen()));
|
Navigator.push(context, MaterialPageRoute(builder: (_) => const DiagnosticScreen()));
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
_buildMenuCard(
|
_buildMenuCard(
|
||||||
context,
|
context,
|
||||||
'Respiration',
|
'Respiration',
|
||||||
Icons.explore_outlined,
|
Icons.explore_outlined,
|
||||||
Colors.indigo.shade300,
|
Colors.indigo.shade300,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Navigator.push(context, MaterialPageRoute(builder: (_) => const BreathingScreen()));
|
Navigator.push(context, MaterialPageRoute(builder: (_) => const BreathingScreen()));
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
_buildMenuCard(
|
_buildMenuCard(
|
||||||
context,
|
context,
|
||||||
'Détente',
|
'Détente',
|
||||||
Icons.play_arrow_outlined,
|
Icons.play_arrow_outlined,
|
||||||
Colors.red.shade300,
|
Colors.red.shade300,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Navigator.push(context, MaterialPageRoute(builder: (_) => const RelaxationScreen()));
|
Navigator.push(context, MaterialPageRoute(builder: (_) => const RelaxationScreen()));
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
_buildMenuCard(
|
_buildMenuCard(
|
||||||
context,
|
context,
|
||||||
'Informations',
|
'Informations',
|
||||||
Icons.info_outline,
|
Icons.info_outline,
|
||||||
Colors.lightBlue.shade300,
|
Colors.lightBlue.shade300,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Navigator.push(context, MaterialPageRoute(builder: (_) => const InfoScreen()));
|
Navigator.push(context, MaterialPageRoute(builder: (_) => const InfoScreen()));
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
floatingActionButtonLocation: FloatingActionButtonLocation.endFloat,
|
floatingActionButtonLocation: FloatingActionButtonLocation.endFloat,
|
||||||
floatingActionButton: Padding(
|
floatingActionButton: Padding(
|
||||||
padding: const EdgeInsets.only(bottom: 20.0),
|
padding: const EdgeInsets.only(bottom: 20.0),
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
if (isLoggedIn) {
|
if (isLoggedIn) {
|
||||||
Navigator.push(context, MaterialPageRoute(builder: (_) => const ProfileScreen()));
|
Navigator.push(context, MaterialPageRoute(builder: (_) => const ProfileScreen()));
|
||||||
} else {
|
} else {
|
||||||
Navigator.push(context, MaterialPageRoute(builder: (_) => const LoginScreen()));
|
Navigator.push(context, MaterialPageRoute(builder: (_) => const LoginScreen()));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
child: AnimatedContainer(
|
child: AnimatedContainer(
|
||||||
duration: const Duration(milliseconds: 300),
|
duration: const Duration(milliseconds: 300),
|
||||||
curve: Curves.easeInOut,
|
curve: Curves.easeInOut,
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 15),
|
padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 15),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: const Color(0xFF000080),
|
color: const Color(0xFF000080),
|
||||||
borderRadius: BorderRadius.circular(_isFabExpanded ? 15 : 30),
|
borderRadius: BorderRadius.circular(_isFabExpanded ? 15 : 30),
|
||||||
boxShadow: [
|
boxShadow: [
|
||||||
BoxShadow(
|
BoxShadow(
|
||||||
color: const Color(0xFF000080).withOpacity(0.3),
|
color: const Color(0xFF000080).withOpacity(0.3),
|
||||||
blurRadius: 10,
|
blurRadius: 10,
|
||||||
offset: const Offset(0, 5),
|
offset: const Offset(0, 5),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
child: AnimatedSize(
|
child: AnimatedSize(
|
||||||
duration: const Duration(milliseconds: 300),
|
duration: const Duration(milliseconds: 300),
|
||||||
curve: Curves.easeInOut,
|
curve: Curves.easeInOut,
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
const Icon(Icons.lock, color: Colors.white, size: 20),
|
const Icon(Icons.lock, color: Colors.white, size: 20),
|
||||||
ClipRect(
|
ClipRect(
|
||||||
child: AnimatedOpacity(
|
child: AnimatedOpacity(
|
||||||
opacity: _isFabExpanded ? 1.0 : 0.0,
|
opacity: _isFabExpanded ? 1.0 : 0.0,
|
||||||
duration: const Duration(milliseconds: 200),
|
duration: const Duration(milliseconds: 200),
|
||||||
child: AnimatedSize(
|
child: AnimatedSize(
|
||||||
duration: const Duration(milliseconds: 300),
|
duration: const Duration(milliseconds: 300),
|
||||||
curve: Curves.easeInOut,
|
curve: Curves.easeInOut,
|
||||||
child: _isFabExpanded
|
child: _isFabExpanded
|
||||||
? const Row(
|
? const Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
SizedBox(width: 10),
|
SizedBox(width: 10),
|
||||||
Text(
|
Text(
|
||||||
'Espace Santé',
|
'Espace Santé',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
: const SizedBox.shrink(),
|
: const SizedBox.shrink(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildMenuCard(BuildContext context, String title, IconData icon, Color iconColor, {VoidCallback? onTap, bool isLocked = false}) {
|
Widget _buildMenuCard(BuildContext context, String title, IconData icon, Color iconColor, {VoidCallback? onTap, bool isLocked = false}) {
|
||||||
return InkWell(
|
return InkWell(
|
||||||
onTap: isLocked
|
onTap: isLocked
|
||||||
? () {
|
? () {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
const SnackBar(
|
const SnackBar(
|
||||||
content: Text('Connectez-vous pour accéder à cette fonctionnalité'),
|
content: Text('Connectez-vous pour accéder à cette fonctionnalité'),
|
||||||
backgroundColor: Color(0xFF000080),
|
backgroundColor: Color(0xFF000080),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
: onTap,
|
: onTap,
|
||||||
borderRadius: BorderRadius.circular(20),
|
borderRadius: BorderRadius.circular(20),
|
||||||
child: Container(
|
child: Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
borderRadius: BorderRadius.circular(20),
|
borderRadius: BorderRadius.circular(20),
|
||||||
border: Border.all(color: Colors.grey.shade200),
|
border: Border.all(color: Colors.grey.shade200),
|
||||||
boxShadow: [
|
boxShadow: [
|
||||||
BoxShadow(
|
BoxShadow(
|
||||||
color: Colors.black.withOpacity(0.02),
|
color: Colors.black.withOpacity(0.02),
|
||||||
blurRadius: 5,
|
blurRadius: 5,
|
||||||
offset: const Offset(0, 2),
|
offset: const Offset(0, 2),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
child: Stack(
|
child: Stack(
|
||||||
children: [
|
children: [
|
||||||
Center(
|
Center(
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Icon(
|
Icon(
|
||||||
icon,
|
icon,
|
||||||
size: 36,
|
size: 36,
|
||||||
color: isLocked ? Colors.grey.shade300 : iconColor
|
color: isLocked ? Colors.grey.shade300 : iconColor
|
||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
Text(
|
Text(
|
||||||
title,
|
title,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
color: isLocked ? Colors.grey : Colors.black87,
|
color: isLocked ? Colors.grey : Colors.black87,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (isLocked)
|
if (isLocked)
|
||||||
const Positioned(
|
const Positioned(
|
||||||
top: 10,
|
top: 10,
|
||||||
right: 10,
|
right: 10,
|
||||||
child: Icon(Icons.lock_outline, size: 18, color: Colors.grey),
|
child: Icon(Icons.lock_outline, size: 18, color: Colors.grey),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
flutter/ephemeral
|
flutter/ephemeral
|
||||||
|
|||||||
+128
-128
@@ -1,128 +1,128 @@
|
|||||||
# Project-level configuration.
|
# Project-level configuration.
|
||||||
cmake_minimum_required(VERSION 3.13)
|
cmake_minimum_required(VERSION 3.13)
|
||||||
project(runner LANGUAGES CXX)
|
project(runner LANGUAGES CXX)
|
||||||
|
|
||||||
# The name of the executable created for the application. Change this to change
|
# The name of the executable created for the application. Change this to change
|
||||||
# the on-disk name of your application.
|
# the on-disk name of your application.
|
||||||
set(BINARY_NAME "mobile")
|
set(BINARY_NAME "mobile")
|
||||||
# The unique GTK application identifier for this application. See:
|
# The unique GTK application identifier for this application. See:
|
||||||
# https://wiki.gnome.org/HowDoI/ChooseApplicationID
|
# https://wiki.gnome.org/HowDoI/ChooseApplicationID
|
||||||
set(APPLICATION_ID "com.example.mobile")
|
set(APPLICATION_ID "com.example.mobile")
|
||||||
|
|
||||||
# Explicitly opt in to modern CMake behaviors to avoid warnings with recent
|
# Explicitly opt in to modern CMake behaviors to avoid warnings with recent
|
||||||
# versions of CMake.
|
# versions of CMake.
|
||||||
cmake_policy(SET CMP0063 NEW)
|
cmake_policy(SET CMP0063 NEW)
|
||||||
|
|
||||||
# Load bundled libraries from the lib/ directory relative to the binary.
|
# Load bundled libraries from the lib/ directory relative to the binary.
|
||||||
set(CMAKE_INSTALL_RPATH "$ORIGIN/lib")
|
set(CMAKE_INSTALL_RPATH "$ORIGIN/lib")
|
||||||
|
|
||||||
# Root filesystem for cross-building.
|
# Root filesystem for cross-building.
|
||||||
if(FLUTTER_TARGET_PLATFORM_SYSROOT)
|
if(FLUTTER_TARGET_PLATFORM_SYSROOT)
|
||||||
set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT})
|
set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT})
|
||||||
set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT})
|
set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT})
|
||||||
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||||
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
|
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
|
||||||
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||||
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Define build configuration options.
|
# Define build configuration options.
|
||||||
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
||||||
set(CMAKE_BUILD_TYPE "Debug" CACHE
|
set(CMAKE_BUILD_TYPE "Debug" CACHE
|
||||||
STRING "Flutter build mode" FORCE)
|
STRING "Flutter build mode" FORCE)
|
||||||
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
|
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
|
||||||
"Debug" "Profile" "Release")
|
"Debug" "Profile" "Release")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Compilation settings that should be applied to most targets.
|
# Compilation settings that should be applied to most targets.
|
||||||
#
|
#
|
||||||
# Be cautious about adding new options here, as plugins use this function by
|
# Be cautious about adding new options here, as plugins use this function by
|
||||||
# default. In most cases, you should add new options to specific targets instead
|
# default. In most cases, you should add new options to specific targets instead
|
||||||
# of modifying this function.
|
# of modifying this function.
|
||||||
function(APPLY_STANDARD_SETTINGS TARGET)
|
function(APPLY_STANDARD_SETTINGS TARGET)
|
||||||
target_compile_features(${TARGET} PUBLIC cxx_std_14)
|
target_compile_features(${TARGET} PUBLIC cxx_std_14)
|
||||||
target_compile_options(${TARGET} PRIVATE -Wall -Werror)
|
target_compile_options(${TARGET} PRIVATE -Wall -Werror)
|
||||||
target_compile_options(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:-O3>")
|
target_compile_options(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:-O3>")
|
||||||
target_compile_definitions(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:NDEBUG>")
|
target_compile_definitions(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:NDEBUG>")
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
# Flutter library and tool build rules.
|
# Flutter library and tool build rules.
|
||||||
set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter")
|
set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter")
|
||||||
add_subdirectory(${FLUTTER_MANAGED_DIR})
|
add_subdirectory(${FLUTTER_MANAGED_DIR})
|
||||||
|
|
||||||
# System-level dependencies.
|
# System-level dependencies.
|
||||||
find_package(PkgConfig REQUIRED)
|
find_package(PkgConfig REQUIRED)
|
||||||
pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0)
|
pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0)
|
||||||
|
|
||||||
# Application build; see runner/CMakeLists.txt.
|
# Application build; see runner/CMakeLists.txt.
|
||||||
add_subdirectory("runner")
|
add_subdirectory("runner")
|
||||||
|
|
||||||
# Run the Flutter tool portions of the build. This must not be removed.
|
# Run the Flutter tool portions of the build. This must not be removed.
|
||||||
add_dependencies(${BINARY_NAME} flutter_assemble)
|
add_dependencies(${BINARY_NAME} flutter_assemble)
|
||||||
|
|
||||||
# Only the install-generated bundle's copy of the executable will launch
|
# Only the install-generated bundle's copy of the executable will launch
|
||||||
# correctly, since the resources must in the right relative locations. To avoid
|
# correctly, since the resources must in the right relative locations. To avoid
|
||||||
# people trying to run the unbundled copy, put it in a subdirectory instead of
|
# people trying to run the unbundled copy, put it in a subdirectory instead of
|
||||||
# the default top-level location.
|
# the default top-level location.
|
||||||
set_target_properties(${BINARY_NAME}
|
set_target_properties(${BINARY_NAME}
|
||||||
PROPERTIES
|
PROPERTIES
|
||||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run"
|
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
# Generated plugin build rules, which manage building the plugins and adding
|
# Generated plugin build rules, which manage building the plugins and adding
|
||||||
# them to the application.
|
# them to the application.
|
||||||
include(flutter/generated_plugins.cmake)
|
include(flutter/generated_plugins.cmake)
|
||||||
|
|
||||||
|
|
||||||
# === Installation ===
|
# === Installation ===
|
||||||
# By default, "installing" just makes a relocatable bundle in the build
|
# By default, "installing" just makes a relocatable bundle in the build
|
||||||
# directory.
|
# directory.
|
||||||
set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle")
|
set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle")
|
||||||
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
|
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
|
||||||
set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE)
|
set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Start with a clean build bundle directory every time.
|
# Start with a clean build bundle directory every time.
|
||||||
install(CODE "
|
install(CODE "
|
||||||
file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\")
|
file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\")
|
||||||
" COMPONENT Runtime)
|
" COMPONENT Runtime)
|
||||||
|
|
||||||
set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data")
|
set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data")
|
||||||
set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib")
|
set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib")
|
||||||
|
|
||||||
install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}"
|
install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}"
|
||||||
COMPONENT Runtime)
|
COMPONENT Runtime)
|
||||||
|
|
||||||
install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
|
install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
|
||||||
COMPONENT Runtime)
|
COMPONENT Runtime)
|
||||||
|
|
||||||
install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
|
install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
|
||||||
COMPONENT Runtime)
|
COMPONENT Runtime)
|
||||||
|
|
||||||
foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES})
|
foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES})
|
||||||
install(FILES "${bundled_library}"
|
install(FILES "${bundled_library}"
|
||||||
DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
|
DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
|
||||||
COMPONENT Runtime)
|
COMPONENT Runtime)
|
||||||
endforeach(bundled_library)
|
endforeach(bundled_library)
|
||||||
|
|
||||||
# Copy the native assets provided by the build.dart from all packages.
|
# Copy the native assets provided by the build.dart from all packages.
|
||||||
set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/linux/")
|
set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/linux/")
|
||||||
install(DIRECTORY "${NATIVE_ASSETS_DIR}"
|
install(DIRECTORY "${NATIVE_ASSETS_DIR}"
|
||||||
DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
|
DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
|
||||||
COMPONENT Runtime)
|
COMPONENT Runtime)
|
||||||
|
|
||||||
# Fully re-copy the assets directory on each build to avoid having stale files
|
# Fully re-copy the assets directory on each build to avoid having stale files
|
||||||
# from a previous install.
|
# from a previous install.
|
||||||
set(FLUTTER_ASSET_DIR_NAME "flutter_assets")
|
set(FLUTTER_ASSET_DIR_NAME "flutter_assets")
|
||||||
install(CODE "
|
install(CODE "
|
||||||
file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\")
|
file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\")
|
||||||
" COMPONENT Runtime)
|
" COMPONENT Runtime)
|
||||||
install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}"
|
install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}"
|
||||||
DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime)
|
DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime)
|
||||||
|
|
||||||
# Install the AOT library on non-Debug builds only.
|
# Install the AOT library on non-Debug builds only.
|
||||||
if(NOT CMAKE_BUILD_TYPE MATCHES "Debug")
|
if(NOT CMAKE_BUILD_TYPE MATCHES "Debug")
|
||||||
install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
|
install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
|
||||||
COMPONENT Runtime)
|
COMPONENT Runtime)
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
@@ -1,88 +1,88 @@
|
|||||||
# This file controls Flutter-level build steps. It should not be edited.
|
# This file controls Flutter-level build steps. It should not be edited.
|
||||||
cmake_minimum_required(VERSION 3.10)
|
cmake_minimum_required(VERSION 3.10)
|
||||||
|
|
||||||
set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral")
|
set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral")
|
||||||
|
|
||||||
# Configuration provided via flutter tool.
|
# Configuration provided via flutter tool.
|
||||||
include(${EPHEMERAL_DIR}/generated_config.cmake)
|
include(${EPHEMERAL_DIR}/generated_config.cmake)
|
||||||
|
|
||||||
# TODO: Move the rest of this into files in ephemeral. See
|
# TODO: Move the rest of this into files in ephemeral. See
|
||||||
# https://github.com/flutter/flutter/issues/57146.
|
# https://github.com/flutter/flutter/issues/57146.
|
||||||
|
|
||||||
# Serves the same purpose as list(TRANSFORM ... PREPEND ...),
|
# Serves the same purpose as list(TRANSFORM ... PREPEND ...),
|
||||||
# which isn't available in 3.10.
|
# which isn't available in 3.10.
|
||||||
function(list_prepend LIST_NAME PREFIX)
|
function(list_prepend LIST_NAME PREFIX)
|
||||||
set(NEW_LIST "")
|
set(NEW_LIST "")
|
||||||
foreach(element ${${LIST_NAME}})
|
foreach(element ${${LIST_NAME}})
|
||||||
list(APPEND NEW_LIST "${PREFIX}${element}")
|
list(APPEND NEW_LIST "${PREFIX}${element}")
|
||||||
endforeach(element)
|
endforeach(element)
|
||||||
set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE)
|
set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE)
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
# === Flutter Library ===
|
# === Flutter Library ===
|
||||||
# System-level dependencies.
|
# System-level dependencies.
|
||||||
find_package(PkgConfig REQUIRED)
|
find_package(PkgConfig REQUIRED)
|
||||||
pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0)
|
pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0)
|
||||||
pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0)
|
pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0)
|
||||||
pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0)
|
pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0)
|
||||||
|
|
||||||
set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so")
|
set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so")
|
||||||
|
|
||||||
# Published to parent scope for install step.
|
# Published to parent scope for install step.
|
||||||
set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE)
|
set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE)
|
||||||
set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE)
|
set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE)
|
||||||
set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE)
|
set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE)
|
||||||
set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE)
|
set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE)
|
||||||
|
|
||||||
list(APPEND FLUTTER_LIBRARY_HEADERS
|
list(APPEND FLUTTER_LIBRARY_HEADERS
|
||||||
"fl_basic_message_channel.h"
|
"fl_basic_message_channel.h"
|
||||||
"fl_binary_codec.h"
|
"fl_binary_codec.h"
|
||||||
"fl_binary_messenger.h"
|
"fl_binary_messenger.h"
|
||||||
"fl_dart_project.h"
|
"fl_dart_project.h"
|
||||||
"fl_engine.h"
|
"fl_engine.h"
|
||||||
"fl_json_message_codec.h"
|
"fl_json_message_codec.h"
|
||||||
"fl_json_method_codec.h"
|
"fl_json_method_codec.h"
|
||||||
"fl_message_codec.h"
|
"fl_message_codec.h"
|
||||||
"fl_method_call.h"
|
"fl_method_call.h"
|
||||||
"fl_method_channel.h"
|
"fl_method_channel.h"
|
||||||
"fl_method_codec.h"
|
"fl_method_codec.h"
|
||||||
"fl_method_response.h"
|
"fl_method_response.h"
|
||||||
"fl_plugin_registrar.h"
|
"fl_plugin_registrar.h"
|
||||||
"fl_plugin_registry.h"
|
"fl_plugin_registry.h"
|
||||||
"fl_standard_message_codec.h"
|
"fl_standard_message_codec.h"
|
||||||
"fl_standard_method_codec.h"
|
"fl_standard_method_codec.h"
|
||||||
"fl_string_codec.h"
|
"fl_string_codec.h"
|
||||||
"fl_value.h"
|
"fl_value.h"
|
||||||
"fl_view.h"
|
"fl_view.h"
|
||||||
"flutter_linux.h"
|
"flutter_linux.h"
|
||||||
)
|
)
|
||||||
list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/")
|
list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/")
|
||||||
add_library(flutter INTERFACE)
|
add_library(flutter INTERFACE)
|
||||||
target_include_directories(flutter INTERFACE
|
target_include_directories(flutter INTERFACE
|
||||||
"${EPHEMERAL_DIR}"
|
"${EPHEMERAL_DIR}"
|
||||||
)
|
)
|
||||||
target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}")
|
target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}")
|
||||||
target_link_libraries(flutter INTERFACE
|
target_link_libraries(flutter INTERFACE
|
||||||
PkgConfig::GTK
|
PkgConfig::GTK
|
||||||
PkgConfig::GLIB
|
PkgConfig::GLIB
|
||||||
PkgConfig::GIO
|
PkgConfig::GIO
|
||||||
)
|
)
|
||||||
add_dependencies(flutter flutter_assemble)
|
add_dependencies(flutter flutter_assemble)
|
||||||
|
|
||||||
# === Flutter tool backend ===
|
# === Flutter tool backend ===
|
||||||
# _phony_ is a non-existent file to force this command to run every time,
|
# _phony_ is a non-existent file to force this command to run every time,
|
||||||
# since currently there's no way to get a full input/output list from the
|
# since currently there's no way to get a full input/output list from the
|
||||||
# flutter tool.
|
# flutter tool.
|
||||||
add_custom_command(
|
add_custom_command(
|
||||||
OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS}
|
OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS}
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/_phony_
|
${CMAKE_CURRENT_BINARY_DIR}/_phony_
|
||||||
COMMAND ${CMAKE_COMMAND} -E env
|
COMMAND ${CMAKE_COMMAND} -E env
|
||||||
${FLUTTER_TOOL_ENVIRONMENT}
|
${FLUTTER_TOOL_ENVIRONMENT}
|
||||||
"${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh"
|
"${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh"
|
||||||
${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE}
|
${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE}
|
||||||
VERBATIM
|
VERBATIM
|
||||||
)
|
)
|
||||||
add_custom_target(flutter_assemble DEPENDS
|
add_custom_target(flutter_assemble DEPENDS
|
||||||
"${FLUTTER_LIBRARY}"
|
"${FLUTTER_LIBRARY}"
|
||||||
${FLUTTER_LIBRARY_HEADERS}
|
${FLUTTER_LIBRARY_HEADERS}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,26 +1,26 @@
|
|||||||
cmake_minimum_required(VERSION 3.13)
|
cmake_minimum_required(VERSION 3.13)
|
||||||
project(runner LANGUAGES CXX)
|
project(runner LANGUAGES CXX)
|
||||||
|
|
||||||
# Define the application target. To change its name, change BINARY_NAME in the
|
# Define the application target. To change its name, change BINARY_NAME in the
|
||||||
# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer
|
# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer
|
||||||
# work.
|
# work.
|
||||||
#
|
#
|
||||||
# Any new source files that you add to the application should be added here.
|
# Any new source files that you add to the application should be added here.
|
||||||
add_executable(${BINARY_NAME}
|
add_executable(${BINARY_NAME}
|
||||||
"main.cc"
|
"main.cc"
|
||||||
"my_application.cc"
|
"my_application.cc"
|
||||||
"${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc"
|
"${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Apply the standard set of build settings. This can be removed for applications
|
# Apply the standard set of build settings. This can be removed for applications
|
||||||
# that need different build settings.
|
# that need different build settings.
|
||||||
apply_standard_settings(${BINARY_NAME})
|
apply_standard_settings(${BINARY_NAME})
|
||||||
|
|
||||||
# Add preprocessor definitions for the application ID.
|
# Add preprocessor definitions for the application ID.
|
||||||
add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}")
|
add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}")
|
||||||
|
|
||||||
# Add dependency libraries. Add any application-specific dependencies here.
|
# Add dependency libraries. Add any application-specific dependencies here.
|
||||||
target_link_libraries(${BINARY_NAME} PRIVATE flutter)
|
target_link_libraries(${BINARY_NAME} PRIVATE flutter)
|
||||||
target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK)
|
target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK)
|
||||||
|
|
||||||
target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}")
|
target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}")
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#include "my_application.h"
|
#include "my_application.h"
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
g_autoptr(MyApplication) app = my_application_new();
|
g_autoptr(MyApplication) app = my_application_new();
|
||||||
return g_application_run(G_APPLICATION(app), argc, argv);
|
return g_application_run(G_APPLICATION(app), argc, argv);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,148 +1,148 @@
|
|||||||
#include "my_application.h"
|
#include "my_application.h"
|
||||||
|
|
||||||
#include <flutter_linux/flutter_linux.h>
|
#include <flutter_linux/flutter_linux.h>
|
||||||
#ifdef GDK_WINDOWING_X11
|
#ifdef GDK_WINDOWING_X11
|
||||||
#include <gdk/gdkx.h>
|
#include <gdk/gdkx.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "flutter/generated_plugin_registrant.h"
|
#include "flutter/generated_plugin_registrant.h"
|
||||||
|
|
||||||
struct _MyApplication {
|
struct _MyApplication {
|
||||||
GtkApplication parent_instance;
|
GtkApplication parent_instance;
|
||||||
char** dart_entrypoint_arguments;
|
char** dart_entrypoint_arguments;
|
||||||
};
|
};
|
||||||
|
|
||||||
G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION)
|
G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION)
|
||||||
|
|
||||||
// Called when first Flutter frame received.
|
// Called when first Flutter frame received.
|
||||||
static void first_frame_cb(MyApplication* self, FlView* view) {
|
static void first_frame_cb(MyApplication* self, FlView* view) {
|
||||||
gtk_widget_show(gtk_widget_get_toplevel(GTK_WIDGET(view)));
|
gtk_widget_show(gtk_widget_get_toplevel(GTK_WIDGET(view)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implements GApplication::activate.
|
// Implements GApplication::activate.
|
||||||
static void my_application_activate(GApplication* application) {
|
static void my_application_activate(GApplication* application) {
|
||||||
MyApplication* self = MY_APPLICATION(application);
|
MyApplication* self = MY_APPLICATION(application);
|
||||||
GtkWindow* window =
|
GtkWindow* window =
|
||||||
GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application)));
|
GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application)));
|
||||||
|
|
||||||
// Use a header bar when running in GNOME as this is the common style used
|
// Use a header bar when running in GNOME as this is the common style used
|
||||||
// by applications and is the setup most users will be using (e.g. Ubuntu
|
// by applications and is the setup most users will be using (e.g. Ubuntu
|
||||||
// desktop).
|
// desktop).
|
||||||
// If running on X and not using GNOME then just use a traditional title bar
|
// If running on X and not using GNOME then just use a traditional title bar
|
||||||
// in case the window manager does more exotic layout, e.g. tiling.
|
// in case the window manager does more exotic layout, e.g. tiling.
|
||||||
// If running on Wayland assume the header bar will work (may need changing
|
// If running on Wayland assume the header bar will work (may need changing
|
||||||
// if future cases occur).
|
// if future cases occur).
|
||||||
gboolean use_header_bar = TRUE;
|
gboolean use_header_bar = TRUE;
|
||||||
#ifdef GDK_WINDOWING_X11
|
#ifdef GDK_WINDOWING_X11
|
||||||
GdkScreen* screen = gtk_window_get_screen(window);
|
GdkScreen* screen = gtk_window_get_screen(window);
|
||||||
if (GDK_IS_X11_SCREEN(screen)) {
|
if (GDK_IS_X11_SCREEN(screen)) {
|
||||||
const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen);
|
const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen);
|
||||||
if (g_strcmp0(wm_name, "GNOME Shell") != 0) {
|
if (g_strcmp0(wm_name, "GNOME Shell") != 0) {
|
||||||
use_header_bar = FALSE;
|
use_header_bar = FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (use_header_bar) {
|
if (use_header_bar) {
|
||||||
GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new());
|
GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new());
|
||||||
gtk_widget_show(GTK_WIDGET(header_bar));
|
gtk_widget_show(GTK_WIDGET(header_bar));
|
||||||
gtk_header_bar_set_title(header_bar, "mobile");
|
gtk_header_bar_set_title(header_bar, "mobile");
|
||||||
gtk_header_bar_set_show_close_button(header_bar, TRUE);
|
gtk_header_bar_set_show_close_button(header_bar, TRUE);
|
||||||
gtk_window_set_titlebar(window, GTK_WIDGET(header_bar));
|
gtk_window_set_titlebar(window, GTK_WIDGET(header_bar));
|
||||||
} else {
|
} else {
|
||||||
gtk_window_set_title(window, "mobile");
|
gtk_window_set_title(window, "mobile");
|
||||||
}
|
}
|
||||||
|
|
||||||
gtk_window_set_default_size(window, 1280, 720);
|
gtk_window_set_default_size(window, 1280, 720);
|
||||||
|
|
||||||
g_autoptr(FlDartProject) project = fl_dart_project_new();
|
g_autoptr(FlDartProject) project = fl_dart_project_new();
|
||||||
fl_dart_project_set_dart_entrypoint_arguments(
|
fl_dart_project_set_dart_entrypoint_arguments(
|
||||||
project, self->dart_entrypoint_arguments);
|
project, self->dart_entrypoint_arguments);
|
||||||
|
|
||||||
FlView* view = fl_view_new(project);
|
FlView* view = fl_view_new(project);
|
||||||
GdkRGBA background_color;
|
GdkRGBA background_color;
|
||||||
// Background defaults to black, override it here if necessary, e.g. #00000000
|
// Background defaults to black, override it here if necessary, e.g. #00000000
|
||||||
// for transparent.
|
// for transparent.
|
||||||
gdk_rgba_parse(&background_color, "#000000");
|
gdk_rgba_parse(&background_color, "#000000");
|
||||||
fl_view_set_background_color(view, &background_color);
|
fl_view_set_background_color(view, &background_color);
|
||||||
gtk_widget_show(GTK_WIDGET(view));
|
gtk_widget_show(GTK_WIDGET(view));
|
||||||
gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view));
|
gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view));
|
||||||
|
|
||||||
// Show the window when Flutter renders.
|
// Show the window when Flutter renders.
|
||||||
// Requires the view to be realized so we can start rendering.
|
// Requires the view to be realized so we can start rendering.
|
||||||
g_signal_connect_swapped(view, "first-frame", G_CALLBACK(first_frame_cb),
|
g_signal_connect_swapped(view, "first-frame", G_CALLBACK(first_frame_cb),
|
||||||
self);
|
self);
|
||||||
gtk_widget_realize(GTK_WIDGET(view));
|
gtk_widget_realize(GTK_WIDGET(view));
|
||||||
|
|
||||||
fl_register_plugins(FL_PLUGIN_REGISTRY(view));
|
fl_register_plugins(FL_PLUGIN_REGISTRY(view));
|
||||||
|
|
||||||
gtk_widget_grab_focus(GTK_WIDGET(view));
|
gtk_widget_grab_focus(GTK_WIDGET(view));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implements GApplication::local_command_line.
|
// Implements GApplication::local_command_line.
|
||||||
static gboolean my_application_local_command_line(GApplication* application,
|
static gboolean my_application_local_command_line(GApplication* application,
|
||||||
gchar*** arguments,
|
gchar*** arguments,
|
||||||
int* exit_status) {
|
int* exit_status) {
|
||||||
MyApplication* self = MY_APPLICATION(application);
|
MyApplication* self = MY_APPLICATION(application);
|
||||||
// Strip out the first argument as it is the binary name.
|
// Strip out the first argument as it is the binary name.
|
||||||
self->dart_entrypoint_arguments = g_strdupv(*arguments + 1);
|
self->dart_entrypoint_arguments = g_strdupv(*arguments + 1);
|
||||||
|
|
||||||
g_autoptr(GError) error = nullptr;
|
g_autoptr(GError) error = nullptr;
|
||||||
if (!g_application_register(application, nullptr, &error)) {
|
if (!g_application_register(application, nullptr, &error)) {
|
||||||
g_warning("Failed to register: %s", error->message);
|
g_warning("Failed to register: %s", error->message);
|
||||||
*exit_status = 1;
|
*exit_status = 1;
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_application_activate(application);
|
g_application_activate(application);
|
||||||
*exit_status = 0;
|
*exit_status = 0;
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implements GApplication::startup.
|
// Implements GApplication::startup.
|
||||||
static void my_application_startup(GApplication* application) {
|
static void my_application_startup(GApplication* application) {
|
||||||
// MyApplication* self = MY_APPLICATION(object);
|
// MyApplication* self = MY_APPLICATION(object);
|
||||||
|
|
||||||
// Perform any actions required at application startup.
|
// Perform any actions required at application startup.
|
||||||
|
|
||||||
G_APPLICATION_CLASS(my_application_parent_class)->startup(application);
|
G_APPLICATION_CLASS(my_application_parent_class)->startup(application);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implements GApplication::shutdown.
|
// Implements GApplication::shutdown.
|
||||||
static void my_application_shutdown(GApplication* application) {
|
static void my_application_shutdown(GApplication* application) {
|
||||||
// MyApplication* self = MY_APPLICATION(object);
|
// MyApplication* self = MY_APPLICATION(object);
|
||||||
|
|
||||||
// Perform any actions required at application shutdown.
|
// Perform any actions required at application shutdown.
|
||||||
|
|
||||||
G_APPLICATION_CLASS(my_application_parent_class)->shutdown(application);
|
G_APPLICATION_CLASS(my_application_parent_class)->shutdown(application);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implements GObject::dispose.
|
// Implements GObject::dispose.
|
||||||
static void my_application_dispose(GObject* object) {
|
static void my_application_dispose(GObject* object) {
|
||||||
MyApplication* self = MY_APPLICATION(object);
|
MyApplication* self = MY_APPLICATION(object);
|
||||||
g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev);
|
g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev);
|
||||||
G_OBJECT_CLASS(my_application_parent_class)->dispose(object);
|
G_OBJECT_CLASS(my_application_parent_class)->dispose(object);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void my_application_class_init(MyApplicationClass* klass) {
|
static void my_application_class_init(MyApplicationClass* klass) {
|
||||||
G_APPLICATION_CLASS(klass)->activate = my_application_activate;
|
G_APPLICATION_CLASS(klass)->activate = my_application_activate;
|
||||||
G_APPLICATION_CLASS(klass)->local_command_line =
|
G_APPLICATION_CLASS(klass)->local_command_line =
|
||||||
my_application_local_command_line;
|
my_application_local_command_line;
|
||||||
G_APPLICATION_CLASS(klass)->startup = my_application_startup;
|
G_APPLICATION_CLASS(klass)->startup = my_application_startup;
|
||||||
G_APPLICATION_CLASS(klass)->shutdown = my_application_shutdown;
|
G_APPLICATION_CLASS(klass)->shutdown = my_application_shutdown;
|
||||||
G_OBJECT_CLASS(klass)->dispose = my_application_dispose;
|
G_OBJECT_CLASS(klass)->dispose = my_application_dispose;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void my_application_init(MyApplication* self) {}
|
static void my_application_init(MyApplication* self) {}
|
||||||
|
|
||||||
MyApplication* my_application_new() {
|
MyApplication* my_application_new() {
|
||||||
// Set the program name to the application ID, which helps various systems
|
// Set the program name to the application ID, which helps various systems
|
||||||
// like GTK and desktop environments map this running application to its
|
// like GTK and desktop environments map this running application to its
|
||||||
// corresponding .desktop file. This ensures better integration by allowing
|
// corresponding .desktop file. This ensures better integration by allowing
|
||||||
// the application to be recognized beyond its binary name.
|
// the application to be recognized beyond its binary name.
|
||||||
g_set_prgname(APPLICATION_ID);
|
g_set_prgname(APPLICATION_ID);
|
||||||
|
|
||||||
return MY_APPLICATION(g_object_new(my_application_get_type(),
|
return MY_APPLICATION(g_object_new(my_application_get_type(),
|
||||||
"application-id", APPLICATION_ID, "flags",
|
"application-id", APPLICATION_ID, "flags",
|
||||||
G_APPLICATION_NON_UNIQUE, nullptr));
|
G_APPLICATION_NON_UNIQUE, nullptr));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
#ifndef FLUTTER_MY_APPLICATION_H_
|
#ifndef FLUTTER_MY_APPLICATION_H_
|
||||||
#define FLUTTER_MY_APPLICATION_H_
|
#define FLUTTER_MY_APPLICATION_H_
|
||||||
|
|
||||||
#include <gtk/gtk.h>
|
#include <gtk/gtk.h>
|
||||||
|
|
||||||
G_DECLARE_FINAL_TYPE(MyApplication,
|
G_DECLARE_FINAL_TYPE(MyApplication,
|
||||||
my_application,
|
my_application,
|
||||||
MY,
|
MY,
|
||||||
APPLICATION,
|
APPLICATION,
|
||||||
GtkApplication)
|
GtkApplication)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* my_application_new:
|
* my_application_new:
|
||||||
*
|
*
|
||||||
* Creates a new Flutter-based application.
|
* Creates a new Flutter-based application.
|
||||||
*
|
*
|
||||||
* Returns: a new #MyApplication.
|
* Returns: a new #MyApplication.
|
||||||
*/
|
*/
|
||||||
MyApplication* my_application_new();
|
MyApplication* my_application_new();
|
||||||
|
|
||||||
#endif // FLUTTER_MY_APPLICATION_H_
|
#endif // FLUTTER_MY_APPLICATION_H_
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# Flutter-related
|
# Flutter-related
|
||||||
**/Flutter/ephemeral/
|
**/Flutter/ephemeral/
|
||||||
**/Pods/
|
**/Pods/
|
||||||
|
|
||||||
# Xcode-related
|
# Xcode-related
|
||||||
**/dgph
|
**/dgph
|
||||||
**/xcuserdata/
|
**/xcuserdata/
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
#include "ephemeral/Flutter-Generated.xcconfig"
|
#include "ephemeral/Flutter-Generated.xcconfig"
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
#include "ephemeral/Flutter-Generated.xcconfig"
|
#include "ephemeral/Flutter-Generated.xcconfig"
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
+8
-8
@@ -1,8 +1,8 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict>
|
<dict>
|
||||||
<key>IDEDidComputeMac32BitWarning</key>
|
<key>IDEDidComputeMac32BitWarning</key>
|
||||||
<true/>
|
<true/>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|||||||
@@ -1,99 +1,99 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<Scheme
|
<Scheme
|
||||||
LastUpgradeVersion = "1510"
|
LastUpgradeVersion = "1510"
|
||||||
version = "1.3">
|
version = "1.3">
|
||||||
<BuildAction
|
<BuildAction
|
||||||
parallelizeBuildables = "YES"
|
parallelizeBuildables = "YES"
|
||||||
buildImplicitDependencies = "YES">
|
buildImplicitDependencies = "YES">
|
||||||
<BuildActionEntries>
|
<BuildActionEntries>
|
||||||
<BuildActionEntry
|
<BuildActionEntry
|
||||||
buildForTesting = "YES"
|
buildForTesting = "YES"
|
||||||
buildForRunning = "YES"
|
buildForRunning = "YES"
|
||||||
buildForProfiling = "YES"
|
buildForProfiling = "YES"
|
||||||
buildForArchiving = "YES"
|
buildForArchiving = "YES"
|
||||||
buildForAnalyzing = "YES">
|
buildForAnalyzing = "YES">
|
||||||
<BuildableReference
|
<BuildableReference
|
||||||
BuildableIdentifier = "primary"
|
BuildableIdentifier = "primary"
|
||||||
BlueprintIdentifier = "33CC10EC2044A3C60003C045"
|
BlueprintIdentifier = "33CC10EC2044A3C60003C045"
|
||||||
BuildableName = "mobile.app"
|
BuildableName = "mobile.app"
|
||||||
BlueprintName = "Runner"
|
BlueprintName = "Runner"
|
||||||
ReferencedContainer = "container:Runner.xcodeproj">
|
ReferencedContainer = "container:Runner.xcodeproj">
|
||||||
</BuildableReference>
|
</BuildableReference>
|
||||||
</BuildActionEntry>
|
</BuildActionEntry>
|
||||||
</BuildActionEntries>
|
</BuildActionEntries>
|
||||||
</BuildAction>
|
</BuildAction>
|
||||||
<TestAction
|
<TestAction
|
||||||
buildConfiguration = "Debug"
|
buildConfiguration = "Debug"
|
||||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||||
<MacroExpansion>
|
<MacroExpansion>
|
||||||
<BuildableReference
|
<BuildableReference
|
||||||
BuildableIdentifier = "primary"
|
BuildableIdentifier = "primary"
|
||||||
BlueprintIdentifier = "33CC10EC2044A3C60003C045"
|
BlueprintIdentifier = "33CC10EC2044A3C60003C045"
|
||||||
BuildableName = "mobile.app"
|
BuildableName = "mobile.app"
|
||||||
BlueprintName = "Runner"
|
BlueprintName = "Runner"
|
||||||
ReferencedContainer = "container:Runner.xcodeproj">
|
ReferencedContainer = "container:Runner.xcodeproj">
|
||||||
</BuildableReference>
|
</BuildableReference>
|
||||||
</MacroExpansion>
|
</MacroExpansion>
|
||||||
<Testables>
|
<Testables>
|
||||||
<TestableReference
|
<TestableReference
|
||||||
skipped = "NO"
|
skipped = "NO"
|
||||||
parallelizable = "YES">
|
parallelizable = "YES">
|
||||||
<BuildableReference
|
<BuildableReference
|
||||||
BuildableIdentifier = "primary"
|
BuildableIdentifier = "primary"
|
||||||
BlueprintIdentifier = "331C80D4294CF70F00263BE5"
|
BlueprintIdentifier = "331C80D4294CF70F00263BE5"
|
||||||
BuildableName = "RunnerTests.xctest"
|
BuildableName = "RunnerTests.xctest"
|
||||||
BlueprintName = "RunnerTests"
|
BlueprintName = "RunnerTests"
|
||||||
ReferencedContainer = "container:Runner.xcodeproj">
|
ReferencedContainer = "container:Runner.xcodeproj">
|
||||||
</BuildableReference>
|
</BuildableReference>
|
||||||
</TestableReference>
|
</TestableReference>
|
||||||
</Testables>
|
</Testables>
|
||||||
</TestAction>
|
</TestAction>
|
||||||
<LaunchAction
|
<LaunchAction
|
||||||
buildConfiguration = "Debug"
|
buildConfiguration = "Debug"
|
||||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
launchStyle = "0"
|
launchStyle = "0"
|
||||||
useCustomWorkingDirectory = "NO"
|
useCustomWorkingDirectory = "NO"
|
||||||
ignoresPersistentStateOnLaunch = "NO"
|
ignoresPersistentStateOnLaunch = "NO"
|
||||||
debugDocumentVersioning = "YES"
|
debugDocumentVersioning = "YES"
|
||||||
debugServiceExtension = "internal"
|
debugServiceExtension = "internal"
|
||||||
enableGPUValidationMode = "1"
|
enableGPUValidationMode = "1"
|
||||||
allowLocationSimulation = "YES">
|
allowLocationSimulation = "YES">
|
||||||
<BuildableProductRunnable
|
<BuildableProductRunnable
|
||||||
runnableDebuggingMode = "0">
|
runnableDebuggingMode = "0">
|
||||||
<BuildableReference
|
<BuildableReference
|
||||||
BuildableIdentifier = "primary"
|
BuildableIdentifier = "primary"
|
||||||
BlueprintIdentifier = "33CC10EC2044A3C60003C045"
|
BlueprintIdentifier = "33CC10EC2044A3C60003C045"
|
||||||
BuildableName = "mobile.app"
|
BuildableName = "mobile.app"
|
||||||
BlueprintName = "Runner"
|
BlueprintName = "Runner"
|
||||||
ReferencedContainer = "container:Runner.xcodeproj">
|
ReferencedContainer = "container:Runner.xcodeproj">
|
||||||
</BuildableReference>
|
</BuildableReference>
|
||||||
</BuildableProductRunnable>
|
</BuildableProductRunnable>
|
||||||
</LaunchAction>
|
</LaunchAction>
|
||||||
<ProfileAction
|
<ProfileAction
|
||||||
buildConfiguration = "Profile"
|
buildConfiguration = "Profile"
|
||||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||||
savedToolIdentifier = ""
|
savedToolIdentifier = ""
|
||||||
useCustomWorkingDirectory = "NO"
|
useCustomWorkingDirectory = "NO"
|
||||||
debugDocumentVersioning = "YES">
|
debugDocumentVersioning = "YES">
|
||||||
<BuildableProductRunnable
|
<BuildableProductRunnable
|
||||||
runnableDebuggingMode = "0">
|
runnableDebuggingMode = "0">
|
||||||
<BuildableReference
|
<BuildableReference
|
||||||
BuildableIdentifier = "primary"
|
BuildableIdentifier = "primary"
|
||||||
BlueprintIdentifier = "33CC10EC2044A3C60003C045"
|
BlueprintIdentifier = "33CC10EC2044A3C60003C045"
|
||||||
BuildableName = "mobile.app"
|
BuildableName = "mobile.app"
|
||||||
BlueprintName = "Runner"
|
BlueprintName = "Runner"
|
||||||
ReferencedContainer = "container:Runner.xcodeproj">
|
ReferencedContainer = "container:Runner.xcodeproj">
|
||||||
</BuildableReference>
|
</BuildableReference>
|
||||||
</BuildableProductRunnable>
|
</BuildableProductRunnable>
|
||||||
</ProfileAction>
|
</ProfileAction>
|
||||||
<AnalyzeAction
|
<AnalyzeAction
|
||||||
buildConfiguration = "Debug">
|
buildConfiguration = "Debug">
|
||||||
</AnalyzeAction>
|
</AnalyzeAction>
|
||||||
<ArchiveAction
|
<ArchiveAction
|
||||||
buildConfiguration = "Release"
|
buildConfiguration = "Release"
|
||||||
revealArchiveInOrganizer = "YES">
|
revealArchiveInOrganizer = "YES">
|
||||||
</ArchiveAction>
|
</ArchiveAction>
|
||||||
</Scheme>
|
</Scheme>
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user